Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear All,

I have some simple code to process a Value Change Dump file and writes out data in the time ranges into one hash and writes out the last time a signal changed into another hash, besides other things.


All of these are further processed to split all the value changes into two groups: (1) signals that are changing in the time regions (time regions are specified using the syntax #time in the value change dump and (2) last change of any signal found in the Value Change Dump


Here is my code:
#!/usr/bin/perl use strict; use warnings; use diagnostics; use diagnostics -verbose; use Getopt::Long; use File::Path; use File::Copy; use Cwd; my $currentDir = getcwd; use Cwd 'abs_path'; my $vcdFile = $ARGV[0]; my $vcdObj = ClassVcd->new(); my $dataGenObj = ClassDataGen->new(); my ($inTimeRangeSignalsHRef, $sigsNotInTimeRangeHRef, $timeRngRef, $hi +erScopeRef) = $vcdObj->getSignalsWithValsInTimeWindow($vcdFile); foreach my $vcdFile (keys %{$inTimeRangeSignalsHRef}) { foreach my $s +igNm (keys %{$inTimeRangeSignalsHRef->{$vcdFile}}) { foreach my $sigId (keys %{$inTimeRangeSignalsHRef->{$vcdFile}->{$sig +Nm}}) { if (exists $inTimeRangeSignalsHRef->{$vcdFile}->{$sigNm}->{$sigId}- +>{$$timeRngRef}) { if (exists $inTimeRangeSignalsHRef->{$vcdFile}->{$sigNm}->{$sigId} +->{$$timeRngRef}->{$$hierScopeRef}) { print "Line 23 ::Dbg:: $vcdFile $sigNm $$timeRngRef\n"; } } } } $dataGenObj->matcher($inTimeRangeSignalsHRef, $sigsNotInTimeRangeHRef +, $timeRngRef, $hierScopeRef); } package ClassDataGen; sub new { my $class = shift; my $self = {}; bless($self, $class); return $self; } sub matcher { my $self = shift; my $inTimeRangeSignalsHRef = shift; my $sigsNotInTimeRangeHRef = shift; my $timeRangeRef = shift; my $hierScopeRef = shift; my %failedChecksH = (); my %matchingWhenRiRoCondsH = (); my %sigNmsVcdH = (); foreach my $vcdFile (keys %{$inTimeRangeSignalsHRef}) { foreach my $signalNm (keys %{$inTimeRangeSignalsHRef->{$vcdFile}}) { print "Line 67 ::Dbg:: $signalNm inTimeRangeSignalsHash\n"; } } } package ClassVcd; sub new { my $class = shift; my $self = {}; bless($self, $class); return $self; } sub getSignalsWithValsInTimeWindow { my $self = shift; my $vcdFileOrig = shift; my %vcdSigValsScopeH = (); my %inTimeRangeSignalsH = (); my %sigsNotInTimeRangeH = (); my $timeRng = ""; my $hierScope = ""; my $vcdObj = ClassVcd->new(); my ($lastKnownSigValHRef, $scopesHierHRef, $scopesHRef, $timeRangeHRe +f, $timeIntervalBasedActivityHRef, $vcdFile, $timeUnits) = $vcdObj->p +arseVcd($vcdFileOrig); if(exists $timeRangeHRef->{$vcdFile}) { $timeRng = $timeRangeHRef->{$vcdFile}->{'TIMERANGES'}->[-1]; if(exists $timeIntervalBasedActivityHRef->{$vcdFile}) { if(exists $timeIntervalBasedActivityHRef->{$vcdFile}->{$timeRng}) { foreach my $sigId (keys %{$timeIntervalBasedActivityHRef->{$vcdFil +e}->{$timeRng}}) { foreach my $sigName (keys %{$timeIntervalBasedActivityHRef->{$vcd +File}->{$timeRng}->{$sigId}}) { foreach my $scopeNm (keys %{$timeIntervalBasedActivityHRef->{$vc +dFile}->{$timeRng}->{$sigId}->{$sigName}}) { if ( ($scopeNm =~ /_TB/) && (exists $timeIntervalBasedActivityH +Ref->{$vcdFile}->{$timeRng}->{$sigId}->{$sigName}->{$scopeNm}->{'EXPA +NDEDVAL'}) ) { $hierScope = $scopeNm; my $sigValue = $timeIntervalBasedActivityHRef->{$vcdFile}->{$ +timeRng}->{$sigId}->{$sigName}->{$scopeNm}->{'EXPANDEDVAL'}->[-1]; $inTimeRangeSignalsH{$vcdFile}{$sigName}{$sigId}{$timeRng}{$sc +opeNm} = $sigValue; } } } } } } } if(exists $lastKnownSigValHRef->{$vcdFile}) { foreach my $signalId (keys %{$lastKnownSigValHRef->{$vcdFile}}) { foreach my $signalNm (keys %{$lastKnownSigValHRef->{$vcdFile}->{$si +gnalId}}) { if(!exists $inTimeRangeSignalsH{$vcdFile}{$signalNm}{$signalId}) { $sigsNotInTimeRangeH{$vcdFile}{$signalNm}{$signalId} = $lastKnown +SigValHRef->{$vcdFile}->{$signalId}->{$signalNm}->{$hierScope}->[0]; } } } } return(\%inTimeRangeSignalsH, \%sigsNotInTimeRangeH, \$timeRng, \$hie +rScope); } sub parseVcd { my $self = shift; my $vcdFile = shift; my @scopesA = (); my @timeValsA = (); my %scopesHierH = (); my %timedSigChangesH = (); my %totalSigActivityH = (); my %signalNotFoundInAnyScope = (); my %timeRangeH = (); my %timeValsH = (); my %dumpVarsH = (); my %scopesH = (); my %lastKnownSigValH = (); my $timescaleFlg = 0; my $scopeFlg = 0; my $scopeCnt = 0; my $upscopeCnt = 0; my $dumpvarsFlg = 0; my $inTimeFlg = 0; my $timeCnt = 0; my $timeScale = ""; my $timeUnits = ""; my $timeMultiplier = ""; my $scopeName = ""; my $timeValue = ""; my $foundSignalInSomeScope = 0; open(VCD,"<", $vcdFile) or die "Cannot open $vcdFile:$!"; while(<VCD>) { chomp; if(/^\s*\$timescale\s*$/) { $timescaleFlg = 1; } if($timescaleFlg == 1) { if(/^\s*\$end\s*$/) { $timescaleFlg = 0; }else{ if(/^\s*([0-9]+)\s+(\S+)\s*$/) { $timeMultiplier = $1; $timeUnits = $2; } } } if(/^\s*\$scope\s+module\s+(\S+)\s+\$end/) { $scopeFlg = 1; $scopeName = $1; $scopeCnt++; push(@{$scopesHierH{$vcdFile}{'SCOPES'}}, $scopeName); } if($scopeFlg == 1) { if(/^\s*\$upscope\s+\$end/) { $upscopeCnt++; if($upscopeCnt == $scopeCnt) { $scopeFlg = 0; } }else{ my $varLine = ""; if(/^\s*\$var\s+.*\$end\s*$/) { $varLine = $_; $varLine =~ s/\s+\[(.*)\]\s+\$end/\[$1\] \$end/g; } if($varLine =~ /^\s*\$var\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+\$end\ +s*$/) { my $sigName = $4; my $sigId = $3; my $sigSize = $2; my $sigType = $1; if($sigName =~ /\[\S+\]/) { } if( (defined $scopeName) && ($scopeName ne "")) { if((defined $sigId) && ($sigId ne "")) { if((defined $sigName) && ($sigName ne "")) { if((defined $sigSize) && ($sigSize ne "")) { if((defined $sigType) && ($sigType ne "")) { $scopesH{$vcdFile}{$sigId}{$sigName}{$scopeName} = [$sigType +, $sigSize]; } } } } } } } } if( (/^\s*\$dumpvars\s*$/) && ($inTimeFlg == 0) ) { $dumpvarsFlg = 1; } if( ($dumpvarsFlg == 1) && ($inTimeFlg == 0) ) { if(/^\s*\$end\s*$/) { $dumpvarsFlg = 0; }else{ if(/^\s*(b.*)\s+(\S+)\s*$/) { my $sigId = $2; my $sigVal = $1; if(exists $scopesH{$vcdFile}{$sigId}) { foreach my $sigNm (sort keys %{$scopesH{$vcdFile}{$sigId}}) { foreach my $scopeNm (sort keys %{$scopesH{$vcdFile}{$sigId}{$s +igNm}}) { $lastKnownSigValH{$vcdFile}{$sigId}{$sigNm}{$scopeNm} = [$sigV +al, 'dumpvars']; } } } }elsif( (/^\s*(\S)(\S+)\s*$/) && !(/^\s*(b.*)\s+(\S+)\s*$/) ) { my $sigId = $2; my $sigVal = $1; if(exists $scopesH{$vcdFile}{$sigId}) { foreach my $sigNm (sort keys %{$scopesH{$vcdFile}{$sigId}}) { foreach my $scopeNm (sort keys %{$scopesH{$vcdFile}{$sigId}{$s +igNm}}) { $lastKnownSigValH{$vcdFile}{$sigId}{$sigNm}{$scopeNm} = [$sigV +al, 'dumpvars']; } } } } } } if(/^\s*(#\S+)\s*$/) { $inTimeFlg = 1; my $timePoint = $1; } if($inTimeFlg == 1) { if(/^\s*#(\S+)\s*$/) { my $time = $1; $time *= $timeMultiplier; $timeValue = '#'.$time; push(@timeValsA, $timeValue); }elsif( (/^\s*(\S)(\S+)\s*$/) || (/^\s*(b.*)\s+(\S+)\s*$/) ) { my $signalVal = $1; my $signalId = $2; if(!exists $totalSigActivityH{$vcdFile}{$signalId}) { $totalSigActivityH{$vcdFile}{$signalId}{'CNT'} = 0; }else{ $totalSigActivityH{$vcdFile}{$signalId}{'CNT'}++; } if(exists $scopesH{$vcdFile}{$signalId}) { foreach my $sigNm (sort keys %{$scopesH{$vcdFile}{$signalId}}) { foreach my $scopeNm (sort keys %{$scopesH{$vcdFile}{$signalId}{ +$sigNm}}) { $lastKnownSigValH{$vcdFile}{$signalId}{$sigNm}{$scopeNm} = [$si +gnalVal, $timeValue]; if(exists $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$s +igNm}{$scopeNm}) { if( (exists $timedSigChangesH{$vcdFile}{$timeValue}{$signalId} +{$sigNm}{$scopeNm}{'VAL'}) && ($timedSigChangesH{$vcdFile}{$timeValue +}{$signalId}{$sigNm}{$scopeNm}{'VAL'} ne "") ) { if($timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm} +{$scopeNm}{'VAL'} ne $signalVal) { if(exists $timedSigChangesH{$vcdFile}{$timeValue}{$signalId} +{$sigNm}{$scopeNm}{'CNT'}) { $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{ +$scopeNm}{'CNT'}++; }else{ $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{ +$scopeNm}{'CNT'} = 0; } $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{$ +scopeNm}{'VAL'} = $signalVal; my $expandedVal = $signalVal; push(@{$timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$s +igNm}{$scopeNm}{'EXPANDEDVAL'}}, $expandedVal); }elsif($timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$si +gNm}{$scopeNm}{'VAL'} eq $signalVal) { my $expandedVal = $signalVal; push(@{$timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$s +igNm}{$scopeNm}{'EXPANDEDVAL'}}, $expandedVal); if (!exists $timedSigChangesH{$vcdFile}{$timeValue}{$signalI +d}{$sigNm}{$scopeNm}{'CNT'}) { $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{ +$scopeNm}{'CNT'} = 0; } } }elsif(!exists $timedSigChangesH{$vcdFile}{$timeValue}{$signal +Id}{$sigNm}{$scopeNm}{'VAL'}) { $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{$s +copeNm}{'VAL'} = $signalVal; $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{$s +copeNm}{'CNT'} = 0; my $expandedVal = $signalVal; push(@{$timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$si +gNm}{$scopeNm}{'EXPANDEDVAL'}}, $expandedVal); $signalNotFoundInAnyScope{$vcdFile}{$signalId}++;; } }elsif(!exists $timedSigChangesH{$vcdFile}{$timeValue}{$signalI +d}{$sigNm}{$scopeNm}) { $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{$sc +opeNm}{'VAL'} = $signalVal; $timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sigNm}{$sc +opeNm}{'CNT'} = 0; my $expandedVal = $signalVal; push(@{$timedSigChangesH{$vcdFile}{$timeValue}{$signalId}{$sig +Nm}{$scopeNm}{'EXPANDEDVAL'}}, $expandedVal); } } } } } } } close VCD; my %timeIntervalBasedActivityH = (); my @timeRangeA = (); push(@timeValsA, 'END'); my $limit = scalar (@timeValsA) - 1; for(my $i = 0; $i <= $limit; $i++) { if(exists $timedSigChangesH{$vcdFile}{$timeValsA[$i]}) { my $lBound = $timeValsA[$i]; my $hBound = $timeValsA[$i+1]; my $timeRange = $lBound." ".$hBound; push(@{$timeRangeH{$vcdFile}{'TIMERANGES'}}, $timeRange); foreach my $sigId (keys %{$timedSigChangesH{$vcdFile}{$lBound}}) { foreach my $sigName (keys %{$timedSigChangesH{$vcdFile}{$lBound}{$ +sigId}}) { foreach my $scopeNm (keys %{$timedSigChangesH{$vcdFile}{$lBound}{ +$sigId}{$sigName}}) { if(exists $timedSigChangesH{$vcdFile}{$lBound}{$sigId}{$sigName} +{$scopeNm}{'CNT'}) { $timeIntervalBasedActivityH{$vcdFile}{$timeRange}{$sigId}{$sigN +ame}{$scopeNm}{'CNT'} = $timedSigChangesH{$vcdFile}{$lBound}{$sigId}{ +$sigName}{$scopeNm}{'CNT'}; } if(exists $timedSigChangesH{$vcdFile}{$lBound}{$sigId}{$sigName} +{$scopeNm}{'EXPANDEDVAL'}) { foreach my $expandedVal (@{$timedSigChangesH{$vcdFile}{$lBound} +{$sigId}{$sigName}{$scopeNm}{'EXPANDEDVAL'}}) { push(@{$timeIntervalBasedActivityH{$vcdFile}{$timeRange}{$sigI +d}{$sigName}{$scopeNm}{'EXPANDEDVAL'}}, $expandedVal); } } } } } } } return(\%lastKnownSigValH, \%scopesHierH, \%scopesH, \%timeRangeH, \% +timeIntervalBasedActivityH, $vcdFile, $timeUnits); } <code> Here is a sample input file, I used to run the above code (saved the a +bove file into a file called <code>min.pl
and saved my input file as junk.vcd and then executed min.pl ./junk.vcd from my Linux command prompt):
$date Dec 02, 2012 04:51:31 $end $version TOOL: ncsim(64) 10.20-s027 $end $timescale 1 ps $end $scope module JUNKCELL_TB $end $var wire 1 ! I0 $end $var wire 1 " I1 $end $var wire 1 # I2 $end $var wire 1 $ RIGHT $end $var wire 1 % SERIAL $end $var wire 1 & ZEN $end $scope module DUTJNKCELL $end $var wire 1 ! I0 $end $var wire 1 " I1 $end $var wire 1 # I2 $end $var wire 1 & ZEN $end $var wire 1 $ RIGHT $end $var wire 1 % SERIAL $end $var wire 1 ' lnx0_out $end $var wire 1 ( lnx1_out $end $var wire 1 ) lnx2_out $end $var wire 1 * lnx3_out $end $var wire 1 + lnx4_out $end $var wire 1 , lnx5_out $end $upscope $end $upscope $end $enddefinitions $end $dumpvars 0! 0" 0# 1$ 1% 1& 0' 0( 1) 0* 1+ 0, $end #10 1! 1' 1( 0) 0$ 0& #20
Here is the output I got:
[jeff@lnx02_sfo]$ ./min.pl ./junkCell.vcd
Produces the output below:
Line 23 ::Dbg:: ./junkCell.vcd I0 #10 #20 Line 23 ::Dbg:: ./junkCell.vcd ZEN #10 #20 Line 23 ::Dbg:: ./junkCell.vcd RIGHT #10 #20 Line 67 ::Dbg:: lnx4_out inTimeRangeSignalsHash Line 67 ::Dbg:: I0 inTimeRangeSignalsHash Line 67 ::Dbg:: lnx1_out inTimeRangeSignalsHash Line 67 ::Dbg:: ZEN inTimeRangeSignalsHash Line 67 ::Dbg:: lnx3_out inTimeRangeSignalsHash Line 67 ::Dbg:: RIGHT inTimeRangeSignalsHash Line 67 ::Dbg:: lnx2_out inTimeRangeSignalsHash Line 67 ::Dbg:: lnx5_out inTimeRangeSignalsHash Line 67 ::Dbg:: lnx0_out inTimeRangeSignalsHash Line 67 ::Dbg:: SSERIAL inTimeRangeSignalsHash Line 67 ::Dbg:: I2 inTimeRangeSignalsHash Line 67 ::Dbg:: SERIAL inTimeRangeSignalsHash Line 67 ::Dbg:: I1 inTimeRangeSignalsHash
Please see the lines "Line 67 ::Dbg::...". These are printed by calling $dataGenObj->matcher($inTimeRangeSignalsHRef, $sigsNotInTimeRangeHRef, $timeRngRef, $hierScopeRef); Why does calling $dataGenObj->matcher($inTimeRangeSignalsHRef, $sigsNotInTimeRangeHRef, $timeRngRef, $hierScopeRef); print all these extra signals as part of $inTimeRangeSignalsHRef? I was expecting that the Hash %inTimeRangeSignalsH contains only three signals as shown below:
Line 23 ::Dbg:: ./junkCell.vcd I0 #10 #20 Line 23 ::Dbg:: ./junkCell.vcd ZEN #10 #20 Line 23 ::Dbg:: ./junkCell.vcd RIGHT #10 #20

Please help me understand what is the mistake I am making. Thanks so much.

Replies are listed 'Best First'.
Re: Hashes not working as expected
by Anonymous Monk on Feb 27, 2016 at 07:02 UTC
    Never mind, dear friends. I figured out the problem and corrected it. Thanks.
      That's great that you solved your issue, but for the benefit of future readers, could you please let us know what you did that fixed it?

      Was the problem autovivification in sub getSignalsWithValsInTimeWindow() ?

      if(exists $lastKnownSigValHRef->{$vcdFile}) {
        foreach my $signalId (keys %{$lastKnownSigValHRef->{$vcdFile}}) {
         foreach my $signalNm (keys %{$lastKnownSigValHRef->{$vcdFile}->{$signalId}}) {
      
        #### this line is creating the extra signals 
        #### as you check the lowest level
          if(!exists $inTimeRangeSignalsH{$vcdFile}{$signalNm}{$signalId}) {
      
      
           $sigsNotInTimeRangeH{$vcdFile}{$signalNm}{$signalId} = $lastKnownSigValHRef->{$vcdFile}->{$signalId}->{$signalNm}->{$hierScope}->[0];
          } 
         }
        }
       }
      
      poj