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], &reg) != 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], &reg) != 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

Reply via email to