From 183d46a33182b9db029c6118b9e5371a08c148af Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 27 Sep 2010 21:05:12 +0000 Subject: [PATCH] New Programmable Logic Devices (PLD) subsystem by Michael Walle git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1852 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- urjtag/ChangeLog | 7 + urjtag/configure.ac | 1 + urjtag/doc/Makefile.am | 1 + urjtag/doc/README.pld | 34 ++ urjtag/include/urjtag/Makefile.am | 1 + urjtag/include/urjtag/error.h | 2 + urjtag/include/urjtag/pld.h | 128 +++++ urjtag/src/Makefile.am | 2 + urjtag/src/cmd/Makefile.am | 3 +- urjtag/src/cmd/cmd_list.h | 1 + urjtag/src/cmd/cmd_pld.c | 156 ++++++ urjtag/src/global/log-error.c | 2 + urjtag/src/pld/Makefile.am | 33 ++ urjtag/src/pld/pld.c | 200 ++++++++ urjtag/src/pld/xilinx.c | 784 ++++++++++++++++++++++++++++++ urjtag/src/pld/xilinx.h | 125 +++++ urjtag/src/pld/xilinx_bitstream.c | 145 ++++++ 17 files changed, 1624 insertions(+), 1 deletion(-) create mode 100644 urjtag/doc/README.pld create mode 100644 urjtag/include/urjtag/pld.h create mode 100644 urjtag/src/cmd/cmd_pld.c create mode 100644 urjtag/src/pld/Makefile.am create mode 100644 urjtag/src/pld/pld.c create mode 100644 urjtag/src/pld/xilinx.c create mode 100644 urjtag/src/pld/xilinx.h create mode 100644 urjtag/src/pld/xilinx_bitstream.c diff --git a/urjtag/ChangeLog b/urjtag/ChangeLog index 6b15f7d0..aa8751f6 100644 --- a/urjtag/ChangeLog +++ b/urjtag/ChangeLog @@ -21,6 +21,13 @@ * include/urjtag/tap_register.h, src/tap/register.c (urj_tap_register_realloc): Likewise. + * include/urjtag/Makefile.am, include/urjtag/pld.h, include/urjtag/error.h, + src/Makefile.am, src/pld/Makefile.am, src/pld/pld.c, src/pld/xilinx.h, + src/pld/xilinx.c, src/pld/xilinx_bitstream.c, + src/cmd/Makefile.am, src/cmd/cmd_pld.c, src/cmd/cmd_list.h, + doc/Makefile.am, doc/README.pld, src/global/log-error.c, configure.ac: + New Programmable Logic Devices (PLD) subsystem by Michael Walle. + 2010-08-30 Mike Frysinger * configure.ac: Clean up libusb detection to prefer 1.0 over 0.1, and accept diff --git a/urjtag/configure.ac b/urjtag/configure.ac index 74692763..1c7075ae 100644 --- a/urjtag/configure.ac +++ b/urjtag/configure.ac @@ -78,6 +78,7 @@ AC_CONFIG_FILES( src/svf/Makefile src/bsdl/Makefile src/jim/Makefile + src/pld/Makefile src/global/Makefile src/apps/jtag/Makefile src/apps/bsdl2jtag/Makefile diff --git a/urjtag/doc/Makefile.am b/urjtag/doc/Makefile.am index fd0f6283..f6f52da5 100644 --- a/urjtag/doc/Makefile.am +++ b/urjtag/doc/Makefile.am @@ -30,6 +30,7 @@ EXTRA_DIST = \ fdl.txt \ UrJTAG.txt \ README.ejtag \ + README.pld \ howto_add_support_for_more_flash.txt \ $(man_MANS) diff --git a/urjtag/doc/README.pld b/urjtag/doc/README.pld new file mode 100644 index 00000000..0b672ff0 --- /dev/null +++ b/urjtag/doc/README.pld @@ -0,0 +1,34 @@ +With the Programmable Logic Devices (PLD) subsystem you can load a bitstream +into a FPGA via JTAG. Besides benefits in development it supports production +of boards with NOR flashes connected to the FPGA. You can load a fjmem core +into the FPGA and program (fast!) the flash through it. + +The subsystem needs several instructions to be defined. These have to be +manually added by the user (eg. through the ~/.jtag/rc): + + Spartan-3/Spartan-6: + instruction CFG_OUT 000100 BYPASS + instruction CFG_IN 000101 BYPASS + instruction JSTART 001100 BYPASS + instruction JPROGRAM 001011 BYPASS + + Virtex-4: + instruction CFG_OUT 1111000100 BYPASS + instruction CFG_IN 1111000101 BYPASS + instruction JPROGRAM 1111001011 BYPASS + instruction JSTART 1111001100 BYPASS + + +The following example flashes a NOR flash connected to the FGPA: + + cable Turtelizer2 vid=0x0403 pid=0x6010 + detect + instruction CFG_OUT 000100 BYPASS + instruction CFG_IN 000101 BYPASS + instruction JSTART 001100 BYPASS + instruction JPROGRAM 001011 BYPASS + pld load /path/to/fjmem.bit + initbus fjmem opcode=000010 + detectflash 0 + flashmem 0 /path/to/data.bin + pld reconfigure diff --git a/urjtag/include/urjtag/Makefile.am b/urjtag/include/urjtag/Makefile.am index ece50530..0f0cb9e1 100644 --- a/urjtag/include/urjtag/Makefile.am +++ b/urjtag/include/urjtag/Makefile.am @@ -49,6 +49,7 @@ pkginclude_HEADERS = \ parse.h \ part.h \ part_instruction.h \ + pld.h \ pod.h \ tap_register.h \ tap_state.h \ diff --git a/urjtag/include/urjtag/error.h b/urjtag/include/urjtag/error.h index 35e119c9..ee47fa3d 100644 --- a/urjtag/include/urjtag/error.h +++ b/urjtag/include/urjtag/error.h @@ -70,6 +70,8 @@ typedef enum URJ_ERROR URJ_ERROR_BFIN, + URJ_ERROR_PLD, + URJ_ERROR_UNIMPLEMENTED, } urj_error_t; diff --git a/urjtag/include/urjtag/pld.h b/urjtag/include/urjtag/pld.h new file mode 100644 index 00000000..5db4b24e --- /dev/null +++ b/urjtag/include/urjtag/pld.h @@ -0,0 +1,128 @@ +/* + * $Id$ + * + * Support for Programmable Logic Devices (PLD) + * + * Copyright (C) 2010, Michael Walle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Michael Walle , 2010 + * + */ + +#ifndef URJ_PLD_H +#define URJ_PLD_H + +#include +#include + +#include "types.h" + +typedef struct +{ + urj_chain_t *chain; + urj_part_t *part; + void *priv; +} urj_pld_t; + +typedef struct +{ + const char *name; + int (*detect) (urj_pld_t *pld); + int (*print_status) (urj_pld_t *pld); + int (*configure) (urj_pld_t *pld, FILE *pld_file); + int (*reconfigure) (urj_pld_t *pld); + int (*read_register) (urj_pld_t *pld, uint32_t reg, uint32_t *value); + int (*write_register) (urj_pld_t *pld, uint32_t reg, uint32_t value); + int register_width; +} urj_pld_driver_t; + +/** + * urj_pld_configure(chain, pld_file) + * + * Main entry point for the 'pld load' command. + * + * XXX Description here + * + * @param chain pointer to global chain + * @param pld_file file handle of PLD file + * + * @return + * URJ_STATUS_OK, URJ_STATUS_FAIL + */ +int urj_pld_configure (urj_chain_t *chain, FILE *pld_file); + +/** + * urj_pld_reconfigure(chain) + * + * Main entry point for the 'pld reconfigure' command. + * + * XXX Description here + * + * @param chain pointer to global chain + * + * @return + * URJ_STATUS_OK, URJ_STATUS_FAIL + */ +int urj_pld_reconfigure (urj_chain_t *chain); + +/** + * urj_pld_status(chain) + * + * Main entry point for the 'pld status' command. + * + * XXX Description here + * + * @param chain pointer to global chain + * + * @return + * URJ_STATUS_OK, URJ_STATUS_FAIL + */ +int urj_pld_print_status (urj_chain_t *chain); + +/** + * urj_pld_read_register(chain) + * + * Main entry point for the 'pld readreg' command. + * + * XXX Description here + * + * @param chain pointer to global chain + * @param reg register number + * + * @return + * URJ_STATUS_OK, URJ_STATUS_FAIL + */ +int urj_pld_read_register (urj_chain_t *chain, uint32_t reg); + +/** + * urj_pld_write_register(chain) + * + * Main entry point for the 'pld writereg' command. + * + * XXX Description here + * + * @param chain pointer to global chain + * @param reg register number + * @param value value + * + * @return + * URJ_STATUS_OK, URJ_STATUS_FAIL + */ +int urj_pld_write_register (urj_chain_t *chain, uint32_t reg, uint32_t value); + +#endif /* URJ_PLD_H */ diff --git a/urjtag/src/Makefile.am b/urjtag/src/Makefile.am index 708e03af..6be03a5f 100644 --- a/urjtag/src/Makefile.am +++ b/urjtag/src/Makefile.am @@ -31,6 +31,7 @@ SUBDIRS = \ bfin \ bus \ cmd \ + pld \ global if ENABLE_SVF @@ -61,6 +62,7 @@ liburjtag_la_LIBADD = \ bfin/libbfin.la \ bus/libbus.la \ cmd/libcmd.la \ + pld/libpld.la \ global/libglobal.la \ -lm \ @FTD2XXLIB@ \ diff --git a/urjtag/src/cmd/Makefile.am b/urjtag/src/cmd/Makefile.am index a240c877..2a7fcddb 100644 --- a/urjtag/src/cmd/Makefile.am +++ b/urjtag/src/cmd/Makefile.am @@ -65,7 +65,8 @@ libcmd_la_SOURCES = \ cmd_addpart.c \ cmd_cmd.c \ cmd_usleep.c \ - cmd_bfin.c + cmd_bfin.c \ + cmd_pld.c if ENABLE_SVF libcmd_la_SOURCES += cmd_svf.c diff --git a/urjtag/src/cmd/cmd_list.h b/urjtag/src/cmd/cmd_list.h index 48e5b324..8aa6833a 100644 --- a/urjtag/src/cmd/cmd_list.h +++ b/urjtag/src/cmd/cmd_list.h @@ -61,6 +61,7 @@ _URJ_CMD(initbus) _URJ_CMD(instruction) _URJ_CMD(part) _URJ_CMD(peek) +_URJ_CMD(pld) _URJ_CMD(pod) _URJ_CMD(poke) _URJ_CMD(print) diff --git a/urjtag/src/cmd/cmd_pld.c b/urjtag/src/cmd/cmd_pld.c new file mode 100644 index 00000000..ec9c7ec5 --- /dev/null +++ b/urjtag/src/cmd/cmd_pld.c @@ -0,0 +1,156 @@ +/* + * $Id$ + * + * Support for Programmable Logic Devices (PLD) + * + * Copyright (C) 2010, Michael Walle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Michael Walle , 2010 + * + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "cmd.h" + +static int +cmd_pld_run (urj_chain_t *chain, char *params[]) +{ + FILE *pld_file; + int num_params; + int result = URJ_STATUS_OK; + + num_params = urj_cmd_params (params); + if (num_params < 2) + { + urj_error_set (URJ_ERROR_SYNTAX, + _("%s: #parameters should be >= %d, not %d"), + params[0], 2, urj_cmd_params (params)); + return URJ_STATUS_FAIL; + } + + if (strcasecmp (params[1], "load") == 0) + { + if (num_params < 3) + { + urj_error_set (URJ_ERROR_SYNTAX, + _("%s: no filename specified"), + params[0]); + return URJ_STATUS_FAIL; + } + + if ((pld_file = fopen (params[2], "rb")) != NULL) + { + result = urj_pld_configure (chain, pld_file); + fclose (pld_file); + } + else + { + urj_error_IO_set (_("%s: cannot open file '%s'"), + params[0], params[1]); + result = URJ_STATUS_FAIL; + } + } + else if (strcasecmp (params[1], "status") == 0) + { + result = urj_pld_print_status (chain); + } + else if (strcasecmp (params[1], "readreg") == 0) + { + unsigned long reg; + + if (num_params < 3) + { + urj_error_set (URJ_ERROR_SYNTAX, + _("%s: #parameters should be >= %d, not %d"), + params[0], 3, urj_cmd_params (params)); + return URJ_STATUS_FAIL; + } + + if (urj_cmd_get_number (params[2], ®) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + result = urj_pld_read_register (chain, reg); + } + else if (strcasecmp (params[1], "writereg") == 0) + { + unsigned long reg; + unsigned long value; + + if (num_params < 4) + { + urj_error_set (URJ_ERROR_SYNTAX, + _("%s: #parameters should be >= %d, not %d"), + params[0], 4, urj_cmd_params (params)); + return URJ_STATUS_FAIL; + } + + if (urj_cmd_get_number (params[2], ®) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (urj_cmd_get_number (params[3], &value) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + result = urj_pld_write_register (chain, reg, value); + } + else if (strcasecmp (params[1], "reconfigure") == 0) + { + result = urj_pld_reconfigure (chain); + } + else + { + urj_error_set (URJ_ERROR_SYNTAX, + _("%s: unkown command"), params[0]); + return URJ_STATUS_FAIL; + } + + return result; +} + + +static void +cmd_pld_help (void) +{ + urj_log (URJ_LOG_LEVEL_NORMAL, + _("Usage: %s load PLDFILE\n" + "Usage: %s reconfigure\n" + "Usage: %s status\n" + "Usage: %s readreg REG\n" + "Usage: %s writereg REG VALUE\n" + "Configure FPGA from PLDFILE, query status, read and write registers.\n"), + "pld", "pld", "pld", "pld", "pld"); +} + +const urj_cmd_t urj_cmd_pld = { + "pld", + N_("configure a Programmable Logic Device from file"), + cmd_pld_help, + cmd_pld_run +}; diff --git a/urjtag/src/global/log-error.c b/urjtag/src/global/log-error.c index 458a4868..f6b2ff25 100644 --- a/urjtag/src/global/log-error.c +++ b/urjtag/src/global/log-error.c @@ -132,6 +132,8 @@ urj_error_string (urj_error_t err) case URJ_ERROR_BFIN: return "blackfin"; + case URJ_ERROR_PLD: return "pld subsystem"; + case URJ_ERROR_UNIMPLEMENTED: return "unimplemented"; } diff --git a/urjtag/src/pld/Makefile.am b/urjtag/src/pld/Makefile.am new file mode 100644 index 00000000..08244b38 --- /dev/null +++ b/urjtag/src/pld/Makefile.am @@ -0,0 +1,33 @@ +# +# $Id$ +# +# Copyright (C) 2010 Michael Walle +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# +# Written by Michael Walle , 2010. +# + +include $(top_srcdir)/Makefile.rules + +noinst_LTLIBRARIES = libpld.la + +libpld_la_SOURCES = \ + pld.c \ + xilinx_bitstream.c \ + xilinx.c + +AM_CFLAGS = $(WARNINGCFLAGS) diff --git a/urjtag/src/pld/pld.c b/urjtag/src/pld/pld.c new file mode 100644 index 00000000..53cd1b53 --- /dev/null +++ b/urjtag/src/pld/pld.c @@ -0,0 +1,200 @@ +/* + * $Id$ + * + * Support for Programmable Logic Devices (PLD) + * + * Copyright (C) 2010, Michael Walle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Michael Walle , 2010 + * + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "xilinx.h" + +const urj_pld_driver_t * const urj_pld_drivers[] = { + &urj_pld_xc3s_driver, + &urj_pld_xc6s_driver, + &urj_pld_xc4v_driver, + NULL +}; + +static const urj_pld_driver_t *pld_driver = NULL; +static urj_pld_t pld; + +static int +set_pld_driver (urj_chain_t *chain, urj_part_t *part) +{ + int i; + uint32_t idcode; + + pld_driver = NULL; + pld.chain = chain; + pld.part = part; + + for (i = 0; urj_pld_drivers[i] != NULL; i++) + { + if (urj_pld_drivers[i]->detect (&pld) == URJ_STATUS_OK) + { + pld_driver = urj_pld_drivers[i]; + return URJ_STATUS_OK; + } + } + + idcode = urj_tap_register_get_value (part->id); + urj_log (URJ_LOG_LEVEL_ERROR, + _("No PLD driver for device with ID %08x\n"), + idcode); + + urj_error_set (URJ_ERROR_UNSUPPORTED, _("PLD not supported")); + + return URJ_STATUS_FAIL; +} + +int +urj_pld_configure (urj_chain_t *chain, FILE *pld_file) +{ + urj_part_t *part; + + part = urj_tap_chain_active_part (chain); + + if (part == NULL) + return URJ_STATUS_FAIL; + + if (set_pld_driver (chain, part) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (pld_driver->configure == NULL) + { + urj_error_set (URJ_ERROR_UNSUPPORTED, + _("PLD doesn't support this operation")); + return URJ_STATUS_FAIL; + } + + return pld_driver->configure (&pld, pld_file); +} + +int +urj_pld_reconfigure (urj_chain_t *chain) +{ + urj_part_t *part; + + part = urj_tap_chain_active_part (chain); + + if (part == NULL) + return URJ_STATUS_FAIL; + + if (set_pld_driver (chain, part) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (pld_driver->reconfigure == NULL) + { + urj_error_set (URJ_ERROR_UNSUPPORTED, + _("PLD doesn't support this operation")); + return URJ_STATUS_FAIL; + } + + return pld_driver->reconfigure (&pld); +} + +int +urj_pld_print_status (urj_chain_t *chain) +{ + urj_part_t *part; + + part = urj_tap_chain_active_part (chain); + + if (part == NULL) + return URJ_STATUS_FAIL; + + if (set_pld_driver (chain, part) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (pld_driver->print_status == NULL) + { + urj_error_set (URJ_ERROR_UNSUPPORTED, + _("PLD doesn't support this operation")); + return URJ_STATUS_FAIL; + } + + return pld_driver->print_status (&pld); +} + +int +urj_pld_read_register (urj_chain_t *chain, uint32_t reg) +{ + urj_part_t *part; + uint32_t value; + + part = urj_tap_chain_active_part (chain); + + if (part == NULL) + return URJ_STATUS_FAIL; + + if (set_pld_driver (chain, part) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (pld_driver->read_register == NULL) + { + urj_error_set (URJ_ERROR_UNSUPPORTED, + _("PLD doesn't support this operation")); + return URJ_STATUS_FAIL; + } + + if (pld_driver->read_register (&pld, reg, &value) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_log (URJ_LOG_LEVEL_NORMAL, N_("REG[%d]=0x%0*x\n"), + reg, pld_driver->register_width * 2, value); + + return URJ_STATUS_OK; +} + +int +urj_pld_write_register (urj_chain_t *chain, uint32_t reg, uint32_t data) +{ + urj_part_t *part; + + part = urj_tap_chain_active_part (chain); + + if (part == NULL) + return URJ_STATUS_FAIL; + + if (set_pld_driver (chain, part) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (pld_driver->write_register == NULL) + { + urj_error_set (URJ_ERROR_UNSUPPORTED, + _("PLD doesn't support this operation")); + return URJ_STATUS_FAIL; + } + + return pld_driver->write_register (&pld, reg, data); +} diff --git a/urjtag/src/pld/xilinx.c b/urjtag/src/pld/xilinx.c new file mode 100644 index 00000000..9527cef9 --- /dev/null +++ b/urjtag/src/pld/xilinx.c @@ -0,0 +1,784 @@ +/* + * $Id$ + * + * Driver for Xilinx FPGAs + * + * Copyright (C) 2010, Michael Walle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Michael Walle , 2010 + * + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xilinx.h" + +static int +xlx_set_ir_and_shift (urj_chain_t *chain, urj_part_t *part, char *iname) +{ + urj_part_set_instruction (part, iname); + if (part->active_instruction == NULL) + { + urj_error_set (URJ_ERROR_PLD, "unknown instruction '%s'", iname); + return URJ_STATUS_FAIL; + } + urj_tap_chain_shift_instructions (chain); + + return URJ_STATUS_OK; +} + +static int +xlx_set_dr_and_shift (urj_chain_t *chain, urj_part_t *part, + uint64_t value, int exitmode) +{ + if (part->active_instruction == NULL) + return URJ_STATUS_FAIL; + + urj_tap_register_t *r = part->active_instruction->data_register->in; + urj_tap_register_set_value (r, value); + urj_tap_defer_shift_register (chain, r, NULL, exitmode); + + return URJ_STATUS_OK; +} + +static int +xlx_instruction_resize_dr (urj_part_t *part, const char *ir_name, + const char *dr_name, int dr_len) +{ + urj_data_register_t *d; + urj_part_instruction_t *i; + + i = urj_part_find_instruction (part, ir_name); + + if (i == NULL) + { + urj_error_set (URJ_ERROR_PLD, "unknown instruction '%s'", ir_name); + return URJ_STATUS_FAIL; + } + + d = urj_part_find_data_register (part, dr_name); + + if (d == NULL) + { + d = urj_part_data_register_alloc (dr_name, dr_len); + d->next = part->data_registers; + part->data_registers = d; + } + else if (d->in->len != dr_len) + { + /* data register length does not match */ + urj_part_data_register_realloc (d, dr_len); + } + + i->data_register = d; + + return URJ_STATUS_OK; +} + +static int +xlx_write_register_xc3s (urj_pld_t *pld, uint32_t reg, uint32_t value) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + + if (value & 0xffff0000) + { + urj_log (URJ_LOG_LEVEL_WARNING, + _("Only 16 bit values supported. Truncating value.")); + + value &= 0xffff; + } + + /* use the same data register as they have the same length */ + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + if (xlx_instruction_resize_dr (part, "CFG_OUT", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_capture_dr (chain); + /* sync */ + xlx_set_dr_and_shift (chain, part, flip16 (0xffff), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0xaa99), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + /* type 2 packet (word count = 1) */ + reg = 0x3001 | ((reg & 0x3f) << 5); + xlx_set_dr_and_shift (chain, part, flip16 (reg), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (value), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_IDLE); + + urj_tap_chain_flush (chain); + + return URJ_STATUS_OK; +} + +static int +xlx_write_register_xc4v (urj_pld_t *pld, uint32_t reg, uint32_t value) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + + /* use the same data register as they have the same length */ + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", 32) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + if (xlx_instruction_resize_dr (part, "CFG_OUT", "CFG_DR", 32) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_capture_dr (chain); + /* sync */ + xlx_set_dr_and_shift (chain, part, flip32 (0xffffffff), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip32 (0xaa995566), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip32 (0x20000000), + URJ_CHAIN_EXITMODE_SHIFT); + /* type 2 packet (word count = 1) */ + reg = 0x30000001 | ((reg & 0x1f) << 13); + xlx_set_dr_and_shift (chain, part, flip32 (reg), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip32 (value), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip32 (0x20000000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip32 (0x20000000), + URJ_CHAIN_EXITMODE_IDLE); + + urj_tap_chain_flush (chain); + + return URJ_STATUS_OK; +} + +static int +xlx_write_register_xc6s (urj_pld_t *pld, uint32_t reg, uint32_t value) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + + if (value & 0xffff0000) + { + urj_log (URJ_LOG_LEVEL_WARNING, + _("Only 16 bit values supported. Truncating value.")); + + value &= 0xffff; + } + + /* use the same data register as they have the same length */ + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + if (xlx_instruction_resize_dr (part, "CFG_OUT", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_capture_dr (chain); + /* sync */ + xlx_set_dr_and_shift (chain, part, flip16 (0xaa99), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x5566), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + /* type 2 packet (word count = 1) */ + reg = 0x3001 | ((reg & 0x3f) << 5); + xlx_set_dr_and_shift (chain, part, flip16 (reg), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (value), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_IDLE); + + urj_tap_chain_flush (chain); + + return URJ_STATUS_OK; +} + +static int +xlx_read_register_xc3s (urj_pld_t *pld, uint32_t reg, uint32_t *value) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + urj_tap_register_t *r; + + /* use the same data register as they have the same length */ + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + if (xlx_instruction_resize_dr (part, "CFG_OUT", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_capture_dr (chain); + /* sync */ + xlx_set_dr_and_shift (chain, part, flip16 (0xffff), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0xaa99), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + /* type 1 packet (word count = 1) */ + reg = 0x2801 | ((reg & 0x3f) << 5); + xlx_set_dr_and_shift (chain, part, flip16 (reg), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_IDLE); + + if (xlx_set_ir_and_shift (chain, part, "CFG_OUT") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_chain_shift_data_registers (chain, 1); + + r = part->active_instruction->data_register->out; + + *value = flip16 (urj_tap_register_get_value (r)); + + return URJ_STATUS_OK; +} + +static int +xlx_read_register_xc4v (urj_pld_t *pld, uint32_t reg, uint32_t *value) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + urj_tap_register_t *r; + + /* use the same data register as they have the same length */ + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", 32) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + if (xlx_instruction_resize_dr (part, "CFG_OUT", "CFG_DR", 32) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_capture_dr (chain); + /* sync */ + xlx_set_dr_and_shift (chain, part, flip32 (0xffffffff), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip32 (0xaa995566), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip32 (0x20000000), + URJ_CHAIN_EXITMODE_SHIFT); + /* type 1 packet (word count = 1) */ + reg = 0x28000001 | ((reg & 0x1f) << 13); + xlx_set_dr_and_shift (chain, part, flip32 (reg), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip32 (0x20000000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip32 (0x20000000), + URJ_CHAIN_EXITMODE_IDLE); + + if (xlx_set_ir_and_shift (chain, part, "CFG_OUT") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_chain_shift_data_registers (chain, 1); + + r = part->active_instruction->data_register->out; + + *value = flip32 (urj_tap_register_get_value (r)); + + return URJ_STATUS_OK; +} + +static int +xlx_read_register_xc6s (urj_pld_t *pld, uint32_t reg, uint32_t *value) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + urj_tap_register_t *r; + + /* use the same data register as they have the same length */ + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + if (xlx_instruction_resize_dr (part, "CFG_OUT", "CFG_DR", 16) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_capture_dr (chain); + /* sync */ + xlx_set_dr_and_shift (chain, part, flip16 (0xffff), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0xaa99), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x5566), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + /* type 1 packet (word count = 1) */ + reg = 0x2801 | ((reg & 0x3f) << 5); + xlx_set_dr_and_shift (chain, part, flip16 (reg), + URJ_CHAIN_EXITMODE_SHIFT); + /* noop */ + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_SHIFT); + xlx_set_dr_and_shift (chain, part, flip16 (0x2000), + URJ_CHAIN_EXITMODE_IDLE); + + if (xlx_set_ir_and_shift (chain, part, "CFG_OUT") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_chain_shift_data_registers (chain, 1); + + r = part->active_instruction->data_register->out; + + *value = flip16 (urj_tap_register_get_value (r)); + + return URJ_STATUS_OK; +} + +static int +xlx_print_status_xc3s (urj_pld_t *pld) +{ + uint32_t status; + + if (xlx_read_register_xc3s (pld, XILINX_XC3S_REG_STAT, &status) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_log (URJ_LOG_LEVEL_NORMAL, _("Status register (0x%04x)\n"), status); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tSYNC_TIMEOUT %d\n"), + (status & XC3S_STATUS_SYNC_TIMEOUT) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tSEUR_ERR %d\n"), + (status & XC3S_STATUS_SEU_ERR) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDONE %d\n"), + (status & XC3S_STATUS_DONE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tINIT %d\n"), + (status & XC3S_STATUS_INIT) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tMODE_M2 %d\n"), + (status & XC3S_STATUS_MODE_M2) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tMODE_M1 %d\n"), + (status & XC3S_STATUS_MODE_M1) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tMODE_M0 %d\n"), + (status & XC3S_STATUS_MODE_M0) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tVSEL_VS2 %d\n"), + (status & XC3S_STATUS_VSEL_VS2) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tVSEL_VS1 %d\n"), + (status & XC3S_STATUS_VSEL_VS1) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tVSEL_VS0 %d\n"), + (status & XC3S_STATUS_VSEL_VS0) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tGHIGH_B %d\n"), + (status & XC3S_STATUS_GHIGH_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tGWE %d\n"), + (status & XC3S_STATUS_GWE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tGTS_CFG_B %d\n"), + (status & XC3S_STATUS_GTS_CFG_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDCM_LOCK %d\n"), + (status & XC3S_STATUS_DCM_LOCK) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tID_ERROR %d\n"), + (status & XC3S_STATUS_ID_ERROR) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tCRC_ERROR %d\n"), + (status & XC3S_STATUS_CRC_ERROR) ? 1 : 0); + + return URJ_STATUS_OK; +} + +static int +xlx_print_status_xc4v (urj_pld_t *pld) +{ + uint32_t status; + + if (xlx_read_register_xc4v (pld, XILINX_XC4V_REG_STAT, &status) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_log (URJ_LOG_LEVEL_NORMAL, _("Status register (0x%08x)\n"), status); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_DEC_ERROR %d\n"), + (status & XC4V_STATUS_DEC_ERROR) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_ID_ERROR %d\n"), + (status & XC4V_STATUS_ID_ERROR) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_DONE %d\n"), + (status & XC4V_STATUS_DONE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_RELEASE_DONE %d\n"), + (status & XC4V_STATUS_RELEASE_DONE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_INIT %d\n"), + (status & XC4V_STATUS_INIT) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_INIT_COMPLETE %d\n"), + (status & XC4V_STATUS_INIT_COMPLETE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_MODE_M2 %d\n"), + (status & XC4V_STATUS_MODE_M2) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_MODE_M1 %d\n"), + (status & XC4V_STATUS_MODE_M1) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_MODE_M0 %d\n"), + (status & XC4V_STATUS_MODE_M0) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_GHIGH_B %d\n"), + (status & XC4V_STATUS_GHIGH_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_GWE %d\n"), + (status & XC4V_STATUS_GWE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_GTS_CFG_B %d\n"), + (status & XC4V_STATUS_GTS_CFG_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_EOS %d\n"), + (status & XC4V_STATUS_EOS) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_DCI_MATCH %d\n"), + (status & XC4V_STATUS_DCI_MATCH) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_DCM_LOCK %d\n"), + (status & XC4V_STATUS_DCM_LOCK) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_PART_SECURED %d\n"), + (status & XC4V_STATUS_PART_SECURED) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tXC4V_STATUS_CRC_ERROR %d\n"), + (status & XC4V_STATUS_CRC_ERROR) ? 1 : 0); + + return URJ_STATUS_OK; +} + + +static int +xlx_print_status_xc6s (urj_pld_t *pld) +{ + uint32_t status; + + if (xlx_read_register_xc6s (pld, XILINX_XC6S_REG_STAT, &status) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_log (URJ_LOG_LEVEL_NORMAL, _("Status register (0x%04x)\n"), status); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tSWWD %d\n"), + (status & XC6S_STATUS_SWWD) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tIN_PWRDN %d\n"), + (status & XC6S_STATUS_IN_PWRDN) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDONE %d\n"), + (status & XC6S_STATUS_DONE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tINIT_B %d\n"), + (status & XC6S_STATUS_INIT_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tMODE_M1 %d\n"), + (status & XC6S_STATUS_MODE_M1) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tMODE_M0 %d\n"), + (status & XC6S_STATUS_MODE_M0) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tHSWAPEN %d\n"), + (status & XC6S_STATUS_HSWAPEN) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tPART_SECURED %d\n"), + (status & XC6S_STATUS_PART_SECURED) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDEC_ERROR %d\n"), + (status & XC6S_STATUS_DEC_ERROR) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tGHIGH_B %d\n"), + (status & XC6S_STATUS_GHIGH_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tGWE %d\n"), + (status & XC6S_STATUS_GWE) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tGTS_CFG_B %d\n"), + (status & XC6S_STATUS_GTS_CFG_B) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDCM_LOCK %d\n"), + (status & XC6S_STATUS_DCM_LOCK) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tID_ERROR %d\n"), + (status & XC6S_STATUS_ID_ERROR) ? 1 : 0); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tCRC_ERROR %d\n"), + (status & XC6S_STATUS_CRC_ERROR) ? 1 : 0); + + return URJ_STATUS_OK; +} + +static int +xlx_configure (urj_pld_t *pld, FILE *bit_file) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + urj_part_instruction_t *i; + xlx_bitstream_t *bs; + uint32_t u; + int dr_len; + char *dr_data; + int status = URJ_STATUS_OK; + + /* set all devices in bypass mode */ + urj_tap_reset_bypass (chain); + + bs = xlx_bitstream_alloc (); + if (bs == NULL) + { + status = URJ_STATUS_FAIL; + goto fail; + } + + /* parse bit file */ + if (xlx_bitstream_load_bit (bit_file, bs) != URJ_STATUS_OK) + { + urj_error_set (URJ_ERROR_PLD, _("Invalid bitfile")); + + status = URJ_STATUS_FAIL; + goto fail_free; + } + + urj_log (URJ_LOG_LEVEL_NORMAL, _("Bitstream information:\n")); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDesign: %s\n"), bs->design); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tPart name: %s\n"), bs->part_name); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tDate: %s\n"), bs->date); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tTime: %s\n"), bs->time); + urj_log (URJ_LOG_LEVEL_NORMAL, _("\tBitstream length: %d\n"), bs->length); + + dr_len = bs->length * 8; + + if (xlx_instruction_resize_dr (part, "CFG_IN", "CFG_DR", dr_len) + != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + i = urj_part_find_instruction (part, "CFG_IN"); + + /* copy data into shift register */ + dr_data = i->data_register->in->data; + for (u = 0; u < bs->length; u++) + { + /* flip bits */ + dr_data[8*u+0] = (bs->data[u] & 0x80) ? 1 : 0; + dr_data[8*u+1] = (bs->data[u] & 0x40) ? 1 : 0; + dr_data[8*u+2] = (bs->data[u] & 0x20) ? 1 : 0; + dr_data[8*u+3] = (bs->data[u] & 0x10) ? 1 : 0; + dr_data[8*u+4] = (bs->data[u] & 0x08) ? 1 : 0; + dr_data[8*u+5] = (bs->data[u] & 0x04) ? 1 : 0; + dr_data[8*u+6] = (bs->data[u] & 0x02) ? 1 : 0; + dr_data[8*u+7] = (bs->data[u] & 0x01) ? 1 : 0; + } + + if (xlx_set_ir_and_shift (chain, part, "JPROGRAM") != URJ_STATUS_OK) + { + status = URJ_STATUS_FAIL; + goto fail_free; + } + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + { + status = URJ_STATUS_FAIL; + goto fail_free; + } + + /* wait until device is unconfigured */ + do { + urj_tap_chain_shift_instructions_mode (chain, 1, 1, + URJ_CHAIN_EXITMODE_IDLE); + } while (!(urj_tap_register_get_value (part->active_instruction->out) + & XILINX_SR_INIT)); + + if (xlx_set_ir_and_shift (chain, part, "CFG_IN") != URJ_STATUS_OK) + { + status = URJ_STATUS_FAIL; + goto fail_free; + } + + urj_tap_chain_shift_data_registers (chain, 0); + + if (xlx_set_ir_and_shift (chain, part, "JSTART") != URJ_STATUS_OK) + { + status = URJ_STATUS_FAIL; + goto fail_free; + } + + urj_tap_chain_defer_clock (chain, 0, 0, 32); + + urj_tap_reset_bypass (chain); + + urj_tap_chain_flush (chain); + + fail_free: + xlx_bitstream_free (bs); + fail: + return status; +} + +static int +xlx_reconfigure (urj_pld_t *pld) +{ + urj_chain_t *chain = pld->chain; + urj_part_t *part = pld->part; + + urj_tap_reset_bypass (chain); + + if (xlx_set_ir_and_shift (chain, part, "JPROGRAM") != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_tap_reset (chain); + urj_tap_chain_flush (chain); + + return URJ_STATUS_OK; +} + +static int +xlx_detect_xc3s (urj_pld_t *pld) +{ + urj_part_t *part = pld->part; + uint32_t idcode; + uint32_t family; + + /* get fpga family from idcode */ + idcode = urj_tap_register_get_value (part->id); + family = (idcode >> 21) & 0x7f; + + switch (family) + { + case XILINX_FAMILY_XC3S: + case XILINX_FAMILY_XC3SE: + case XILINX_FAMILY_XC3A: + case XILINX_FAMILY_XC3AN: + case XILINX_FAMILY_XC3SD: + return URJ_STATUS_OK; + default: + return URJ_STATUS_FAIL; + } +} + +static int +xlx_detect_xc4v (urj_pld_t *pld) +{ + urj_part_t *part = pld->part; + uint32_t idcode; + uint32_t family; + + /* get fpga family from idcode */ + idcode = urj_tap_register_get_value (part->id); + family = (idcode >> 21) & 0x7f; + + switch (family) + { + case XILINX_FAMILY_XC4VFX: + case XILINX_FAMILY_XC4VLX: + case XILINX_FAMILY_XC4VSX: + return URJ_STATUS_OK; + default: + return URJ_STATUS_FAIL; + } +} + +static int +xlx_detect_xc6s (urj_pld_t *pld) +{ + urj_part_t *part = pld->part; + uint32_t idcode; + uint32_t family; + + /* get fpga family from idcode */ + idcode = urj_tap_register_get_value (part->id); + family = (idcode >> 21) & 0x7f; + + switch (family) + { + case XILINX_FAMILY_XC6S: + return URJ_STATUS_OK; + default: + return URJ_STATUS_FAIL; + } +} + +const urj_pld_driver_t urj_pld_xc3s_driver = { + .name = N_("Xilinx Spartan 3 Family"), + .detect = xlx_detect_xc3s, + .print_status = xlx_print_status_xc3s, + .configure = xlx_configure, + .reconfigure = xlx_reconfigure, + .read_register = xlx_read_register_xc3s, + .write_register = xlx_write_register_xc3s, + .register_width = 2, +}; + +const urj_pld_driver_t urj_pld_xc6s_driver = { + .name = N_("Xilinx Spartan 6 Family"), + .detect = xlx_detect_xc6s, + .print_status = xlx_print_status_xc6s, + .configure = xlx_configure, + .reconfigure = xlx_reconfigure, + .read_register = xlx_read_register_xc6s, + .write_register = xlx_write_register_xc6s, + .register_width = 2, +}; + +const urj_pld_driver_t urj_pld_xc4v_driver = { + .name = N_("Xilinx Virtex 4 Family"), + .detect = xlx_detect_xc4v, + .print_status = xlx_print_status_xc4v, + .configure = xlx_configure, + .reconfigure = xlx_reconfigure, + .read_register = xlx_read_register_xc4v, + .write_register = xlx_write_register_xc4v, + .register_width = 2, +}; diff --git a/urjtag/src/pld/xilinx.h b/urjtag/src/pld/xilinx.h new file mode 100644 index 00000000..1949d01e --- /dev/null +++ b/urjtag/src/pld/xilinx.h @@ -0,0 +1,125 @@ +/* + * $Id$ + * + * Driver for Xilinx FPGAs + * + * Copyright (C) 2010, Michael Walle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Michael Walle , 2010 + * + */ + +#ifndef URJ_PLD_XILINX_H +#define URJ_PLD_XILINX_H + +#include + +#define XILINX_SR_DONE URJ_BIT(5) +#define XILINX_SR_INIT URJ_BIT(4) +#define XILINX_SR_ISC_ENABLED URJ_BIT(3) +#define XILINX_SR_ISC_DONE URJ_BIT(2) + +#define XILINX_XC3S_REG_STAT 8 +#define XILINX_XC4V_REG_STAT 7 +#define XILINX_XC6S_REG_STAT 8 + +#define XILINX_FAMILY_XC2V 0x08 +#define XILINX_FAMILY_XC3S 0x0A +#define XILINX_FAMILY_XC4VLX 0x0B +#define XILINX_FAMILY_XC3SE 0x0E +#define XILINX_FAMILY_XC4VFX 0x0F +#define XILINX_FAMILY_XC4VSX 0x10 +#define XILINX_FAMILY_XC3A 0x11 +#define XILINX_FAMILY_XC3AN 0x13 +#define XILINX_FAMILY_XC3SD 0x1C +#define XILINX_FAMILY_XC5VLX 0x14 +#define XILINX_FAMILY_XC5VLXT 0x15 +#define XILINX_FAMILY_XC5VSXT 0x17 +#define XILINX_FAMILY_XC5CFXT 0x19 +#define XILINX_FAMILY_XC5CTXT 0x22 +#define XILINX_FAMILY_XC6S 0x20 + +#define XC3S_STATUS_SYNC_TIMEOUT URJ_BIT(15) +#define XC3S_STATUS_SEU_ERR URJ_BIT(14) +#define XC3S_STATUS_DONE URJ_BIT(13) +#define XC3S_STATUS_INIT URJ_BIT(12) +#define XC3S_STATUS_MODE_M2 URJ_BIT(11) +#define XC3S_STATUS_MODE_M1 URJ_BIT(10) +#define XC3S_STATUS_MODE_M0 URJ_BIT(9) +#define XC3S_STATUS_VSEL_VS2 URJ_BIT(8) +#define XC3S_STATUS_VSEL_VS1 URJ_BIT(7) +#define XC3S_STATUS_VSEL_VS0 URJ_BIT(6) +#define XC3S_STATUS_GHIGH_B URJ_BIT(5) +#define XC3S_STATUS_GWE URJ_BIT(4) +#define XC3S_STATUS_GTS_CFG_B URJ_BIT(3) +#define XC3S_STATUS_DCM_LOCK URJ_BIT(2) +#define XC3S_STATUS_ID_ERROR URJ_BIT(1) +#define XC3S_STATUS_CRC_ERROR URJ_BIT(0) + +#define XC4V_STATUS_DEC_ERROR URJ_BIT(16) +#define XC4V_STATUS_ID_ERROR URJ_BIT(15) +#define XC4V_STATUS_DONE URJ_BIT(14) +#define XC4V_STATUS_RELEASE_DONE URJ_BIT(13) +#define XC4V_STATUS_INIT URJ_BIT(12) +#define XC4V_STATUS_INIT_COMPLETE URJ_BIT(12) +#define XC4V_STATUS_MODE_M2 URJ_BIT(10) +#define XC4V_STATUS_MODE_M1 URJ_BIT(9) +#define XC4V_STATUS_MODE_M0 URJ_BIT(8) +#define XC4V_STATUS_GHIGH_B URJ_BIT(7) +#define XC4V_STATUS_GWE URJ_BIT(6) +#define XC4V_STATUS_GTS_CFG_B URJ_BIT(5) +#define XC4V_STATUS_EOS URJ_BIT(4) +#define XC4V_STATUS_DCI_MATCH URJ_BIT(3) +#define XC4V_STATUS_DCM_LOCK URJ_BIT(2) +#define XC4V_STATUS_PART_SECURED URJ_BIT(1) +#define XC4V_STATUS_CRC_ERROR URJ_BIT(0) + +#define XC6S_STATUS_SWWD URJ_BIT(15) +#define XC6S_STATUS_IN_PWRDN URJ_BIT(14) +#define XC6S_STATUS_DONE URJ_BIT(13) +#define XC6S_STATUS_INIT_B URJ_BIT(12) +#define XC6S_STATUS_MODE_M1 URJ_BIT(10) +#define XC6S_STATUS_MODE_M0 URJ_BIT(9) +#define XC6S_STATUS_HSWAPEN URJ_BIT(8) +#define XC6S_STATUS_PART_SECURED URJ_BIT(7) +#define XC6S_STATUS_DEC_ERROR URJ_BIT(6) +#define XC6S_STATUS_GHIGH_B URJ_BIT(5) +#define XC6S_STATUS_GWE URJ_BIT(4) +#define XC6S_STATUS_GTS_CFG_B URJ_BIT(3) +#define XC6S_STATUS_DCM_LOCK URJ_BIT(2) +#define XC6S_STATUS_ID_ERROR URJ_BIT(1) +#define XC6S_STATUS_CRC_ERROR URJ_BIT(0) + +extern const urj_pld_driver_t urj_pld_xc3s_driver; +extern const urj_pld_driver_t urj_pld_xc6s_driver; +extern const urj_pld_driver_t urj_pld_xc4v_driver; + +typedef struct { + char *design; + char *part_name; + char *date; + char *time; + uint32_t length; + uint8_t *data; +} xlx_bitstream_t; + +int xlx_bitstream_load_bit (FILE *BIT_FILE, xlx_bitstream_t *bs); +xlx_bitstream_t* xlx_bitstream_alloc (void); +void xlx_bitstream_free (xlx_bitstream_t *bs); + +#endif /* URJ_PLD_XILINX_H */ diff --git a/urjtag/src/pld/xilinx_bitstream.c b/urjtag/src/pld/xilinx_bitstream.c new file mode 100644 index 00000000..4afe9eb3 --- /dev/null +++ b/urjtag/src/pld/xilinx_bitstream.c @@ -0,0 +1,145 @@ +/* + * $Id$ + * + * Functions to parse Xilinx bitstream files + * + * Copyright (C) 2010, Michael Walle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Michael Walle , 2010 + * + */ + +#include +#include +#include + +#include +#include + +#include "xilinx.h" + +static int +xlx_read_section (FILE *bit_file, char *id, uint8_t **data, uint32_t *len) +{ + uint8_t buf[4]; + int lenbytes; + + /* first read 1 bytes, the section key */ + if (fread (buf, 1, 1, bit_file) != 1) + return URJ_STATUS_FAIL; + + *id = buf[0]; + + /* section 'e' has 4 bytes indicating section length */ + if (*id == 'e') + lenbytes = 4; + else + lenbytes = 2; + + /* first read 1 bytes */ + if (fread (buf, 1, lenbytes, bit_file) != lenbytes) + return URJ_STATUS_FAIL; + + /* second and third is section length */ + if (*id != 'e') + *len = buf[0] << 8 | buf[1]; + else + *len = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; + + /* now allocate memory for data */ + *data = malloc (*len); + + if (fread (*data, 1, *len, bit_file) != *len) + return URJ_STATUS_FAIL; + + return URJ_STATUS_OK; +} + +int +xlx_bitstream_load_bit (FILE *bit_file, xlx_bitstream_t *bs) +{ + char sid = 0; + uint8_t *sdata; + uint32_t slen; + + uint8_t buf[128]; + uint8_t header[] = { + 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, + 0x0f, 0xf0, 0x00, 0x00, 0x01, + }; + + if (fread (buf, 1, sizeof (header), bit_file) != sizeof (header)) + return URJ_STATUS_FAIL; + + if (memcmp (buf, header, sizeof (header)) != 0) + return URJ_STATUS_FAIL; + + urj_log (URJ_LOG_LEVEL_DEBUG, + _("Valid xilinx bitfile header found.\n")); + + while (sid != 'e') + { + if (xlx_read_section (bit_file, &sid, &sdata, &slen) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + urj_log (URJ_LOG_LEVEL_DEBUG, + _("Read section id=%c len=%d.\n"), sid, slen); + + /* make sure that strings are terminated */ + if (sid != 'e') + sdata[slen-1] = '\0'; + + switch (sid) + { + case 'a': bs->design = (char *) sdata; break; + case 'b': bs->part_name = (char *) sdata; break; + case 'c': bs->date = (char *) sdata; break; + case 'd': bs->time = (char *) sdata; break; + case 'e': bs->data = sdata; bs->length = slen; break; + } + } + + return URJ_STATUS_OK; +} + +xlx_bitstream_t * +xlx_bitstream_alloc (void) +{ + xlx_bitstream_t *bs = calloc (1, sizeof (xlx_bitstream_t)); + + if (!bs) + { + urj_error_set (URJ_ERROR_OUT_OF_MEMORY, _("malloc(%zu) fails"), + sizeof (xlx_bitstream_t)); + return NULL; + } + + return bs; +} + +void +xlx_bitstream_free (xlx_bitstream_t *bs) +{ + free (bs->design); + free (bs->part_name); + free (bs->date); + free (bs->time); + free (bs->data); + + free (bs); +}