/**** * upload.c Andrew Huang Xtreme Ideas * bunnie@mit.edu * * version 1.0 <8/3/97> * basic DOS support built into program with hooks for linux version * * version 2.0 <1/23/98> * linux compatibility integrated into code; code cleaned up for * readibility * * NOTE: when compiling this under linux, you must use the -O2 compiler flag. * for example, * * gcc -O2 upload.c -o upload * * This is because the I/O port instructions turn into in-line assembly. * Also, you must be super-user to run this program. ****/ /*** defines ***/ #if 0 /* dos compatibility commented out */ #undef LINUX 0 #define DOS 1 #endif #if 1 #define LINUX 1 #undef DOS #endif #undef SCANARGV /* scanargv library support; off for max compatibility */ /* debug options */ #define SSTEP 0 #define RHPDEBUG 0 /* open-loop wait parameters there is enough "play" in the loop such that this number does not really need to be adjusted even if this program is targetted for a variety of architectures */ #define WAIT 50 /*** includes ***/ #include "pport.h" /*** typedefs ***/ /*** globals ***/ /*** func protos ***/ static int flip_byte(int byte); void init_ports(); void frob_cclk(); void one_byte(); void print_banner(); void main( int argc, char *argv[] ) { /* main */ /* locals */ unsigned int i, count; long wait; FILE *bitstream = NULL; char c; int verbose = 0; char *fname; /* body */ #if SCANARGV scanargv( argc, argv, "%s [-v] [-f filename]", "[-v %+|-f %r]", &verbose, &bitstream ); #else fname = argv[1]; printf( "Using %s for FPGA bitstream.\n", fname ); if( NULL IS (bitstream = fopen( fname, "r" ) ) ) { printf( "Can't open %s...\n", fname ); exit(0); } /* if */ verbose = 0; #endif if( verbose ) print_banner(); /***** * init any machine-specific stuph *****/ init_ports(); /***** * perform a low-level init and clear of the FPGA *****/ /* set strobe to inactive value */ outb( (char) (inb( LP1_CR ) | CR_STB) & 0xFF, LP1_CR ); /* clear strobe */ /* initialize the LCA */ /* this is done by slamming init low and holding it there */ /* then returning it to the high value */ outb( (char) inb( LP1_CR ) & ~CR_INIT, LP1_CR ); for( wait = 0; wait < 40000; wait++ ) ; /* wait for LCA to reset */ outb( (char) inb( LP1_CR ) | CR_INIT, LP1_CR ); #if RHPDEBUG printf( "Initialize array\n" ); getchar(); #endif /* wait for /init to go high */ /* this allows us to determine if the device is connected */ count = 0; while( !(inb( LP1_SR ) & SR_ERR) ) { count++; if( count > TIMEOUT ) { printf( "Init did not go high; is it plugged in?\n" ); exit(0); } /* if */ } /* while */ /***** * upload the bitstream *****/ /* scan past the bitfile header */ c = 0; count = 0; while( (unsigned char) c AINT 0xFF ) { fread( &c, 1, 1, bitstream ); count++; } /* while */ /* set the data output to all 1's to handle weird parallel ports */ outb( (char) 0xFF, LP1_DR ); /* from cclk once to get the FPGA in the proper state */ for(wait = 0; wait < 10000; wait++ ) ; frob_cclk(); for(wait = 0; wait < 10000; wait++ ) ; #if RHPDEBUG printf( "Entering main loop.\n" ); getchar(); #endif /***** * main upload loop *****/ while( !feof( bitstream ) ) { fread( &c, 1, 1, bitstream ); count++; /* keep a running count of bytes processed, incl header */ /* check for error by INIT going low */ if(!( inb(LP1_SR) & SR_ERR)) { printf( "Got error while downloading on byte %d.\n", count ); exit(0); } /* if */ /* bizarrity #2935: MSB and LSB are mixed up in Xilinx world */ outb( (char) flip_byte(c) & 0xFF, LP1_DR ); #if SSTEP printf( "Data now available: %X.\n", c & 0xFF ); getchar(); #endif /* send the byte to the FPGA */ one_byte(); /* martching .'s to monitor progress */ if( !(count % 1024) ) { /* printf( "count: %d\n", count ); */ printf( "." ); fflush(stdout); /* in case of buffered I/O */ } /* if */ } /* while */ outb( (char) (inb( LP1_CR ) | CR_STB) & 0xFF, LP1_CR ); printf( "\nuploaded %d bytes\n", count ); } /* main */ void init_ports() { /* init_ports */ /* locals */ /* body */ /* if in linux mode, enable access to the parallel port I/O space. you must be superuser to do this. */ #ifdef LINUX ioperm((unsigned long) LP1_BASE, (unsigned long) 0x3, 0x2 ); #endif } /* init_ports */ static int flip_byte(int byte) { /* flip_byte */ int bit=0, result = 0; for (bit = 0; bit < 8; bit++) if (byte & (1 << bit)) result |= (1 << (7 - bit)); return (result); } /* flip_bypte */ void frob_cclk() { /* frob_cclk */ /* locals */ long wait; /* body */ outb( (char) (inb( LP1_CR ) & ~CR_STB) & 0xFF, LP1_CR ); #if SSTEP printf( "strobe is now high\n" ); getchar(); #endif for( wait = 0; wait < WAIT; wait++ ) ; outb( (char) (inb( LP1_CR ) | CR_STB) & 0xFF, LP1_CR ); #if SSTEP printf( "strobe is now low\n" ); getchar(); #endif for( wait = 0; wait < WAIT; wait++ ) ; } /* frob_cclk */ void one_byte() { /* one_byte */ /* locals */ int i; /* body */ for( i = 0 ; i < 8; i++ ) frob_cclk(); } /* one_byte */ void print_banner() { /* print_banner */ /* locals */ /* body */ printf( "upload v2.0b (1/23/98)\n" ); } /* print_banner */