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
master
Mike Frysinger 14 years ago
parent 4763d8162a
commit 183d46a331

@ -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 <vapier@gentoo.org>
* configure.ac: Clean up libusb detection to prefer 1.0 over 0.1, and accept

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

@ -30,6 +30,7 @@ EXTRA_DIST = \
fdl.txt \
UrJTAG.txt \
README.ejtag \
README.pld \
howto_add_support_for_more_flash.txt \
$(man_MANS)

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

@ -49,6 +49,7 @@ pkginclude_HEADERS = \
parse.h \
part.h \
part_instruction.h \
pld.h \
pod.h \
tap_register.h \
tap_state.h \

@ -70,6 +70,8 @@ typedef enum URJ_ERROR
URJ_ERROR_BFIN,
URJ_ERROR_PLD,
URJ_ERROR_UNIMPLEMENTED,
}
urj_error_t;

@ -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 <michael@walle.cc>, 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 */

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

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

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

@ -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 <michael@walle.cc>, 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)
{
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], &reg) != 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], &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, 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
};

@ -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";
}

@ -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 <michael@walle.cc>, 2010.
#
include $(top_srcdir)/Makefile.rules
noinst_LTLIBRARIES = libpld.la
libpld_la_SOURCES = \
pld.c \
xilinx_bitstream.c \
xilinx.c
AM_CFLAGS = $(WARNINGCFLAGS)

@ -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 <michael@walle.cc>, 2010
*
*/
#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,
&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);
}

@ -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 <michael@walle.cc>, 2010
*
*/
#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 <urjtag/bitops.h>
#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,
};

@ -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 <michael@walle.cc>, 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_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 */

@ -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 <michael@walle.cc>, 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(%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);
}
Loading…
Cancel
Save