| |
/*--------------------------------------------------------------------
* Xilinx Virtex and Spartan JTAG programmer, based on
reference doc: XAPP 139 V1.6
Table 7
Rene van Leuken, April 2004
--------------------------------------------------------------------*/
/*--------------------------------------------------------------------
ljp.c: Linux JTAG Xilinx Programmer - version 0.1
Programs Xilinx FPGAs in JTAG mode through a parallel port,
using a Xilinx Parallel Cable III/IV compatible interface by default.
Input bitstream files must be in .bit (binary) format. The parallel
port is used only in 'compatible' mode, so any old hardware will
do. Requires a Linux kernel with ppdev/parport drivers, i.e. 2.4+
or 2.2.17 with the ppdev patch; for more information see
http://people.redhat.com/twaugh/parport/.
You must have r/w permissions for the parport device you want to
use. Typical use:
$ ljp bitstream.bit /dev/parport0
or:
$ gunzip < bitstream.bit.gz | ljp - /dev/parport0
To compile this code use something like: gcc -O2 -o ljp ljp.c
Rudolf Usselmann ASICS World Services rudi(at)asics(dot)ws
Based on original work by:
Reinoud <reinoud@remove.et.tudelft.nl>
--------------------------------------------------------------------
(c) 2003/2004 Rudolf Usselmann
(c) 2001 Reinoud Lamberts
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 <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
/*--- interface configuration ---*/
/* Configure the interface/cable with the defines below. Xilinx
parallel cable compatible is the default. If your interface
doesn't use a signal, simply make the corresponding mask all zero.
Note that the mask defines below are named after FPGA signals they
control, and not after names used in the Xilinx parallel cable
schematic. This is because the Xilinx cable is not the only
target, and the names it uses are confusing. */
// select data or control output lines: PPWDATA or PPWCONTROL
#define O_WRITECMD PPWDATA
// output signal masks
#define O_ENABLE 0x10 // Enable TDI, TCK and TSM outputs
#define O_START 0x10 // Pulses TDO (DONE Input to Par. Port) (UNUSED)
#define O_TDI_0 0x00 // TDI Low
#define O_TDI_1 0x01 // TDI High
#define O_TCK_0 0x00 // TCK Low
#define O_TCK_1 0x02 // TCK High
#define O_TMS_0 0x00 // TMS Low
#define O_TMS_1 0x04 // TMS High
// input signal masks; for *_OK give masked expected OK value
#define I_SENSE PARPORT_STATUS_ERROR
#define I_SENSE_OK I_SENSE
#define I_DONE PARPORT_STATUS_SELECT
#define I_DONE_OK I_DONE
// JTAG Commands
#define CMD_CFG 0x05
#define CMD_JSTART 0x0c
#define CMD_IDCODE 0x09
static int d; // descriptor for parport device
unsigned char byte;
// --- print error and clean up if needed ---
void
err (int d, char *s)
{
unsigned char o;
perror (s);
if (d != -1)
{
o = 0x00;
ioctl (d, O_WRITECMD, &o);
ioctl (d, PPRELEASE);
}
exit (1);
}
// Read TDO pin
unsigned char
read_tdo ()
{
unsigned char stat; /* status (input) data from parport */
if (ioctl (d, PPRSTATUS, &stat))
err (d, "read status parport");
if ((stat & I_DONE) == I_DONE_OK)
return (1);
else
return (0);
}
// Read Vcc sense pin
unsigned char
read_vcc ()
{
unsigned char stat; /* status (input) data from parport */
if (ioctl (d, PPRSTATUS, &stat))
err (d, "read status parport");
if ((stat & I_SENSE) == I_SENSE_OK)
return (1);
else
return (0);
}
// Send a single bit to the device (1 clock cycle). 'val' is the
// value for TDI and tms is the value for the TMS pin.
void
send_bit (unsigned char val, unsigned char tms)
{
unsigned char out;
ut = O_TCK_0 | O_ENABLE;
out |= (tms == 0) ? O_TMS_0 : O_TMS_1;
out |= (val == 0) ? O_TDI_0 : O_TDI_1;
ioctl (d, O_WRITECMD, &out);
ut = O_TCK_1 | O_ENABLE;
out |= (tms == 0) ? O_TMS_0 : O_TMS_1;
out |= (val == 0) ? O_TDI_0 : O_TDI_1;
ioctl (d, O_WRITECMD, &out);
}
// Send an enitre byte to the device. If last is '1', TMS will
// be high for the last bit transmitteda (e.g. force trasnition
// to EXIT1 state).
void
send_data_byte (unsigned char val, unsigned char last)
{
int n;
for (n = 7; n >= 0; n--)
{
send_bit ((val >> n) & 0x01, (n == 0 & last));
}
}
// Identical to send_data_byte, but also reads TDO. Created seperate
// subroutines for write only and write & read mainly for speed-up
// reasons.
void
read_data_byte (unsigned char val, unsigned char last)
{
int n;
unsigned char bit;
byte = 0;
for (n = 7; n >= 0; n--)
{
send_bit ((val >> n) & 0x01, (n == 0 & last));
bit = read_tdo ();
byte |= bit << (7 - n);
}
}
void
decode_id (int id)
{
int manuf, size, family, rev;
if ((id & 0x01) != 1)
{
printf ("Warning: Bit 0 (LSB) of devcice id is not '1' !\n");
}
manuf = (id >> 01) & 0x07ff;
size = (id >> 12) & 0x01ff;
family = (id >> 21) & 0x007f;
rev = (id >> 28) & 0x000f;
printf ("Device ID: %x\n", id);
printf ("Manuf: %x, Part Size: %x, Family Code: %x, Revision: %0d\n", manuf,
size, family, rev);
if (manuf != 0x49)
{
printf ("I can only program Xilinx Virtex and Spartan devices\n");
}
}
int
main (int argc, char *argv[])
{
char *rbname; /* rbt file name */
char *ppname; /* parport device file name */
FILE *f; /* rbt file ptr */
char c, next; /* char from f */
unsigned char uc;
char *mem;
char mem2[256];
unsigned char o; /* output data for parport */
unsigned char stat; /* status (input) data from parport */
long bitcount; /* bits transferred */
int n, x, len, len2, token;
int devid;
// ====================================================
// ===== get arguments
if (argc != 3)
{
fprintf (stderr,
"usage: %s <BIT file, or - for stdin> <parport device>\n",
argv[0]);
exit (2);
}
rbname = argv[1];
ppname = argv[2];
// ====================================================
// ===== get input file
if (strcmp (rbname, "-"))
f = fopen (rbname, "r");
else
f = stdin;
if (f == NULL)
err (-1, "open bitstream file");
// ====================================================
// ===== Parse binary Header PLEASE REWRITE THIS !
uc = getc (f);
len = uc << 8;
uc = getc (f);
len += uc;
for (x = 0; x < len; x++)
c = getc (f);
uc = getc (f);
len = uc << 8;
uc = getc (f);
len += uc;
//printf("Length: %0d\n",len);
uc = getc (f);
token = uc;
//printf("Token: %x\n",token);
uc = getc (f);
len = uc << 8;
uc = getc (f);
len += uc;
//printf("Length: %0d\n",len);
printf ("Design Name: ");
for (x = 0; x < len; x++)
{
uc = getc (f);
printf ("%c", uc);
}
printf ("\n");
uc = getc (f);
token = uc;
//printf("Token: %x\n",token);
uc = getc (f);
len = uc << 8;
uc = getc (f);
len += uc;
//printf("Length: %0d\n",len);
printf ("Device: ");
for (x = 0; x < len; x++)
{
uc = getc (f);
printf ("%c", uc);
}
printf ("\n");
uc = getc (f);
token = uc;
//printf("Token: %x\n",token);
uc = getc (f);
len = uc << 8;
uc = getc (f);
len += uc;
//printf("Length: %0d\n",len);
printf ("Date: ");
for (x = 0; x < len; x++)
{
uc = getc (f);
printf ("%c", uc);
}
printf ("\n");
uc = getc (f);
token = uc;
//printf("Token: %x\n",token);
uc = getc (f);
len = uc << 8;
uc = getc (f);
len += uc;
//printf("Length: %0d\n",len);
printf ("Time: ");
for (x = 0; x < len; x++)
{
uc = getc (f);
printf ("%c", uc);
}
printf ("\n");
uc = getc (f);
token = uc;
//printf("Token: %x\n",token);
uc = getc (f);
len = uc << 24;
uc = getc (f);
len += uc << 16;
uc = getc (f);
len += uc << 8;
uc = getc (f);
len += uc;
printf ("Bitstream Length: %0d bits\n", len * 8);
// ====================================================
// ===== get parport
d = open (ppname, O_RDWR);
if (d == -1)
err (-1, "open parport");
if (ioctl (d, PPCLAIM))
err (-1, "claim parport");
// ====================================================
// ===== check power
if (!read_vcc ())
{
fprintf (stderr, "ERROR: no power on interface\n");
o = 0x00; // Turn off driver
if (ioctl (d, O_WRITECMD, &o))
err (d, "write parport");
if (ioctl (d, PPRELEASE))
err (-1, "release parport");
exit (-1);
}
// ====================================================
// ########## Start of JTAG Programming sequence
// ====================================================
// ########## RESET Test Logic
for (n = 0; n < 6; n++)
send_bit (0, 1); // Test Logic Reset // 1
// tdi tms
send_bit (0, 0); // 2
// State = IDLE
send_bit (0, 1); // 3
send_bit (0, 1); // 3
send_bit (0, 0); // 4
send_bit (0, 0); // 4
// ====================================================
// ########## IDCODE Instruction
send_bit (1, 0); //
send_bit (0, 0); //
send_bit (0, 0); //
send_bit (1, 0); //
send_bit (0, 1); //
send_bit (0, 1); //
send_bit (0, 1); //
send_bit (0, 0); //
send_bit (0, 0); //
read_data_byte (0x00, 0);
devid = byte;
read_data_byte (0x00, 0);
devid += byte << 8;
read_data_byte (0x00, 0);
devid += byte << 16;
read_data_byte (0x00, 1);
devid += byte << 24;
decode_id (devid);
send_bit (0, 1); //
send_bit (0, 1); //
send_bit (0, 1); //
send_bit (0, 0); //
send_bit (0, 0); //
// END IDCODE
// ====================================================
// ########## CONFIGURE
// CFG_IN 0101
send_bit (1, 0); // 5
send_bit (0, 0); // 5
send_bit (1, 0); // 5
send_bit (0, 0); // 5
send_bit (0, 1); // 6
send_bit (0, 1); // 7
send_bit (0, 1); // 7
send_bit (0, 0); // 8
send_bit (0, 0); // 8
// ====================================================
// SEND DATA
bitcount = 0;
fprintf (stderr, "\nProgramming ... ");
for (n = 0; n < len; n++)
{
uc = getc (f);
send_data_byte (uc, n == (len - 1));
bitcount += 8;
if ((bitcount % (256 * 1024)) == 0)
putc ('*', stderr);
}
fprintf (stderr, "\nProgrammed %0d bits", bitcount);
send_bit (0, 1); // 11
send_bit (0, 1); // 12
send_bit (0, 1); // 12
send_bit (0, 0); // 13
send_bit (0, 0); // 13
// ====================================================
// ########## JSTART 1100
send_bit (0, 0); // 14
send_bit (0, 0); // 14
send_bit (1, 0); // 14
send_bit (1, 0); // 14
send_bit (0, 1); // 15
send_bit (0, 1); // 16
send_bit (0, 1); // 16
for (n = 0; n < 17; n++)
send_bit (0, 0); // Clock-in RUN-TEST sequence
send_bit (0, 1); // 18
send_bit (0, 1); // 18
send_bit (0, 0); // 19
send_bit (0, 0); // 19
// DONE !
// ====================================================
printf ("\n");
o = 0x00; // Turn off driver
if (ioctl (d, O_WRITECMD, &o))
err (d, "write parport");
if (ioctl (d, PPRELEASE))
err (-1, "release parport");
return 0;
}
source html http://ens.ewi.tudelft.nl/~rene/xilinx-jtag.c