Message-ID: <3A9ACE4C.6922CAA5@wanabe.nl> Date: Mon, 26 Feb 2001 22:44:44 +0100 From: Reinoud Organization: remains troubled X-Mailer: Mozilla 4.7 [en] (X11; I; Linux 2.2.17 i686) X-Accept-Language: en MIME-Version: 1.0 Newsgroups: comp.arch.fpga Subject: Linux Xilinx Programmer Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Lines: 249 NNTP-Posting-Host: 12dyn250.delft.casema.net X-Trace: reader4 983227787 15694 212.64.19.250 X-Complaints-To: http://www.casema.net/abuse X-Abuse-Info: Please be sure to include a copy of ALL headers X-Abuse-Info: Otherwise we will be unable to process your complaint properly X-Server-Date: 26 Feb 2001 22:49:47 GMT Path: chonsp.franklin.ch!pfaff.ethz.ch!news-zh.switch.ch!news.ifi.unizh.ch!news.imp.ch!fr.clara.net!heighliner.fr.clara.net!grolier!skynet.be!cleanfeed.casema.net!news.casema.net!not-for-mail Xref: chonsp.franklin.ch comp.arch.fpga:4850 Hi, Here is C source for a Xilinx FPGA programmer for Linux 2.4+, using the nice new ppdev parallel port driver. - Reinoud (Spam goes to wanabe, mail to wanadoo.) /*-------------------------------------------------------------------- lxp.c: Linux Xilinx Programmer - version 0 Programs Xilinx FPGAs in slave serial mode through a parallel port, using a Xilinx Parallel Cable III compatible interface by default. Input bitstream files must be in RBT (ASCII) 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: $ lxp bitstream.rbt /dev/parport0 or: $ gunzip < bitstream.rbt.gz | lxp - /dev/parport0 At the moment of this writing, I have tested lxp with a 2.2.17 kernel+patch, and with Spartan-II and XC4000XL devices. Please let me know of your results with other setups. - Reinoud -------------------------------------------------------------------- (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 -------------------------------------------------------------------- Development funded in part by NWO and Delft University, the Netherlands. Many thanks to the Linux parport developers. Any trademarks are the property of their respective owners. --------------------------------------------------------------------*/ #include #include #include #include #include #include #include /*--- 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_DIN 0x01 #define O_CCLK 0x02 #define O_PROG 0x04 #define O_ENABLE 0x08 /* enable outputs */ #define O_DONE 0x10 /* Default state, determines 'inactive' levels for output signals. Make DONE asserted, others deasserted (at the FPGA). For CCLK, be sure to use the level before the active edge (low). */ #define O_DEFAULT (O_PROG | O_ENABLE | O_DONE) /* 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 /* usec to wait after PROGRAM release */ #define PROG_DELAY 50000 /*--- print error and clean up if needed ---*/ void err (int d, char *s) { unsigned char o; perror(s); if (d != -1) { o = O_DEFAULT; ioctl(d, O_WRITECMD, &o); ioctl(d, PPRELEASE); } exit(1); } int main(int argc, char *argv[]) { char *rbname; /* rbt file name */ char *ppname; /* parport device file name */ FILE *f; /* rbt file ptr */ int c; /* char from f */ int d; /* descriptor for parport device */ unsigned char o; /* output data for parport */ unsigned char stat; /* status (input) data from parport */ long bitcount; /* bits transferred */ /*--- get arguments ---*/ if (argc != 3) { fprintf(stderr, "usage: %s \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"); /*--- find data start ('0' or '1' at beginning of a line) ---*/ /* note: no file format sanity checks implemented, header format not defined by Xilinx */ while ( ((c = getc(f)) != EOF) && (c != '0') && (c != '1') ) while ( (c != '\n') && ((c = getc(f)) != EOF) ); if (c == EOF) { if (ferror(f)) err(-1, "read bitstream file"); else err(-1, "find EOF in bitstream header"); } /*--- get parport ---*/ d = open(ppname, O_RDWR); if (d == -1) err(-1, "open parport"); if (ioctl(d, PPCLAIM)) err(-1, "claim parport"); /*--- check power ---*/ /* note: makes no sense for broken Xilinx parallel cable hardware */ if (ioctl(d, PPRSTATUS, &stat)) err(d, "read status parport"); if ((stat & I_SENSE) != I_SENSE_OK) fprintf(stderr, "-- warning: no power on interface\n"); /*--- init FPGA ---*/ o = O_DEFAULT ^ O_ENABLE ^ O_PROG; if (ioctl(d, O_WRITECMD, &o)) err(d, "write parport"); usleep(10); o = O_DEFAULT ^ O_ENABLE; ioctl(d, O_WRITECMD, &o); usleep(PROG_DELAY); /*--- download bitstream ---*/ /* note: no checks, no timing control (assumes parport hardware is slow enough, which is reasonable if only because every parport acces goes through some high-latency bus in practice) */ fprintf(stderr, "programming"); bitcount = 0; while (c != EOF) { o = (c == '0') ? O_DEFAULT ^ O_ENABLE : O_DEFAULT ^ O_ENABLE ^ O_DIN; ioctl(d, O_WRITECMD, &o); /* set up data */ o ^= O_CCLK; ioctl(d, O_WRITECMD, &o); /* toggle clock */ if (!(bitcount++ & 0x1FFFF)) /* another dot every 128k bits */ putc('.', stderr); while ( ((c = getc(f)) != EOF) && (c != '0') && (c != '1') ); /* next c */ } fprintf(stderr, "\ntransferred %li bits\n", bitcount); if (ferror(f)) err(d, "read bitstream file"); /*--- check DONE ---*/ if (ioctl(d, PPRSTATUS, &stat)) err(d, "read status parport"); if ((stat & I_DONE) != I_DONE_OK) fprintf(stderr, "-- warning: not DONE\n"); /*--- clean up ---*/ o = O_DEFAULT; if (ioctl(d, O_WRITECMD, &o)) err(d, "write parport"); if (ioctl(d, PPRELEASE)) err(-1, "release parport"); return 0; }