Hello all,
I created a patch that adds support for Xilinx FPGA devices. The following
operations are possible:
- configure the FPGA with a bitstream
- force a reconfiguration (based on the mode pins)
- read and write configuration registers
- read and decode status (register)
Besides benefits in development (by being able to configure a FPGA) 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 patch adds a new command "pld" (src/cmd/cmd_pld.c) which invokes functions
from the generic pld layer (src/pld/pld.c). The real work takes place in the
device specific 'pld drivers' (for now only xilinx Spartan-6 and Spartan-3
devices, the latter is untested, src/pld/xilinx.c). The drivers register
themselves with the generic pld layer. This makes it easy to write new drivers
for other PLD devices.
The patch is attached and can be found in my git repository at
http://git.serverraum.org/?p=mw/urjtag.git;a=commit;h=a95fcca167b9c93b4c7f06461294045dae07a551
--
wkr michael
diff --git a/urjtag/configure.ac b/urjtag/configure.ac
index 5789622..606a9b6 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/include/urjtag/error.h b/urjtag/include/urjtag/error.h
index 35e119c..ee47fa3 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 0000000..803dd17
--- /dev/null
+++ b/urjtag/include/urjtag/pld.h
@@ -0,0 +1,136 @@
+/*
+ * $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 <[email protected]>, 2010.
+ *
+ */
+
+#ifndef URJ_PLD_H
+#define URJ_PLD_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#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 708e03a..6be03a5 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 a240c87..2a7fcdd 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 48e5b32..8aa6833 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 0000000..f11151e
--- /dev/null
+++ b/urjtag/src/cmd/cmd_pld.c
@@ -0,0 +1,154 @@
+/*
+ * $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 <[email protected]>, 2010
+ *
+ */
+
+
+#include <sysdep.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <urjtag/error.h>
+#include <urjtag/log.h>
+
+#include <urjtag/pld.h>
+#include <urjtag/cmd.h>
+
+#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)
+ {
+ long unsigned int 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, (uint32_t)reg);
+ }
+ else if (strcasecmp (params[1], "writereg") == 0)
+ {
+ long unsigned int reg;
+ long unsigned int 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, (uint32_t)reg, (uint32_t)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 FPGA 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 458a486..99254a6 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 0000000..08244b3
--- /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 <[email protected]>, 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 0000000..a2c35e3
--- /dev/null
+++ b/urjtag/src/pld/pld.c
@@ -0,0 +1,192 @@
+/* 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.
+ */
+
+#include <sysdep.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <urjtag/pld.h>
+#include <urjtag/chain.h>
+#include <urjtag/part.h>
+#include <urjtag/tap_register.h>
+#include "xilinx.h"
+
+const urj_pld_driver_t * const urj_pld_drivers[] = {
+ &urj_pld_xc3s_driver,
+ &urj_pld_xc6s_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) & 0xffffffff;
+ 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 0000000..fc8a024
--- /dev/null
+++ b/urjtag/src/pld/xilinx.c
@@ -0,0 +1,504 @@
+/* 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.
+ */
+
+#include <sysdep.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <urjtag/tap.h>
+#include <urjtag/part.h>
+#include <urjtag/chain.h>
+#include <urjtag/tap_state.h>
+#include <urjtag/tap_register.h>
+#include <urjtag/data_register.h>
+#include <urjtag/part_instruction.h>
+#include <urjtag/pld.h>
+#include "xilinx.h"
+
+static inline uint16_t
+xlx_flip16 (uint16_t v)
+{
+ int i;
+ uint16_t out = 0;
+
+ /* flip bits (from left to right) */
+ for (i = 0; i < 16; i++)
+ if (v & (1 << i)) out |= (1 << (15 - i));
+
+ return out;
+}
+
+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_dr_realloc(urj_data_register_t *dr, int len)
+{
+ urj_tap_register_free (dr->in);
+ dr->in = NULL;
+ urj_tap_register_free (dr->out);
+ dr->out = NULL;
+
+ dr->in = urj_tap_register_alloc (len);
+ if (!dr->in)
+ return URJ_STATUS_FAIL;
+
+ dr->out = urj_tap_register_alloc (len);
+ if (!dr->out)
+ return URJ_STATUS_FAIL;
+
+ return URJ_STATUS_OK;
+}
+
+static void
+xlx_create_instruction (urj_part_t *part, const char *ir_name,
+ const char *ir_code, const char *dr_name, int dr_len)
+{
+ urj_data_register_t *d;
+ urj_part_instruction_t *i;
+
+ 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 */
+ xlx_dr_realloc(d, dr_len);
+ }
+
+ /* check if instruction exists */
+ i = urj_part_find_instruction (part, ir_name);
+
+ if (i == NULL)
+ {
+ /* create instruction */
+ i = urj_part_instruction_define (part, ir_name, ir_code, dr_name);
+ }
+}
+
+static int
+xlx_write_register (urj_pld_t *pld, uint32_t reg, uint32_t value)
+{
+ urj_chain_t *chain = pld->chain;
+ urj_part_t *part = pld->part;
+ urj_part_instruction_t *i;
+ int dr_len = 16;
+
+ 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 */
+ xlx_create_instruction (part, "CFG_IN", "000101", "CFG_DR", 16);
+ xlx_create_instruction (part, "CFG_OUT", "000100", "CFG_DR", 16);
+
+ 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, xlx_flip16(0xaa99),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x5566),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ /* noop */
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ /* type 2 packet (word count = 1) */
+ reg = 0x3001 | ((reg & 0x3f) << 5);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(reg),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(value),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ /* noop */
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_IDLE);
+
+ urj_tap_chain_flush(chain);
+
+ return URJ_STATUS_OK;
+}
+
+static int
+xlx_read_register (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 */
+ xlx_create_instruction (part, "CFG_IN", "000101", "CFG_DR", 16);
+ xlx_create_instruction (part, "CFG_OUT", "000100", "CFG_DR", 16);
+
+ 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, xlx_flip16(0xaa99),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x5566),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ /* noop */
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ /* type 2 packet (word count = 1) */
+ reg = 0x2801 | ((reg & 0x3f) << 5);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(reg),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ /* noop */
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_flip16(0x2000),
+ URJ_CHAIN_EXITMODE_SHIFT);
+ xlx_set_dr_and_shift (chain, part, xlx_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 = xlx_flip16 ((uint16_t)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 (pld, XILINX_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_xc6s (urj_pld_t *pld)
+{
+ uint32_t status;
+
+
+ if (xlx_read_register (pld, XILINX_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;
+
+ i = urj_part_find_instruction (part, "CFG_IN");
+
+ xlx_create_instruction (part, "CFG_IN", "000101", "CFG_DR", dr_len);
+
+ /* 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_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) & 0xffffffff;
+ family = (idcode >> 21) & 0x7f;
+
+ switch (family)
+ {
+ case XILINX_FAMILY_XC6S:
+ return URJ_STATUS_OK;
+ default:
+ return URJ_STATUS_FAIL;
+ }
+}
+
+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) & 0xffffffff;
+ 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;
+ }
+}
+
+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,
+ .write_register = xlx_write_register,
+ .register_width = 2,
+};
+
+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,
+ .write_register = xlx_write_register,
+ .register_width = 2,
+};
+
diff --git a/urjtag/src/pld/xilinx.h b/urjtag/src/pld/xilinx.h
new file mode 100644
index 0000000..9674453
--- /dev/null
+++ b/urjtag/src/pld/xilinx.h
@@ -0,0 +1,100 @@
+/*
+ * $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 <[email protected]>, 2010.
+ *
+ */
+
+#ifndef URJ_PLD_XILINX_H
+#define URJ_PLD_XILINX_H
+
+#include <urjtag/pld.h>
+
+#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_REG_STAT 8
+
+#define XILINX_FAMILY_XC2V 0x08
+#define XILINX_FAMILY_XC3S 0x0A
+#define XILINX_FAMILY_XC3SE 0x0E
+#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 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)
+
+#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)
+
+extern const urj_pld_driver_t urj_pld_xc3s_driver;
+extern const urj_pld_driver_t urj_pld_xc6s_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
+
diff --git a/urjtag/src/pld/xilinx_bitstream.c b/urjtag/src/pld/xilinx_bitstream.c
new file mode 100644
index 0000000..59b6de1
--- /dev/null
+++ b/urjtag/src/pld/xilinx_bitstream.c
@@ -0,0 +1,143 @@
+/*
+ * $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 <[email protected]>, 2010.
+ *
+ */
+
+#include <sysdep.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <urjtag/log.h>
+#include <urjtag/error.h>
+
+#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(%zd) fails"),
+ sizeof (xlx_bitstream_t));
+ return NULL;
+ }
+
+ return bs;
+}
+
+void
+xlx_bitstream_free (xlx_bitstream_t *bs)
+{
+ if (bs->design) free (bs->design);
+ if (bs->part_name) free (bs->part_name);
+ if (bs->date) free (bs->date);
+ if (bs->time) free (bs->time);
+ if (bs->data) free (bs->data);
+
+ free(bs);
+}
+
------------------------------------------------------------------------------
Sell apps to millions through the Intel(R) Atom(Tm) Developer Program
Be part of this innovative community and reach millions of netbook users
worldwide. Take advantage of special opportunities to increase revenue and
speed time-to-market. Join now, and jumpstart your future.
http://p.sf.net/sfu/intel-atom-d2d
_______________________________________________
UrJTAG-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/urjtag-development