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

📄 vpassert

📁 Verilog Parser in Perl
💻
📖 第 1 页 / 共 4 页
字号:
    foreach my $i (@values) {	my $nexpr = $expr;	$nexpr =~ s/\$ui\b/($i)/g	    or die "%Error: ".$Last_Parser->fileline.": No \$ui in \$ucover_foreach_clk expression: $expr\n";	_ucover_clk_guts($clk, $label."__".$i, "(${nexpr})");    }}sub ucover_clk {    my $clk = shift;    my $label = shift;    $#_==-1	or die "%Error: ".$Last_Parser->fileline.": Extra arguments to \$ucover_clk: $_[0]\n";    # We require quotes around the label so synthesis tools won't gripe if not wrapping in vpassert    # (Otherwise it would look like a system call with a variable of the name of the label.)    ($label =~ s/^\s*\"([a-zA-Z][a-zA-Z0-9_]+)\"\s*$/$1/)	or die "%Error: ".$Last_Parser->fileline.": Non-string label \$ucover_clk second argument: $label\n";    _ucover_clk_guts($clk,$label, "1'b1");}sub _ucover_clk_guts {    my $clk = shift;    my $label = shift;    my $expr = shift;    $ReqAck_Num or die "%Error: ".$Last_Parser->fileline.": \$ucover_clk can't find module statement\n";    my $sig = "_ucoverclk${ReqAck_Num}";    $Insure_Symbols{$Last_Module}{$sig} = ['reg', 0];	# Make this symbol exist if doesn't    $ReqAck_Num++;    sendout("/*vpassert*/$sig=${expr};/*vpassert*/");    _insert_always_begin('cover', "/*vpassert*/ $sig=1'b0; /*vpassert*/");    # Alas, `line is required to see correct cover point    my $bot = "";    if ($Opt_Line) {	$bot .= "\n`line ".$Last_Parser->lineno." \"".$Last_Parser->filename."\" 0\n";    }    $bot .= " $label: cover property (@(posedge $clk) ($sig));\n";    if ($Opt_Line) {	$bot .= "`line /*vpassert_endmod_line*/ \"".$Last_Parser->filename."\" 0\n";    }    push @Endmodule_Inserts, $bot;}sub _insert_always_begin {    my $for_assert = shift;    my $text = shift;    my $beginl;    for (my $l = $#Sendout; $l>=0; $l--) {	my $tok = $Sendout[$l][1];	#print "HUNT $l: ".($beginl||"").": $tok\n";	# Fortunately all comments must be a single array entry	$tok =~ s!//.*?\n!!go;	$tok =~ s!/\*.*?\*/$!!go;	if ($tok =~ /\bbegin\b/) {	    $beginl = $l;	}	if ($tok =~ /\b(if|initial|final)\b/) {	    $beginl = undef;	}	if ($tok =~ /\bposedge\b/) {	    if ($for_assert ne 'cover') {		die "%Error: ".$Last_Parser->fileline.": \$uerror_clk is under a posedge clk, use \$uerror instead\n";	    }	}	if ($tok =~ /\balways\b/) {	    last if !defined $beginl;  # And die below	    my $insert = "";	    $insert .= "\n" if $Opt_Line;	    $insert .= $text;	    $insert .= "\n`line ".$Sendout[$l][0]." \"".$Last_Parser->filename."\" 0\n" if $Opt_Line;	    $Sendout[$beginl][1] =~ s/(\bbegin\b)/$1$insert/;	    return;	}    }    die "%Error: ".$Last_Parser->fileline.": \$uerror_clk is not somewhere under an 'always begin' block\n";}sub get_lineinfo {    # Align the lineinfo so that right hand sides are aligned    my $message_filename = $Last_Parser->filename;    $message_filename =~ s/^.*\///g;    my $lineinfo = substr ($message_filename, 0, 17); # Don't make too long    $lineinfo = $lineinfo . sprintf(":%04d:", $Last_Parser->lineno );    $lineinfo = sprintf ("%-21s", $lineinfo);}use vars qw($Msg_Header_Level);sub message_header {    my $out = "";    if (!$Msg_Header_Level) {	$out .= "\n/*summit modcovoff -bpen*/\n" if $Vericov_Enabled;	$out .= "\n/*ri userpass BE on*/\n" if $Opt_RealIntent;	$out .= "/*vpassert*/";    }    $out .= "begin ";    $out .= "`coverage_block_off " if ($Opt_Verilator && !$Msg_Header_Level);    $Msg_Header_Level++;    return $out;}sub message_trailer {    my $out = 'end ';    $out .= '/*vpassert*/' if ((--$Msg_Header_Level)==0);    $out .= "\n/*summit modcovon -bpen*/\n" if $Vericov_Enabled;    $out .= "\n/*ri userpass BE off*/\n" if $Opt_RealIntent;    return $out;}sub message {    my $lineinfo = shift;    my $show_id = shift;    my $char = shift;    my $cond = shift;    my $otherargs = shift;    my @params = @_;	# Level, printf string, args    if ($params[0] =~ /^\s*\"/) {	# No digit in first parameter	# Push new parameter [0] as a 0.	unshift @params, '0';    }    $params[1] = convert_concat_string($params[1]);    unless ($char =~ /^-I/i) {	if ($params[1] =~ s/\s*\"\s*$//) {	    # For a well-formed message, $params[1] now ends in "\\n".	    $params[1] .= "\\n" if $params[1] !~ /\\n$/;	    $params[1] = $params[1]."${char}: In %m\\n\"";	}    }    ($params[0] =~ /^\s*[0-9]/)	or die "%Error: ".$Last_Parser->fileline.": Non-numeric \$message first argument: $params[0]\n";    ($params[1] =~ /^\s*\"/)	or die "%Error: ".$Last_Parser->fileline.": Non-string \$message second argument: $params[1]\n";    my $out = message_header();    # These long lines without breaks are intentional; I want to preserve line numbers    my $is_warn = (($char eq "%%E") || ($char eq "%%W") || ($char eq "-i"));    if ($cond ne "1") {	# Conditional code, for $uassert	# Note this will only work in RTL code!  Chiponly build issues otherwise.	$out .= "if (!($cond) && (`__message_on)) ";    } elsif ($params[0] =~ /^\s*0\s*$/) {	# Always enabled	if ($is_warn) {	    $out .= "if (`__message_on) ";	}    } else {	# Complex test	$Insure_Symbols{$Last_Module}{__message} = ['integer',5];	# Make this symbol exist if doesn't	my $chk = 'if ((__message >= (' . $params[0] . '))';	$chk .= ' && (`__message_minimum >= (' . $params[0] . '))' if $Opt_Minimum;	$chk .= " && (`__message_on) " if $is_warn;	$chk .= ') ';	$out .= $chk;    }    my $task;    if (($char eq "-I") || ($char eq "-i")) {}    elsif ($char eq "%%E") {	$task = ($Opt_Stop ? '$stop;' : "`pli.errors = `pli.errors+1;");    } elsif ($char eq "%%W") {	$task = ($Opt_Stop ? '$stop;' : "`pli.warnings = `pli.warnings+1;");    } else { die "%Error: Unknown message character class '$char'\n"; }    {	# if's body	$out .= "begin";	$out .= " \$timeformat($Opt_Timeformat_Units, $Opt_Timeformat_Precision,\"\",20);"	    if defined $Opt_Timeformat_Units;	$out .= " \$write (\"[%0t] ${char}:${lineinfo} ";	my $par = $params[1];	$par =~ s/^\s*\"//;	$out .= "$par,\$time$otherargs";	for my $parn (2 .. $#params) {	    my $p = $params[$parn];	    $out .= ", $p";	    print "MESSAGE $char, Parameter $p\n" if ($Debug);	}	$out .= ');';	$out .= $task    if ($task && !$Opt_Chiponly);	$out .= '$stop;' if ($task && $Opt_Chiponly);	$out .= ' end ';    }    $out .= message_trailer();    return $out;}######################################################################sub _convert_foreach_comma {    my $in = shift;    # Similar to Verilog::Language::split_bus    my @out;    $in =~ s/\s+//g;    while ($in =~ s!,?(((\d+):(\d+))|(\d+))!!) {	if (defined $3 && defined $4) {	    if ($3<$4) {		foreach (my $i=$3; $i<=$4; $i++) {		    push @out, $i;		}	    } else {		foreach (my $i=$3; $i>=$4; $i--) {		    push @out, $i;		}	    }	} elsif (defined $5) {	    push @out, $5;	}    }    $in eq ""	or die "%Error: ".$Last_Parser->fileline.": Strange range expression: $in\n";    return @out;}sub convert_concat_string {    my $string = shift;    # Convert {"string"} or {"str","in","g"} to just "string"    # Beware embedded quotes "\""    return $string if ($string !~ /^\s*\{\s*(\".*)\s*\}\s*$/);    my $in = $1;    my $out = "";    my $quote; my $slash;    for (my $i=0; $i<length($in); $i++) {	my $c = substr($in,$i,1);	if ($quote && $c eq '"' && !$slash) {	    $quote = 0;	    $out .= $c;	} elsif ($quote) {	    $out .= $c;	} elsif ($c eq '"') {	    $quote = 1;	    $out .= $c;	    $out =~ s/\"\"$//;	# Join "" strings	} elsif ($c =~ /\s/) {	} elsif ($c eq ',') {	} else {	    # Something strange, just don't convert it	    return $string;	}	$slash = ($c eq "\\");    }    return $out;}########################################################################################################################################################################################################################################################################################sub sendout {    # Send out the string to the output file, consider this a change.    my $string = shift;    push @Sendout, [0, $string];    $Got_Change = 1;}sub sendout_orig {    # Send out the string to the output file, not a change.    # The first argument is the line number.  Right now only certain things    # need to set it.  In the future we may adopt a more general scheme    # whereby all original text sets it, the autos indicate "-1" and the    # outputter does the appropriate `lines for us.    my $string = shift;    push @Sendout, [0, $string];}########################################################################################################################################################################################################################################################################################sub form_conversions_regexp {    # Create $Vpassert_Conversions_Regexp, a regexp that matches any of the conversions    # This regexp will allow us to quickly look at the file and ignore it if no matches    $Vpassert_Conversions_Regexp = '\$(';    my $last_tok = "\$ignore";    foreach my $tok (sort (keys %Vpassert_Conversions)) {	($tok =~ s/^\$//) or die "%Error: Vpassert_Conversion $tok doesn't have leading \$\n";	if (substr ($tok, 0, length($last_tok)) eq $last_tok) {	    #print "Suppress $tok   $last_tok\n" if $Debug;	} else {	    $Vpassert_Conversions_Regexp .= "${tok}|";	    $last_tok = $tok;	}    }    $Vpassert_Conversions_Regexp =~ s/\|$ /\)/x;    $Vpassert_Conversions_Regexp = "\$NEVER_MATCH_ANYTHING" if $Vpassert_Conversions_Regexp eq '\$()';    #print "CV REGEXP $Vpassert_Conversions_Regexp\n" if $Debug;}sub vpassert_process {    # Read all signals in this filename    # Return TRUE if the file changed    my $filename = shift;    my $outname = shift;    $Got_Change = shift;	# True if should always write output, not only if have change    if ($outname =~ /[\/\\]$/) {	# Directory, not file, so append filename	my $basename = $filename;	$basename =~ s/.*[\/\\]//g;	$outname .= $basename;    }    print "vpassert_process ($filename, $outname, $Got_Change)\n"	if ($Debug);    ($filename ne $outname) or die "%Error: $filename: Would overwrite self.";    @Sendout = ();    @instance_tests_list = ();    # Set up parsing    my $parser = new Verilog::Vpassert::Parser;    $parser->filename($filename);    $parser->lineno(1);    $Last_Parser = $parser;    # Open file for reading and parse it    my $fh = IO::File->new("<$filename") or die "%Error: $! $filename.";    if (!$Got_Change) {	while (<$fh>) {	    goto diff if (/$Vpassert_Conversions_Regexp/o);	    goto diff if ($Opt_NoPli && /\$/);	}	print "$filename: No dollars, not processing\n" if ($Debug);	return;      diff:	$fh->seek(0,0);	$. = 1;    }    while (my $line = $fh->getline() ) {	$parser->parse ($line);    }    $parser->eof;    sendout_orig($parser->unreadback());    $parser->unreadback('');    $fh->close;    # Hack the output text to add in the messages variable    foreach my $mod (keys %Insure_Symbols) {	my $insert="";	my $n=0;  # Some compilers choke if lines get too long;	foreach my $sym (keys %{$Insure_Symbols{$mod}}) {	    #if ! $module_symbols{$sym} 	# For now always put it in	    my $type = $Insure_Symbols{$mod}{$sym}[0];	    my $value = $Insure_Symbols{$mod}{$sym}[1];	    $insert .= "$type $sym; initial $sym = $value;";	    if (++$n > 10) {		$insert .= "\n";		$n=0;	    }	}	if ($insert) {	    my $hit;	    for (my $l = $#Sendout; $l>=0; $l--) {		my $tok = $Sendout[$l][1];		if ($tok =~ m%/\*vpassert beginmodule $mod\*/%) {		    my $lineno = $Sendout[$l][0];		    if ($Opt_Line) {			$insert .= "\n`line ".$lineno." \"".$Last_Parser->filename."\" 0\n";		    }		    $tok =~ s%/\*vpassert beginmodule $mod\*/%/*vpassert*/$insert%g or die;  # Must exist, found above!		    $Sendout[$l][1] = $tok;		    $hit = 1;		    # Don't exit the loop, keep looking for more.		    # It's possible there's a `ifdef with multiple "module x" headers

⌨️ 快捷键说明

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