⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plglobal.pl

📁 自动生成VERILOG 工具
💻 PL
字号:
## This file is part of the Perlilog project.## Copyright (C) 2003, Eli Billauer## 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## A copy of the license can be found in a file named "licence.txt", at the# root directory of this project.#${__PACKAGE__.'::errorcrawl'}='system';sub who {  return "The Global Object";}sub new {  my $this = shift;  my $self = $this->SUPER::new(@_);  my $name = $self->get('name');  puke("The \'global\' class can generate an object only with the name \'globalobject\'".       " and not \'$name\'\n") unless ($name eq 'globalobject');  return $self;}  sub complete {  my $self = shift;  my $dir=$self->get('filesdir');  blow("The \'filesdir\' property was not set for ".$self->who()."\n")    unless ($dir);  mkdir $dir, 0777 unless -e $dir;  opendir(DIR,$dir) || blow("Failed to open $dir as a directory\n");  my @A=readdir(DIR);  closedir(DIR);  foreach (grep /[^.]/, @A) {    unlink "$dir/$_";  }}# NOTE: execute does not allow extra methods or objects to be# added once started.sub execute {  my $global = shift; # We're the global object, aren't we?  puke("The execute method was not run from the global object\n")    unless ($global == $global->globalobj());  my $system = $global -> get('system');  my @methods = $system -> get('methods');  my @objects = ($global -> get('beginobjects'),		 $global -> get('objects'),		 $global -> get('endobjects'));  my ($method, $object);  # Note that the global object sneaks in first here  @methods = grep { defined } @methods;  @objects = grep { defined } ($global, @objects);  foreach $method (@methods) {    foreach $object (@objects) {      $object->$method();    }    last if ($Perlilog::wrongflag);  }}sub constreset {  my ($self, $ID, $type) = @_;  wrong ("Reset of unknown type \'$type\'")    unless grep {$type eq $_} qw(sync negsync async negasync);  wrong ("Unproper ID \'$ID\' given for reset signal\n")    unless (defined $Perlilog::VARS[$ID]);  # $self is global object!  $self->const('reset_type', $type);  $self->const('reset_ID', $ID);}sub instantiate {  my $self = shift;  $self->SUPER::instantiate(@_);  my ($i, $ID, $drive, $obj, $var, $type, $parent);  my ($from, $start, $to, $next, $f, $t, $toname);  my ($fv, $tv, $dim, $nv, $nID, $tmp, $wf, $hashref);  my %eqvars;  my @eq;  # Type conversion hashes  my %toin=('input' => 'input',	    'wire'  => 'input',	    'inout' => 'inout',	    'output'=> 'inout');  my %toout=('output' => 'output',	     'reg'    => 'outreg',	     'outreg' => 'outreg',	     'wire'   => 'output',	     'inout'  => 'inout',	     'input'  => 'inout');  # We begin with triggering off tree studies.  foreach $i (values %Perlilog::objects) {    next unless (defined $i->get('inshash')); # Only Verilog objects...    next if (ref $i->get('parent')); # Only "root" objects...    $i->treestudy;  }  # Now we collapse the EQVARS list to the minimal number  # of distinct lists. Note that the hash keys are the  # string representation of the reference, and only  # functions as a unique representation of the reference.  # The value points to the index in EQVARS, which makes  # is possible to retrieve the EQVARS list again.  # We loop in reverse order, so that the value will represent  # the variable in the cluster that was defined earliest.  my $imax = $#Perlilog::EQVARS;  for ($i=$imax; $i>=0; $i--) {    next unless (ref $Perlilog::EQVARS[$i]);    $eqvars{$Perlilog::EQVARS[$i]}=$i;  }  my @in;  my @out;  my @zout;  my %where;  # This little subroutine will help up make nice error messages.  # Note that it runs in the current scope.  my $s = sub {    my $r = "These are the variables involved:\n";    if (@out) {      $r.="Driving variables:\n";      foreach (@out)	{ $r.="  Variable ".$self->varwho($_)."\n"; }    }    if (@zout) {      $r.="Weakly driving variables:\n";      foreach (@zout)	{ $r.="  Variable ".$self->varwho($_)."\n"; }    }    if (@in) {      $r.="Driven variables:\n";      foreach (@in)	{ $r.="  Variable ".$self->varwho($_)."\n"; }    }    return $r;  };  # This is the main loop. Each $i is a variable cluster that  # needs to be interconnected.  foreach $i (sort values %eqvars) {    my @ids=@{$Perlilog::EQVARS[$i]}; # Get a local copy. The original may change    next unless ($#ids>0); # No hassle with unconnected variables    @in=(); @out=(); @zout=();    %where=();    # We now distribute the variables to the respective lists. We    # also set up the %where hash that tells us the names of the    # variables in the objects, if they exist. Again, the keys    # are not real references but string representations, but it's    # good enough for looking up.  IDLOOP:    foreach $ID (sort @ids) {      ($obj, $var) = @{$Perlilog::VARS[$ID]};      $drive = $obj->get(['vars', $var, 'drive']);      # If $where{$obj} is already defined, it means we have two      # equal variables in the same module. This is handled quite      # gracefully as long as they don't happen to be both zouts.      # For the case when they are both zouts, by make a nonstrength-      # reducing transistor connecting, as would an inout connection,      # and don't deal with the new variable any more.      if (defined $where{$obj}) {	if ($drive eq 'zout') {	  if ($obj->get(['vars', $where{$obj}, 'drive']) eq 'zout') {	    # Horrors! Two zouts in the same module!	    my $tranins = $obj->suggestins('PL_tran');	    $obj->addins($tranins, 'detached');	    wrong("Failed to handle bidirectional variable \'".$var."\' in ".$obj->who.		  " because the Verilog is static\n")	      unless ($obj->append("  tran $tranins ($var, ".$where{$obj}.");\n"));	    next IDLOOP; # Don't register this variable. It's already handled	  } else {	    # The existing variable wasn't a zout, but we'll set $where{$obj} to this	    # variable, so we won't miss a zout clash in the future...	    $where{$obj} = $var;	  }	}	# Note that we do nothing if this is not a zout case. We let the previously	# registered variable persist.      } else {	$where{$obj} = $var; # This is just the normal case. A first-timer      }            # We put the variable in the right list, according to "drive"      if ($drive eq 'in') { push @in, $ID; }      elsif ($drive eq 'out') { push @out, $ID; }      elsif ($drive eq 'zout') { push @zout, $ID; }      elsif ($drive eq 'via') {	wrong("Variable ".$self->varwho($ID).	      " was of drive-type \'via\' (System error?)\n");      } else {	wrong("Variable ".$self->varwho($ID).	      " is of unknown drive-type \'$drive\'\n");      }    }    # Now we complain if things aren't so good...    if (($#out<0) && ($#zout<0)) {      wrong("No driving variable in cluster\n".&$s);    } elsif ($#out>0) {      wrong("More than one exclusively driving variable in cluster\n".&$s);    } elsif (($#out==0) && ($#zout>=0)) {      wrong("Exclusiveness of driving variable was offended by weakly driven variables\n".&$s);    }    # Now we draw lines from every driving variable to every    # driven variable.  FLOOP: # The "from" loop -- driving variables    foreach $f ((sort @out), (sort @zout)) {      ($start, $fv) = @{$Perlilog::VARS[$f]};    TLOOP: # The "to" loop -- driven variables      foreach $t ((sort @in), (sort @zout)) {	next TLOOP if ($t == $f);	($to, $tv) = @{$Perlilog::VARS[$t]};	$from = $start;	$toname = $to->get('name');	# If we happen to start and end at the same object,	# why hassle? Just make an internal assignment. But	# alas, the current object may not allow its Verilog	# content to change, in which case append() fails.	# In that case we simply go on, which will cause	# a walk-up to the parent and back (good).	next TLOOP	  if (($start == $to) &&	      ($start->append("  assign $tv = $fv;\n")));	# OK, now we come to SLOOP: The walking around loop.	# We travel our way to $to. treestudy() earlier	# promised to take us there, so we trust it and	# run the loop until we reach the place.      SLOOP:	while (1) {	  # We fetch the next object to walk to	  $next = ${$from->get('treepath')}{$toname};	  unless (ref $next) {	    wrong("No path found between variables ".$self->varwho($f).		  " and ".$self->varwho($t)."\n");	    next TLOOP;	  }	  	  # Now the world splits in two: Either we went from child	  # to parent, or the opposite way. Anyhow, this takes	  # opposite treatment, since we always create the inputs and	  # outputs on the child, whereas the parent gets a "wire" at	  # most.	  $parent = $next->get('parent');	  if (defined ($parent) && ($parent == $from)) {	    # This is the parent to child walk part:	    # Get the variable name an $next's object. If we happen to	    # have reached our destination, take $tv. This is because	    # if there are two input variables in the same object,	    # only one will be represented in $where{$next}	    $nv = ($next==$to) ? $tv : $where{$next};	    # If $nv is not defined, it means that object currently	    # has no access to the variable. We create a via.	    unless (defined $nv) {	      # Now we want to set the name nicely. If the current object	      # has the 'viasource' (list) property set, we scan through the objects	      # from which we may borrow the name. Only non-via variables	      # may donate names.	      	    VIALOOP1:	      foreach my $source ($next->get('viasource')) {		if ((defined $where{$source}) &&		    ($source->get(['vars',$where{$source},'drive']) ne 'via')) {		  $nv = $next->suggestvar($where{$source}); # This is a good source!		  last VIALOOP1; # No more search!		}	      }	      $nv = $next->suggestvar($fv.'_via') # Make _via		unless (defined $nv);	      $nID = $next->addvar($nv, 'wire', 'via');	      $next->attach($f, $nID); # This will also get the 'dim' property right	      $where{$next}=$nv; # Register it, so we won't do this again	    }	    	    # Now we change the variable's type if needed.	    $tmp = $toin{$next->get(['vars',$nv,'type'])};	    blow("Expected a variable convertable to input/inout, got ".		 "variable \'$nv\' of type \'".$next->get(['vars',$nv,'type'])."\' on ".		 $next->who."\n")	      unless (defined $tmp);	    # We can't change variable types of static objects. Be sure.	    	    if ($next->get('static')) {	      wrong("Attempted to change the variable type of $nv to $tmp in ".		    $next->who()." but it is a static Verilog object\n") 		unless ($next->get(['vars',$nv,'type']) eq $tmp)	      } else {		$next->set(['vars',$nv,'type'], $tmp);	      }	    # And finally, we register the connection in 'inshash'. We are not	    # worried about if the entry is already set, because it will always	    # be set to the same value, $where{$from}	    $hashref = $next->get('inshash');	    ${$hashref}{$nv}=$where{$from};		  } else {	    # This is the child to parent walk part: (quite similar)	    # Get the variable name an $next's object. If we happen to	    # have reached our destination, take $tv. This is because	    # if there are two input variables in the same object,	    # only one will be represented in $where{$next}	    $nv = ($next==$to) ? $tv : $where{$next};	    # If $nv is not defined, it means that object currently	    # has no access to the variable. We create a via.	    unless (defined $nv) {	      # Now we want to set the name nicely. If the current object	      # has the 'viasource' (list) property set, we scan through the objects	      # from which we may borrow the name. Only non-via variables	      # may donate names.	    	    VIALOOP2:	      foreach my $source ($next->get('viasource')) {		if ((defined $where{$source}) &&		    ($source->get(['vars',$where{$source},'drive']) ne 'via')) {		  $nv = $next->suggestvar($where{$source}); # This is a good source!		  last VIALOOP2; # No more search!		}	      }	      $nv = $next->suggestvar($fv.'_via') # Make _via		unless (defined $nv);	      	      $nID = $next->addvar($nv, 'wire', 'via');	      $next->attach($f, $nID); # This will also get the 'dim' property right	      $where{$next}=$nv; # Register it, so we won't do this again	    }	    	    # Now we change the variable's type if needed.	    $wf = $where{$from}; # We use it a lot here, so...	    $tmp = $toout{$from->get(['vars',$wf,'type'])};	    blow("Expected a variable convertable to output/inout, got ".		 "variable \'$wf\' of type \'".$from->get(['vars',$wf,'type'])."\' on ".		 $from->who."\n")	      unless (defined $tmp);	    # We can't change variable types of static objects. Be sure.	    if ($from->get('static')) {	      wrong("Attempted to change the variable type of $wf to $tmp in ".		    $from->who()." but it is a static Verilog object\n") 		unless ($from->get(['vars',$wf,'type']) eq $tmp)	      } else {		$from->set(['vars',$wf,'type'], $tmp);	      }	    # And finally, we register the connection in 'inshash'. If the entry	    # is already initialized, then we've already connected that variable.	    # We use an assign instead. Note that this won't work with zouts.	    $hashref = $from->get('inshash');	    $tmp = ${$hashref}{$wf};            if ((defined $tmp) && ($tmp ne $nv)) {	      $next->append("  assign $nv = $tmp;\n");	    } else {	      ${$hashref}{$wf}=$nv;            }	  }	  # Now it's time to see if we're finished. That is, have we	  # reached our destination?	  last SLOOP if ($next == $to);	  $from = $next; # This is the actual walking	}      }    }  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -