#!/usr/local/bin/perl use strict; use POSIX; use Class::Struct; use vars qw($opt_c $opt_d $opt_u $opt_e $opt_m); use Getopt::Std; # generate Synplify and Xilinx contraint files from the board level # models (saves re-typing and prevents transcribe errors) # expected general format: # pin # 'A0': # PINUSE='BI'; # INPUT_LOAD='(*,*)'; # OUTPUT_LOAD='(*,*)'; # BIDIRECTIONAL='TRUE'; # PIN_NUMBER='(B19)'; # ..... # end_pin; #my $in_file = "/projects/hw/asm1/pba/current/worklib/dpssram_x18/chips/chips.prt"; #my $in_file = "/projects/hwcae/cadence/lib/asics/fireflow_bussed/chips/chips.prt"; my $prt_file; my @pin_list; my $state=0; my $num_pins = 0; my $pin; my $pincount = 0; my $pwr_pincount = 0; my $nc_pincount = 0; my $bussed_pincount = 0; my $unum; # unum of FPGA in dialcnet.dat file my $exclude_file; my $target_unum; my $x; my $y; my @exclude; my $pin_name; my $pin_loc; my $pin_index; my $comp; my $match; my $xlen; my $last_name; my $exc; my $component = ""; my $traverse_done = 0; my $tmp_name; my $dial_file; my @no_match; my $no_match_count = 0; my @dial_all_lines; my @dial_unum_lines; my $dial_line; my $entry; my $default_sim_type = "TTL"; my @sig_list; struct Pin => {name => '$', index => '$', loc => '$', pull => '$', high_index => '$', low_index => '$', sim_type => '$'}; sub usage { print "\nusage: pins.pl -c filename -d filename -u # -e excludefile -m model\n\n"; print "It is probably best to run this in a temp directory and either copy\n"; print "the dialcnet.dat file, and chips.prt file into this directory or\n"; print "create links to them from there.\n\n"; print "-c chips.prt file\n"; print "-d dialcnet.dat file\n"; print "-u U# of part in question\n"; print "-e signal names to exclude (optional)\n"; print "-m simulation model\n"; print "\nOutput files:\n"; print " fpga.sdc (Simplicity pin lock file)\n"; print " fpga.ucf (Xilinx pin lock file)\n"; print " fpga.sim (Signal simulation file)\n"; print " page1.csa (Concept file)\n"; print "\n"; print "version 1.1, 4/19/02, Mike Zimmerman\n\n"; exit 1; } sub pinsort { # if different roots, then just alphabetize return ($a->name cmp $b->name) if ($a->name ne $b->name); return ($a->index <=> $b->index); } getopts('c:d:u:e:m:'); &usage unless ($opt_c); &usage unless ($opt_d); &usage unless ($opt_u); $prt_file = $opt_c; $dial_file = $opt_d; $target_unum = $opt_u; $target_unum =~ s/u//i; $exclude_file = $opt_e; $default_sim_type = $opt_m; open (INFILE, "<$prt_file") or die "Could not open $prt_file\n"; my $line = ""; # read until the primitive line until ($line =~ /primitive/i) { $line = ; } my ($title) = ($line =~ /primitive\s+\'(.+)\'/i); # read until the pin line until ($line =~ /pin/) { $line = ; } my $temp; # now process the file until the end_pin line is reached while (defined($line) && ($state != 99)) { # looking for new pin or end_pin line if($state == 0) { $line = ; $line =~ s/\s//g; # kill all white space on line if ($line =~ /end_pin/) { $state = 99; } elsif ($line =~ m/^\'+.*<.+>*/) { $state = 1; $pin = Pin->new(); $line =~ /\'(.+)<(.+)>\':/; $pin->name($1); $pin->index($2); $pin->pull(0); $pin->sim_type($default_sim_type); $pin->high_index(-1); $pin->low_index(-1); $bussed_pincount++; } elsif ($line =~ m/^\'+(.*)'+/) { $state = 1; $pin = Pin->new(); $pin->name($1); $pin->sim_type($default_sim_type); $pin->pull(0); $pin->high_index(-1); $pin->low_index(-1); # push(@pin_list, $pin); $pincount++; # print STDERR "$line\n"; } } elsif ($state == 1){ do { $line = ; $line =~ s/\s//g; # kill all white space on line } until ($line =~ /PIN_NUMBER/); ($temp) = $line =~ /PIN_NUMBER=\'\((.+)\)\'/; foreach (split(/,/, $temp)) { # print "$_\n"; $temp = $_ if ($_ ne "0"); } $pin->loc($temp); push(@pin_list, $pin); $num_pins++; $state = 0; } } my $count = 0; my @sorted_pins = sort pinsort @pin_list; my @junk; while ($line = ) { $line =~ s/\s//g; # kill all white space on line if ($line =~ /POWER_PINS=\'\((.+):(.+)\)\';/){ $line = $2; $pin_name = $1; # print "$line\n"; @junk = split(',',$line); foreach $entry(@junk) { $pin = Pin->new(); $pin->name($pin_name); $pin->loc($entry); $pin->pull(0); $pin->sim_type($pin_name); $pin->high_index(-1); $pin->low_index(-1); push(@pin_list, $pin); } $pwr_pincount += ($#junk + 1); # count the # of power/gnd pins } elsif ($line =~ /NC_PINS=\'\((.+)\)\';/){ $line = $1; $line =~ s/FID\d+//g; # remove Fiducials from NC list and thus from pincount $line =~ s/,,/,/g; # remove Fiducials from NC list and thus from pincount $line =~ s/^,//g; # remove Fiducials from NC list and thus from pincount @junk = split(',',$line); foreach $entry(@junk) { $pin = Pin->new(); $pin->name("NC"); $pin->loc($entry); $pin->pull(0); $pin->high_index(-1); $pin->sim_type("NC"); $pin->low_index(-1); push(@pin_list, $pin); } $nc_pincount += ($#junk + 1); $line = "NC: ".$line; } } close(INFILE); print STDERR "Pincount\n"; print STDERR "\tbussed: $bussed_pincount\n"; print STDERR "\tother i/o: $pincount\n"; print STDERR "\tpwr/gnd: $pwr_pincount\n"; print STDERR "\tnc: $nc_pincount\n"; print STDERR "Total:",$bussed_pincount+$pincount+$pwr_pincount+$nc_pincount,"\n"; ######################################################## sub traverse { } sub sigsort { # if different roots, then just alphabetize return ($a->name cmp $b->name) if ($a->name ne $b->name); # sort array highest to lowest return ($b->index <=> $a->index); } sub locsort { my $root_a; my $index_a; my $root_b; my $index_b; ($root_a, $index_a) = ($a->loc =~ /(\D+)(\d+)/i); ($root_b, $index_b) = ($b->loc =~ /(\D+)(\d+)/i); # print "$root_a, $index_a VS. $root_b, $index_b\n"; # if different roots, then just alphabetize return ($root_a cmp $root_b) if ($root_a ne $root_b); return ($index_a <=> $index_b); } print "Reading from $prt_file "; print $exclude_file ? "excluding pins from $exclude_file, " : " no exclude file, "; print "for U# $target_unum\n"; open (SDCFILE, ">fpga.sdc") or die "Could not open fpga.sdc\n"; open (UCFFILE, ">fpga.ucf") or die "Could not open fpga.ucf\n"; open (SIMFILE, ">fpga.sim") or die "Could not open fpga.sim\n"; if ($exclude_file) { open (EXCLUDEFILE, "<$exclude_file") or die "Could not open $exclude_file\n"; @exclude = ; close(EXCLUDEFILE); } open (SCHFILE, ">page1.csa") or die "Could not open page1.csa\n"; print SDCFILE "#PINLOCK_BEGIN\n"; print UCFFILE "#PINLOCK_BEGIN\n"; print SCHFILE << 'EOF'; FILE_TYPE = MACRO_DRAWING; SET COLOR_WIRE YELLOW; SET COLOR_PROP ORANGE; SET COLOR_DOT WHITE; SET COLOR_ARC YELLOW; SET COLOR_BODY GREEN; SET COLOR_NOTE PURPLE; SET PROP_DISPLAY VALUE; EOF $target_unum = "U".$target_unum; $x = 0; $y = 0; $xlen = 1200; $num_pins = 0; my @prt_lines; open (INFILE, "<$dial_file") or die "Could not open $dial_file\n"; while(){ $line = $_; push (@dial_all_lines, $line); push (@dial_unum_lines, $line) if ($line =~ /$target_unum/i); } close(INFILE); my %seen; my %sig_list; my $sig; foreach $pin (@pin_list) { $match=0; # print "Searching for ",$pin->name," at location:",$pin->loc," on $target_unum...."; foreach $line (@dial_unum_lines) { next if ($match == 1); $line =~ s/\s+/!/g; ($pin_name, $unum, $pin_loc) = split('!',$line); next if ($unum ne $target_unum); next unless ($pin_loc eq $pin->loc); $pin_name =~ /(.+\D+)(\d*)$/; $pin->name($1); # $pin->high_index(-1); # $pin->low_index(-1); $pin_index = $2; $pin->index($pin_index) if ($pin_index =~ /\d+/); # for any UNNAMED pins, go back and find the sig name on the other side # of any other compment if ($pin->name =~ /UNNAMED/){ $component = ""; $tmp_name = $pin->name; $tmp_name .= $pin->index if ($pin->index != -1); print "Searching for real net name for $tmp_name connected to:"; foreach $dial_line (@dial_all_lines) { $dial_line =~ s/\s+/!/g; ($pin_name, $unum) = split('!',$dial_line); next if ($pin_name ne $tmp_name); next if ($unum eq $target_unum); $component = $unum; } print $component,"\n"; $traverse_done = 0; foreach $line (@dial_all_lines) { next if($traverse_done == 1); $line =~ s/\s+/!/g; ($pin_name, $comp) = split('!',$line); next unless ($comp eq $component); next if ($pin_name eq $tmp_name); next if ($traverse_done); # need to find the OTHER component connected to this net print $pin->name," replaced by:$pin_name\n"; $pin->name($pin_name); $traverse_done = 1; $pin->pull(1) if ($pin_name =~ /^GND/); $pin->pull(1) if ($pin_name =~ /^POS/); } print $pin->name," ($tmp_name) not replaced\n" if ($traverse_done == 0); } ## if UNNAMED done $match = 1; $num_pins++; # add to signal list (unique names only) if ($seen{$pin->name}) { if ($pin_index =~ /\d+/) { $sig_list{$pin->name}->high_index($pin_index) if ((($pin_index > $sig_list{$pin->name}->high_index) && ($pin_index != -1)) || (($sig_list{$pin->name}->high_index == -1) && ($pin_index != -1))); $sig_list{$pin->name}->low_index($pin_index) if ((($pin_index < $sig_list{$pin->name}->low_index) && ($pin_index != -1)) || (($sig_list{$pin->name}->low_index == -1) && ($pin_index != -1))); } } else { $seen{$pin->name} = 1; $sig_list{$pin->name} = $pin; if ($pin_index =~ /\d+/) { $sig_list{$pin->name}->high_index($pin_index); # print "Starting high index is $pin_index for $pin_name\n"; } if ($pin_index =~ /\d+/) { $sig_list{$pin->name}->low_index($pin_index); # print "Starting low index is $pin_index for $pin_name\n"; } # print "Adding ",$sig_list{$pin->name}->name," to sig list with ",$sig_list{$pin->name}->high_index,":",$sig_list{$pin->name}->low_index,"\n"; } } if ($match == 0) { print "No match: ",$pin->name,"\n"; push (@no_match, $pin); $no_match_count++; } } @sorted_pins = sort sigsort @pin_list; # sort pins by location for sim file my @loc_sorted_pins = sort locsort @pin_list; foreach $pin (@loc_sorted_pins) { $tmp_name = $pin->name; $tmp_name .= $pin->index if ($pin->index != -1); print SIMFILE $pin->loc,' ',substr($tmp_name,-20),' ',$pin->sim_type; print SIMFILE " | Pullup/down??" if ($pin->pull ==1); print SIMFILE "\n"; } foreach $pin (@sorted_pins) { $match = 0; $pin->index("") if ($pin->index == -1); foreach $exc (@exclude) { chomp ($exc); $match++ if ($pin->name eq $exc); } next if ($match != 0); print UCFFILE 'NET "',$pin->name,'[',$pin->index,']" LOC = "',$pin->loc,"\";\n"; print SDCFILE 'define_attribute {',$pin->name,$pin->index,'} xc_loc "',$pin->loc,"\"\n"; } print SDCFILE "#PINLOCK_END\n"; print UCFFILE "#PINLOCK_END\n"; close (SIMILE); close (SDCFILE); close (UCFFILE); print "added $num_pins pins\n"; print "no match count: $no_match_count\n"; #foreach $pin (@no_match) { # print $pin->name,,":",$pin->loc,"\n"; #} $num_pins = 0; foreach my $sig (sort keys %sig_list) { # print SCHFILE 'FORCEPROP 2 LAST SIG_NAME ',$pin->name,$pin->index,"\n"; $y += 100; if ($y >= 5000) { $y = 0; $x = $x + $xlen + 500; } print SCHFILE " FORCEADD FLAG..5 (",$x+$xlen+50," $y); FORCEPROP 2 LAST CDS_LIB standard J 0 (",$x+$xlen+50," $y); DISPLAY INVISIBLE (",$x+$xlen+50," $y); FORCEPROP 1 LAST PATH I",$num_pins+1," J 0 (",$x+$xlen+55," ",$y-15,"); DISPLAY 0.804878 (",$x+$xlen+55," ",$y-15,"); PAINT GREEN (",$x+$xlen+55," ",$y-15,"); FORCEPROP 1 LASTPIN (",$x+$xlen+50," $y) HDL_PORT OUT J 0 (",$x+$xlen+375," ",$y-125,"); DISPLAY 1.000000 (",$x+$xlen+375," ",$y-125,"); PAINT GREEN (",$x+$xlen+375," ",$y-125,"); DISPLAY INVISIBLE (",$x+$xlen+375," ",$y-125,"); FORCEPROP 1 LAST NEEDS_NO_SIZE TRUE J 0 (",$x+$xlen+25," ",$y+25,"); DISPLAY 1.000000 (",$x+$xlen+25," ",$y+25,"); PAINT GREEN (",$x+$xlen+25," ",$y+25,"); DISPLAY INVISIBLE (",$x+$xlen+25," ",$y+25,"); FORCEPROP 1 LAST BODY_TYPE FLAG J 0 (",$x+$xlen," ",$y+50,"); DISPLAY 1.000000 (",$x+$xlen," ",$y+50,"); PAINT GREEN (",$x+$xlen," ",$y+50,"); DISPLAY INVISIBLE (",$x+$xlen," ",$y+50,"); FORCEPROP 1 LASTPIN (",$x+$xlen," ",$y,") OUTPUT_LOAD (*,*) J 0 (",$x+$xlen-25," ",$y-50,"); DISPLAY 1.000000 (",$x+$xlen-25," ",$y-50,"); PAINT GREEN (",$x+$xlen-25," ",$y-50,"); DISPLAY INVISIBLE (",$x+$xlen-25," ",$y-50,"); FORCEADD FLAG..1 (",$x-50," ",$y,"); FORCEPROP 2 LAST CDS_LIB standard J 0 (",$x-50," ",$y,"); DISPLAY INVISIBLE (",$x-50," ",$y,"); FORCEPROP 1 LAST PATH I2 J 0 (",$x-195," ",$y-15,"); DISPLAY 0.804878 (",$x-195," ",$y-15,"); PAINT GREEN (",$x-195," ",$y-15,"); FORCEPROP 1 LASTPIN (",$x," ",$y,") HDL_PORT IN J 0 (",$x+275," ",$y-125,"); DISPLAY 1.000000 (",$x+275," ",$y-125,"); PAINT GREEN (",$x+275," ",$y-125,"); DISPLAY INVISIBLE (",$x+275," ",$y-125,"); FORCEPROP 1 LAST NEEDS_NO_SIZE TRUE J 0 (",$x-25," ",$y+25,"); DISPLAY 1.000000 (",$x-25," ",$y+25,"); PAINT GREEN (",$x-25," ",$y+25,"); DISPLAY INVISIBLE (",$x-25," ",$y+25,"); FORCEPROP 1 LAST BODY_TYPE FLAG J 0 (",$x-50," ",$y+50,"); DISPLAY 1.000000 (",$x-50," ",$y+50,"); PAINT GREEN (",$x-50," ",$y+50,"); DISPLAY INVISIBLE (",$x-50," ",$y+50,"); FORCEPROP 1 LASTPIN (",$x," ",$y,") INPUT_LOAD (*,*) J 0 (",$x+50," ",$y-100,"); DISPLAY 1.000000 (",$x+50," ",$y-100,"); PAINT GREEN (",$x+50," ",$y-100,"); DISPLAY INVISIBLE (",$x+50," ",$y-100,"); "; if (($sig_list{$sig}->high_index != -1) && ($sig_list{$sig}->low_index != -1)) { if ($sig_list{$sig}->high_index == $sig_list{$sig}->low_index) { print SCHFILE "WIRE 16 -1 ($x $y)(",$x + $xlen," $y);\n"; print SCHFILE 'FORCEPROP 2 LAST SIG_NAME ',$sig_list{$sig}->name,$sig_list{$sig}->high_index,"\n"; } else { print SCHFILE "WIRE 17 -1 ($x $y)(",$x + $xlen," $y);\n"; # heavy line for bus print SCHFILE 'FORCEPROP 2 LAST SIG_NAME ',$sig_list{$sig}->name,"<",$sig_list{$sig}->high_index,'..',$sig_list{$sig}->low_index,">\n"; } $num_pins += $sig_list{$sig}->high_index - $sig_list{$sig}->low_index + 1; } elsif (($sig_list{$sig}->high_index != -1) || ($sig_list{$sig}->low_index != -1)) { print STDERR "********* Error on ",$sig_list{$sig}->name,"<",$sig_list{$sig}->high_index,'..',$sig_list{$sig}->low_index,">\n"; } else { print SCHFILE "WIRE 16 -1 ($x $y)(",$x + $xlen," $y);\n"; print SCHFILE 'FORCEPROP 2 LAST SIG_NAME ',$sig_list{$sig}->name,"\n"; $num_pins++; } print SCHFILE "J 0\n"; print SCHFILE "(",$x+200," ",$y + 10,");\n"; } print SCHFILE "QUIT\n"; close (SCHFILE); print "added $num_pins pins\n";