/* * Copyright 1996 University of Toronto * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Toronto not be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. The University of Toronto * makes no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * THE UNIVERSITY OF TORONTO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL THE UNIVERSITY OF TORONTO BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* Authors: Guy Lemieux Department of Electrical and Computer Engineering 10 King's College Road University of Toronto, Toronto M5S 3G4, Canada e-mail: lemieux@eecg.toronto.edu */ /* This source file converts a CGE or SEGA-style netlist into * a connectivity (BLIF) file and a placement file for VPR. * * Usage: sega2blif filename * * Inputs: filename in SEGA-compatible format * * Outputs: filename.blif blif file for vpr, use blifmap to create a .net file * filename.place vpr-compatible placement file * * Caveats: -filename.place includes a hard-coded 'architecture file' parameter * which VPR checks for consistency. it will probably be wrong. fix it as needed. * -beware of the io_rat parameter for VPR, which must be consistent with the * placement file. * -VPR uses a different coordinate system than SEGA so beware of the X * and Y dimension sizes. * -SEGA allows the 4 corners to be used as I/O pads but VPR does not (VPR is more * realistic). if the SEGA circuit uses an I/O pad on the corner, it moves it to * an adjacent location so VPR will be happy. thus, the VPR circuit may be * slightly different than the SEGA circuit. * -VPR does many checks on a circuit to test correctness (e.g., only one output * driver on a net). the k2 benchmark supplied with SEGA fails this test. i modified * k2 circuit, called k2fix, is available. VPR gives the z03D4 benchmark a warning, * but this can be safely ignored. */ #include #include #include #include typedef int BOOL; typedef struct _node { int x,y; int netnum; char name[80]; int pin; struct _node *inputs[6]; int num_inputs; } nodes; /* each input/output/logic block has (x,y) of driver, net number & name */ /* inputs and outputs also have pin numbers */ #define SIZE 100 nodes inputs[SIZE]; nodes outputs[SIZE]; nodes logic_blocks[SIZE][SIZE]; nodes nets[2*SIZE*SIZE]; int num_inputs = 0; int num_outputs = 0; int num_nets = 0; int maxx = 0; int maxy = 0; static void check_net( int netnum, char *pucNetName, int x, int y, int pin ) { nets[num_nets].x = x; nets[num_nets].y = y; nets[num_nets].netnum = netnum; nets[num_nets].pin = pin; strcpy( nets[num_nets].name, pucNetName ); num_nets++; if( x > maxx ) { maxx = (x+1)&(~1); if( maxx > SIZE ) { fprintf( stderr, "FPGA too big in X dir, more than %d\n", SIZE ); exit( -1 ); } } if( y > maxy ) { maxy = (y+1)&(~1); if( maxy > SIZE ) { fprintf( stderr, "FPGA too big in Y dir, more than %d\n", SIZE ); exit( -1 ); } } } char pucNetName[80]; static int read_graph_from_file( FILE *fp ) { int x,y,netnum,outdegree, headpin, tailpin; if( fscanf( fp, "%s", pucNetName ) < 1 ) return -1; /* RC_EOF */ if( fscanf( fp, "%d ", &netnum ) < 1 ) return -1; if( fscanf( fp, "%d ", &x ) < 1 ) return -1; if( fscanf( fp, "%d ", &y ) < 1 ) return -1; if( fscanf( fp, "%d ", &outdegree ) < 1 ) return -1; if( fscanf( fp, "%d ", &headpin ) < 1 ) return -1; check_net( netnum, pucNetName, x, y, headpin ); while ( outdegree > 0 ) { if( fscanf( fp, "%d ", &x ) < 1 ) return -1; if( fscanf( fp, "%d ", &y ) < 1 ) return -1; if( x > maxx ) maxx = (x+1)&(~1); if( y > maxy ) maxy = (y+1)&(~1); if( fscanf( fp, "%d ", &outdegree ) < 1 ) return -1; } if( fscanf( fp, "%d", &tailpin ) < 1 ) return -1; check_net( netnum, pucNetName, x, y, tailpin ); return 0; } void process_nets( int net ) { int i; int input; nodes *lb; if( nets[net].x ==0 || nets[net].y ==0 || nets[net].x == maxx || nets[net].y == maxy ) { /* signal is either an input or an output pin */ /* assume an input, look for a driver of the net inside the * fpga. if no drivers exist, it is an input pin, else an output pin */ input = 1; for( i=0; i SIZE ) { fprintf( stderr, "too many inputs, more than %d\n", SIZE ); exit( -1 ); } } else /*output*/ { /* don't add if already present */ for( i=0; i SIZE ) { fprintf( stderr, "too many outputs, more than %d\n", SIZE ); exit( -1 ); } } } else /* not an i/o pin, but a logic block */ { lb = &(logic_blocks[nets[net].x][nets[net].y]); if( nets[net].pin < 6 ) { /* an input pin to logic block */ /* see if input was added already */ input = 0; for( i=0; i < lb->num_inputs; i++ ) { if( lb->inputs[i]->pin == nets[net].pin ) { input = 1; break; } } if( input==0 ) { /* pin was never added to lb, add it now */ lb->inputs[ lb->num_inputs++ ] = &(nets[net]); } } else /* add an output pin to logic block */ { lb->x = nets[net].x; lb->y = nets[net].y; lb->netnum = nets[net].netnum; lb->pin = nets[net].pin; strcpy( lb->name, nets[net].name ); } } } void write_blif( char *fname ) { FILE *blif, *place; int i, x, y, numchar, archnum; int blocknum=0; int subblock[SIZE][SIZE]; char name[80]; for( x=0; x<=maxx; x++ ) for( y=0; y<=maxy; y++ ) subblock[x][y] = 0; sprintf( name, "%s.blif", fname ); blif = fopen( name, "w" ); sprintf( name, "%s.place", fname ); place = fopen( name, "w" ); fprintf( blif, ".model top\n" ); archnum = 0; for( i=0; i archnum ) { archnum = subblock[inputs[i].x/2][inputs[i].y/2]; } } for( i=0; i archnum ) { archnum = subblock[outputs[i].x/2][outputs[i].y/2]; } } fprintf( place, "Netlist file: %s.net\tArchitecture file: cge.arch.%d\n", fname, archnum ); fprintf( place, "block\tx\ty\tname\tsubblock\n" ); for( x=0; x<=maxx; x++ ) for( y=0; y<=maxy; y++ ) subblock[x][y] = 0; numchar = fprintf( blif, ".inputs" ); for( i=0; i 60 ) { fprintf( blif, " \\\n\t" ); numchar = 0; } numchar += fprintf( blif, " %s", inputs[i].name ); fprintf( place, "%d\t%d\t%d\t%s\t%d\n", blocknum++, inputs[i].x/2, inputs[i].y/2, inputs[i].name, subblock[inputs[i].x/2][inputs[i].y/2]++ ); } fprintf( blif, "\n" ); numchar = fprintf( blif, ".outputs" ); for( i=0; i 60 ) { fprintf( blif, " \\\n\t" ); numchar = 0; } numchar += fprintf( blif, " %s", outputs[i].name ); fprintf( place, "%d\t%d\t%d\tout:%s\t%d\n", blocknum++, outputs[i].x/2, outputs[i].y/2, outputs[i].name, subblock[outputs[i].x/2][outputs[i].y/2]++ ); } fprintf( blif, "\n" ); for( x=0; x<=maxx; x++ ) { for( y=0; y<=maxy; y++ ) { if( logic_blocks[x][y].x != 0 ) { fprintf( blif, ".names" ); for( i=0; iname ); } fprintf( blif, " %s\n", logic_blocks[x][y].name ); fprintf( place, "%d\t%d\t%d\t%s\t%d\n", blocknum++, logic_blocks[x][y].x/2, logic_blocks[x][y].y/2, logic_blocks[x][y].name, subblock[x][y]++ ); } } } fprintf( blif, ".end\n" ); fclose( blif ); fclose( place ); } void main( int argc, char *argv[] ) { FILE *fp; int i; bzero( (char*)logic_blocks, SIZE*SIZE*sizeof(nodes) ); if( argc != 2 ) { fprintf( stderr, "Usage: %s filename\n", argv[0] ); exit( -1 ); } fp = fopen( argv[1], "r" ); if( fp == NULL ) { fprintf( stderr, "%s: cannot stat\n", argv[1] ); exit( -1 ); } while( !feof(fp) ) { read_graph_from_file( fp ); } for( i=0; i