From 945496d6d9680030fbb1997af7389b47b4aaede0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Jan 2021 13:36:46 -0500 Subject: [PATCH 01/79] devel release --- Changes | 3 +++ configure.ac | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 1547bfedb..70834a094 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,9 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.109 devel + + * Verilator 4.108 2021-01-10 ** Many VPI changes for IEEE compatibility, which may alter behavior from previous releases. diff --git a/configure.ac b/configure.ac index f3c39b4bd..0ef39b109 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.108 2021-01-10], +AC_INIT([Verilator],[4.109 devel], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file From e9726681699b2e60b3c95412c457ec1d1094fa97 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Jan 2021 18:55:56 -0500 Subject: [PATCH 02/79] CI: Fix coverage action --- .github/workflows/coverage.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 00623317b..5504fd433 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -44,14 +44,11 @@ jobs: run: | ./ci/ci-script.bash - mkdir tarball/ - cp -vr bin tarball/ - cp -vr src/obj*/*.gcno tarball/ - tar cvzf verilator-${CI_COMMIT}.tgz -C ./tarball . + tar cvzf verilator-${CI_COMMIT}-coverage.tgz bin src/obj*/*.gcno - uses: actions/upload-artifact@v2 with: - path: verilator-${{ env.CI_COMMIT }}.tgz + path: verilator-${{ env.CI_COMMIT }}-coverage.tgz Test: @@ -89,7 +86,7 @@ jobs: - name: Install Verilator and test dependencies run: | - tar xvzf artifact/verilator-${CI_COMMIT}.tgz + tar xvzf artifact/verilator-${CI_COMMIT}-coverage.tgz ./ci/ci-install.bash - name: Test From 6060acc73d7185709b4579eba9ceb108c8d8c084 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Jan 2021 19:15:39 -0500 Subject: [PATCH 03/79] CI: Fix coverage action --- .github/workflows/coverage.yml | 3 ++- ci/ci-script.bash | 22 +++++++++++----------- nodist/code_coverage | 9 +++++++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5504fd433..706a40690 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -44,7 +44,7 @@ jobs: run: | ./ci/ci-script.bash - tar cvzf verilator-${CI_COMMIT}-coverage.tgz bin src/obj*/*.gcno + tar cvzf verilator-${CI_COMMIT}-coverage.tgz bin src/obj*/*.o src/obj*/*.gcno - uses: actions/upload-artifact@v2 with: @@ -87,6 +87,7 @@ jobs: - name: Install Verilator and test dependencies run: | tar xvzf artifact/verilator-${CI_COMMIT}-coverage.tgz + touch src/obj*/*.o src/obj*/*.gcno ./ci/ci-install.bash - name: Test diff --git a/ci/ci-script.bash b/ci/ci-script.bash index bcfc24285..eb3b828cf 100755 --- a/ci/ci-script.bash +++ b/ci/ci-script.bash @@ -51,7 +51,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then stat bin/verilator_bin_dbg fi else - nodist/code_coverage --stages 1-2 + nodist/code_coverage --stages 0-2 fi elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then ############################################################################## @@ -97,34 +97,34 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2 ;; coverage-all) - nodist/code_coverage --stages 3- + nodist/code_coverage --stages 1- ;; coverage-dist) - nodist/code_coverage --stages 3- --scenarios=--dist + nodist/code_coverage --stages 1- --scenarios=--dist ;; coverage-vlt-0) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4 + nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=0/4 ;; coverage-vlt-1) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4 + nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=1/4 ;; coverage-vlt-2) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4 + nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=2/4 ;; coverage-vlt-3) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4 + nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=3/4 ;; coverage-vltmt-0) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4 + nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=0/4 ;; coverage-vltmt-1) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4 + nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=1/4 ;; coverage-vltmt-2) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4 + nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=2/4 ;; coverage-vltmt-3) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4 + nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=3/4 ;; *) fatal "Unknown test: $TESTS" diff --git a/nodist/code_coverage b/nodist/code_coverage index ce797e942..4dc57d96a 100755 --- a/nodist/code_coverage +++ b/nodist/code_coverage @@ -26,10 +26,15 @@ def test(): sys.exit("%Error: Run code_coverage from the top of the verilator kit") exec(open("./nodist/code_coverage.dat").read()) + if Args.stage_enabled[0]: + ci_fold_start("distclean") + print("Stage 0: distclean") + run("make distclean || true") + ci_fold_end() + if Args.stage_enabled[1]: ci_fold_start("configure") print("Stage 1: configure (coverage on)") - run("make distclean || true") run("autoconf") # Exceptions can pollute the branch coverage data run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'" @@ -387,7 +392,7 @@ if True: start = int(match_from.group(1)) else: os.exit("%Error: --stages not understood: " + Args.stages) - for n in range(1, 100): + for n in range(0, 100): Args.stage_enabled[n] = False for n in range(start, end + 1): Args.stage_enabled[n] = True From d4d9e12b6669505146b793fb41b667a2b8ecaa16 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Jan 2021 19:45:43 -0500 Subject: [PATCH 04/79] CI: Fix coverage action (install systemc) --- .github/workflows/coverage.yml | 8 ++++++-- nodist/code_coverage | 5 ++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 706a40690..4e6f4567f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,6 +23,8 @@ jobs: runs-on: ubuntu-20.04 env: CI_BUILD_STAGE_NAME: build + CI_RUNS_ON: ${{ matrix.os }} + CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }}-coverage steps: - uses: actions/checkout@v2 @@ -32,7 +34,7 @@ jobs: cache-name: ccache with: path: ${{ github.workspace }}/.ccache - key: coverage-${{ env.cache-name }}-${{ github.sha }} + key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }} restore-keys: coverage-${{ env.cache-name }} - name: Install dependencies for build @@ -70,6 +72,8 @@ jobs: runs-on: ubuntu-20.04 env: CI_BUILD_STAGE_NAME: test + CI_RUNS_ON: ${{ matrix.os }} + CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }}-coverage steps: - uses: actions/checkout@v2 @@ -79,7 +83,7 @@ jobs: cache-name: ccache with: path: ${{ github.workspace }}/.ccache - key: coverage-${{ env.cache-name }}-${{ github.sha }} + key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }} restore-keys: coverage-${{ env.cache-name }} - uses: actions/download-artifact@v2 diff --git a/nodist/code_coverage b/nodist/code_coverage index 4dc57d96a..782bab1a7 100755 --- a/nodist/code_coverage +++ b/nodist/code_coverage @@ -310,18 +310,17 @@ def source_globs(*dirs): def run(command): # run a system command, check errors print("\t%s" % command) - os.system(command) status = subprocess.call(command, shell=True) if status < 0: raise Exception("%Error: Command failed " + command + ", stopped") def ci_fold_start(action): - print("::group::" + action) + print("::group::" + action, flush=True) def ci_fold_end(): - print("::endgroup::\n") + print("::endgroup::\n", flush=True) ####################################################################### From bd551a7444015a23c24d5ef005c929377af01728 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Jan 2021 22:53:59 -0500 Subject: [PATCH 05/79] Internals: Convert bisonpre to python3 --- Makefile.in | 1 + src/Makefile_obj.in | 2 +- src/bisonpre | 992 +++++++++++++++++++++----------------------- 3 files changed, 474 insertions(+), 521 deletions(-) diff --git a/Makefile.in b/Makefile.in index acb3e43bd..67a14921c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -479,6 +479,7 @@ YAPF_FLAGS = -i YAPF_FILES = \ examples/xml_py/vl_file_copy \ examples/xml_py/vl_hier_graph \ + src/bisonpre \ src/config_rev \ src/cppcheck_filtered \ src/flexfix \ diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index a5db6d5e9..c194ab79a 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -326,7 +326,7 @@ V3ParseBison.h: V3ParseBison.c # Have only one output file in this rule to prevent parallel make issues V3ParseBison.c: verilog.y $(BISONPRE) @echo "If you get errors from verilog.y below, try upgrading bison to version 1.875 or newer." - $(PERL) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $< + $(PYTHON3) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $< V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS) ${LEX} --version diff --git a/src/bisonpre b/src/bisonpre index f4555c823..130ed8578 100755 --- a/src/bisonpre +++ b/src/bisonpre @@ -1,601 +1,553 @@ -#!/usr/bin/env perl -# See copyright, etc in below POD section. +#!/usr/bin/env python3 ###################################################################### -use warnings; -use Getopt::Long; -use IO::File; -use Pod::Usage; -use strict; -use vars qw($Debug $VERSION); +import argparse +import os +import re +import subprocess +import sys +from pprint import pprint, pformat -$VERSION = '3.404'; +###################################################################### -our $Self; -#====================================================================== -# main +def process(): + unlink_outputs() -our $Opt_Debug; -our $Opt_Definitions; -our $Opt_File_Prefix; -our $Opt_Name_Prefix; -our $Opt_Output; -our $Opt_Token_Table; -our $Opt_Verbose; -our $Opt_Yacc = "bison"; -our $Opt_Input; + bison_version_check() + supports_report = Bison_Version >= 2.3 -autoflush STDOUT 1; -autoflush STDERR 1; -Getopt::Long::config("no_auto_abbrev"); -if (! GetOptions( - # Local options - "help" => \&usage, - "version" => sub { print "Version $VERSION\n"; exit(0); }, - "yacc=s" => \$Opt_Yacc, - # Passed to Bison - "t|debug" => sub { $Opt_Debug = 1; }, - "b|file-prefix=s" => \$Opt_File_Prefix, - "d" => \$Opt_Definitions, - "k|token-table" => \$Opt_Token_Table, - "o=s" => \$Opt_Output, - "p|name-prefix=s" => \$Opt_Name_Prefix, - "v|verbose" => \$Opt_Verbose, - "<>" => \¶meter, - )) { - die "%Error: Bad usage, try 'bisonpre --help'\n"; -} - -$Opt_Input or die "bisonpre: %Error: input file not specified\n"; -$Opt_Output or die "bisonpre: %Error: --o option is required\n"; - -process(); - -#---------------------------------------------------------------------- - -sub usage { - print "Version $VERSION\n"; - pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT, -noperldoc=>1); - exit(1); # Unreachable -} - -sub parameter { - my $param = shift; - if (!defined $Opt_Input) { - $Opt_Input = $param; - } else { - die "bisonpre: %Error: Unknown parameter: $param\n"; - } -} - -####################################################################### - -sub process { - remove_outputs(); - - $Self->{bison_version} = bison_version_check(); - my $supports_report = ($Self->{bison_version} >= 2.3); - - clean_input($Opt_Input, tmp_prefix().".y"); + clean_input(Args.input, tmp_prefix() + ".y") # Run bison - my $command = ($Opt_Yacc - .($Opt_Debug?" -t":"") - .($Opt_Definitions?" -d":"") - .($Opt_Token_Table?" -k":"") - .($Opt_Verbose?" -v":"") - .(($Opt_Verbose && $supports_report)?" --report=itemset --report=lookahead":"") - # -p required for GLR parsers; they write to -p basename, not -o - .($Opt_Name_Prefix?" -p $Opt_Name_Prefix":"") - ." -b ".tmp_prefix() - ." -o ".tmp_prefix().".c" - ." ".tmp_prefix().".y" ); + command = ( + Args.yacc + (" -t" if Args.debug else "") + + (" -d" if Args.definitions else "") + + (" -k" if Args.token_table else "") + (" -v" if Args.verbose else "") + + (" --report=itemset --report=lookahead" if + (Args.verbose and supports_report) else "") + # -p required for GLR parsers; they write to -p basename, not -o + + ((" -p " + Args.name_prefix) if Args.name_prefix else "") + " -b " + + tmp_prefix() + " -o " + tmp_prefix() + ".c" + " " + tmp_prefix() + + ".y") - print " $command\n"; - system $command; - my $status = $?; - if ($status != 0) { - remove_outputs(); - my $v = bison_version_check(); - die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n"; - } + print(" " + command) + status = subprocess.call(command, shell=True) + if status != 0: + unlink_outputs() + sys.exit("bisonpre: %Error: " + Args.yacc + " version " + + Bison_Version + " run failed due to errors\n") - clean_output(tmp_prefix().".output",output_prefix().".output", 1,0); - warning_check(output_prefix().".output"); + clean_output(tmp_prefix() + ".output", + output_prefix() + ".output", True, False) + warning_check(output_prefix() + ".output") - clean_output(tmp_prefix().".c", output_prefix().".c", 0,1); - clean_output(tmp_prefix().".h", output_prefix().".h", 0,1); - remove_tmp(); -} + clean_output(tmp_prefix() + ".c", output_prefix() + ".c", False, True) + clean_output(tmp_prefix() + ".h", output_prefix() + ".h", False, True) + unlink_tmp() -sub tmp_prefix { - return output_prefix()."_pretmp"; -} -sub output_prefix { - my $o; - if ($Opt_Output) { - (my $o = $Opt_Output) =~ s!\.[^.]*$!!; - return $o; - } else { - return $Opt_File_Prefix.".tab"; - } -} +def tmp_prefix(): + return output_prefix() + "_pretmp" -sub remove_tmp { - unlink(tmp_prefix().".c"); # Ok if errors - unlink(tmp_prefix().".h"); # Ok if errors - unlink(tmp_prefix().".output"); # Ok if errors -} -sub remove_outputs { - remove_tmp(); - unlink(output_prefix().".c"); # Ok if errors - unlink(output_prefix().".h"); # Ok if errors +def output_prefix(): + if Args.output: + o = re.sub(r'\.[^.]*$', '', Args.output) + return o + else: + return Args.file_prefix + ".tab" + + +def unlink_ok(filename): + try: + os.unlink(filename) + except OSError: + pass + + +def unlink_tmp(): + unlink_ok(tmp_prefix() + ".c") + unlink_ok(tmp_prefix() + ".h") + unlink_ok(tmp_prefix() + ".output") + + +def unlink_outputs(): + unlink_tmp() + unlink_ok(output_prefix() + ".c") + unlink_ok(output_prefix() + ".h") # We don't remove .output file, as it's useful for debugging errors -} -sub bison_version_check { - my $v = `$Opt_Yacc --version`; - if ($v && $v =~ /([0-9]+\.[0-9]+)/) { - my $v = $1; - ($v >= 1.875) or die "bisonpre: %Error: '$Opt_Yacc' is version $v; version 1.875 or newer is required\n"; - return $v; - } else { - die "bisonpre: %Error: '$Opt_Yacc' is not installed, or not working\n"; - } -} -sub clean_output { - my $filename = shift; - my $outname = shift || $filename; - my $is_output = shift; - my $is_c = shift; - print " edit $filename $outname\n"; +def bison_version_check(): + sp = subprocess.Popen(Args.yacc + " --version", + shell=True, + stdout=subprocess.PIPE) + out = str(sp.stdout.read()) + match = re.search(r'([0-9]+\.[0-9]+)', out) + if match: + v = float(match.group(1)) + if v < 1.875: + sys.exit("bisonpre: %Error: '" + Args.yacc + "' is version " + v + + "; version 1.875 or newer is required\n") + global Bison_Version + Bison_Version = v + return - my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n"; - my @lines = $fh->getlines; - $fh->close; + sys.exit("bisonpre: %Error: '" + Args.yacc + + "' is not installed, or not working\n") - (my $basename = tmp_prefix().".") =~ s!.*/!!; - $basename = quotemeta($basename); - (my $newbase = $Opt_Input) =~ s!.*/!!; - $newbase =~ s/\.y/./; - if ($is_output) { - my %state_line; my $l=0; - foreach my $line (@lines) { - $l++; +def clean_output(filename, outname, is_output, is_c): + print(" edit " + filename + " " + outname) + + with open(filename) as fh: + lines = fh.readlines() + + basename = re.sub(r'.*/', '', tmp_prefix() + ".") + basename = re.escape(basename) + newbase = re.sub(r'.*/', '', Args.input) + newbase = re.sub(r'\.y', '.', newbase) + + if is_output: + state_line = {} + l = 0 + for line in lines: + l += 1 # We add a colon so it's easy to search for the definition - $state_line{$1} = $l if $line =~ s/^state (\d+)\s*$/state $1:/; - } - my @out; - foreach my $line (@lines) { - if ($line =~ /^State (\d+) (conflicts)/) { - chomp $line; - $line .= " // line $state_line{$1}" if $state_line{$1}; - $line .= "\n"; - } - push @out, $line; - } - @lines = @out; @out = (); - } - if ($is_c) { - my %token_values; - my $in_en=0; - foreach my $line (@lines) { - $in_en=1 if $line =~ /enum\s+yytokentype/; - $in_en=0 if $line =~ /;/; - $token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/; - } - my @out; - foreach my $line (@lines) { - if (_enaline($line) && $line =~ /BISONPRE_TOKEN_NAMES/) { - push @out, $line; - foreach my $tv (sort keys %token_values) { - push @out, sprintf("\tcase %d: return \"%s\";\n", - $tv, $token_values{$tv}); - } - next; - } - push @out, $line; - } - @lines = @out; @out = (); - } + match = re.match(r'^state (\d+)\s*', line) + if match: + state_line[match.group(1)] = l + out = [] + for line in lines: + match = re.match(r'^State (\d+) (conflicts)', line) + if match: + line = line.rstrip() + if match.group(1) in state_line: + line += " // line " + state_line[match.group(1)] + line += "\n" + out.append(line) + lines = out + out = [] - $fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n"; - foreach my $line (@lines) { - # Fix filename refs - $line =~ s!$basename!$newbase!g; - # Fix bison 2.3 and GCC 4.2.1 - $line =~ s!\(YY_\("!(YY_((char*)"!g; - # Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit - $line =~ s!(YYLTYPE yyerrloc;)!$1 yyerrloc.yydummy=0;/*bisonpre*/!g; - # Fix bison 3.6.1 unexpected nested-comment - $line =~ s!/\* "/\*.*\*/" \*/!!g; - $fh->write($line); - } - $fh->close; -} + if is_c: + token_values = {} + for line in lines: + if re.search(r'enum\s+yytokentype', + line) and not re.search(r';', line): + match = re.search(r'\b(\S+) = (\d+)', line) + if match: + token_values[match.group(2)] = match.group(1) + out = [] + for line in lines: + if _enaline(line) and re.search(r'BISONPRE_TOKEN_NAMES', line): + out.append(line) + for tv in sorted(token_values.keys()): + out.append("\tcase %d: return \"%s\";\n" % + (tv, token_values[tv])) + continue + out.append(line) + lines = out + out = [] -sub warning_check { - my $filename = shift; + with open(outname, "w") as fh: + for line in lines: + # Fix filename refs + line = re.sub(basename, newbase, line) + # Fix bison 2.3 and GCC 4.2.1 + line = re.sub(r'\(YY_\("', '(YY_((char*)"', line) + # Fix bison 2.3 glr-parser warning about yyerrorloc.YYTYPE::yydummy uninit + line = re.sub(r'(YYLTYPE yyerrloc;)', + r'\1 yyerrloc.yydummy=0;/*bisonpre*/', line) + # Fix bison 3.6.1 unexpected nested-comment + line = re.sub(r'/\* "/\*.*\*/" \*/', '', line) + fh.write(line) - my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n"; - while (defined(my $line = $fh->getline)) { - if ($line =~ /(conflicts|warning:|^useless)/i) { - die "%Error: $filename:$.: $line\n"; - } - } - $fh->close; -} -####################################################################### +def warning_check(filename): + with open(filename) as fh: + linenum = 0 + for line in fh: + linenum += 1 + if re.search(r'(conflicts|warning:|^useless)', + line, + flags=re.IGNORECASE): + sys.exit("%Error: " + filename + ":" + linenum + ": " + line + + "\n") -sub clean_input { - my $filename = shift; - my $outname = shift || $filename; # Can == filename if desired - print " edit $filename $outname\n"; - $Self->{filename} = $filename; - my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n"; - my @lines = $fh->getlines; - $fh->close; +###################################################################### + + +def clean_input(filename, outname): + print(" edit " + filename + " " + outname) + + global Filename + Filename = filename + + with open(filename) as fh: + lines = fh.readlines() # Find "%tokens:" # Find "rule:" and replace with just "rule:" - my %types; - my %rules; $Self->{rules} = \%rules; - my %tokens; - my $last_rule; - my $section = 1; - { - my @linesin = @lines; @lines=(); my $l=0; - foreach my $line (@linesin) { - $l++; - # ^/ to prevent comments from matching - $line =~ m!^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]! and die "%Error: $filename:$l: Move text on rule line to next line: $line\n"; - if ($line =~ /^%%/) { - $section++; - if ($section==2) { $last_rule = undef; } - } - elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) { - !$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n"; - $types{$2}{$1} = 1; - $rules{$1}{name} = $1; - $rules{$1}{type} = $2; - !$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n"; - $last_rule = $1; - } elsif ($line =~ /^([a-zA-Z0-9_]+):/) { - !$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n"; - $rules{$1}{name} = $1; - $rules{$1}{type} = ""; - !$last_rule or die "%Error: $filename:$l: Unterminated previous rule\n"; - $last_rule = $1; - } - push @lines, $line; - # Now clean the line and extract some more info - (my $cline = $line) =~ s/\/\/.*$/\n/; - (my $rline = $line) =~ s/\/\/.*$/\n/; - if ($cline =~ /^\s*;/) { - $last_rule or die "%Error: $filename:$l: Stray semicolon\n"; - $last_rule = undef; - } elsif ($last_rule) { - $rules{$last_rule}{rules_and_productions} .= $cline; - } - if ($cline =~ /^%token\s*<(\S+)>\s*(\S+)/) { - !$tokens{$2} or die "%Error: $filename:$l: Redeclaring '$2': $line\n"; - $tokens{$2} = $1; - } - foreach my $tok (split /[^a-zA-Z0-9_]+/, $cline) { - if ($last_rule && $tok=~/^[a-zA-Z]/) { - #print "TT $last_rule $tok\n"; - $rules{$last_rule}{subrules}{$tok} = 1; - $rules{$tok}{parentrules}{$last_rule} = 1; - } - } - } - } + global Rules + Rules = {} - #use Data::Dumper; print Dumper(\%rules); + types = {} + tokens = {} + last_rule = None + section = 1 + if True: + linesin = lines + lines = [] + l = 0 + for line in linesin: + l += 1 + # ^/ to prevent comments from matching + if re.match(r'^[a-zA-Z0-9_<>]+:[^/]*[a-zA-Z]', line): + sys.exit("%Error: " + filename + ":" + str(l) + + ": Move text on rule line to next line: " + line + + "\n") + + matcha = re.match(r'^([a-zA-Z0-9_]+)<(\S*)>(.*)$', line, flags=re.DOTALL) + matchb = re.match(r'^([a-zA-Z0-9_]+):', line) + + if re.match(r'^%%', line): + section += 1 + if section == 2: + last_rule = None + elif matcha: + name = matcha.group(1) + dtype = matcha.group(2) + line = name + matcha.group(3) + if name in Rules: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Redeclaring '" + name + "': " + line) + if dtype not in types: + types[dtype] = {} + types[dtype][name] = 1 + Rules[name] = { + 'name': name, + 'type': dtype, + 'rules_and_productions': "", + 'subrules': {} + } + if last_rule: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Unterminated previous rule\n") + last_rule = name + elif matchb: + name = matchb.group(1) + if name != 'public' and name != 'private': + if name in Rules: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Redeclaring '" + name + "': " + line) + Rules[name] = { + 'name': name, + 'type': "", + 'rules_and_productions': "", + 'subrules': {} + } + if last_rule: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Unterminated previous rule\n") + last_rule = name + + lines.append(line) + # Now clean the line and extract some more info + cline = re.sub(r'//.*$', '\n', line) + rline = re.sub(r'//.*$', '\n', line) + if re.match(r'^\s*;', cline): + if not last_rule: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Stray semicolon\n") + last_rule = None + elif last_rule: + Rules[last_rule]['rules_and_productions'] += cline + + match = re.match(r'^%token\s*<(\S+)>\s*(\S+)', cline) + if match: + dtype = match.group(1) + tok = match.group(2) + if tok in tokens: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Redeclaring '" + tok + "': " + line) + tokens[tok] = dtype + + for tok in re.split(r'[^a-zA-Z0-9_]+', cline): + if last_rule and re.match(r'^[a-zA-Z]', tok): + # print("TT "+last_rule+" "+tok+"\n") + Rules[last_rule]['subrules'][tok] = 1 + + #pprint(Rules) # Replace BISONPRE_VERSION(ver,,...) with expanded list - { - my @linesin = @lines; @lines=(); my $l=0; - foreach my $line (@linesin) { - $l++; - if (_enaline($line) && $line =~ /BISONPRE_VERSION/) { - # 1 3 4 - ($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/) - or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n"; - my $ver=$1; my $ver_max=$3; my $cmd=$4; - if ($Self->{bison_version} >= $1 - && (!$ver_max || $Self->{bison_version} <= $ver_max)) { - $line = $cmd."\n"; - } else { - $line = "//NOP: $line"; - } - } - push @lines, $line; - } - } + if True: + linesin = lines + lines = [] + l = 0 + for line in linesin: + l += 1 + if _enaline(line) and re.search(r'BISONPRE_VERSION', line): + # 1 2 3 4 + match = re.search( + r'BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$', + line) + if not match: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Bad form of BISONPRE_VERSION: " + line) + ver = match.group(1) + ver_max = match.group(3) + cmd = match.group(4) + if Bison_Version >= float(ver) and ( + not ver_max or Bison_Version <= float(ver_max)): + line = cmd + "\n" + else: + line = "//NOP: " + line + lines.append(line) # Replace BISONPRE_NOT(type,...) with expanded list - { - my @linesin = @lines; @lines=(); my $l=0; - foreach my $line (@linesin) { - $l++; - if (_enaline($line) && $line =~ /BISONPRE_NOT/) { - ($line =~ s/BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*$//) - or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n"; - my $endtok = $1; my $action = $2; - my @endtoks = split(/,/, $endtok); - map { $tokens{$_} or die "%Error: $filename:$l: Can't find definition for token: $_\n" - } @endtoks; + if True: + linesin = lines + lines = [] + l = 0 + for line in linesin: + l += 1 + if _enaline(line) and re.search(r'BISONPRE_NOT', line): + match = re.search(r'(.*)BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*(.*)$', + line, flags=re.DOTALL) + if not match: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Bad form of BISONPRE_NOT: " + line) + line = match.group(1) + match.group(4) + endtok = match.group(2) + action = match.group(3) + endtoks = endtok.split(',') + for etok in endtoks: + if not etok in tokens: + sys.exit("%Error: " + filename + ":" + str(l) + + ": Can't find definition for token: " + etok + + "\n") # Push it all onto one line to avoid error messages changing - my $bar = ""; - tok: - foreach my $tok (sort keys %tokens) { - foreach (@endtoks) { - next tok if $tok eq $_; - } - if ($endtok ne $tok) { - $line .= "\t$bar $tok $action"; - $bar = "|"; - } - } - $line .= "\n"; - } - push @lines, $line; - } - } + bar = "" + for tok in sorted(tokens.keys()): + hit = False + for etok in endtoks: + if tok == etok: + hit = True + break + if not hit and endtok != tok: + line += "\t" + bar + " " + tok + " " + action + bar = "|" + line += "\n" + lines.append(line) # Replace BISONPRE_COPY(type,{code}) - { - my @linesin = @lines; @lines=(); my $l=0; - foreach my $line (@linesin) { - $l++; - if (_enaline($line) && $line =~ /BISONPRE_COPY/) { - $line = _bisonpre_copy($line,$l,0); - } - push @lines, $line; - } - } + if True: + linesin = lines + lines = [] + l = 0 + for line in linesin: + l += 1 + if _enaline(line) and re.search(r'BISONPRE_COPY', line): + line = _bisonpre_copy(line, l, 0) + lines.append(line) # Replace ~[x]~ - must be after BISONPRE_COPY expansion - { - my @linesin = @lines; @lines=(); my $l=0; - foreach my $line (@linesin) { - $l++; - $line =~ s/~[a-zA-Z0-9_]+~//g; - push @lines, $line; - } - } + if True: + linesin = lines + lines = [] + l = 0 + for line in linesin: + l += 1 + line = re.sub(r'~[a-zA-Z0-9_]+~', '', line) + lines.append(line) # Find "BISONPRE_TYPES" - { - my @linesin = @lines; @lines=(); my $l=0; - my $needmore = 0; - foreach my $line (@linesin) { - $l++; - if (_enaline($line) && $line =~ m!//BISONPRE_TYPES!) { - push @lines, $line; - foreach my $type (sort keys %types) { - next if !$type; - my $line = "%type<$type>\t"; - foreach my $rule (sort keys %{$types{$type}}) { - $line.=" ".$rule; - } - $line .= "\n"; - push @lines, $line; - $needmore++ - } - } elsif ($needmore) { + if True: + linesin = lines + lines = [] + l = 0 + needmore = 0 + for line in linesin: + l += 1 + if _enaline(line) and re.search(r'//BISONPRE_TYPES', line): + lines.append(line) + for type in sorted(types.keys()): + if not type: + continue + line = "%type<" + type + ">\t" + for rule in sorted(types[type].keys()): + line += " " + rule + line += "\n" + lines.append(line) + needmore += 1 + elif needmore > 0: # Bison doesn't have a #line directive, so we need somewhere to insert into - $line =~ s!^\s*//.*$!!; - ($line =~ m/^\s*$/) - or die "%Error: $filename:$l: Need $needmore more blank lines to keep line numbers are constant\n"; - $needmore--; - } else { - push @lines, $line; - } - } - } + line = re.sub(r'^\s*//.*$', '', line) + if not re.match(r'^\s*$', line): + sys.exit( + "%Error: " + filename + ":" + str(l) + ": Need " + + needmore + + " more blank lines to keep line numbers are constant\n" + ) + needmore -= 1 + else: + lines.append(line) - $fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n"; - foreach my $line (@lines) { - $fh->write($line); - } - $fh->close; -} + with open(outname, "w") as fh: + for line in lines: + fh.write(line) -sub _bisonpre_copy { - my $text = shift; - my $l = shift; - my $depth = shift; - while ($text =~ /BISONPRE_COPY/) { - ($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)/{HERE}/) - or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n"; - my $once = $1; my $rule = $2; my $code = $3; - $Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n"; - if ($depth > 0 && $once) { + +def _bisonpre_copy(text, l, depth): + while re.search(r'BISONPRE_COPY', text): + match = re.match( + # 1 2 3 4 5 + r'(.*)BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)(.*)', text, flags=re.DOTALL) + if not match: + sys.exit("%Error: " + Filename + ":" + str(l) + + ": Bad form of BISONPRE_NOT: " + text) + text = match.group(1) + '{HERE}' + match.group(5) + once = match.group(2) + rule = match.group(3) + code = match.group(4) + if not rule in Rules: + sys.exit("%Error: " + Filename + ":" + str(l) + + ": Can't find definition for rule: " + rule) + if depth > 0 and once: # _ONCE means don't inherit - $text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing - $text =~ s/{HERE}//; - } else { + text = re.sub(r'\|[ \t]+{HERE}', '', text) # Don't OR in nothing + text = re.sub(r'{HERE}', '', text) + else: # Push it all onto one line to avoid error messages changing - my $insert = $Self->{rules}{$rule}{rules_and_productions}; - $insert =~ s/^\S+://g; # Strip rule name + insert = Rules[rule]['rules_and_productions'] + insert = re.sub(r'^\S+:', '', insert) # Strip rule name # Recurse so BISONPRE under B - #print "COPY $l code $code\n"; - #print "COPY $l in $insert\n"; - $_=$insert; eval("$code; \$_;"); $insert = $_; - #print "COPY $l out $insert\n"; - while ($insert =~ s/[ \t\n]+\n/\n/go) {} - while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering - $text =~ s/{HERE}/$insert/; - } - $depth++; - } - return $text; -} + #print "COPY $l code $code\n" + #print "COPY $l in $insert\n" + for op in code.split(';'): + if re.match(r'^\s*$', op): + continue + match = re.match(r'^\s*s/(.*?)/(.*?)/g\s*$', op) + if not match: + sys.exit("%Error: " + Filename + ":" + str(l) + + ": Didn't understand replacement: " + op) + left = match.group(1) + right = match.group(2) + insert = re.sub(left, right, insert) -sub _enaline { - my $line = shift; - return 0 if $line =~ m!//UN!; - return 1; -} - -####################################################################### -__END__ - -=pod - -=head1 NAME - -bisonpre - Bison wrapper with pre and post processing - -=head1 SYNOPSIS - - bisonpre --yacc bison --debug --verbose --defines X.h -k $< -pX -o X.c + #print "COPY $l out $insert\n" + insert = re.sub(r'[ \t\n]+\n', "\n", insert) + insert = re.sub(r'\n', " ", + insert) # Optional - preserve line numbering + text = re.sub(r'{HERE}', insert, text) + depth += 1 + return text -=head1 DESCRIPTION +def _enaline(line): + return not re.search(r'//UN', line) -Bisonpre is a wrapper for the Bison YACC replacement. Input to Bison is + +###################################################################### +# main + +parser = argparse.ArgumentParser( + allow_abbrev=False, + formatter_class=argparse.RawDescriptionHelpFormatter, + description= + """Bisonpre is a wrapper for the Bison YACC replacement. Input to Bison is preprocessed with substitution as described below under EXTENSIONS. Output from Bison is checked for additional errors, and corrected to work around -various compile warnings. +various compile warnings.""", + epilog=""" +BISON GRAMMAR EXTENSIONS -=head1 EXTENSIONS + //BISONPRE_TYPES -=over 4 + This is expanded into %type declarations. -=item //BISONPRE_TYPES + ~[a-z]+~ -This is expanded into %type declarations. + Any text matching ~[a-z]+~ is removed. This allows optional text to be + used only when the rule containing the ~~ is used in a BISONPRE_COPY. -=item ~[a-z]+~ + rule_label: -Any text matching ~[a-z]+~ is removed. This allows optional text to be -used only when the rule containing the ~~ is used in a BISONPRE_COPY. + This allows the label declaring a rule to also specify the type of the + rule. The type will be inserted where /*BISONPRE_TYPES*/ is + encountered. -=item rule_label: + BISONPRE_COPY(rule, {code}) -This allows the label declaring a rule to also specify the type of the -rule. The type will be inserted where /*BISONPRE_TYPES*/ is encountered. + Copy the rules and productions from the specified rule, filter through + the Python code provided in the {} and insert here into the output + file. -=item BISONPRE_COPY(rule, {code}) + BISONPRE_COPY_ONCE(rule, {code}) -Copy the rules and productions from the specified rule, filter through the -Perl code provided in the {} and insert here into the output file. + As with BISONPRE_COPY, but if called from underneath another + BISONPRE_COPY rule, ignore it. -=item BISONPRE_COPY_ONCE(rule, {code}) + BISONPRE_NOT(token[, token...]) -As with BISONPRE_COPY, but if called from underneath another BISONPRE_COPY -rule, ignore it. + Create a rule that matches every token except for those specified. -=item BISONPRE_NOT(token[, token...]) + BISONPRE_VERSION(ver, cmd) -Create a rule that matches every token except for those specified. + If the bison version is >= the specified version, include the given + command. -=item BISONPRE_VERSION(ver, cmd) - -If the bison version is >= the specified version, include the given command. - -=back - -=head1 ARGUMENTS - -=over 4 - -=item -b file-prefix -=item --file-prefix=file-prefix - -Passed to bison. - -Specify a prefix to use for all bison output file names. The names are -chosen as if the input file were named file-prefix.c. - -=item -d - -Passed to bison. - -Write an extra output file containing macro definitions for the token type -names defined in the grammar and the semantic value type YYSTYPE, as well -as a few extern variable declarations. If the parser output file is named -name.c then this file is named name.h. This output file is essential if -you wish to put the definition of yylex in a separate source file, because -yylex needs to be able to refer to token type codes and the variable -yylval. - -=item --help - -Displays this message and program version and exits. - -=item -k -=item --token-table - -Passed to bison. - -This switch causes the name.tab.c output to include a list of token names -in order by their token numbers; this is defined in the array yytname. -Also generated are #defines for YYNTOKENS, YYNNTS, YYNRULES, and YYNSTATES. - -=item -t -=item --debug - -Passed to bison. - -In the parser file, define the macro YYDEBUG to 1 if it is not already -defined, so that the debugging facilities are compiled. - -=item -v -=item --verbose - -Passed to bison. - -Write an extra output file containing verbose descriptions of the parser -states and what is done for each type of look-ahead token in that state. -This file also describes all the conflicts, both those resolved by operator -precedence and the unresolved ones. The file's name is made by removing -.tab.c or .c from the parser output file name, and adding .output instead. -Therefore, if the input file is foo.y, then the parser file is called -foo.tab.c by default. As a consequence, the verbose output file is called -foo.output. - -=item --version - -Print the version number and exit. - -=item --yacc - -Specify the name of the bison executable, defaults to "bison." - -=back - -=head1 DISTRIBUTION - -This is part of the L free Verilog EDA software -tool suite. The latest version is available from CPAN and from -L. - -Copyright 2008-2021 by Wilson Snyder. This program is free software; you +Copyright 2002-2021 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU -Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. +Lesser General Public License Version 3 or the Perl Artistic License +Version 2.0. -SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -=head1 AUTHORS +# Local options +parser.add_argument('--yacc', + action='store', + default='bison', + help='name of the bison executable, defaults to "bison"') -Wilson Snyder +# Arguments passed through to bison +parser.add_argument('-b', + '--file-prefix', + action='store', + help='Passed to bison.') +parser.add_argument('-d', + '--definitions', + action='store_true', + help='Passed to bison.') +parser.add_argument('-k', + '--token-table', + action='store_true', + help='Passed to bison.') +parser.add_argument('-o', + '--output', + action='store', + required=True, + help='Passed to bison. Sets output file name') +parser.add_argument('-p', + '--name-prefix', + action='store', + help='Passed to bison.') +parser.add_argument('-t', + '--debug', + action='store_true', + help='Passed to bison.') +parser.add_argument('-v', + '--verbose', + action='store_true', + help='Passed to bison.') -=head1 SEE ALSO +parser.add_argument('input', help='Passed to bison. Input grammar file.') -C +Args = parser.parse_args() -=cut +process() ###################################################################### ### Local Variables: From 4f1867a4f8683aadc4d45f01eb0e3f3a88e3ac5e Mon Sep 17 00:00:00 2001 From: github action Date: Mon, 11 Jan 2021 03:55:27 +0000 Subject: [PATCH 06/79] Apply clang-format --- src/bisonpre | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/bisonpre b/src/bisonpre index 130ed8578..2d1c79934 100755 --- a/src/bisonpre +++ b/src/bisonpre @@ -209,7 +209,9 @@ def clean_input(filename, outname): ": Move text on rule line to next line: " + line + "\n") - matcha = re.match(r'^([a-zA-Z0-9_]+)<(\S*)>(.*)$', line, flags=re.DOTALL) + matcha = re.match(r'^([a-zA-Z0-9_]+)<(\S*)>(.*)$', + line, + flags=re.DOTALL) matchb = re.match(r'^([a-zA-Z0-9_]+):', line) if re.match(r'^%%', line): @@ -314,8 +316,10 @@ def clean_input(filename, outname): for line in linesin: l += 1 if _enaline(line) and re.search(r'BISONPRE_NOT', line): - match = re.search(r'(.*)BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*(.*)$', - line, flags=re.DOTALL) + match = re.search( + r'(.*)BISONPRE_NOT\((\S+)\)\s*(\{[^}]+})\s*(.*)$', + line, + flags=re.DOTALL) if not match: sys.exit("%Error: " + filename + ":" + str(l) + ": Bad form of BISONPRE_NOT: " + line) @@ -404,7 +408,9 @@ def _bisonpre_copy(text, l, depth): while re.search(r'BISONPRE_COPY', text): match = re.match( # 1 2 3 4 5 - r'(.*)BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)(.*)', text, flags=re.DOTALL) + r'(.*)BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*\{([^}]*)}\s*\)(.*)', + text, + flags=re.DOTALL) if not match: sys.exit("%Error: " + Filename + ":" + str(l) + ": Bad form of BISONPRE_NOT: " + text) From b7c26dbea9e36a55fef7170c50a71be57f3fe69c Mon Sep 17 00:00:00 2001 From: Philipp Wagner Date: Mon, 11 Jan 2021 16:23:54 +0000 Subject: [PATCH 07/79] Fix to include limits header for std::numeric_limits (#2747) Code using `std::numeric_limits` wasn't including the limits header, leading to a compilation error in Fedora Rawhide (GCC 11.0). --- include/verilated.cpp | 1 + src/V3Trace.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/verilated.cpp b/include/verilated.cpp index 0a1bf95cd..cb910e8a0 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -32,6 +32,7 @@ #include #include // mkdir #include +#include #include // clang-format off diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 4f6a7df98..70ede0bf8 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -46,6 +46,7 @@ #include "V3Stats.h" #include +#include #include //###################################################################### From bcf9abf4909767af1255e3a32b3e0a21464aa3ef Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 11 Jan 2021 22:42:14 -0500 Subject: [PATCH 08/79] Internals: Var rename. No functional change. --- src/V3EmitMk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 8464de0eb..6622d17e6 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -298,8 +298,8 @@ class EmitMkHierVerilation final { of.puts("VM_HIER_RUN_DIR := " + cwd + "\n"); of.puts("# Common options for hierarchical blocks\n"); const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.bin()); - const string perl_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator"; - of.puts("VM_HIER_VERILATOR := " + perl_wrapper + "\n"); + const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator"; + of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n"); of.puts("VM_HIER_INPUT_FILES := \\\n"); const V3StringList& vFiles = v3Global.opt.vFiles(); for (const string& i : vFiles) of.puts("\t" + V3Os::filenameRealPath(i) + " \\\n"); From ab5d4bd51dbd409b54a689d8db6ce2dc9644de44 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 12 Jan 2021 18:09:56 -0500 Subject: [PATCH 09/79] Tests: Abstract out common test comparison --- test_regress/driver.pl | 6 ++++++ test_regress/t/t_cover_line_cc.pl | 3 ++- test_regress/t/t_cover_line_cc_vlt.pl | 3 ++- test_regress/t/t_display_noopt.pl | 2 +- test_regress/t/t_display_real_noopt.pl | 2 +- test_regress/t/t_display_signed_noopt.pl | 2 +- test_regress/t/t_dpi_arg_inout_type.pl | 8 +++----- test_regress/t/t_dpi_arg_inout_unpack.pl | 8 +++----- test_regress/t/t_dpi_arg_input_type.pl | 8 +++----- test_regress/t/t_dpi_arg_input_unpack.pl | 8 +++----- test_regress/t/t_dpi_arg_output_type.pl | 8 +++----- test_regress/t/t_dpi_arg_output_unpack.pl | 8 +++----- test_regress/t/t_dpi_result_type.pl | 8 +++----- test_regress/t/t_gen_genblk_noinl.pl | 3 ++- test_regress/t/t_interface_ref_trace_inla.pl | 2 +- test_regress/t/t_interface_ref_trace_inlab.pl | 2 +- test_regress/t/t_interface_ref_trace_inlb.pl | 2 +- test_regress/t/t_preproc_dos.pl | 2 +- test_regress/t/t_trace_array_fst_portable.pl | 2 +- test_regress/t/t_trace_array_fst_threads_1.pl | 2 +- test_regress/t/t_trace_array_fst_threads_2.pl | 2 +- test_regress/t/t_trace_complex_fst_threads_1.pl | 2 +- test_regress/t/t_trace_complex_fst_threads_2.pl | 2 +- test_regress/t/t_trace_complex_old_api.pl | 3 ++- test_regress/t/t_trace_complex_portable.pl | 3 ++- test_regress/t/t_trace_complex_threads_1.pl | 2 +- test_regress/t/t_trace_public_func.pl | 4 ++-- test_regress/t/t_trace_public_func_vlt.pl | 4 ++-- test_regress/t/t_trace_public_sig.pl | 4 ++-- test_regress/t/t_trace_public_sig_vlt.pl | 5 +++-- 30 files changed, 59 insertions(+), 61 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index ff7c66fc1..9b94e8fc9 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1385,6 +1385,12 @@ sub errors { return $self->{errors}; } +sub golden_filename { + my $self = (ref $_[0]? shift : $Self); + $self->{golden_filename} = shift if defined $_[0]; + return $self->{golden_filename}; +} + sub scenario_off { my $self = (ref $_[0]? shift : $Self); return $self->{scenario_off}; diff --git a/test_regress/t/t_cover_line_cc.pl b/test_regress/t/t_cover_line_cc.pl index 08a0a6f03..8c8d785ae 100755 --- a/test_regress/t/t_cover_line_cc.pl +++ b/test_regress/t/t_cover_line_cc.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_cover_line.v"); +golden_filename("t/t_cover_line.out"); compile( verilator_flags2 => ['--cc --coverage-line +define+ATTRIBUTE'], @@ -29,7 +30,7 @@ run(cmd => ["../bin/verilator_coverage", verilator_run => 1, ); -files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"); +files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", $Self->{golden_filename}); # Also try lcov run(cmd => ["../bin/verilator_coverage", diff --git a/test_regress/t/t_cover_line_cc_vlt.pl b/test_regress/t/t_cover_line_cc_vlt.pl index 1d21931e1..6b885fb8f 100755 --- a/test_regress/t/t_cover_line_cc_vlt.pl +++ b/test_regress/t/t_cover_line_cc_vlt.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_cover_line.v"); +golden_filename("t/t_cover_line.out"); compile( verilator_flags2 => ['--cc', '--coverage-line', "t/t_cover_line.vlt"], @@ -30,7 +31,7 @@ run(cmd => ["../bin/verilator_coverage", verilator_run => 1, ); -files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"); +files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_display_noopt.pl b/test_regress/t/t_display_noopt.pl index 795598e65..ced4aa8a5 100755 --- a/test_regress/t/t_display_noopt.pl +++ b/test_regress/t/t_display_noopt.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_display.v"); -$Self->{golden_filename} = "t/t_display.out"; # Match unopt version +golden_filename("t/t_display.out"); compile( verilator_flags2 => ["-O0"], diff --git a/test_regress/t/t_display_real_noopt.pl b/test_regress/t/t_display_real_noopt.pl index 04d0a8222..a41a102e4 100755 --- a/test_regress/t/t_display_real_noopt.pl +++ b/test_regress/t/t_display_real_noopt.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_display_real.v"); -$Self->{golden_filename} = "t/t_display_real.out"; # Match unopt version +golden_filename("t/t_display_real.out"); compile( verilator_flags2 => ["-O0"], diff --git a/test_regress/t/t_display_signed_noopt.pl b/test_regress/t/t_display_signed_noopt.pl index 669394f5f..e113d374d 100755 --- a/test_regress/t/t_display_signed_noopt.pl +++ b/test_regress/t/t_display_signed_noopt.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_display_signed.v"); -$Self->{golden_filename} = "t/t_display_signed.out"; # Match unopt version +golden_filename("t/t_display_signed.out"); compile( verilator_flags2 => ["-O0"], diff --git a/test_regress/t/t_dpi_arg_inout_type.pl b/test_regress/t/t_dpi_arg_inout_type.pl index c885022e4..4bdfdef91 100755 --- a/test_regress/t/t_dpi_arg_inout_type.pl +++ b/test_regress/t/t_dpi_arg_inout_type.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_arg_inout_type.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_arg_inout_type__Dpi.h", - "t/t_dpi_arg_inout_type__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_dpi_arg_inout_unpack.pl b/test_regress/t/t_dpi_arg_inout_unpack.pl index b46d023f8..ec76ba91c 100755 --- a/test_regress/t/t_dpi_arg_inout_unpack.pl +++ b/test_regress/t/t_dpi_arg_inout_unpack.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_arg_inout_unpack.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_arg_inout_unpack__Dpi.h", - "t/t_dpi_arg_inout_unpack__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_dpi_arg_input_type.pl b/test_regress/t/t_dpi_arg_input_type.pl index 8c609be40..4bdfdef91 100755 --- a/test_regress/t/t_dpi_arg_input_type.pl +++ b/test_regress/t/t_dpi_arg_input_type.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_arg_input_type.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_arg_input_type__Dpi.h", - "t/t_dpi_arg_input_type__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_dpi_arg_input_unpack.pl b/test_regress/t/t_dpi_arg_input_unpack.pl index f6772ebcc..ec76ba91c 100755 --- a/test_regress/t/t_dpi_arg_input_unpack.pl +++ b/test_regress/t/t_dpi_arg_input_unpack.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_arg_input_unpack.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_arg_input_unpack__Dpi.h", - "t/t_dpi_arg_input_unpack__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_dpi_arg_output_type.pl b/test_regress/t/t_dpi_arg_output_type.pl index d469bfc8a..4bdfdef91 100755 --- a/test_regress/t/t_dpi_arg_output_type.pl +++ b/test_regress/t/t_dpi_arg_output_type.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_arg_output_type.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_arg_output_type__Dpi.h", - "t/t_dpi_arg_output_type__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_dpi_arg_output_unpack.pl b/test_regress/t/t_dpi_arg_output_unpack.pl index c4b0c26de..ec76ba91c 100755 --- a/test_regress/t/t_dpi_arg_output_unpack.pl +++ b/test_regress/t/t_dpi_arg_output_unpack.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_arg_output_unpack.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_arg_output_unpack__Dpi.h", - "t/t_dpi_arg_output_unpack__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_dpi_result_type.pl b/test_regress/t/t_dpi_result_type.pl index 7796879c7..4bdfdef91 100755 --- a/test_regress/t/t_dpi_result_type.pl +++ b/test_regress/t/t_dpi_result_type.pl @@ -19,7 +19,7 @@ if ($Self->{nc}) { } compile( - v_flags2 => ["t/t_dpi_result_type.cpp"], + v_flags2 => ["t/$Self->{name}.cpp"], # --no-decoration so .out file doesn't comment on source lines verilator_flags2 => ["-Wall -Wno-DECLFILENAME --no-decoration"], # NC: Gdd the obj_dir to the C include path @@ -30,10 +30,8 @@ compile( ); if ($Self->{vlt_all}) { - files_identical( - "$Self->{obj_dir}/Vt_dpi_result_type__Dpi.h", - "t/t_dpi_result_type__Dpi.out" - ); + files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + "t/$Self->{name}__Dpi.out"); } execute( diff --git a/test_regress/t/t_gen_genblk_noinl.pl b/test_regress/t/t_gen_genblk_noinl.pl index 86adb4a8e..7574a1cfb 100755 --- a/test_regress/t/t_gen_genblk_noinl.pl +++ b/test_regress/t/t_gen_genblk_noinl.pl @@ -9,6 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 top_filename("t_gen_genblk.v"); +golden_filename("t/t_gen_genblk.out"); scenarios(simulator => 1); @@ -19,7 +20,7 @@ compile( ); execute( - expect_filename => "t/t_gen_genblk.out", + expect_filename => $Self->{golden_filename}, ); ok(1); diff --git a/test_regress/t/t_interface_ref_trace_inla.pl b/test_regress/t/t_interface_ref_trace_inla.pl index bbcf8c7d1..60ba35eb9 100755 --- a/test_regress/t/t_interface_ref_trace_inla.pl +++ b/test_regress/t/t_interface_ref_trace_inla.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_interface_ref_trace.v"); -$Self->{golden_filename} = "t/t_interface_ref_trace.out"; +golden_filename("t/t_interface_ref_trace.out"); compile( v_flags2 => ['+define+NO_INLINE_A'], diff --git a/test_regress/t/t_interface_ref_trace_inlab.pl b/test_regress/t/t_interface_ref_trace_inlab.pl index 35e91ccf0..68d5d7a0e 100755 --- a/test_regress/t/t_interface_ref_trace_inlab.pl +++ b/test_regress/t/t_interface_ref_trace_inlab.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_interface_ref_trace.v"); -$Self->{golden_filename} = "t/t_interface_ref_trace.out"; +golden_filename("t/t_interface_ref_trace.out"); compile( v_flags2 => ['+define+NO_INLINE_A +define+NO_INLINE_B'], diff --git a/test_regress/t/t_interface_ref_trace_inlb.pl b/test_regress/t/t_interface_ref_trace_inlb.pl index fd06fd865..10e5c5036 100755 --- a/test_regress/t/t_interface_ref_trace_inlb.pl +++ b/test_regress/t/t_interface_ref_trace_inlb.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_interface_ref_trace.v"); -$Self->{golden_filename} = "t/t_interface_ref_trace.out"; +golden_filename("t/t_interface_ref_trace.out"); compile( v_flags2 => ['+define+NO_INLINE_B'], diff --git a/test_regress/t/t_preproc_dos.pl b/test_regress/t/t_preproc_dos.pl index 166adf78f..a32871293 100755 --- a/test_regress/t/t_preproc_dos.pl +++ b/test_regress/t/t_preproc_dos.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("$Self->{obj_dir}/$Self->{name}.v"); -$Self->{golden_filename} = "$Self->{obj_dir}/$Self->{name}.out"; +golden_filename("$Self->{obj_dir}/$Self->{name}.out"); # Rather then having to maintain a new .v and .out, simply add returns # to all lines of the existing t_preproc test. diff --git a/test_regress/t/t_trace_array_fst_portable.pl b/test_regress/t/t_trace_array_fst_portable.pl index f182ef1b7..3a34b9113 100755 --- a/test_regress/t/t_trace_array_fst_portable.pl +++ b/test_regress/t/t_trace_array_fst_portable.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_trace_array.v"); -$Self->{golden_filename} = "t/t_trace_array_fst.out"; +golden_filename("t/t_trace_array_fst.out"); compile( verilator_flags2 => ['--cc --trace-fst --trace-structs', diff --git a/test_regress/t/t_trace_array_fst_threads_1.pl b/test_regress/t/t_trace_array_fst_threads_1.pl index 0be5ffbc2..c75beb0ca 100755 --- a/test_regress/t/t_trace_array_fst_threads_1.pl +++ b/test_regress/t/t_trace_array_fst_threads_1.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_trace_array.v"); -$Self->{golden_filename} = "t/t_trace_array_fst.out"; +golden_filename("t/t_trace_array_fst.out"); compile( verilator_flags2 => ['--cc --trace-fst --trace-threads 1 --trace-structs'], diff --git a/test_regress/t/t_trace_array_fst_threads_2.pl b/test_regress/t/t_trace_array_fst_threads_2.pl index e20a9056b..75bbc7391 100755 --- a/test_regress/t/t_trace_array_fst_threads_2.pl +++ b/test_regress/t/t_trace_array_fst_threads_2.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_trace_array.v"); -$Self->{golden_filename} = "t/t_trace_array_fst.out"; +golden_filename("t/t_trace_array_fst.out"); compile( verilator_flags2 => ['--cc --trace-fst --trace-threads 2 --trace-structs'], diff --git a/test_regress/t/t_trace_complex_fst_threads_1.pl b/test_regress/t/t_trace_complex_fst_threads_1.pl index e38cce31c..a43a89337 100755 --- a/test_regress/t/t_trace_complex_fst_threads_1.pl +++ b/test_regress/t/t_trace_complex_fst_threads_1.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_trace_complex.v"); -$Self->{golden_filename} = "t/t_trace_complex_fst.out"; +golden_filename("t/t_trace_complex_fst.out"); compile( verilator_flags2 => ['--cc --trace-fst --trace-threads 1'], diff --git a/test_regress/t/t_trace_complex_fst_threads_2.pl b/test_regress/t/t_trace_complex_fst_threads_2.pl index 72d74d432..b2c4721c7 100755 --- a/test_regress/t/t_trace_complex_fst_threads_2.pl +++ b/test_regress/t/t_trace_complex_fst_threads_2.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_trace_complex.v"); -$Self->{golden_filename} = "t/t_trace_complex_fst.out"; +golden_filename("t/t_trace_complex_fst.out"); compile( verilator_flags2 => ['--cc --trace-fst --trace-threads 2'], diff --git a/test_regress/t/t_trace_complex_old_api.pl b/test_regress/t/t_trace_complex_old_api.pl index f1b4027b6..bdf9a0dec 100755 --- a/test_regress/t/t_trace_complex_old_api.pl +++ b/test_regress/t/t_trace_complex_old_api.pl @@ -13,6 +13,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_trace_complex.v"); +golden_filename("t/t_trace_complex.out"); compile( verilator_flags2 => ['--cc --trace -CFLAGS -DVL_TRACE_VCD_OLD_API'], @@ -32,7 +33,7 @@ file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\(/); file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\(/); file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\(/); -vcd_identical ("$Self->{obj_dir}/simx.vcd", "t/t_trace_complex.out"); +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_complex_portable.pl b/test_regress/t/t_trace_complex_portable.pl index 5ddd2e3a4..ec7e5462e 100755 --- a/test_regress/t/t_trace_complex_portable.pl +++ b/test_regress/t/t_trace_complex_portable.pl @@ -13,6 +13,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_trace_complex.v"); +golden_filename("t/t_trace_complex.out"); compile( verilator_flags2 => ['--cc --trace -CFLAGS -DVL_PORTABLE_ONLY'], @@ -32,7 +33,7 @@ file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\(/); file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\(/); file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\(/); -vcd_identical ("$Self->{obj_dir}/simx.vcd", "t/t_trace_complex.out"); +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_complex_threads_1.pl b/test_regress/t/t_trace_complex_threads_1.pl index 483faf3ab..3c7085576 100755 --- a/test_regress/t/t_trace_complex_threads_1.pl +++ b/test_regress/t/t_trace_complex_threads_1.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_trace_complex.v"); -$Self->{golden_filename} = "t/t_trace_complex.out"; +golden_filename("t/t_trace_complex.out"); compile( verilator_flags2 => ['--cc --trace --trace-threads 1'] diff --git a/test_regress/t/t_trace_public_func.pl b/test_regress/t/t_trace_public_func.pl index e17f41601..519178385 100755 --- a/test_regress/t/t_trace_public_func.pl +++ b/test_regress/t/t_trace_public_func.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); top_filename("t/t_trace_public.v"); +golden_filename("t/t_trace_public.out"); compile( make_top_shell => 0, @@ -22,8 +23,7 @@ execute( check_finished => 1, ); -vcd_identical("$Self->{obj_dir}/simx.vcd", - "t/t_trace_public.out"); +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_public_func_vlt.pl b/test_regress/t/t_trace_public_func_vlt.pl index 3c627949a..f532f19d0 100755 --- a/test_regress/t/t_trace_public_func_vlt.pl +++ b/test_regress/t/t_trace_public_func_vlt.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); top_filename("t/t_trace_public.v"); +golden_filename("t/t_trace_public.out"); compile( make_top_shell => 0, @@ -22,8 +23,7 @@ execute( check_finished => 1, ); -vcd_identical("$Self->{obj_dir}/simx.vcd", - "t/t_trace_public.out"); +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_public_sig.pl b/test_regress/t/t_trace_public_sig.pl index 0a577a343..edb8bf2c4 100755 --- a/test_regress/t/t_trace_public_sig.pl +++ b/test_regress/t/t_trace_public_sig.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); top_filename("t/t_trace_public.v"); +golden_filename("t/t_trace_public.out"); compile( make_top_shell => 0, @@ -22,8 +23,7 @@ execute( check_finished => 1, ); -vcd_identical("$Self->{obj_dir}/simx.vcd", - "t/t_trace_public.out"); +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); # vcd_identical doesn't detect "$var a.b;" vs "$scope module a; $var b;" file_grep("$Self->{obj_dir}/simx.vcd", qr/module glbl/i); diff --git a/test_regress/t/t_trace_public_sig_vlt.pl b/test_regress/t/t_trace_public_sig_vlt.pl index 2f20c9ff2..c29e1cdc2 100755 --- a/test_regress/t/t_trace_public_sig_vlt.pl +++ b/test_regress/t/t_trace_public_sig_vlt.pl @@ -11,6 +11,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); top_filename("t/t_trace_public.v"); +golden_filename("t/t_trace_public.out"); + my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( @@ -27,8 +29,7 @@ execute( check_finished => 1, ); -vcd_identical("$Self->{obj_dir}/simx.vcd", - "t/t_trace_public.out"); +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); # vcd_identical doesn't detect "$var a.b;" vs "$scope module a; $var b;" file_grep("$Self->{obj_dir}/simx.vcd", qr/module glbl/i); From 3bb8fbe73b521c4a763de214d1816e085b06f313 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 13 Jan 2021 20:01:10 -0500 Subject: [PATCH 10/79] Internal coverage improvements --- include/verilated.cpp | 2 -- nodist/code_coverage | 11 +++++++++-- test_regress/t/t_dpi_open_c.cpp | 16 ++++++++++++++++ test_regress/t/t_enum_public.cpp | 2 ++ test_regress/t/t_string.v | 13 +++++++++++++ test_regress/t/t_sys_plusargs.pl | 2 +- test_regress/t/t_sys_plusargs.v | 5 +++++ 7 files changed, 46 insertions(+), 5 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index cb910e8a0..a56dcf5e0 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1343,8 +1343,6 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE { VerilatedImp::fdClose(fdi); } -void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); } - void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE { static VL_THREAD_LOCAL std::string t_output; // static only for speed t_output = ""; diff --git a/nodist/code_coverage b/nodist/code_coverage index 782bab1a7..eebc34d03 100755 --- a/nodist/code_coverage +++ b/nodist/code_coverage @@ -92,8 +92,8 @@ def test(): if re.search(regexp, dat): # Remove .gcda/.gcno for files we don't care about before we slowly # read them - os.unlink(dat) - os.unlink(gcno) + unlink_ok(dat) + unlink_ok(gcno) del dats[dat] break @@ -315,6 +315,13 @@ def run(command): raise Exception("%Error: Command failed " + command + ", stopped") +def unlink_ok(filename): + try: + os.unlink(filename) + except OSError: + pass + + def ci_fold_start(action): print("::group::" + action, flush=True) diff --git a/test_regress/t/t_dpi_open_c.cpp b/test_regress/t/t_dpi_open_c.cpp index cff5d506a..d75c822a1 100644 --- a/test_regress/t/t_dpi_open_c.cpp +++ b/test_regress/t/t_dpi_open_c.cpp @@ -161,6 +161,22 @@ void _dpii_all(int c, int p, int u, const svOpenArrayHandle i, const svOpenArray CHECK_RESULT_HEX(svSize(i, d), 7); } } +#ifdef VERILATOR + // Check out-of-bounds read doesn't access bad memory (when sanitizer used) + (void)svLeft(i, -1); + (void)svRight(i, -1); + (void)svLow(i, -1); + (void)svHigh(i, -1); + (void)svIncrement(i, -1); + (void)svSize(i, -1); + // + (void)svLeft(i, 99); + (void)svRight(i, 99); + (void)svLow(i, 99); + (void)svHigh(i, 99); + (void)svIncrement(i, 99); + (void)svSize(i, 99); +#endif if (c == 2 && p == 1 && u == 3) { for (int a = svLow(i, 1); a <= svHigh(i, 1); ++a) { diff --git a/test_regress/t/t_enum_public.cpp b/test_regress/t/t_enum_public.cpp index 328140331..e46b8d57d 100644 --- a/test_regress/t/t_enum_public.cpp +++ b/test_regress/t/t_enum_public.cpp @@ -12,6 +12,8 @@ #include "Vt_enum_public_p3.h" #include "Vt_enum_public_p62.h" +double sc_time_stamp() { return 0; } + int main(int argc, char* argv[]) { Vt_enum_public* topp = new Vt_enum_public; diff --git a/test_regress/t/t_string.v b/test_regress/t/t_string.v index 6b8e48e07..758d5744e 100644 --- a/test_regress/t/t_string.v +++ b/test_regress/t/t_string.v @@ -15,6 +15,10 @@ module t (/*AUTOARG*/ integer cyc=0; + reg [1*8:1] vstr1; + reg [2*8:1] vstr2; + reg [6*8:1] vstr6; + reg [4*8:1] vstr; const string s = "a"; // Check static assignment string s2; @@ -29,6 +33,15 @@ module t (/*AUTOARG*/ // a.itoa, a.hextoa, a.octoa, a.bintoa, a.realtoa initial begin + $sformat(vstr1, "%s", s); + `checks(vstr1, "a"); + + $sformat(vstr2, "=%s", s); + `checks(vstr2, "=a"); + + $sformat(vstr6, "--a=%s", s); + `checks(vstr6, "--a=a"); + $sformat(vstr, "s=%s", s); `checks(vstr, "s=a"); `checks(string'(vstr), "s=a"); diff --git a/test_regress/t/t_sys_plusargs.pl b/test_regress/t/t_sys_plusargs.pl index 05eeca761..362a0c53c 100755 --- a/test_regress/t/t_sys_plusargs.pl +++ b/test_regress/t/t_sys_plusargs.pl @@ -16,7 +16,7 @@ compile( execute( check_finished => 1, - all_run_flags => ['+PLUS +INT=1234 +STRSTR +REAL=1.2345'], + all_run_flags => ['+PLUS +INT=1234 +STRSTR +REAL=1.2345 +IP%P101'], ); ok(1); diff --git a/test_regress/t/t_sys_plusargs.v b/test_regress/t/t_sys_plusargs.v index f387b5fa2..015ccfb2c 100644 --- a/test_regress/t/t_sys_plusargs.v +++ b/test_regress/t/t_sys_plusargs.v @@ -89,6 +89,11 @@ module t; $display("str='%s'",sv_str); if (sv_str != "T=1234") $stop; + sv_str = "none"; + if ($value$plusargs("IP%%P%b", p_i)!==1) $stop; + $display("str='%s'",sv_str); + if (p_i != 'b101) $stop; + sv_in = "INT=%d"; `ifdef VERILATOR if ($c1(0)) sv_in = "NEVER"; // Prevent constant propagation From fb2c243fc731cc9a944c1274214817fc1b276f6b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 13 Jan 2021 20:02:21 -0500 Subject: [PATCH 11/79] Build cmake examples with -j --- examples/cmake_hello_c/Makefile | 2 +- examples/cmake_hello_sc/Makefile | 2 +- examples/cmake_protect_lib/Makefile | 2 +- examples/cmake_tracing_c/Makefile | 2 +- examples/cmake_tracing_sc/Makefile | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/cmake_hello_c/Makefile b/examples/cmake_hello_c/Makefile index 212d264bd..c1a2d7c64 100644 --- a/examples/cmake_hello_c/Makefile +++ b/examples/cmake_hello_c/Makefile @@ -54,7 +54,7 @@ run: @echo @echo "-- BUILD -------------------" - cmake --build build + cmake --build build -j @echo @echo "-- RUN ---------------------" diff --git a/examples/cmake_hello_sc/Makefile b/examples/cmake_hello_sc/Makefile index d368370d5..633e4addd 100644 --- a/examples/cmake_hello_sc/Makefile +++ b/examples/cmake_hello_sc/Makefile @@ -90,7 +90,7 @@ run: @echo @echo "-- BUILD -------------------" - cmake --build build + cmake --build build -j @echo @echo "-- RUN ---------------------" diff --git a/examples/cmake_protect_lib/Makefile b/examples/cmake_protect_lib/Makefile index 1d8ac603c..0dba12ccf 100644 --- a/examples/cmake_protect_lib/Makefile +++ b/examples/cmake_protect_lib/Makefile @@ -54,7 +54,7 @@ run: @echo @echo "-- BUILD -------------------" - cmake --build build + cmake --build build -j @echo @echo "-- RUN ---------------------" diff --git a/examples/cmake_tracing_c/Makefile b/examples/cmake_tracing_c/Makefile index a3f0be678..22f59d125 100644 --- a/examples/cmake_tracing_c/Makefile +++ b/examples/cmake_tracing_c/Makefile @@ -54,7 +54,7 @@ run: @echo @echo "-- BUILD -------------------" - cmake --build build + cmake --build build -j @echo @echo "-- RUN ---------------------" diff --git a/examples/cmake_tracing_sc/Makefile b/examples/cmake_tracing_sc/Makefile index 81dcf4b33..65868d5bf 100644 --- a/examples/cmake_tracing_sc/Makefile +++ b/examples/cmake_tracing_sc/Makefile @@ -90,7 +90,7 @@ run: @echo @echo "-- BUILD -------------------" - cmake --build build + cmake --build build -j @echo @echo "-- RUN ---------------------" From 3c849d7ce0e70e95c30c32446e1b5372a12c3607 Mon Sep 17 00:00:00 2001 From: Pierre-Henri Horrein Date: Fri, 15 Jan 2021 13:31:48 +0100 Subject: [PATCH 12/79] Generate SELRANGE instead of errors for potentially unreachable code (#2625) (#2754) When using a "if" statement inside an always block, part of the code may be unreachable. This can be used to avoid errors, but it generated an error, this commit demotes this to a warning. Partly fixes #2625. --- docs/CONTRIBUTORS | 1 + src/V3Width.cpp | 4 +-- src/V3WidthSel.cpp | 27 +++++++++++--------- test_regress/t/t_mem_multi_ref_bad.out | 6 ++--- test_regress/t/t_param_unreachable.pl | 21 ++++++++++++++++ test_regress/t/t_param_unreachable.v | 34 ++++++++++++++++++++++++++ test_regress/t/t_select_bad_msb.out | 4 +-- 7 files changed, 78 insertions(+), 19 deletions(-) create mode 100755 test_regress/t/t_param_unreachable.pl create mode 100644 test_regress/t/t_param_unreachable.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 67b634c82..9a56dc7be 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -57,6 +57,7 @@ Paul Wright Peter Horvath Peter Monsson Philipp Wagner +Pierre-Henri Horrein Pieter Kapsenberg Piotr Binkowski Qingyao Sun diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e84c0f08a..80324ec6a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -804,8 +804,8 @@ private: } // We're extracting, so just make sure the expression is at least wide enough. if (nodep->fromp()->width() < width) { - nodep->v3error("Extracting " << width << " bits from only " - << nodep->fromp()->width() << " bit number"); + nodep->v3warn(SELRANGE, "Extracting " << width << " bits from only " + << nodep->fromp()->width() << " bit number"); // Extend it. AstNodeDType* subDTypep = nodep->findLogicDType(width, width, nodep->fromp()->dtypep()->numeric()); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 3769c1923..1060f6310 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -369,10 +369,11 @@ private: lsb = x; } if (lsb > msb) { - nodep->v3error("[" - << msb << ":" << lsb - << "] Range extract has backward bit ordering, perhaps you wanted [" - << lsb << ":" << msb << "]"); + nodep->v3warn( + SELRANGE, + "[" << msb << ":" << lsb + << "] Range extract has backward bit ordering, perhaps you wanted [" << lsb + << ":" << msb << "]"); int x = msb; msb = lsb; lsb = x; @@ -398,10 +399,11 @@ private: lsb = x; } if (lsb > msb) { - nodep->v3error("[" - << msb << ":" << lsb - << "] Range extract has backward bit ordering, perhaps you wanted [" - << lsb << ":" << msb << "]"); + nodep->v3warn( + SELRANGE, + "[" << msb << ":" << lsb + << "] Range extract has backward bit ordering, perhaps you wanted [" << lsb + << ":" << msb << "]"); int x = msb; msb = lsb; lsb = x; @@ -419,10 +421,11 @@ private: } else if (VN_IS(ddtypep, NodeUOrStructDType)) { // Classes aren't little endian if (lsb > msb) { - nodep->v3error("[" - << msb << ":" << lsb - << "] Range extract has backward bit ordering, perhaps you wanted [" - << lsb << ":" << msb << "]"); + nodep->v3warn( + SELRANGE, + "[" << msb << ":" << lsb + << "] Range extract has backward bit ordering, perhaps you wanted [" << lsb + << ":" << msb << "]"); int x = msb; msb = lsb; lsb = x; diff --git a/test_regress/t/t_mem_multi_ref_bad.out b/test_regress/t/t_mem_multi_ref_bad.out index e37aa73f6..558de331d 100644 --- a/test_regress/t/t_mem_multi_ref_bad.out +++ b/test_regress/t/t_mem_multi_ref_bad.out @@ -2,10 +2,11 @@ : ... In instance t 15 | dimn[1:0] = 0; | ^ -%Error: t/t_mem_multi_ref_bad.v:15:11: Extracting 2 bits from only 1 bit number - : ... In instance t +%Warning-SELRANGE: t/t_mem_multi_ref_bad.v:15:11: Extracting 2 bits from only 1 bit number + : ... In instance t 15 | dimn[1:0] = 0; | ^ + ... Use "/* verilator lint_off SELRANGE */" and lint_on around source to disable this message. %Error: t/t_mem_multi_ref_bad.v:16:14: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' : ... In instance t 16 | dim0[1][1] = 0; @@ -14,7 +15,6 @@ : ... In instance t 16 | dim0[1][1] = 0; | ^ - ... Use "/* verilator lint_off SELRANGE */" and lint_on around source to disable this message. %Error: t/t_mem_multi_ref_bad.v:17:17: Illegal bit or array select; type does not have a bit range, or bad dimension: data type is 'logic' : ... In instance t 17 | dim1[1][1][1] = 0; diff --git a/test_regress/t/t_param_unreachable.pl b/test_regress/t/t_param_unreachable.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_param_unreachable.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_unreachable.v b/test_regress/t/t_param_unreachable.v new file mode 100644 index 000000000..856944f5f --- /dev/null +++ b/test_regress/t/t_param_unreachable.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Pierre-Henri Horrein +// SPDX-License-Identifier: CC0-1.0 + +module t (input clk); + + parameter DEPTH = 1; + reg [DEPTH-1:0] shiftreg_gen; + reg [DEPTH-1:0] shiftreg; + reg my_sr_input = '1; + + // shiftreg_gen is generated: it should not raise any warning or error + always_ff @(posedge clk) begin + shiftreg_gen[0] <= my_sr_input; + end + if (DEPTH > 1) begin + always_ff @(posedge clk) begin + shiftreg_gen[DEPTH-1:1] <= shiftreg_gen[DEPTH-2:0]; + end + end + // shiftreg is not generated: it can raise a warning + always_ff @(posedge clk) begin + shiftreg[0] <= my_sr_input; + /* verilator lint_off SELRANGE */ + if (DEPTH > 1) shiftreg[DEPTH-1:1] <= shiftreg[DEPTH-2:0]; + /* verilator lint_on SELRANGE */ + end + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_select_bad_msb.out b/test_regress/t/t_select_bad_msb.out index 69147264b..2401969bb 100644 --- a/test_regress/t/t_select_bad_msb.out +++ b/test_regress/t/t_select_bad_msb.out @@ -3,8 +3,8 @@ 12 | reg [0:22] backwd; | ^ ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. -%Error: t/t_select_bad_msb.v:16:16: [1:4] Range extract has backward bit ordering, perhaps you wanted [4:1] - : ... In instance t +%Warning-SELRANGE: t/t_select_bad_msb.v:16:16: [1:4] Range extract has backward bit ordering, perhaps you wanted [4:1] + : ... In instance t 16 | sel2 = mi[1:4]; | ^ %Error: Exiting due to From 22260c6b85f088a43b552c129312c59d744ac05e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Jan 2021 22:12:45 -0500 Subject: [PATCH 13/79] Internals: Rename V3Const TREEOPC to TREEOPA. --- src/V3Const.cpp | 26 +++++++++++++------------- src/astgen | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 8ef02f707..abb703789 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2221,17 +2221,17 @@ private: // ("AstOr {%a, AstAnd{AstNot{%b}, %c}} if %a.width1 if %a==%b", "AstOr{%a,%c}; %b.delete"); // Lhs/rhs would be implied; for non math operations you'd need $lhsp etc. - // Lint Checks + // v--- * * This op done on Verilog or C+++ mode, in all non-m_doConst stages // v--- *1* These ops are always first, as we warn before replacing - // v--- *V* This op is a verilog op, only in m_doV mode - // v--- *C* This op works on all constant children, allowed in m_doConst mode - // v--- *S* This op specifies a type should use short-circuiting of its lhs op + // v--- *V* This op is a (V)erilog op, only in m_doV mode + // v--- *A* This op works on (A)ll constant children, allowed in m_doConst mode + // v--- *S* This op specifies a type should use (S)hort-circuiting of its lhs op TREEOP1("AstSel{warnSelect(nodep)}", "NEVER"); // Generic constants on both side. Do this first to avoid other replacements - TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)"); - TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque(), nodep->isPredictOptimizable()}", "replaceConst(nodep)"); - TREEOPC("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)"); + TREEOPA("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)"); + TREEOPA("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque(), nodep->isPredictOptimizable()}", "replaceConst(nodep)"); + TREEOPA("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)"); // Zero on one side or the other TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstAnd {$lhsp.isZero, $rhsp, isTPure($rhsp)}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure @@ -2294,8 +2294,8 @@ private: // Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump! TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)"); TREEOP ("AstNodeCond{$condp.isNeqZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr1p)"); - TREEOPC("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)"); - TREEOPC("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)"); + TREEOPA("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)"); + TREEOPA("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)"); TREEOP ("AstNodeCond{$condp, operandsSame($expr1p,,$expr2p)}","replaceWChild(nodep,$expr1p)"); // This visit function here must allow for short-circuiting. TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)"); @@ -2486,7 +2486,7 @@ private: TREEOPV("AstSel{$fromp.castSub, operandSelBiLower(nodep)}", "DONE"); TREEOPV("AstSel{$fromp.castXor, operandSelBiLower(nodep)}", "DONE"); TREEOPV("AstSel{$fromp.castShiftR, operandSelShiftLower(nodep)}", "DONE"); - TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)"); + TREEOPA("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)"); TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)"); TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.castConst, operandSelReplicate(nodep) }", "DONE"); // V3Tristate requires selects below BufIf1. @@ -2502,9 +2502,9 @@ private: TREEOPV("AstLogIf{$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}"); TREEOPV("AstLogEq{$lhsp, $rhsp}", "replaceLogEq(nodep)"); // Strings - TREEOPC("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); - TREEOPC("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); - TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())"); + TREEOPA("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); + TREEOPA("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)"); + TREEOPA("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())"); // Custom // Implied by AstIsUnbounded::numberOperate: V("AstIsUnbounded{$lhsp.castConst}", "replaceNum(nodep, 0)"); TREEOPV("AstIsUnbounded{$lhsp.castUnbounded}", "replaceNum(nodep, 1)"); diff --git a/src/astgen b/src/astgen index c69a40417..26834bd9a 100644 --- a/src/astgen +++ b/src/astgen @@ -486,7 +486,7 @@ sub tree_line { $func =~ s!\s*;\s*$!!; # doflag "S" indicates an op specifying short-circuiting for a type. - if ($func =~ /TREEOP(1?)([VCS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) { + if ($func =~ /TREEOP(1?)([VAS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) { my $order = $1; my $doflag = $2; my $from = $3; my $to = $4; #$self->print("// $from $to\n"); if (!$self->{did_out_tree}) { @@ -505,7 +505,7 @@ sub tree_line { my $mif; if ($doflag eq '') { $mif = "m_doNConst"; } elsif ($doflag eq 'V') { $mif = "m_doV"; } - elsif ($doflag eq 'C') { $mif = ""; } + elsif ($doflag eq 'A') { $mif = ""; } elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate else { die; } $subnodes =~ s/,,/__ESCAPEDCOMMA__/g; From cea8b65f8ca36fb33d1acaa6c7b7813cd7822364 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 16 Jan 2021 23:47:04 +0900 Subject: [PATCH 14/79] Internals: Make some accessors in V3Number public (#2756). No functional change. --- src/V3Number.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/V3Number.h b/src/V3Number.h index 47ca60a11..c2fef325b 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -109,6 +109,8 @@ private: return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0) | ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]); } + +public: bool bitIs0(int bit) const { if (bit < 0) return false; if (bit >= m_width) return !bitIsXZ(m_width - 1); @@ -144,6 +146,8 @@ private: return ((~m_value[bit / 32] & (1UL << (bit & 31))) && (m_valueX[bit / 32] & (1UL << (bit & 31)))); } + +private: uint32_t bitsValue(int lsb, int nbits) const { uint32_t v = 0; for (int bitn = 0; bitn < nbits; bitn++) { v |= (bitIs1(lsb + bitn) << bitn); } From b82085fbc6de91a9ce39f1365688ff71da636df7 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 16 Jan 2021 23:47:27 +0900 Subject: [PATCH 15/79] Internals: Use size_t to compare with vector::capacity(). No functional change intended. (#2758) --- include/verilated_imp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated_imp.h b/include/verilated_imp.h index e81f5e908..6102425f9 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -595,7 +595,7 @@ private: } } else { // MCD Case - for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { + for (size_t i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { if (fdi & VL_MASK_I(1)) fp.push_back(s_s.v.m_fdps[i]); } } From 1f105edf6922df478310205c615cd023e0e084ca Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Jan 2021 13:24:14 -0500 Subject: [PATCH 16/79] Internals: Convert astgen to python. --- Makefile.in | 1 + src/Makefile_obj.in | 4 +- src/astgen | 1398 ++++++++++++++++++++----------------------- 3 files changed, 666 insertions(+), 737 deletions(-) mode change 100644 => 100755 src/astgen diff --git a/Makefile.in b/Makefile.in index 67a14921c..1f069f909 100644 --- a/Makefile.in +++ b/Makefile.in @@ -479,6 +479,7 @@ YAPF_FLAGS = -i YAPF_FILES = \ examples/xml_py/vl_file_copy \ examples/xml_py/vl_hier_graph \ + src/astgen \ src/bisonpre \ src/config_rev \ src/cppcheck_filtered \ diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index c194ab79a..8313ba6f1 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -288,7 +288,7 @@ V3Number_test: V3Number_test.o #### Modules %__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h - $(PERL) $(ASTGEN) -I$(srcdir) $*.cpp + $(PYTHON3) $(ASTGEN) -I$(srcdir) $*.cpp %.o: %.cpp $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@ @@ -319,7 +319,7 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h touch $@ V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h - $(PERL) $(ASTGEN) -I$(srcdir) --classes + $(PYTHON3) $(ASTGEN) -I$(srcdir) --classes V3ParseBison.h: V3ParseBison.c diff --git a/src/astgen b/src/astgen old mode 100644 new mode 100755 index 26834bd9a..9cfeace9a --- a/src/astgen +++ b/src/astgen @@ -1,790 +1,718 @@ -#!/usr/bin/env perl -# See copyright, etc in below POD section. +#!/usr/bin/env python3 ###################################################################### -use warnings; -use Getopt::Long; -use IO::File; -use Pod::Usage; -use strict; -use vars qw($Debug @Types %Classes %Children %ClassRefs %Stages); +import argparse +import glob +import re +import sys +#from pprint import pprint, pformat -#====================================================================== -# main +Types = [] +Classes = {} +Children = {} +ClassRefs = {} +Stages = {} -$Debug = 0; -my $opt_classes; -my $opt_report; -my @Opt_Cpt; -my @Opt_I; -Getopt::Long::config("pass_through", "no_auto_abbrev"); -if (! GetOptions( - "help" => \&usage, - "debug" => sub { $Debug = 1; }, - "classes!" => \$opt_classes, - "report!" => \$opt_report, - "<>" => \¶meter, - )) { - usage(); -} -read_types("$Opt_I[0]/V3Ast.h"); -read_types("$Opt_I[0]/V3AstNodes.h"); -foreach my $type (sort (keys %Classes)) { - # Check all leaves are not AstNode* and non-leaves are AstNode* - my @children = children_of($type); - if ($type =~ /^Node/) { - @children || die "Error: Final AstNode subclasses must not be named AstNode*: Ast$type" - } else { - !@children || die "Error: Non-final AstNode subclasses must be named AstNode*: Ast$type" - } -} -read_stages("$Opt_I[0]/Verilator.cpp"); -read_refs(glob("$Opt_I[0]/*.y"), glob("$Opt_I[0]/*.h"), glob("$Opt_I[0]/*.cpp")); -if ($opt_report) { - write_report(undef); -} -if ($opt_classes) { - write_report("V3Ast__gen_report.txt"); - write_classes("V3Ast__gen_classes.h"); - write_visitor("V3Ast__gen_visitor.h"); - write_impl("V3Ast__gen_impl.h"); - write_types("V3Ast__gen_types.h"); - write_header("V3AstNodes__gen.h"); -} -foreach my $cpt (@Opt_Cpt) { - Cpt::process(in_filename=>"$Opt_I[0]/${cpt}.cpp", out_filename=>"${cpt}__gen.cpp"); -} +class Cpt: + def __init__(self): + self.did_out_tree = False + self.out_lines = [] + self.out_linenum = 1 + self.treeop = {} + self.tree_skip_visit = {} + self._exec_nsyms = 0 + self._exec_syms = {} -#---------------------------------------------------------------------- + def error(self, txt): + sys.exit("%%Error: %s:%d: %s" % + (self.in_filename, self.in_linenum, txt)) -sub usage { - pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT); - exit(1); # Unreachable -} + def print(self, txt): + self.out_lines.append(txt) -sub parameter { - my $param = shift; - if ($param =~ /^-+I(\S+)/) { - push @Opt_I, $1; - } elsif ($param =~ s/\.cpp$//) { - push @Opt_Cpt, $param; - } else { - die "%Error: Unknown parameter: $param,"; - } -} + def output_func(self, func): + self.out_lines.append(func) -####################################################################### + def _output_line(self): + self.print("#line " + str(self.out_linenum + 2) + " \"" + + self.out_filename + "\"\n") -sub read_types { - my $filename = shift; + def process(self, in_filename, out_filename): + self.in_filename = in_filename + self.out_filename = out_filename + ln = 0 + didln = False - my $fh = IO::File->new($filename) or die "%Error: $! $filename,"; - while (defined (my $line = $fh->getline())) { - $line =~ s/\/\/.*$//; - next if $line =~ /^\s*$/; - if ($line =~ /^\s*(class|struct)\s*(\S+)/) { - my $class = $2; - my $inh = ""; - $inh = $1 if ($line =~ /:\s*public\s+(\S+)/); - print "class $class : $inh\n" if $Debug; - $inh = "" if $class eq "AstNode"; - if ($inh =~ /Ast/ || $class eq "AstNode") { - $class =~ s/^Ast//; - $inh =~ s/^Ast//; - $Classes{$class} = $inh; - $Children{$inh}{$class} = 1; + # Read the file and parse into list of functions that generate output + with open(self.in_filename) as fhi: + for line in fhi: + ln += 1 + if not didln: + self.print("#line " + str(ln) + " \"" + self.in_filename + + "\"\n") + didln = True + match = re.match(r'^\s+(TREE.*)$', line) + if match: + func = match.group(1) + self.in_linenum = ln + self.print("//" + line) + self.output_func(lambda self: self._output_line()) + self.tree_line(func) + didln = False + elif not re.match(r'^\s*/[/\*]\s*TREE', line) and re.search( + r'\s+TREE', line): + self.error("Unknown astgen line: " + line) + else: + self.print(line) + + # Put out the resultant file, if the list has a reference to a + # function, then call that func to generate output + with open_file(self.out_filename) as fho: + togen = self.out_lines + for line in togen: + if type(line) is str: + self.out_lines = [line] + else: + self.out_lines = [] + line(self) # lambda call + for out in self.out_lines: + for _ in re.findall(r'\n', out): + self.out_linenum += 1 + fho.write(out) + + def tree_line(self, func): + func = re.sub(r'\s*//.*$', '', func) + func = re.sub(r'\s*;\s*$', '', func) + + # doflag "S" indicates an op specifying short-circuiting for a type. + match = re.search( + # 1 2 3 4 + r'TREEOP(1?)([ASV]?)\s*\(\s*\"([^\"]*)\"\s*,\s*\"([^\"]*)\"\s*\)', + func) + match_skip = re.search(r'TREE_SKIP_VISIT\s*\(\s*\"([^\"]*)\"\s*\)', + func) + + if match: + order = match.group(1) + doflag = match.group(2) + fromn = match.group(3) + to = match.group(4) + #self.print("// $fromn $to\n") + if not self.did_out_tree: + self.did_out_tree = True + self.output_func(lambda self: self.tree_match_base()) + match = re.search(r'Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$', fromn) + if not match: + self.error("Can't parse from function: " + func) + typen = match.group(1) + subnodes = match.group(2) + if not subclasses_of(typen): + self.error("Unknown AstNode typen: " + typen + ": in " + func) + + mif = "" + if doflag == '': + mif = "m_doNConst" + elif doflag == 'A': + mif = "" + elif doflag == 'S': + mif = "m_doNConst" # Not just for m_doGenerate + elif doflag == 'V': + mif = "m_doV" + else: + self.error("Unknown flag: " + doflag) + subnodes = re.sub(r',,', '__ESCAPEDCOMMA__', subnodes) + for subnode in re.split(r'\s*,\s*', subnodes): + subnode = re.sub(r'__ESCAPEDCOMMA__', ',', subnode) + if re.match(r'^\$([a-zA-Z0-9]+)$', subnode): + continue # "$lhs" is just a comment that this op has a lhs + subnodeif = subnode + subnodeif = re.sub( + r'\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$', + r'VN_IS(nodep->\1(),\2)', subnodeif) + subnodeif = re.sub(r'\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$', + r'nodep->\1()->\2()', subnodeif) + subnodeif = self.add_nodep(subnodeif) + if mif != "" and subnodeif != "": + mif += " && " + mif += subnodeif + + exec_func = self.treeop_exec_func(to) + exec_func = re.sub( + r'([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)', + r'VN_CAST(\1,\2)', exec_func) + + if typen not in self.treeop: + self.treeop[typen] = [] + n = len(self.treeop[typen]) + typefunc = { + 'order': order, + 'comment': func, + 'match_func': "match_" + typen + "_" + str(n), + 'match_if': mif, + 'exec_func': exec_func, + 'uinfo': re.sub(r'[ \t\"\{\}]+', ' ', func), + 'uinfo_level': (0 if re.match(r'^!', to) else 7), + 'short_circuit': (doflag == 'S'), } - } - } -} + self.treeop[typen].append(typefunc) -sub read_stages { - my $filename = shift; + elif match_skip: + typen = match_skip.group(1) + self.tree_skip_visit[typen] = 1 + if typen not in Classes: + self.error("Unknown node type: " + typen) - my $fh = IO::File->new($filename) or die "%Error: $! $filename,"; - my $n = 0; - while (defined (my $line = $fh->getline())) { - $line =~ s/\/\/.*$//; - next if $line =~ /^\s*$/; - if ($line =~ /^\s*([A-Za-z0-9]+)::/) { - my $stage = $1.".cpp"; - if (!defined ($Stages{$stage})) { - $Stages{$stage} = $n++; - } - } - } -} + else: + self.error("Unknown astgen op: " + func) -sub read_refs { - my @filenames = @_; + @staticmethod + def add_nodep(str): + str = re.sub(r'\$([a-zA-Z0-9]+)', r'nodep->\1()', str) + return str - foreach my $filename (@filenames) { - (my $basename = $filename) =~ s!.*/!!; - my $fh = IO::File->new($filename) or die "%Error: $! $filename,"; - while (defined (my $line = $fh->getline())) { - $line =~ s/\/\/.*$//; - while ($line =~ /\bnew\s*(Ast[A-Za-z0-9_]+)/g) { - $ClassRefs{$1}{newed}{$basename} = 1; - } - while ($line =~ /\b(Ast[A-Za-z0-9_]+)/g) { - $ClassRefs{$1}{used}{$basename} = 1; - } - } - } - #use Data::Dumper;print Dumper(\%ClassRefs); -} + def _exec_syms_recurse(self, aref): + for sym in aref: + if type(sym) is list: + self._exec_syms_recurse(sym) + elif re.search(r'^\$.*', sym): + if sym not in self._exec_syms: + self._exec_nsyms += 1 + self._exec_syms[sym] = "arg" + str(self._exec_nsyms) + "p" -#---------------------------------------------------------------------- + def _exec_new_recurse(self, aref): + out = "new " + aref[0] + "(nodep->fileline()" + first = True + for sym in aref: + if first: + first = False + continue + out += ", " + if type(sym) is list: + out += self._exec_new_recurse(sym) + elif re.match(r'^\$.*', sym): + out += self._exec_syms[sym] + else: + out += sym + return out + ")" -sub open_file { - my $filename = shift; - my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,"; - if ($filename =~ /\.txt$/) { - print $fh '// Generated by astgen'."\n"; - } else { - print $fh '// Generated by astgen // -*- mode: C++; c-file-style: "cc-mode" -*-'."\n"; - } - return $fh; -} + def treeop_exec_func(self, func): + out = "" + func = re.sub(r'^!', '', func) -#---------------------------------------------------------------------- + if re.match(r'^\s*[a-zA-Z0-9]+\s*\(', func): # Function call + outl = re.sub(r'\$([a-zA-Z0-9]+)', r'nodep->\1()', func) + out += outl + ";" + elif re.match(r'^\s*Ast([a-zA-Z0-9]+)\s*\{\s*(.*)\s*\}$', func): + nargs = 0 + argnums = [] # Number for each argument name + aref = None + # Recursive array with structure to form + astack = [] + forming = "" + argtext = func + "\000" # EOF character + for tok in argtext: + if tok == "\000": + None + elif re.match(r'\s+', tok): + None + elif tok == "{": + newref = [forming] + if not aref: + aref = [] + aref.append(newref) + astack.append(aref) + aref = newref + forming = "" + elif tok == "}": + if forming: + aref.append(forming) + if len(astack) == 0: + self.error("Too many } in execution function: " + func) + aref = astack.pop() + forming = "" + elif tok == ",": + if forming: + aref.append(forming) + forming = "" + else: + forming += tok + if not (aref and len(aref) == 1): + self.error("Badly formed execution function: " + func) + aref = aref[0] -sub subclasses_of { - my $type = shift; + # Assign numbers to each $ symbol + self._exec_syms = {} + self._exec_nsyms = 0 + self._exec_syms_recurse(aref) - my @cllist; - for (my $subclass = $::Classes{$type}; $subclass; ) { - push @cllist, $subclass; - $subclass = $::Classes{$subclass}; - } + for sym in sorted(self._exec_syms.keys(), + key=lambda val: self._exec_syms[val]): + argnp = self._exec_syms[sym] + arg = self.add_nodep(sym) + out += "AstNode* " + argnp + " = " + arg + "->unlinkFrBack();\n" - return (reverse @cllist); -} + out += "AstNode* newp = " + self._exec_new_recurse(aref) + ";\n" + out += "nodep->replaceWith(newp);" + out += "VL_DO_DANGLING(nodep->deleteTree(), nodep);" + elif func == "NEVER": + out += "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");" + elif func == "DONE": + None + else: + self.error("Unknown execution function format: " + func + "\n") + return out -sub children_of { - my $type = shift; + def tree_match_base(self): + self.tree_match() + self.tree_base() - my @cllist; - my @todo; - push @todo, $type; - while (my $subclass = shift @todo) { - foreach my $child (sort keys %{$::Children{$subclass}}) { - push @todo, $child; - push @cllist, $child; - } - } + def tree_match(self): + self.print( + " // TREEOP functions, each return true if they matched & transformed\n" + ) + for base in sorted(self.treeop.keys()): + for typefunc in self.treeop[base]: + self.print(" // Generated by astgen\n") + self.print(" bool " + typefunc['match_func'] + "(Ast" + + base + "* nodep) {\n") + self.print("\t// " + typefunc['comment'] + "\n") + self.print("\tif (" + typefunc['match_if'] + ") {\n") + self.print("\t UINFO(" + str(typefunc['uinfo_level']) + + ",cvtToHex(nodep)" + "<<\" " + typefunc['uinfo'] + + "\\n\");\n") + self.print("\t " + typefunc['exec_func'] + "\n") + self.print("\t return true;\n") + self.print("\t}\n") + self.print("\treturn false;\n") + self.print(" }\n", ) - return (@cllist); -} + def tree_base(self): + self.print(" // TREEOP visitors, call each base type's match\n") + self.print( + " // Bottom class up, as more simple transforms are generally better\n" + ) + for typen in sorted(Classes.keys()): + out_for_type_sc = [] + out_for_type = [] + bases = subclasses_of(typen) + bases.append(typen) + for base in bases: + if not base in self.treeop: + continue + for typefunc in self.treeop[base]: + lines = [ + " if (" + typefunc['match_func'] + + "(nodep)) return;\n" + ] + if (typefunc['short_circuit']): # short-circuit match fn + out_for_type_sc.extend(lines) + else: # Standard match fn + if typefunc[ + 'order']: # TREEOP1's go in front of others + out_for_type = lines + out_for_type + else: + out_for_type.extend(lines) -#---------------------------------------------------------------------- + # We need to deal with two cases. For short circuited functions we + # evaluate the LHS, then apply the short-circuit matches, then + # evaluate the RHS and possibly THS (ternary operators may + # short-circuit) and apply all the other matches. -sub write_report { - my $filename = shift; - my $fh = defined($filename) ? open_file($filename) : \*STDOUT; + # For types without short-circuits, we just use iterateChildren, which + # saves one comparison. + if len(out_for_type_sc) > 0: # Short-circuited types + self.print( + " // Generated by astgen with short-circuiting\n" + + " virtual void visit(Ast" + typen + + "* nodep) override {\n" + + " iterateAndNextNull(nodep->lhsp());\n" + + "".join(out_for_type_sc)) + if out_for_type[0]: + self.print( + " iterateAndNextNull(nodep->rhsp());\n" + + " AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n" + + + " if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n" + + "".join(out_for_type) + " }\n") + elif len(out_for_type) > 0: # Other types with something to print + skip = typen in self.tree_skip_visit + gen = "Gen" if skip else "" + override = "" if skip else " override" + self.print( + " // Generated by astgen\n" + " virtual void visit" + + gen + "(Ast" + typen + "* nodep)" + override + " {\n" + + ("" if skip else " iterateChildren(nodep);\n") + + ''.join(out_for_type) + " }\n") - $fh->print("Processing stages (approximate, based on order in Verilator.cpp):\n"); - foreach my $class (sort {$Stages{$a} <=> $Stages{$b}} keys %Stages) { - $fh->print(" $class\n"); - } - $fh->print("\nClasses:\n"); - foreach my $type (sort (keys %Classes)) { - printf $fh " class %-20s\n", "Ast${type}"; - $fh->print(" parent: "); - foreach my $subclass (subclasses_of($type)) { - next if $subclass eq 'Node'; - printf $fh "Ast%-12s ",$subclass; - } - printf $fh "\n"; - $fh->print(" childs: "); - foreach my $subclass (children_of($type)) { - next if $subclass eq 'Node'; - printf $fh "Ast%-12s ",$subclass; - } - printf $fh "\n"; - if (my $refs = $ClassRefs{"Ast${type}"}) { - $fh->print(" newed: "); - foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)} - keys %{$refs->{newed}}) { - $fh->print($stage." "); - } - $fh->print("\n"); - $fh->print(" used: "); - foreach my $stage (sort {($Stages{$a}||-1) <=> ($Stages{$b}||-1)} - keys %{$refs->{used}}) { - $fh->print($stage." "); - } - $fh->print("\n"); - } - $fh->print("\n"); - } -} +###################################################################### +###################################################################### -sub write_classes { - my $fh = open_file(@_); - printf $fh "class AstNode;\n"; - foreach my $type (sort (keys %Classes)) { - printf $fh "class %-20s // ", "Ast${type};"; - foreach my $subclass (subclasses_of($type)) { - printf $fh "Ast%-12s ",$subclass; - } - printf $fh "\n"; - } - $fh->close(); -} -sub write_visitor { - my $fh = open_file(@_); - foreach my $type (sort (keys %Classes)) { - my $base = $Classes{$type}; - if ($base) { - printf $fh " virtual void visit(Ast${type}* nodep) { visit((Ast${base}*)(nodep)); }\n"; - } else { - printf $fh " virtual void visit(Ast${type}*) = 0;\n"; - } - } - $fh->close(); -} +def read_types(filename): + with open(filename) as fh: + for line in fh: + line = re.sub(r'//.*$', '', line) + if re.match(r'^\s*$', line): + continue + match = re.search(r'^\s*(class|struct)\s*(\S+)', line) + if match: + classn = match.group(2) + inh = "" + match = re.search(r':\s*public\s+(\S+)', line) + if match: + inh = match.group(1) + #print("class "+classn+" : "+inh) + if classn == "AstNode": + inh = "" + if re.search(r'Ast', inh) or classn == "AstNode": + classn = re.sub(r'^Ast', '', classn) + inh = re.sub(r'^Ast', '', inh) + Classes[classn] = inh + if inh != '': + if inh not in Children: + Children[inh] = {} + Children[inh][classn] = 1 -sub write_impl { - my $fh = open_file(@_); - print $fh "\n"; +def read_stages(filename): + with open(filename) as fh: + n = 100 + for line in fh: + line = re.sub(r'//.*$', '', line) + if re.match(r'^\s*$', line): + continue + match = re.match(r'^\s*([A-Za-z0-9]+)::', line) + if match: + stage = match.group(1) + ".cpp" + if stage not in Stages: + Stages[stage] = n + n += 1 - print $fh " // These for use by VN_IS only\n"; - foreach my $type (sort (keys %Classes)) { - print $fh "template<> inline bool AstNode::privateIs(const AstNode* nodep) { "; - if ($type eq "Node") { - print $fh "return nodep != NULL; "; - } else { - print $fh "return nodep && "; - if ($type =~ /^Node/) { - print $fh "(static_cast(nodep->type()) >= static_cast(AstType::first",$type,")) && "; - print $fh "(static_cast(nodep->type()) <= static_cast(AstType::last",$type,")); "; - } else { - print $fh "(static_cast(nodep->type()) == static_cast(AstType::at",$type,")); "; - } - } - print $fh "}\n" - } - print $fh " // These for use by VN_CAST macro only\n"; - foreach my $type (sort (keys %Classes)) { - print $fh "template<> inline Ast",$type,"* AstNode::privateCast(AstNode* nodep) { "; - if ($type eq "Node") { - print $fh "return nodep; "; - } else { - print $fh "return AstNode::privateIs(nodep) ? "; - print $fh "reinterpret_cast(nodep) : NULL; "; - } - print $fh "}\n"; - } +def read_refs(filename): + basename = re.sub(r'.*/', '', filename) + with open(filename) as fh: + for line in fh: + line = re.sub(r'//.*$', '', line) + for match in re.finditer(r'\bnew\s*(Ast[A-Za-z0-9_]+)', line): + ref = match.group(1) + if ref not in ClassRefs: + ClassRefs[ref] = {'newed': {}, 'used': {}} + ClassRefs[ref]['newed'][basename] = 1 + for match in re.finditer(r'\b(Ast[A-Za-z0-9_]+)', line): + ref = match.group(1) + if ref not in ClassRefs: + ClassRefs[ref] = {'newed': {}, 'used': {}} + ClassRefs[ref]['used'][basename] = 1 - print $fh " // These for use by VN_CAST_CONST macro only\n"; - foreach my $type (sort (keys %Classes)) { - print $fh "template<> inline const Ast",$type,"* AstNode::privateConstCast(const AstNode* nodep) { "; - if ($type eq "Node") { - print $fh "return nodep; "; - } else { - print $fh "return AstNode::privateIs(nodep) ? "; - print $fh "reinterpret_cast(nodep) : NULL; "; - } - print $fh "}\n"; - } - $fh->close(); -} +def open_file(filename): + fh = open(filename, "w") + if re.search(r'\.txt$', filename): + fh.write("// Generated by astgen\n") + else: + fh.write( + '// Generated by astgen // -*- mode: C++; c-file-style: "cc-mode" -*-' + + "\n") + return fh -sub write_type_enum { - my $fh = shift; - my $type = shift; - my $idx = shift; - my $processed = shift; - my $kind = shift; - my $indent = shift; +def subclasses_of(typen): + cllist = [] + subclass = Classes[typen] + while True: + if not subclass in Classes: + break + cllist.append(subclass) + subclass = Classes[subclass] + + cllist.reverse() + return cllist + + +def children_of(typen): + cllist = [] + todo = [] + todo.append(typen) + while len(todo) != 0: + subclass = todo.pop(0) + if subclass in Children: + for child in sorted(Children[subclass].keys()): + todo.append(child) + cllist.append(child) + + return cllist + + +#--------------------------------------------------------------------- + + +def write_report(filename): + with open_file(filename) as fh: + + fh.write( + "Processing stages (approximate, based on order in Verilator.cpp):\n" + ) + for classn in sorted(Stages.keys(), key=lambda val: Stages[val]): + fh.write(" " + classn + "\n") + + fh.write("\nClasses:\n") + for typen in sorted(Classes.keys()): + fh.write(" class Ast%-17s\n" % typen) + fh.write(" parent: ") + for subclass in subclasses_of(typen): + if subclass != 'Node': + fh.write("Ast%-12s " % subclass) + fh.write("\n") + fh.write(" childs: ") + for subclass in children_of(typen): + if subclass != 'Node': + fh.write("Ast%-12s " % subclass) + fh.write("\n") + if ("Ast" + typen) in ClassRefs: + refs = ClassRefs["Ast" + typen] + fh.write(" newed: ") + for stage in sorted(refs['newed'].keys(), + key=lambda val: Stages[val] + if (val in Stages) else -1): + fh.write(stage + " ") + fh.write("\n") + fh.write(" used: ") + for stage in sorted(refs['used'].keys(), + key=lambda val: Stages[val] + if (val in Stages) else -1): + fh.write(stage + " ") + fh.write("\n") + fh.write("\n") + + +def write_classes(filename): + with open_file(filename) as fh: + fh.write("class AstNode;\n") + for typen in sorted(Classes.keys()): + fh.write("class Ast%-17s // " % (typen + ";")) + for subclass in subclasses_of(typen): + fh.write("Ast%-12s " % subclass) + fh.write("\n") + + +def write_visitor(filename): + with open_file(filename) as fh: + for typen in sorted(Classes.keys()): + if typen == "Node": + fh.write(" virtual void visit(Ast" + typen + "*) = 0;\n") + else: + base = Classes[typen] + fh.write(" virtual void visit(Ast" + typen + + "* nodep) { visit((Ast" + base + "*)(nodep)); }\n") + + +def write_impl(filename): + with open_file(filename) as fh: + fh.write("\n") + fh.write(" // These for use by VN_IS only\n") + for typen in sorted(Classes.keys()): + fh.write("template<> inline bool AstNode::privateIs(const AstNode* nodep) { ") + if typen == "Node": + fh.write("return nodep != NULL; ") + else: + fh.write("return nodep && ") + if re.search(r'^Node', typen): + fh.write( + "(static_cast(nodep->type()) >= static_cast(AstType::first" + + typen + ")) && ") + fh.write( + "(static_cast(nodep->type()) <= static_cast(AstType::last" + + typen + ")); ") + else: + fh.write( + "(static_cast(nodep->type()) == static_cast(AstType::at" + + typen + ")); ") + fh.write("}\n") + + fh.write(" // These for use by VN_CAST macro only\n") + for typen in sorted(Classes.keys()): + fh.write("template<> inline Ast" + typen + + "* AstNode::privateCast(AstNode* nodep) { ") + if typen == "Node": + fh.write("return nodep; ") + else: + fh.write("return AstNode::privateIs(nodep) ? ") + fh.write("reinterpret_cast(nodep) : NULL; ") + fh.write("}\n") + + fh.write(" // These for use by VN_CAST_CONST macro only\n") + for typen in sorted(Classes.keys()): + fh.write("template<> inline const Ast" + typen + + "* AstNode::privateConstCast(const AstNode* nodep) { ") + if typen == "Node": + fh.write("return nodep; ") + else: + fh.write("return AstNode::privateIs(nodep) ? ") + fh.write("reinterpret_cast(nodep) : NULL; ") + fh.write("}\n") + + +def write_type_enum(fh, typen, idx, processed, kind, indent): # Skip this if it has already been processed - return $idx if (exists $processed->{$type}); - + if typen in processed: + return idx # Mark processed - $processed->{$type} = 1; + processed[typen] = 1 # The last used index - my $last; - - if ($type !~ /^Node/) { - $last = $idx; - if ($kind eq "concrete-enum") { - print $fh " "x($indent*4), "at",$type," = ",$idx,",\n"; - } elsif ($kind eq "concrete-ascii") { - print $fh " "x($indent*4), "\"", uc $type, "\",\n"; - } - $idx += 1; - } elsif ($kind eq "abstract-enum") { - print $fh " "x($indent*4), "first",$type," = ",$idx,",\n"; - } - - foreach my $child (sort keys %{$::Children{$type}}) { - ($idx, $last) = write_type_enum($fh, $child, $idx, $processed, $kind, $indent); - } - - if ($type =~ /^Node/ && ($kind eq "abstract-enum")) { - print $fh " "x($indent*4), "last",$type," = ",$last,",\n"; - } - - return $idx, $last; -} - -sub write_types { - my $fh = open_file(@_); - - printf $fh " enum en : uint16_t {\n"; - (my $final, undef) = write_type_enum($fh, "Node", 0, {}, "concrete-enum", 2); - printf $fh " _ENUM_END = $final\n"; - printf $fh " };\n"; - - printf $fh " enum bounds : uint16_t {\n"; - write_type_enum($fh, "Node", 0, {}, "abstract-enum", 2); - printf $fh " _BOUNDS_END\n"; - printf $fh " };\n"; - - printf $fh " const char* ascii() const {\n"; - printf $fh " static const char* const names[_ENUM_END + 1] = {\n"; - write_type_enum($fh, "Node", 0, {}, "concrete-ascii", 3); - printf $fh " \"_ENUM_END\"\n"; - printf $fh " };\n"; - printf $fh " return names[m_e];\n"; - printf $fh " }\n"; - $fh->close(); -} - -sub write_header { - my $fh = open_file(@_); - - my $type = "None"; - my $base = "None"; - - my $in_filename = "V3AstNodes.h"; - my $ifile = "$Opt_I[0]/$in_filename"; - my $ifh = IO::File->new($ifile) or die "%Error: $! $ifile,"; - - $fh->print("#line 1 \"../$in_filename\"\n"); - - while (defined (my $line = $ifh->getline())) { - # Drop expanded macro definitions - but keep empty line so compiler - # message locations are accurate - $line =~ s/^\s*#(define|undef)\s+ASTGEN_.*$//; - - # Track current node type and base class - if ($line =~ /^\s*class\s*Ast(\S+)\s*(final|VL_NOT_FINAL)?\s*:\s*(public)?\s*(AstNode\S*)/) { - $type = $1; - $base = $4; - } - - # Substitute macros - $line =~ s/\bASTGEN_SUPER\s*\(/$base(AstType::at$type, /; - - # Emit the line - print $fh $line; - } - - $ifh->close(); - $fh->close(); -} - -####################################################################### - -package Cpt; - -sub error { - my $self = shift; - my $txt = join('', @_); - die "%Error: $self->{in_filename}:$self->{in_linenum}: $txt\n"; -} - -sub print { - my $self = shift; - my $txt = join('', @_); - push @{$self->{out_lines}}, $txt; -} - -sub output_func { - my $self = shift; - my $func = shift; - push @{$self->{out_lines}}, $func; -} - -sub _output_line { - my $self = shift; - $self->print("#line ",$self->{out_linenum}+2," \"$self->{out_filename}\"\n"); -} - -sub process { - my $self = { - in_filename => undef, - out_filename => undef, - out_lines => [], - out_linenum => 1, - @_, - }; - bless $self, __PACKAGE__; - - my $ln = 1; - my $didln; - - # Read the file and parse into list of functions that generate output - my $fhi = IO::File->new($self->{in_filename}) or die "%Error: $! $self->{in_filename},"; - while (defined(my $line = $fhi->getline)) { - if (!$didln) { - $self->print("#line $. \"$self->{in_filename}\"\n"); - $didln = 1; - } - if ($line =~ /^\s+(TREE.*)$/) { - my $func = $1; - $self->{in_linenum} = $.; - $self->print("//$line"); - $self->output_func(sub{my $self=shift; $self->_output_line(); }); - $self->tree_line($func); - $didln = 0; - } - elsif ($line !~ /^\s*\/[\/\*]\s*TREE/ - && $line =~ /\s+TREE/) { - $self->error("Unknown astgen line: $line"); - } - else { - $self->print($line); - } - } - $fhi->close; - - # Put out the resultant file, if the list has a reference to a - # function, then call that func to generate output - my $fho = ::open_file($self->{out_filename}); - my @togen = @{$self->{out_lines}}; - foreach my $line (@togen) { - if (ref $line) { - $self->{out_lines} = []; - &$line($self); - } else { - $self->{out_lines} = [$line]; - } - foreach my $out (@{$self->{out_lines}}) { - $self->{out_linenum}++ while ($out =~ /\n/smg); - print $fho $out; - } - } - $fho->close; -} - -sub tree_line { - my $self = shift; - my $func = shift; - - $func =~ s!\s*//.*$!!; - $func =~ s!\s*;\s*$!!; - - # doflag "S" indicates an op specifying short-circuiting for a type. - if ($func =~ /TREEOP(1?)([VAS]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) { - my $order = $1; my $doflag = $2; my $from = $3; my $to = $4; - #$self->print("// $from $to\n"); - if (!$self->{did_out_tree}) { - $self->{did_out_tree} = 1; - $self->output_func(sub{ my $self=shift; - $self->tree_match(); - $self->tree_base(); - }); - } - $from =~ /Ast([a-zA-Z0-9]+)\s*\{(.*)\}\s*$/ - or $self->error("Can't parse from function: $func"); - my $type = $1; - my $subnodes = $2; - (::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func"); - - my $mif; - if ($doflag eq '') { $mif = "m_doNConst"; } - elsif ($doflag eq 'V') { $mif = "m_doV"; } - elsif ($doflag eq 'A') { $mif = ""; } - elsif ($doflag eq 'S') { $mif = "m_doNConst"; } # Not just for m_doGenerate - else { die; } - $subnodes =~ s/,,/__ESCAPEDCOMMA__/g; - foreach my $subnode (split /\s*,\s*/, $subnodes) { - $subnode =~ s/__ESCAPEDCOMMA__/,/g; - next if $subnode =~ /^\$([a-z0-9]+)$/gi; # "$lhs" is just a comment that this op has a lhs - $mif .= " && " if $mif; - my $subnodeif = $subnode; - $subnodeif =~ s/\$([a-zA-Z0-9]+)\.cast([A-Z][A-Za-z0-9]+)$/VN_IS(nodep->$1(),$2)/g; - $subnodeif =~ s/\$([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)$/nodep->$1()->$2()/g; - $subnodeif = add_nodep($subnodeif); - $mif .= $subnodeif; - } - - my $exec_func = treeop_exec_func($self, $to); - while ($exec_func =~ s/([-()a-zA-Z0-9_>]+)->cast([A-Z][A-Za-z0-9]+)\(\)/VN_CAST($1,$2)/) {} - - $self->{treeop}{$type} ||= []; - my $n = $#{$self->{treeop}{$type}} + 1; - my $typefunc = { - order => $order, - comment => $func, - match_func => "match_${type}_${n}", - match_if => $mif, - exec_func => $exec_func, - uinfo_level => ($to =~ /^!/ ? 0:7), - short_circuit => ($doflag eq 'S'), - }; - - ($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g; - push @{$self->{treeop}{$type}}, $typefunc; - } - elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) { - my $type = $1; - $self->{tree_skip_visit}{$type} = 1; - $::Classes{$type} or $self->error("Unknown node type: $type"); - } - else { - $self->error("Unknown astgen op: $func"); - } -} - -sub add_nodep { - my $str = shift; - $str =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g; - return $str; -} - -our %_Exec_Syms; -our $_Exec_Nsyms; -sub _exec_syms_recurse { - my $aref = shift; - foreach my $sym (@{$aref}) { - if (ref $sym) { _exec_syms_recurse($sym); } - elsif ($sym =~ /^\$.*/) { - if (!defined $_Exec_Syms{$sym}) { - $_Exec_Syms{$sym} = "arg".(++$_Exec_Nsyms)."p"; - } - } - } -} - -sub _exec_new_recurse { - my $aref = shift; - my $out = "new ".$aref->[0]."(nodep->fileline()"; - my $first = 1; - foreach my $sym (@{$aref}) { - if ($first) { $first=0; next; } - $out .= ", "; - if (ref $sym) { $out.=_exec_new_recurse($sym); } - elsif ($sym =~ /^\$.*/) { - $out .= $_Exec_Syms{$sym}; - } else { - $out .= $sym; - } - } - return $out.")"; -} - -sub treeop_exec_func { - my $self = shift; - my $func = shift; - my $out = ""; - $func =~ s/^!//; - if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call - (my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g; - $out .= $outl.";"; - } - elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) { - - my $nargs = 0; - my %argnums; # Number for each argument name - - my $aref = undef; # Recursive array with structure to form - my @astack; - my $forming = ""; - my $argtext = $func . "\000"; # EOF character - #print "FF $func\n" if $Debug; - while ($argtext =~ s/^(.)//) { - my $tok = $1; - #print "TOK: $tok $forming\n" if $tok !~ /[a-zA-Z0-9]/; - - if ($tok eq "\000") { - } elsif ($tok =~ /\s+/) { - } elsif ($tok eq "{") { - my $newref = [$forming]; - push @{$aref}, $newref; - push @astack, $aref if $aref; - $aref = $newref; - $forming = ""; - } elsif ($tok eq "}") { - push @{$aref}, $forming if $forming; - $aref = pop @astack; - $aref or $self->error("Too many } in execution function: $func\n"); - $forming = ""; - } elsif ($tok eq ",") { - push @{$aref}, $forming if $forming; - $forming = ""; - } else { - $forming .= $tok; - } - } - ($aref && ref $aref->[0] && !$aref->[1]) or $self->error("Badly formed execution function: $func\n"); - $aref = $aref->[0]; - #use Data::Dumper; print Dumper($aref),"\n"; - - # Assign numbers to each $ symbol - %_Exec_Syms = (); - $_Exec_Nsyms = 0; - _exec_syms_recurse($aref); - - foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) { - my $argnp = $_Exec_Syms{$sym}; - my $arg = add_nodep($sym); - $out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n"; - } - - $out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n"; - $out .= "nodep->replaceWith(newp);"; - $out .= "VL_DO_DANGLING(nodep->deleteTree(), nodep);"; - #print "FF $out\n" if $Debug; - } elsif ($func eq "NEVER") { - $out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");"; - } elsif ($func eq "DONE") { - } else { - $self->error("Unknown execution function format: $func\n"); - } - return $out; -} - -sub tree_match { - my $self = shift; - $self->print(" // TREEOP functions, each return true if they matched & transformed\n"); - #use Data::Dumper; print Dumper($self); - foreach my $base (sort (keys %{$self->{treeop}})) { - foreach my $typefunc (@{$self->{treeop}{$base}}) { - $self->print(" // Generated by astgen\n"); - $self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n", - "\t// $typefunc->{comment}\n",); - $self->print( "\tif ($typefunc->{match_if}) {\n"); - $self->print( "\t UINFO($typefunc->{uinfo_level},cvtToHex(nodep)" - ."<<\" $typefunc->{uinfo}\\n\");\n"); - $self->print( "\t $typefunc->{exec_func}\n"); - $self->print( "\t return true;\n"); - $self->print( "\t}\n"); - $self->print( "\treturn false;\n"); - $self->print(" }\n",); - } - } -} - -sub tree_base { - my $self = shift; - $self->print(" // TREEOP visitors, call each base type's match\n"); - $self->print(" // Bottom class up, as more simple transforms are generally better\n"); - foreach my $type (sort (keys %::Classes)) { - my $base = $::Classes{$type}; - my @out_for_type_sc; - my @out_for_type; - foreach my $base (::subclasses_of($type), $type) { - foreach my $typefunc (@{$self->{treeop}{$base}}) { - my @lines = (" if ($typefunc->{match_func}(nodep)) return;\n",); - if ($typefunc->{short_circuit}) { # short-circuit match fn - push @out_for_type_sc, @lines; - } else { # Standard match fn - if ($typefunc->{order}) { - unshift @out_for_type, @lines; # TREEOP1's go in front of others - } else { - push @out_for_type, @lines; - } - } - } - } - - # We need to deal with two cases. For short circuited functions we - # evaluate the LHS, then apply the short-circuit matches, then - # evaluate the RHS and possibly THS (ternary operators may - # short-circuit) and apply all the other matches. - - # For types without short-circuits, we just use iterateChildren, which - # saves one comparison. - if ($out_for_type_sc[0]) { # Short-circuited types - $self->print(" // Generated by astgen with short-circuiting\n", - " virtual void visit(Ast${type}* nodep) override {\n", - " iterateAndNextNull(nodep->lhsp());\n", - @out_for_type_sc); - $self->print(" iterateAndNextNull(nodep->rhsp());\n", - " AstNodeTriop *tnp = VN_CAST(nodep, NodeTriop);\n", - " if (tnp && tnp->thsp()) iterateAndNextNull(tnp->thsp());\n", - @out_for_type, - " }\n") if ($out_for_type[0]); - } elsif ($out_for_type[0]) { # Other types with something to print - my $skip = $self->{tree_skip_visit}{$type}; - my $gen = $skip ? "Gen" : ""; - my $override = $skip ? "" : " override"; - $self->print(" // Generated by astgen\n", - " virtual void visit$gen(Ast${type}* nodep)${override} {\n", - ($skip?"": - " iterateChildren(nodep);\n"), - @out_for_type, - " }\n"); - } - } -} - -####################################################################### -package main; -__END__ - -=pod - -=head1 NAME - -astgen - Generate V3Ast headers to reduce C++ code duplication - -=head1 SYNOPSIS - - astgen - -=head1 DESCRIPTION - -Generates several files for Verilator compilations. - -=head1 ARGUMENTS - -=over 4 - -=item --help - -Displays this message and program version and exits. - -=item --classes - -Makes class declaration files. - -=item --report - -Makes a report report. - -=back - -=head1 DISTRIBUTION - -Copyright 2002-2021 by Wilson Snyder. This program is free software; you + last = None + + if not re.match(r'^Node', typen): + last = idx + if kind == "concrete-enum": + fh.write(" " * (indent * 4) + "at" + typen + " = " + str(idx) + + ",\n") + elif kind == "concrete-ascii": + fh.write(" " * (indent * 4) + "\"" + typen.upper() + "\",\n") + idx += 1 + elif kind == "abstract-enum": + fh.write(" " * (indent * 4) + "first" + typen + " = " + str(idx) + + ",\n") + + if typen in Children: + for child in sorted(Children[typen].keys()): + (idx, last) = write_type_enum(fh, child, idx, processed, kind, + indent) + + if re.match(r'^Node', typen) and kind == "abstract-enum": + fh.write(" " * (indent * 4) + "last" + typen + " = " + str(last) + + ",\n") + + return [idx, last] + + +def write_types(filename): + with open_file(filename) as fh: + fh.write(" enum en : uint16_t {\n") + (final, last) = write_type_enum(fh, "Node", 0, {}, "concrete-enum", 2) + fh.write(" _ENUM_END = " + str(final) + "\n") + fh.write(" };\n") + + fh.write(" enum bounds : uint16_t {\n") + write_type_enum(fh, "Node", 0, {}, "abstract-enum", 2) + fh.write(" _BOUNDS_END\n") + fh.write(" };\n") + + fh.write(" const char* ascii() const {\n") + fh.write(" static const char* const names[_ENUM_END + 1] = {\n") + write_type_enum(fh, "Node", 0, {}, "concrete-ascii", 3) + fh.write(" \"_ENUM_END\"\n") + fh.write(" };\n") + fh.write(" return names[m_e];\n") + fh.write(" }\n") + + +def write_header(filename): + with open_file(filename) as fh: + typen = "None" + base = "None" + + in_filename = "V3AstNodes.h" + ifile = Args.I + "/" + in_filename + with open(ifile) as ifh: + + fh.write("#line 1 \"../" + in_filename + "\"\n") + + for line in ifh: + # Drop expanded macro definitions - but keep empty line so compiler + # message locations are accurate + line = re.sub(r'^\s*#(define|undef)\s+ASTGEN_.*$', '', line) + + # Track current node type and base class + match = re.search( + r'\s*class\s*Ast(\S+)\s*(final|VL_NOT_FINAL)?\s*:\s*(public)?\s*(AstNode\S*)', + line) + if match: + typen = match.group(1) + base = match.group(4) + + # Substitute macros + line = re.sub(r'\bASTGEN_SUPER\s*\(', + base + "(AstType::at" + typen + ", ", line) + + # Emit the line + fh.write(line) + + +###################################################################### +# main + +parser = argparse.ArgumentParser( + allow_abbrev=False, + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Generate V3Ast headers to reduce C++ code duplication.""", + epilog= + """Copyright 2002-2021 by Wilson Snyder. This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. -SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""") -=head1 AUTHORS +parser.add_argument('-I', action='store', help='source code include directory') +parser.add_argument('--classes', + action='store_true', + help='makes class declaration files') +parser.add_argument('--debug', action='store_true', help='enable debug') -Wilson Snyder +parser.add_argument('infiles', nargs='*', help='list of input .cpp filenames') -=head1 SEE ALSO +Args = parser.parse_args() -=cut +read_types(Args.I + "/V3Ast.h") +read_types(Args.I + "/V3AstNodes.h") +for typen in sorted(Classes.keys()): + # Check all leaves are not AstNode* and non-leaves are AstNode* + children = children_of(typen) + if re.match(r'^Node', typen): + if len(children) == 0: + sys.exit( + "%Error: Final AstNode subclasses must not be named AstNode*: Ast" + + typen) + else: + if len(children) != 0: + sys.exit( + "%Error: Non-final AstNode subclasses must be named AstNode*: Ast" + + typen) + +read_stages(Args.I + "/Verilator.cpp") + +source_files = glob.glob(Args.I + "/*.y") +source_files.extend(glob.glob(Args.I + "/*.h")) +source_files.extend(glob.glob(Args.I + "/*.cpp")) +for filename in source_files: + read_refs(filename) + +if Args.classes: + write_report("V3Ast__gen_report.txt") + write_classes("V3Ast__gen_classes.h") + write_visitor("V3Ast__gen_visitor.h") + write_impl("V3Ast__gen_impl.h") + write_types("V3Ast__gen_types.h") + write_header("V3AstNodes__gen.h") + +for cpt in Args.infiles: + if not re.search(r'.cpp$', cpt): + sys.exit("%Error: Expected argument to be .cpp file: " + cpt) + cpt = re.sub(r'.cpp$', '', cpt) + Cpt().process(in_filename=Args.I + "/" + cpt + ".cpp", + out_filename=cpt + "__gen.cpp") ###################################################################### ### Local Variables: -### compile-command: "./astgen -I. --report" +### compile-command: "cd obj_dbg && ../astgen -I.. V3Const.cpp" ### End: From 2517bfd0afb707c6ddf3fe322dcfd8a0f5a9ea8a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Jan 2021 13:57:56 -0500 Subject: [PATCH 17/79] Fix argparse difference on ubuntu 18.04 --- src/Makefile_obj.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 8313ba6f1..8d63aeac7 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -288,7 +288,7 @@ V3Number_test: V3Number_test.o #### Modules %__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h - $(PYTHON3) $(ASTGEN) -I$(srcdir) $*.cpp + $(PYTHON3) $(ASTGEN) -I $(srcdir) $*.cpp %.o: %.cpp $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@ From 5cadabeb2ddb13bb9e55cd3a94bbefd4bbce5928 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Jan 2021 14:14:39 -0500 Subject: [PATCH 18/79] Fix argparse difference on ubuntu 18.04 --- src/Makefile_obj.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 8d63aeac7..9fbc08295 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -319,7 +319,7 @@ vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h touch $@ V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h - $(PYTHON3) $(ASTGEN) -I$(srcdir) --classes + $(PYTHON3) $(ASTGEN) -I $(srcdir) --classes V3ParseBison.h: V3ParseBison.c From 878a252437659d6402f0fdedf1bdc6805d3f0b61 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 17 Jan 2021 13:53:49 +0900 Subject: [PATCH 19/79] Internals: Add TREEOPC() that executes only when m_doCpp==true (#2759) --- src/V3Const.cpp | 1 + src/astgen | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index abb703789..b9d81fef4 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2223,6 +2223,7 @@ private: // v--- * * This op done on Verilog or C+++ mode, in all non-m_doConst stages // v--- *1* These ops are always first, as we warn before replacing + // v--- *C* This op is a (C)++ op, only in m_doCpp mode // v--- *V* This op is a (V)erilog op, only in m_doV mode // v--- *A* This op works on (A)ll constant children, allowed in m_doConst mode // v--- *S* This op specifies a type should use (S)hort-circuiting of its lhs op diff --git a/src/astgen b/src/astgen index 9cfeace9a..98e108f03 100755 --- a/src/astgen +++ b/src/astgen @@ -88,7 +88,7 @@ class Cpt: # doflag "S" indicates an op specifying short-circuiting for a type. match = re.search( # 1 2 3 4 - r'TREEOP(1?)([ASV]?)\s*\(\s*\"([^\"]*)\"\s*,\s*\"([^\"]*)\"\s*\)', + r'TREEOP(1?)([ACSV]?)\s*\(\s*\"([^\"]*)\"\s*,\s*\"([^\"]*)\"\s*\)', func) match_skip = re.search(r'TREE_SKIP_VISIT\s*\(\s*\"([^\"]*)\"\s*\)', func) @@ -115,6 +115,8 @@ class Cpt: mif = "m_doNConst" elif doflag == 'A': mif = "" + elif doflag == 'C': + mif = "m_doCpp" elif doflag == 'S': mif = "m_doNConst" # Not just for m_doGenerate elif doflag == 'V': From fadc6776ece0ebac1944cd5670497aab0cd0a9a7 Mon Sep 17 00:00:00 2001 From: James Hanlon Date: Mon, 18 Jan 2021 13:03:18 +0000 Subject: [PATCH 20/79] For --flatten, override inlining of public and no_inline modules (#2761) --- src/V3Inline.cpp | 6 ++- test_regress/t/t_xml_flat_no_inline_mod.out | 41 +++++++++++++++++++++ test_regress/t/t_xml_flat_no_inline_mod.pl | 25 +++++++++++++ test_regress/t/t_xml_flat_no_inline_mod.v | 13 +++++++ test_regress/t/t_xml_flat_pub_mod.out | 41 +++++++++++++++++++++ test_regress/t/t_xml_flat_pub_mod.pl | 25 +++++++++++++ test_regress/t/t_xml_flat_pub_mod.v | 13 +++++++ 7 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_xml_flat_no_inline_mod.out create mode 100644 test_regress/t/t_xml_flat_no_inline_mod.pl create mode 100644 test_regress/t/t_xml_flat_no_inline_mod.v create mode 100644 test_regress/t/t_xml_flat_pub_mod.out create mode 100644 test_regress/t/t_xml_flat_pub_mod.pl create mode 100644 test_regress/t/t_xml_flat_pub_mod.v diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index e81a28365..f9ea8c53d 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -108,7 +108,9 @@ private: // If inlining moves post-scope this can perhaps be relaxed. cantInline("modIface", true); } - if (m_modp->modPublic()) cantInline("modPublic", false); + if (m_modp->modPublic() && (m_modp->isTop() || !v3Global.opt.flatten())) { + cantInline("modPublic", false); + } iterateChildren(nodep); m_modp = nullptr; @@ -137,7 +139,7 @@ private: } else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) { if (!m_modp) { nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE - } else { + } else if (!v3Global.opt.flatten()) { cantInline("Pragma NO_INLINE_MODULE", false); } // Remove so don't propagate to upper cell... diff --git a/test_regress/t/t_xml_flat_no_inline_mod.out b/test_regress/t/t_xml_flat_no_inline_mod.out new file mode 100644 index 000000000..803aa990b --- /dev/null +++ b/test_regress/t/t_xml_flat_no_inline_mod.out @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_xml_flat_no_inline_mod.pl b/test_regress/t/t_xml_flat_no_inline_mod.pl new file mode 100644 index 000000000..9c51c5674 --- /dev/null +++ b/test_regress/t/t_xml_flat_no_inline_mod.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +compile( + verilator_flags2 => ['--xml-only', '--flatten'], + verilator_make_gmake => 0, + make_top_shell => 0, + make_main => 0, + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_xml_flat_no_inline_mod.v b/test_regress/t/t_xml_flat_no_inline_mod.v new file mode 100644 index 000000000..cf87b71a0 --- /dev/null +++ b/test_regress/t/t_xml_flat_no_inline_mod.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2008 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module foo(input logic i_clk); /* verilator no_inline_module */ +endmodule + +// --flatten forces inlining of 'no_inline_module' module foo. +module top(input logic i_clk); + foo f(.*); +endmodule diff --git a/test_regress/t/t_xml_flat_pub_mod.out b/test_regress/t/t_xml_flat_pub_mod.out new file mode 100644 index 000000000..5515cd69c --- /dev/null +++ b/test_regress/t/t_xml_flat_pub_mod.out @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_xml_flat_pub_mod.pl b/test_regress/t/t_xml_flat_pub_mod.pl new file mode 100644 index 000000000..9c51c5674 --- /dev/null +++ b/test_regress/t/t_xml_flat_pub_mod.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +compile( + verilator_flags2 => ['--xml-only', '--flatten'], + verilator_make_gmake => 0, + make_top_shell => 0, + make_main => 0, + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_xml_flat_pub_mod.v b/test_regress/t/t_xml_flat_pub_mod.v new file mode 100644 index 000000000..4fa40e587 --- /dev/null +++ b/test_regress/t/t_xml_flat_pub_mod.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2008 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module foo(input logic i_clk); /* verilator public_module */ +endmodule + +// --flatten forces inlining of public module foo. +module top(input logic i_clk); + foo f(.*); +endmodule From 64941538b76941f2ddab318a726d996b98776592 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 23 Jan 2021 10:31:27 -0500 Subject: [PATCH 21/79] Fix TIMESCALE warnings on primitives (#2763). --- Changes | 2 ++ src/V3LinkLevel.cpp | 2 ++ test_regress/t/t_flag_timescale.out | 3 +- test_regress/t/t_flag_timescale.v | 11 +++++++ test_regress/t/t_timescale_lint_bad.out | 2 ++ test_regress/t/t_timescale_udp.pl | 22 +++++++++++++ test_regress/t/t_timescale_udp.v | 43 +++++++++++++++++++++++++ 7 files changed, 84 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_timescale_udp.pl create mode 100644 test_regress/t/t_timescale_udp.v diff --git a/Changes b/Changes index 70834a094..d9ebb1599 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.109 devel +**** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi] + * Verilator 4.108 2021-01-10 diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 8572a25e9..b8f2aa104 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -103,10 +103,12 @@ void V3LinkLevel::timescaling(const ModVec& mods) { for (AstNodeModule* nodep : mods) { if (nodep->timeunit().isNone()) { if (modTimedp && !VN_IS(nodep, Iface) + && !VN_IS(nodep, Primitive) && !(VN_IS(nodep, Package) && VN_CAST(nodep, Package)->isDollarUnit())) { nodep->v3warn(TIMESCALEMOD, "Timescale missing on this module as other modules have " "it (IEEE 1800-2017 3.14.2.2)\n" + << nodep->warnContextPrimary() << '\n' << modTimedp->warnOther() << "... Location of module with timescale\n" << modTimedp->warnContextSecondary()); diff --git a/test_regress/t/t_flag_timescale.out b/test_regress/t/t_flag_timescale.out index b82ab0b9a..72dfb1fc5 100644 --- a/test_regress/t/t_flag_timescale.out +++ b/test_regress/t/t_flag_timescale.out @@ -1,2 +1,3 @@ -Time scale of t is 1ms / 1us +t: Time scale of t is 1ms / 1us +sub: Time scale of sub is 1s / 1us *-* All Finished *-* diff --git a/test_regress/t/t_flag_timescale.v b/test_regress/t/t_flag_timescale.v index ed019c442..ce1d0aee8 100644 --- a/test_regress/t/t_flag_timescale.v +++ b/test_regress/t/t_flag_timescale.v @@ -5,9 +5,20 @@ // SPDX-License-Identifier: CC0-1.0 module t; + sub sub(); initial begin + $write("t: "); $printtimescale; + sub.pts(); $write("*-* All Finished *-*\n"); $finish; end endmodule + +`timescale 1s/1s +module sub; + task pts; + $write("sub: "); + $printtimescale; + endtask +endmodule diff --git a/test_regress/t/t_timescale_lint_bad.out b/test_regress/t/t_timescale_lint_bad.out index e397440d8..fece9ec2e 100644 --- a/test_regress/t/t_timescale_lint_bad.out +++ b/test_regress/t/t_timescale_lint_bad.out @@ -1,4 +1,6 @@ %Error-TIMESCALEMOD: t/t_timescale_lint_bad.v:7:8: Timescale missing on this module as other modules have it (IEEE 1800-2017 3.14.2.2) + 7 | module pre_no_ts; + | ^~~~~~~~~ t/t_timescale_lint_bad.v:12:8: ... Location of module with timescale 12 | module t; | ^ diff --git a/test_regress/t/t_timescale_udp.pl b/test_regress/t/t_timescale_udp.pl new file mode 100755 index 000000000..4e42b8db0 --- /dev/null +++ b/test_regress/t/t_timescale_udp.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_timescale_udp.v b/test_regress/t/t_timescale_udp.v new file mode 100644 index 000000000..4b30c71ef --- /dev/null +++ b/test_regress/t/t_timescale_udp.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`timescale 1ns/1ns +module t; + p p (); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + +`timescale 1ns/1ns +program p; +endprogram + +`celldefine +`timescale 1ns/1ns + +primitive a_udp(out, in); +output out; +input in; +reg out; + +table +0 : 1; +1 : 0; +? : ?; +x : x; +endtable +endprimitive +`endcelldefine + +`celldefine +module c_not(in, out); +input in; +output out; +assign out = !in1; +endmodule +`endcelldefine From 555269f7919c1580d3ec10b8e5c1dc8f5c235cbf Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 23 Jan 2021 15:32:52 +0000 Subject: [PATCH 22/79] Apply clang-format --- src/V3LinkLevel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index b8f2aa104..96ef55d56 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -102,8 +102,7 @@ void V3LinkLevel::timescaling(const ModVec& mods) { for (AstNodeModule* nodep : mods) { if (nodep->timeunit().isNone()) { - if (modTimedp && !VN_IS(nodep, Iface) - && !VN_IS(nodep, Primitive) + if (modTimedp && !VN_IS(nodep, Iface) && !VN_IS(nodep, Primitive) && !(VN_IS(nodep, Package) && VN_CAST(nodep, Package)->isDollarUnit())) { nodep->v3warn(TIMESCALEMOD, "Timescale missing on this module as other modules have " From 3c79e00d240c39702bdb8979e58377a451f81e47 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 24 Jan 2021 20:24:12 -0500 Subject: [PATCH 23/79] Commentary (#2764) --- bin/verilator | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/bin/verilator b/bin/verilator index e581f0867..79fafdf86 100755 --- a/bin/verilator +++ b/bin/verilator @@ -2546,6 +2546,27 @@ called from Verilog by querying the scope of that function. See the sections on DPI Context Functions and DPI Header Isolation below and the comments within the svdpi.h header for more information. +=head2 DPI Imports that access signals + +If a DPI import accesses a signal through the VPI Verilator will not be +able to know what variables are accessed and may schedule the code +inappropriately. Ideally pass the values as inputs/outputs so the VPI is +not required. Alternatively a workaround is to use a non-inlined task as a +wrapper: + + logic din; + + // This DPI function will read "din" + import "DPI-C" context function void dpi_that_accesses_din(); + + always @ (...) + dpi_din_args(din); + + task dpi_din_args(input din); + /* verilator no_inline_task */ + dpi_that_accesses_din(); + endtask + =head2 DPI Display Functions Verilator allows writing $display like functions using this syntax: From d891e5ac3a3ea91a8a2238e86eae7fcf340d1f91 Mon Sep 17 00:00:00 2001 From: Paul Wright <68547250+polmacanceart@users.noreply.github.com> Date: Mon, 25 Jan 2021 12:33:38 +0000 Subject: [PATCH 24/79] Fix to exclude strings from toggle coverage (#2766) (#2767) --- src/V3AstNodes.h | 2 +- test_regress/t/t_cover_toggle.v | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b6bb6653a..feebe0714 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2170,7 +2170,7 @@ public: return ((isIO() || isSignal()) && (isIO() || isBitLogic()) // Wrapper would otherwise duplicate wrapped module's coverage - && !isSc() && !isPrimaryIO() && !isConst() && !isDouble()); + && !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString()); } bool isClassMember() const { return varType() == AstVarType::MEMBER; } bool isStatementTemp() const { return (varType() == AstVarType::STMTTEMP); } diff --git a/test_regress/t/t_cover_toggle.v b/test_regress/t/t_cover_toggle.v index 1c4008c3b..eb8e24ae2 100644 --- a/test_regress/t/t_cover_toggle.v +++ b/test_regress/t/t_cover_toggle.v @@ -7,11 +7,13 @@ module t (/*AUTOARG*/ // Inputs clk, - check_real + check_real, + check_string ); input clk; input real check_real; // Check issue #2741 + input string check_string; // Check issue #2766 typedef struct packed { union packed { From 31223d4058eecaa61b66dbb332b52eb9a489d689 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Jan 2021 20:10:27 -0500 Subject: [PATCH 25/79] Fix $ in filenames (#2768). --- src/V3Options.cpp | 9 +++++---- test_regress/t/t_mod_dollar$.pl | 25 +++++++++++++++++++++++++ test_regress/t/t_mod_dollar$.v | 12 ++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_mod_dollar$.pl create mode 100644 test_regress/t/t_mod_dollar$.v diff --git a/src/V3Options.cpp b/src/V3Options.cpp index fdc56aa08..5eebd637e 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -18,6 +18,7 @@ #include "verilatedos.h" #include "V3Global.h" +#include "V3Ast.h" #include "V3String.h" #include "V3Os.h" #include "V3Options.h" @@ -864,10 +865,10 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) { } // Default prefix to the filename - if (prefix() == "" && topModule() != "") m_prefix = string("V") + topModule(); - if (prefix() == "" && vFilesList.size() >= 1) { - m_prefix = string("V") + V3Os::filenameNonExt(*(vFilesList.begin())); - } + if (prefix() == "" && topModule() != "") + m_prefix = string("V") + AstNode::encodeName(topModule()); + if (prefix() == "" && vFilesList.size() >= 1) + m_prefix = string("V") + AstNode::encodeName(V3Os::filenameNonExt(*(vFilesList.begin()))); if (modPrefix() == "") m_modPrefix = prefix(); // Find files in makedir diff --git a/test_regress/t/t_mod_dollar$.pl b/test_regress/t/t_mod_dollar$.pl new file mode 100755 index 000000000..2d8172ca7 --- /dev/null +++ b/test_regress/t/t_mod_dollar$.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +# This doesn't use the general compile rule as we want to make sure we form +# prefix properly using post-escaped identifiers +run(cmd => ["../bin/verilator", + "--cc", + "--Mdir obj_vlt/t_mod_dollar", + "--exe --build --main", + 't/t_mod_dollar$.v', + ], + verilator_run => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_mod_dollar$.v b/test_regress/t/t_mod_dollar$.v new file mode 100644 index 000000000..ee7d6ad75 --- /dev/null +++ b/test_regress/t/t_mod_dollar$.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by engr248. +// SPDX-License-Identifier: CC0-1.0 + +module \foo$bar (/*AUTOARG*/); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 05bb24df6c20c76363887094bf68fb6e03c03780 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 26 Jan 2021 22:20:16 -0500 Subject: [PATCH 26/79] Fix $fread extra semicolon inside statements. --- Changes | 2 ++ src/V3EmitC.cpp | 2 +- test_regress/t/t_sys_fread.v | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index d9ebb1599..33999c758 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi] +**** Fix $fread extra semicolon inside statements. [Leendert van Doorn] + * Verilator 4.108 2021-01-10 diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 95cb52af0..16936bb2d 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -748,7 +748,7 @@ public: } else { puts(cvtToStr(array_size)); } - puts(");\n"); + puts(")"); } virtual void visit(AstSysFuncAsTask* nodep) override { if (!nodep->lhsp()->isWide()) puts("(void)"); diff --git a/test_regress/t/t_sys_fread.v b/test_regress/t/t_sys_fread.v index 60921f3f0..9b1818faa 100644 --- a/test_regress/t/t_sys_fread.v +++ b/test_regress/t/t_sys_fread.v @@ -79,7 +79,8 @@ module t; clear; code = $fread(r_upb, file, 15); `checkd(code, 6); - code = $fread(r_ups, file, 15, 2); `checkd(code, 4); + // Bug where fread in if() broke. + if ($fread(r_ups, file, 15, 2) != 4) $stop; dump; $write("*-* All Finished *-*\n"); From 483516ce4e7754398f04df62c6aeac0e792c207d Mon Sep 17 00:00:00 2001 From: Samuel Riedel Date: Thu, 28 Jan 2021 21:01:33 +0100 Subject: [PATCH 27/79] Fix build to execute vlcovgen with python3. (#2773) --- docs/CONTRIBUTORS | 1 + src/Makefile_obj.in | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 9a56dc7be..0d37a11d5 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -64,6 +64,7 @@ Qingyao Sun Rafal Kapuscik Richard Myers Rupert Swarbrick +Samuel Riedel Sean Cross Sebastien Van Cauwenberghe Sergi Granell diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 9fbc08295..0b38c2108 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -315,7 +315,7 @@ serial:: V3Ast__gen_classes.h V3ParseBison.c serial_vlcov:: vlcovgen.d vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h - $(PERL) $(VLCOVGEN) --srcdir $(srcdir) + $(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir) touch $@ V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h From 843ae2955e55765cecf4d454f9cb6e1adb3a3afb Mon Sep 17 00:00:00 2001 From: Morten Borup Petersen Date: Wed, 3 Feb 2021 20:38:34 +0100 Subject: [PATCH 28/79] Commentary on incorrectly specified debug level (#2777) As seen at https://github.com/verilator/verilator/blob/master/src/V3Options.cpp#L1202 setting --debug enables a debug level of 3. --- bin/verilator | 2 +- docs/CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/verilator b/bin/verilator index 79fafdf86..f88a03e14 100755 --- a/bin/verilator +++ b/bin/verilator @@ -756,7 +756,7 @@ is fairly standard across Verilog tools while -D is similar to GCC. Select the debug executable of Verilator (if available), and enable more internal assertions (equivalent to C<--debug-check>), debugging messages -(equivalent to C<--debugi 4>), and intermediate form dump files (equivalent +(equivalent to C<--debugi 3>), and intermediate form dump files (equivalent to C<--dump-treei 3>). =item --debug-check diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 0d37a11d5..d64856f9d 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -49,6 +49,7 @@ Marshal Qiao Matthew Ballance Michael Killough Mike Popoloski +Morten Borup Petersen Nandu Raj Nathan Kohagen Nathan Myers From e77e4e1fe6317fcbf3982501161ab62b01d79b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80lex=20Torregrosa?= <78434679+atorregrosasmd@users.noreply.github.com> Date: Wed, 3 Feb 2021 20:40:21 +0100 Subject: [PATCH 29/79] Improve struct scopes when dumping structs to VCD (#2776) --- docs/CONTRIBUTORS | 1 + include/verilated_trace.h | 2 +- include/verilated_vcd_c.cpp | 13 +++++-- src/V3TraceDecl.cpp | 10 +++++- test_regress/driver.pl | 2 +- test_regress/t/t_interface_ref_trace.out | 40 +++++++++++----------- test_regress/t/t_trace_complex_structs.out | 28 +++++++-------- 7 files changed, 57 insertions(+), 39 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index d64856f9d..41124837f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -5,6 +5,7 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all. Ahmed El-Mahmoudy Alex Chadwick +Àlex Torregrosa Chris Randall Conor McCullough Dan Petrisko diff --git a/include/verilated_trace.h b/include/verilated_trace.h index a16617146..7e938cf19 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -222,7 +222,7 @@ protected: void declCode(vluint32_t code, vluint32_t bits, bool tri); /// Is this an escape? - bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; } + bool isScopeEscape(char c) { return c != '\f' && (isspace(c) || c == m_scopeEscape); } /// Character that splits scopes. Note whitespace are ALWAYS escapes. char scopeEscape() { return m_scopeEscape; } diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 0460dd8eb..48493a4d6 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -401,13 +401,22 @@ void VerilatedVcd::dumpHeader() { if (*np == ' ') np++; if (*np == '\t') break; // tab means signal name starts printIndent(1); - printStr("$scope module "); + // Find character after name end + const char* sp = np; + while(*sp && *sp != ' ' && *sp != '\t' && *sp != '\f') sp++; + + if (*sp == '\f') { + printStr("$scope struct "); + } else { + printStr("$scope module "); + } + for (; *np && *np != ' ' && *np != '\t'; np++) { if (*np == '[') { printStr("("); } else if (*np == ']') { printStr(")"); - } else { + } else if (*np != '\f'){ *m_writep++ = *np; } } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 0ed6572ce..22d0b2cfe 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -295,7 +295,15 @@ private: VL_RESTORER(m_traShowname); VL_RESTORER(m_traValuep); { - m_traShowname += string(" ") + itemp->prettyName(); + // Add @ to mark as struct + // Since it is not a valid symbol for verilog variable names, no + // collision should happen + if (v3Global.opt.traceFormat().fst()) { + m_traShowname += string(" ") + itemp->prettyName(); + } else { + m_traShowname += string("\f ") + itemp->prettyName(); + } + if (VN_IS(nodep, StructDType)) { m_traValuep = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true), diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 9b94e8fc9..c383747ed 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2238,7 +2238,7 @@ sub _vcd_read { my @hier = ($data); my $lasthier; while (defined(my $line = $fh->getline)) { - if ($line =~ /\$scope module\s+(\S+)/) { + if ($line =~ /\$scope (module|struct)\s+(\S+)/) { $hier[$#hier]->{$1} ||= {}; push @hier, $hier[$#hier]->{$1}; $lasthier = $hier[$#hier]; diff --git a/test_regress/t/t_interface_ref_trace.out b/test_regress/t/t_interface_ref_trace.out index 75875933b..b9de5a2a5 100644 --- a/test_regress/t/t_interface_ref_trace.out +++ b/test_regress/t/t_interface_ref_trace.out @@ -14,7 +14,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -25,7 +25,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -36,7 +36,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 * value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 + val100 [31:0] $end $var wire 32 , val200 [31:0] $end $upscope $end @@ -47,7 +47,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 * value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 + val100 [31:0] $end $var wire 32 , val200 [31:0] $end $upscope $end @@ -57,7 +57,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 * value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 + val100 [31:0] $end $var wire 32 , val200 [31:0] $end $upscope $end @@ -66,7 +66,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -75,7 +75,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -87,7 +87,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -98,7 +98,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -109,7 +109,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 - value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 . val100 [31:0] $end $var wire 32 / val200 [31:0] $end $upscope $end @@ -120,7 +120,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 - value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 . val100 [31:0] $end $var wire 32 / val200 [31:0] $end $upscope $end @@ -130,7 +130,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 - value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 . val100 [31:0] $end $var wire 32 / val200 [31:0] $end $upscope $end @@ -139,7 +139,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -148,7 +148,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -159,7 +159,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -170,7 +170,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -180,7 +180,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -189,7 +189,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -199,7 +199,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end @@ -210,7 +210,7 @@ $timescale 1ps $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope module the_struct $end + $scope struct the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end diff --git a/test_regress/t/t_trace_complex_structs.out b/test_regress/t/t_trace_complex_structs.out index dad2d3736..6fc0af14a 100644 --- a/test_regress/t/t_trace_complex_structs.out +++ b/test_regress/t/t_trace_complex_structs.out @@ -38,52 +38,52 @@ $timescale 1ps $end $var wire 32 H a [31:0] $end $upscope $end $upscope $end - $scope module v_arrp_strp(3) $end + $scope struct v_arrp_strp(3) $end $var wire 1 1 b0 $end $var wire 1 0 b1 $end $upscope $end - $scope module v_arrp_strp(4) $end + $scope struct v_arrp_strp(4) $end $var wire 1 3 b0 $end $var wire 1 2 b1 $end $upscope $end - $scope module v_arru_strp(3) $end + $scope struct v_arru_strp(3) $end $var wire 1 7 b0 $end $var wire 1 6 b1 $end $upscope $end - $scope module v_arru_strp(4) $end + $scope struct v_arru_strp(4) $end $var wire 1 9 b0 $end $var wire 1 8 b1 $end $upscope $end - $scope module v_enumb2_str $end + $scope struct v_enumb2_str $end $var wire 3 E a [2:0] $end $var wire 3 F b [2:0] $end $upscope $end - $scope module v_str32x2(0) $end + $scope struct v_str32x2(0) $end $var wire 32 @ data [31:0] $end $upscope $end - $scope module v_str32x2(1) $end + $scope struct v_str32x2(1) $end $var wire 32 A data [31:0] $end $upscope $end - $scope module v_strp $end + $scope struct v_strp $end $var wire 1 & b0 $end $var wire 1 % b1 $end $upscope $end - $scope module v_strp_strp $end - $scope module x0 $end + $scope struct v_strp_strp $end + $scope struct x0 $end $var wire 1 * b0 $end $var wire 1 ) b1 $end $upscope $end - $scope module x1 $end + $scope struct x1 $end $var wire 1 ( b0 $end $var wire 1 ' b1 $end $upscope $end $upscope $end - $scope module v_unip_strp $end - $scope module x0 $end + $scope struct v_unip_strp $end + $scope struct x0 $end $var wire 1 , b0 $end $var wire 1 + b1 $end $upscope $end - $scope module x1 $end + $scope struct x1 $end $var wire 1 , b0 $end $var wire 1 + b1 $end $upscope $end From af5fc4f1ad11f046d2dff25470f6520f751e6852 Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 3 Feb 2021 19:41:25 +0000 Subject: [PATCH 30/79] Apply clang-format --- include/verilated_vcd_c.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 48493a4d6..2d757bb11 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -403,12 +403,12 @@ void VerilatedVcd::dumpHeader() { printIndent(1); // Find character after name end const char* sp = np; - while(*sp && *sp != ' ' && *sp != '\t' && *sp != '\f') sp++; + while (*sp && *sp != ' ' && *sp != '\t' && *sp != '\f') sp++; if (*sp == '\f') { printStr("$scope struct "); } else { - printStr("$scope module "); + printStr("$scope module "); } for (; *np && *np != ' ' && *np != '\t'; np++) { @@ -416,7 +416,7 @@ void VerilatedVcd::dumpHeader() { printStr("("); } else if (*np == ']') { printStr(")"); - } else if (*np != '\f'){ + } else if (*np != '\f') { *m_writep++ = *np; } } From 2225acd3eca575eb193e9a75a9f8516bdb04c14c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 17:36:25 -0500 Subject: [PATCH 31/79] Tests: Avoid C++11 requirement in TestVpi.h --- test_regress/t/TestVpi.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h index 2dd400b11..9ecc18125 100644 --- a/test_regress/t/TestVpi.h +++ b/test_regress/t/TestVpi.h @@ -11,15 +11,17 @@ #include "vpi_user.h" + // Avoid C++11 in this file as not all simulators allow it + //====================================================================== class TestVpiHandle { /// For testing, etc, wrap vpiHandle in an auto-releasing class - vpiHandle m_handle = NULL; - bool m_freeit = true; + vpiHandle m_handle; // No = as no C++11 + bool m_freeit; // No = as no C++11 public: - TestVpiHandle() {} + TestVpiHandle() : m_handle(NULL), m_freeit(true) {} TestVpiHandle(vpiHandle h) : m_handle(h) {} ~TestVpiHandle() { release(); } From 7bce15b065c2c305f39168c2b9ae0d28fa5ee801 Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 3 Feb 2021 22:39:03 +0000 Subject: [PATCH 32/79] Apply clang-format --- test_regress/t/TestVpi.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h index 9ecc18125..155d924f1 100644 --- a/test_regress/t/TestVpi.h +++ b/test_regress/t/TestVpi.h @@ -11,7 +11,7 @@ #include "vpi_user.h" - // Avoid C++11 in this file as not all simulators allow it +// Avoid C++11 in this file as not all simulators allow it //====================================================================== @@ -21,7 +21,9 @@ class TestVpiHandle { bool m_freeit; // No = as no C++11 public: - TestVpiHandle() : m_handle(NULL), m_freeit(true) {} + TestVpiHandle() + : m_handle(NULL) + , m_freeit(true) {} TestVpiHandle(vpiHandle h) : m_handle(h) {} ~TestVpiHandle() { release(); } From 153335ff35eb5d14684901e7638dad512c85f98f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 18:30:15 -0500 Subject: [PATCH 33/79] Tests: Cleanup some DPI warnings. --- test_regress/t/t_vpi_finish.pl | 3 +- test_regress/t/t_vpi_get.v | 2 +- test_regress/t/t_vpi_memory.v | 2 +- test_regress/t/t_vpi_module.v | 2 +- test_regress/t/t_vpi_param.v | 2 +- test_regress/t/t_vpi_stop_bad.pl | 5 +- test_regress/t/t_vpi_time_cb.v | 85 ++--------------------------- test_regress/t/t_vpi_unimpl.v | 2 +- test_regress/t/t_vpi_var.v | 2 +- test_regress/t/t_vpi_zero_time_cb.v | 85 ++--------------------------- 10 files changed, 19 insertions(+), 171 deletions(-) diff --git a/test_regress/t/t_vpi_finish.pl b/test_regress/t/t_vpi_finish.pl index 050052f66..77affd6a5 100755 --- a/test_regress/t/t_vpi_finish.pl +++ b/test_regress/t/t_vpi_finish.pl @@ -11,7 +11,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - v_flags2 => ["--vpi t/t_vpi_finish_c.cpp"], + v_flags2 => ["t/t_vpi_finish_c.cpp"], + verilator_flags2 => ["--vpi"], ); execute( diff --git a/test_regress/t/t_vpi_get.v b/test_regress/t/t_vpi_get.v index de893386b..93191301c 100644 --- a/test_regress/t/t_vpi_get.v +++ b/test_regress/t/t_vpi_get.v @@ -9,7 +9,7 @@ `ifdef USE_VPI_NOT_DPI //We call it via $c so we can verify DPI isn't required - see bug572 `else -import "DPI-C" context function integer mon_check(); +import "DPI-C" context function int mon_check(); `endif `ifdef VERILATOR_COMMENTS diff --git a/test_regress/t/t_vpi_memory.v b/test_regress/t/t_vpi_memory.v index de2d2b4a7..c16a59cb5 100644 --- a/test_regress/t/t_vpi_memory.v +++ b/test_regress/t/t_vpi_memory.v @@ -9,7 +9,7 @@ `ifdef USE_VPI_NOT_DPI //We call it via $c so we can verify DPI isn't required - see bug572 `else -import "DPI-C" context function integer mon_check(); +import "DPI-C" context function int mon_check(); `endif module t (/*AUTOARG*/ diff --git a/test_regress/t/t_vpi_module.v b/test_regress/t/t_vpi_module.v index e3490e5a4..3ef25ea4b 100644 --- a/test_regress/t/t_vpi_module.v +++ b/test_regress/t/t_vpi_module.v @@ -9,7 +9,7 @@ `ifdef USE_VPI_NOT_DPI //We call it via $c so we can verify DPI isn't required - see bug572 `else -import "DPI-C" context function integer mon_check(); +import "DPI-C" context function int mon_check(); `endif module t (/*AUTOARG*/ diff --git a/test_regress/t/t_vpi_param.v b/test_regress/t/t_vpi_param.v index 082658ff6..4ae1dbb47 100644 --- a/test_regress/t/t_vpi_param.v +++ b/test_regress/t/t_vpi_param.v @@ -9,7 +9,7 @@ `ifdef USE_VPI_NOT_DPI //We call it via $c so we can verify DPI isn't required - see bug572 `else -import "DPI-C" context function integer mon_check(); +import "DPI-C" context function int mon_check(); `endif diff --git a/test_regress/t/t_vpi_stop_bad.pl b/test_regress/t/t_vpi_stop_bad.pl index 89f7e8b16..061b4561c 100755 --- a/test_regress/t/t_vpi_stop_bad.pl +++ b/test_regress/t/t_vpi_stop_bad.pl @@ -11,11 +11,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - v_flags2 => ["--vpi t/t_vpi_stop_bad_c.cpp"], + v_flags2 => ["t/t_vpi_stop_bad_c.cpp"], + verilator_flags2 => ["--vpi"], ); execute( - fails => 1, + fails => $Self->{vlt_all}, check_finished => 0, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_vpi_time_cb.v b/test_regress/t/t_vpi_time_cb.v index a2410c7c5..846302d8a 100644 --- a/test_regress/t/t_vpi_time_cb.v +++ b/test_regress/t/t_vpi_time_cb.v @@ -17,101 +17,24 @@ module t (/*AUTOARG*/ assign clk = clk_r; `endif - reg onebit /*verilator public_flat_rw @(posedge clk) */; - reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */; - reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; - - reg [61:0] quads[3:2] /*verilator public_flat_rw @(posedge clk) */; - reg [31:0] count /*verilator public_flat_rd */; - reg [31:0] half_count /*verilator public_flat_rd */; - - reg [7:0] text_byte /*verilator public_flat_rw @(posedge clk) */; - reg [15:0] text_half /*verilator public_flat_rw @(posedge clk) */; - reg [31:0] text_word /*verilator public_flat_rw @(posedge clk) */; - reg [63:0] text_long /*verilator public_flat_rw @(posedge clk) */; - reg [511:0] text /*verilator public_flat_rw @(posedge clk) */; integer status; - sub sub(); - // Test loop initial begin count = 0; - onebit = 1'b0; - fourthreetwoone[3] = 0; // stop icarus optimizing away - text_byte = "B"; - text_half = "Hf"; - text_word = "Word"; - text_long = "Long64b"; - text = "Verilog Test module"; - -/* - if (status!=0) begin - $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); - $stop; - end - $write("%%Info: Checking results\n"); - if (onebit != 1'b1) $stop; - if (quads[2] != 62'h12819213_abd31a1c) $stop; - if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; - if (text_byte != "A") $stop; - if (text_half != "T2") $stop; - if (text_word != "Tree") $stop; - if (text_long != "44Four44") $stop; - if (text != "lorem ipsum") $stop; - */ end always @(posedge clk) begin +`ifdef TEST_VERBOSE + $display("[%0t] clk", $time); +`endif count <= count + 2; - if (count[1]) - half_count <= half_count + 2; - if (count == 1000) begin -// $write("*-* All Finished *-*\n"); + // See C++ code: $write("*-* All Finished *-*\n"); $finish; end end - genvar i; - generate - for (i=1; i<=128; i=i+1) begin : arr - arr #(.LENGTH(i)) arr(); - end - endgenerate - endmodule : t - -module sub; - reg subsig1 /*verilator public_flat_rd*/; - reg subsig2 /*verilator public_flat_rd*/; -`ifdef IVERILOG - // stop icarus optimizing signals away - wire redundant = subsig1 | subsig2; -`endif -endmodule : sub - -module arr; - - parameter LENGTH = 1; - - reg [LENGTH-1:0] sig /*verilator public_flat_rw*/; - reg [LENGTH-1:0] rfr /*verilator public_flat_rw*/; - - reg check /*verilator public_flat_rw*/; - reg verbose /*verilator public_flat_rw*/; - - initial begin - sig = {LENGTH{1'b0}}; - rfr = {LENGTH{1'b0}}; - end - - always @(posedge check) begin - if (verbose) $display("%m : %x %x", sig, rfr); - if (check && sig != rfr) $stop; - check <= 0; - end - -endmodule : arr diff --git a/test_regress/t/t_vpi_unimpl.v b/test_regress/t/t_vpi_unimpl.v index 978303008..ffad82c75 100644 --- a/test_regress/t/t_vpi_unimpl.v +++ b/test_regress/t/t_vpi_unimpl.v @@ -9,7 +9,7 @@ `ifdef VERILATOR //We call it via $c so we can verify DPI isn't required - see bug572 `else -import "DPI-C" context function integer mon_check(); +import "DPI-C" context function int mon_check(); `endif module t (/*AUTOARG*/ diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 89160dc60..88c9612a6 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -9,7 +9,7 @@ `ifdef USE_VPI_NOT_DPI //We call it via $c so we can verify DPI isn't required - see bug572 `else -import "DPI-C" context function integer mon_check(); +import "DPI-C" context function int mon_check(); `endif module t (/*AUTOARG*/ diff --git a/test_regress/t/t_vpi_zero_time_cb.v b/test_regress/t/t_vpi_zero_time_cb.v index f88aa8e8c..846302d8a 100644 --- a/test_regress/t/t_vpi_zero_time_cb.v +++ b/test_regress/t/t_vpi_zero_time_cb.v @@ -17,101 +17,24 @@ module t (/*AUTOARG*/ assign clk = clk_r; `endif - reg onebit /*verilator public_flat_rw @(posedge clk) */; - reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */; - reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; - - reg [61:0] quads[3:2] /*verilator public_flat_rw @(posedge clk) */; - reg [31:0] count /*verilator public_flat_rd */; - reg [31:0] half_count /*verilator public_flat_rd */; - - reg [7:0] text_byte /*verilator public_flat_rw @(posedge clk) */; - reg [15:0] text_half /*verilator public_flat_rw @(posedge clk) */; - reg [31:0] text_word /*verilator public_flat_rw @(posedge clk) */; - reg [63:0] text_long /*verilator public_flat_rw @(posedge clk) */; - reg [511:0] text /*verilator public_flat_rw @(posedge clk) */; integer status; - sub sub(); - // Test loop initial begin count = 0; - onebit = 1'b0; - fourthreetwoone[3] = 0; // stop icarus optimizing away - text_byte = "B"; - text_half = "Hf"; - text_word = "Word"; - text_long = "Long64b"; - text = "Verilog Test module"; - -/* - if (status!=0) begin - $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); - $stop; - end - $write("%%Info: Checking results\n"); - if (onebit != 1'b1) $stop; - if (quads[2] != 62'h12819213_abd31a1c) $stop; - if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; - if (text_byte != "A") $stop; - if (text_half != "T2") $stop; - if (text_word != "Tree") $stop; - if (text_long != "44Four44") $stop; - if (text != "lorem ipsum") $stop; - */ end always @(posedge clk) begin +`ifdef TEST_VERBOSE + $display("[%0t] clk", $time); +`endif count <= count + 2; - if (count[1]) - half_count <= half_count + 2; - if (count == 1000) begin -// $write("*-* All Finished *-*\n"); + // See C++ code: $write("*-* All Finished *-*\n"); $finish; end end - genvar i; - generate - for (i=1; i<=128; i=i+1) begin : arr - arr #(.LENGTH(i)) arr(); - end - endgenerate - endmodule : t - -module sub; - reg subsig1 /*verilator public_flat_rd*/; - reg subsig2 /*verilator public_flat_rd*/; -`ifdef IVERILOG - // stop icarus optimizing signals away - wire redundant = subsig1 | subsig2; -`endif -endmodule : sub - -module arr; - - parameter LENGTH = 1; - - reg [LENGTH-1:0] sig /*verilator public_flat_rw*/; - reg [LENGTH-1:0] rfr /*verilator public_flat_rw*/; - - reg check /*verilator public_flat_rw*/; - reg verbose /*verilator public_flat_rw*/; - - initial begin - sig = {LENGTH{1'b0}}; - rfr = {LENGTH{1'b0}}; - end - - always @(posedge check) begin - if (verbose) $display("%m : %x %x", sig, rfr); - if (check && sig != rfr) $stop; - check <= 0; - end - -endmodule : arr From fe0a42eaa8e76152e1bfca922fc516e309065e66 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 18:50:15 -0500 Subject: [PATCH 34/79] Tests: Cleanup some unused functions. --- test_regress/t/t_vpi_time_cb.cpp | 36 ++------------------------- test_regress/t/t_vpi_time_cb.pl | 2 +- test_regress/t/t_vpi_zero_time_cb.cpp | 28 --------------------- test_regress/t/t_vpi_zero_time_cb.pl | 2 +- 4 files changed, 4 insertions(+), 64 deletions(-) diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index 54d61a4a1..fea6e218d 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -45,18 +45,6 @@ unsigned int callback_count_start_of_sim = 0; //====================================================================== -#define CHECK_RESULT_VH(got, exp) \ - if ((got) != (exp)) { \ - printf("%%Error: %s:%d: GOT = %p EXP = %p\n", __FILE__, __LINE__, (got), (exp)); \ - return __LINE__; \ - } - -#define CHECK_RESULT_NZ(got) \ - if (!(got)) { \ - printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", __FILE__, __LINE__); \ - return __LINE__; \ - } - // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ @@ -65,26 +53,6 @@ unsigned int callback_count_start_of_sim = 0; return __LINE__; \ } -#define CHECK_RESULT_HEX(got, exp) \ - if ((got) != (exp)) { \ - std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << hex \ - << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ - printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", __FILE__, __LINE__, \ - (got) ? (got) : "", (exp) ? (exp) : ""); \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) - -// We cannot replace those with VL_STRINGIFY, not available when PLI is build -#define STRINGIFY(x) STRINGIFY2(x) -#define STRINGIFY2(x) #x - //====================================================================== #ifdef IS_VPI @@ -243,12 +211,12 @@ int main(int argc, char** argv, char** env) { VL_PRINTF("Enabling waves...\n"); VerilatedVcdC* tfp = new VerilatedVcdC; topp->trace(tfp, 99); - tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); #endif // Load and initialize the PLI application { - const char* filenamep = STRINGIFY(TEST_OBJ_DIR) "/libvpi.so"; + const char* filenamep = VL_STRINGIFY(TEST_OBJ_DIR) "/libvpi.so"; void* lib = dlopen(filenamep, RTLD_LAZY); void* bootstrap = dlsym(lib, "vpi_compat_bootstrap"); if (!bootstrap) { diff --git a/test_regress/t/t_vpi_time_cb.pl b/test_regress/t/t_vpi_time_cb.pl index 0f61b3e1c..b08bfa811 100755 --- a/test_regress/t/t_vpi_time_cb.pl +++ b/test_regress/t/t_vpi_time_cb.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(simulator => 1, iv => 1); +scenarios(simulator => 1); compile( make_top_shell => 0, diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index 00b3a9c28..7127f2d47 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -44,18 +44,6 @@ unsigned int callback_count_start_of_sim = 0; //====================================================================== -#define CHECK_RESULT_VH(got, exp) \ - if ((got) != (exp)) { \ - printf("%%Error: %s:%d: GOT = %p EXP = %p\n", __FILE__, __LINE__, (got), (exp)); \ - return __LINE__; \ - } - -#define CHECK_RESULT_NZ(got) \ - if (!(got)) { \ - printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", __FILE__, __LINE__); \ - return __LINE__; \ - } - // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ @@ -64,22 +52,6 @@ unsigned int callback_count_start_of_sim = 0; return __LINE__; \ } -#define CHECK_RESULT_HEX(got, exp) \ - if ((got) != (exp)) { \ - std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << hex \ - << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ - printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", __FILE__, __LINE__, \ - (got) ? (got) : "", (exp) ? (exp) : ""); \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) - //====================================================================== #ifdef IS_VPI diff --git a/test_regress/t/t_vpi_zero_time_cb.pl b/test_regress/t/t_vpi_zero_time_cb.pl index 767fd64a2..24ae29812 100755 --- a/test_regress/t/t_vpi_zero_time_cb.pl +++ b/test_regress/t/t_vpi_zero_time_cb.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(simulator => 1, iv => 1); +scenarios(simulator => 1); compile( make_top_shell => 0, From 828fa80afaf25479154e22b6f3627003b725d07c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 18:59:27 -0500 Subject: [PATCH 35/79] Tests: Add common use_libvpi for multiple simulators --- test_regress/driver.pl | 4 ++-- test_regress/t/t_dpi_arg_inout_type.pl | 1 - test_regress/t/t_dpi_arg_inout_unpack.pl | 1 - test_regress/t/t_dpi_arg_input_type.pl | 1 - test_regress/t/t_dpi_arg_input_unpack.pl | 1 - test_regress/t/t_dpi_arg_output_type.pl | 1 - test_regress/t/t_dpi_arg_output_unpack.pl | 1 - test_regress/t/t_dpi_open_query.pl | 1 - test_regress/t/t_dpi_result_type.pl | 1 - test_regress/t/t_vpi_get.pl | 2 +- test_regress/t/t_vpi_get_public_rw_switch.pl | 2 +- test_regress/t/t_vpi_memory.pl | 2 +- test_regress/t/t_vpi_module.pl | 2 +- test_regress/t/t_vpi_param.pl | 2 +- test_regress/t/t_vpi_time_cb.pl | 3 +-- test_regress/t/t_vpi_var.pl | 2 +- test_regress/t/t_vpi_zero_time_cb.pl | 3 +-- 17 files changed, 10 insertions(+), 20 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index c383747ed..94e2cd594 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1219,7 +1219,7 @@ sub execute { @{$param{iv_run_flags}}, @{$param{all_run_flags}}, ); - if ($param{iv_pli}) { + if ($param{use_libvpi}) { # don't enter command line on $stop, include vpi unshift @cmd, "vvp -n -m $self->{obj_dir}/libvpi.so"; } @@ -1233,7 +1233,7 @@ sub execute { } elsif ($param{ms}) { my @pli_opt=(); - if ($param{ms_pli}) { + if ($param{use_libvpi}) { unshift @pli_opt, "-pli $self->{obj_dir}/libvpi.so"; } $self->_run(logfile=>"$self->{obj_dir}/ms_sim.log", diff --git a/test_regress/t/t_dpi_arg_inout_type.pl b/test_regress/t/t_dpi_arg_inout_type.pl index 4bdfdef91..9ca750797 100755 --- a/test_regress/t/t_dpi_arg_inout_type.pl +++ b/test_regress/t/t_dpi_arg_inout_type.pl @@ -37,7 +37,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, expect_filename => $Self->{golden_filename}, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_arg_inout_unpack.pl b/test_regress/t/t_dpi_arg_inout_unpack.pl index ec76ba91c..18dfa90cf 100755 --- a/test_regress/t/t_dpi_arg_inout_unpack.pl +++ b/test_regress/t/t_dpi_arg_inout_unpack.pl @@ -36,7 +36,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_arg_input_type.pl b/test_regress/t/t_dpi_arg_input_type.pl index 4bdfdef91..9ca750797 100755 --- a/test_regress/t/t_dpi_arg_input_type.pl +++ b/test_regress/t/t_dpi_arg_input_type.pl @@ -37,7 +37,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, expect_filename => $Self->{golden_filename}, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_arg_input_unpack.pl b/test_regress/t/t_dpi_arg_input_unpack.pl index ec76ba91c..18dfa90cf 100755 --- a/test_regress/t/t_dpi_arg_input_unpack.pl +++ b/test_regress/t/t_dpi_arg_input_unpack.pl @@ -36,7 +36,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_arg_output_type.pl b/test_regress/t/t_dpi_arg_output_type.pl index 4bdfdef91..9ca750797 100755 --- a/test_regress/t/t_dpi_arg_output_type.pl +++ b/test_regress/t/t_dpi_arg_output_type.pl @@ -37,7 +37,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, expect_filename => $Self->{golden_filename}, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_arg_output_unpack.pl b/test_regress/t/t_dpi_arg_output_unpack.pl index ec76ba91c..18dfa90cf 100755 --- a/test_regress/t/t_dpi_arg_output_unpack.pl +++ b/test_regress/t/t_dpi_arg_output_unpack.pl @@ -36,7 +36,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_open_query.pl b/test_regress/t/t_dpi_open_query.pl index 8a94dbf67..32c447dfd 100755 --- a/test_regress/t/t_dpi_open_query.pl +++ b/test_regress/t/t_dpi_open_query.pl @@ -29,7 +29,6 @@ compile( execute( check_finished => 1, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_dpi_result_type.pl b/test_regress/t/t_dpi_result_type.pl index 4bdfdef91..9ca750797 100755 --- a/test_regress/t/t_dpi_result_type.pl +++ b/test_regress/t/t_dpi_result_type.pl @@ -37,7 +37,6 @@ if ($Self->{vlt_all}) { execute( check_finished => 1, expect_filename => $Self->{golden_filename}, - ms_pli => 0 ); ok(1); diff --git a/test_regress/t/t_vpi_get.pl b/test_regress/t/t_vpi_get.pl index dc126dc16..c3f9a81c0 100755 --- a/test_regress/t/t_vpi_get.pl +++ b/test_regress/t/t_vpi_get.pl @@ -23,7 +23,7 @@ compile( ); execute( - iv_pli => 1, + use_libvpi => 1, check_finished => 1 ); diff --git a/test_regress/t/t_vpi_get_public_rw_switch.pl b/test_regress/t/t_vpi_get_public_rw_switch.pl index 8c11341ac..3a5cdf231 100755 --- a/test_regress/t/t_vpi_get_public_rw_switch.pl +++ b/test_regress/t/t_vpi_get_public_rw_switch.pl @@ -29,7 +29,7 @@ compile( ); execute( - iv_pli => 1, + use_libvpi => 1, check_finished => 1 ); diff --git a/test_regress/t/t_vpi_memory.pl b/test_regress/t/t_vpi_memory.pl index c01c0b9ed..9b95b19c4 100755 --- a/test_regress/t/t_vpi_memory.pl +++ b/test_regress/t/t_vpi_memory.pl @@ -23,7 +23,7 @@ compile( ); execute( - iv_pli => 1, + use_libvpi => 1, check_finished => 1 ); diff --git a/test_regress/t/t_vpi_module.pl b/test_regress/t/t_vpi_module.pl index 69d086d90..bee11c3f0 100755 --- a/test_regress/t/t_vpi_module.pl +++ b/test_regress/t/t_vpi_module.pl @@ -23,7 +23,7 @@ compile( ); execute( - iv_pli => 1, + use_libvpi => 1, check_finished => 1 ); diff --git a/test_regress/t/t_vpi_param.pl b/test_regress/t/t_vpi_param.pl index f6900846a..e5c448b01 100755 --- a/test_regress/t/t_vpi_param.pl +++ b/test_regress/t/t_vpi_param.pl @@ -23,7 +23,7 @@ compile( ); execute( - iv_pli => 1, + use_libvpi => 1, check_finished => 1 ); diff --git a/test_regress/t/t_vpi_time_cb.pl b/test_regress/t/t_vpi_time_cb.pl index b08bfa811..98dd60d00 100755 --- a/test_regress/t/t_vpi_time_cb.pl +++ b/test_regress/t/t_vpi_time_cb.pl @@ -21,8 +21,7 @@ compile( ); execute( - iv_pli => 1, - ms_pli => 1, + use_libvpi => 1, check_finished => 1, all_run_flags => ['+PLUS +INT=1234 +STRSTR'] ); diff --git a/test_regress/t/t_vpi_var.pl b/test_regress/t/t_vpi_var.pl index 57c6f6cb7..e9f2bac65 100755 --- a/test_regress/t/t_vpi_var.pl +++ b/test_regress/t/t_vpi_var.pl @@ -21,7 +21,7 @@ compile( ); execute( - iv_pli => 1, + use_libvpi => 1, check_finished => 1, all_run_flags => ['+PLUS +INT=1234 +STRSTR'] ); diff --git a/test_regress/t/t_vpi_zero_time_cb.pl b/test_regress/t/t_vpi_zero_time_cb.pl index 24ae29812..7906bed68 100755 --- a/test_regress/t/t_vpi_zero_time_cb.pl +++ b/test_regress/t/t_vpi_zero_time_cb.pl @@ -21,8 +21,7 @@ compile( ); execute( - iv_pli => 1, - ms_pli => 1, + use_libvpi => 1, check_finished => 1, all_run_flags => ['+PLUS +INT=1234 +STRSTR'] ); From ae311200bfa08545f01daac7a766402c3449a720 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 19:29:24 -0500 Subject: [PATCH 36/79] Tests: Pass tool to allow ifdefs in VPI C code. --- test_regress/driver.pl | 22 +++++++++++++++++++++- test_regress/t/TestVpi.h | 4 ++++ test_regress/t/t_vpi_time_cb.cpp | 7 ++++--- test_regress/t/t_vpi_time_cb.v | 9 ++------- test_regress/t/t_vpi_zero_time_cb.cpp | 7 ++++--- test_regress/t/t_vpi_zero_time_cb.pl | 1 - test_regress/t/t_vpi_zero_time_cb.v | 9 ++------- 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 94e2cd594..8f349fe52 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -598,15 +598,19 @@ sub new { .(($^O eq "darwin" ) ? " -Wl,-undefined,dynamic_lookup" : " -export-dynamic") + .($opt_verbose ? " -DTEST_VERBOSE=1":"") ." -o $self->{obj_dir}/libvpi.so"], + tool_c_flags => [], # ATSIM atsim => 0, + atsim_define => 'ATSIM', atsim_flags => [split(/\s+/,"-c +sv +define+ATSIM"), "+sv_dir+$self->{obj_dir}/.athdl_compile"], atsim_flags2 => [], # Overridden in some sim files atsim_run_flags => [], # GHDL ghdl => 0, + ghdl_define => 'GHDL', ghdl_work_dir => "$self->{obj_dir}/ghdl_compile", ghdl_flags => [($::Debug?"-v":""), "--workdir=$self->{obj_dir}/ghdl_compile", ], @@ -614,29 +618,34 @@ sub new { ghdl_run_flags => [], # IV iv => 0, + iv_define => 'IVERILOG', iv_flags => [split(/\s+/,"+define+IVERILOG -g2012 -o $self->{obj_dir}/simiv")], iv_flags2 => [], # Overridden in some sim files iv_pli => 0, # need to use pli iv_run_flags => [], # VCS vcs => 0, + vcs_define => 'VCS', vcs_flags => [split(/\s+/,"+vcs+lic+wait +cli -debug_access +define+VCS+1 -q -sverilog -CFLAGS '-DVCS' ")], vcs_flags2 => [], # Overridden in some sim files vcs_run_flags => [split(/\s+/,"+vcs+lic_wait")], # NC nc => 0, + nc_define => 'NC', nc_flags => [split(/\s+/,("+licqueue +nowarn+LIBNOU +define+NC=1 -q +assert +sv -c " .($opt_trace ? " +access+r":"")))], nc_flags2 => [], # Overridden in some sim files nc_run_flags => [split(/\s+/,"+licqueue -q +assert +sv -R")], # ModelSim ms => 0, + ms_define => 'MS', ms_flags => [split(/\s+/, ("-sv -work $self->{obj_dir}/work +define+MS=1 -ccflags \"-DMS=1\""))], ms_flags2 => [], # Overridden in some sim files ms_pli => 1, # need to use pli ms_run_flags => [split(/\s+/,"-lib $self->{obj_dir}/work -c -do 'run -all;quit' ")], # XSim xsim => 0, + xsim_define => 'XSIM', xsim_flags => [split(/\s+/,("--nolog --sv --define XSIM --work $self->{name}=$self->{obj_dir}/xsim"))], xsim_flags2 => [], # Overridden in some sim files xsim_run_flags => [split(/\s+/,("--nolog --runall --lib $self->{name}=$self->{obj_dir}/xsim" @@ -645,6 +654,7 @@ sub new { # Verilator vlt => 0, vltmt => 0, + verilator_define => 'VERILATOR', verilator_flags => ["-cc", "-Mdir $self->{obj_dir}", "-OD", # As currently disabled unless -O3 @@ -957,6 +967,7 @@ sub compile { } if ($param{atsim}) { + $param{tool_define} ||= $param{atsim_define}; $self->_make_top(); $self->_run(logfile=>"$self->{obj_dir}/atsim_compile.log", fails=>$param{fails}, @@ -971,6 +982,7 @@ sub compile { ]); } elsif ($param{ghdl}) { + $param{tool_define} ||= $param{ghdl_define}; mkdir $self->{ghdl_work_dir}; $self->_make_top(); $self->_run(logfile=>"$self->{obj_dir}/ghdl_compile.log", @@ -989,6 +1001,7 @@ sub compile { ]); } elsif ($param{vcs}) { + $param{tool_define} ||= $param{vcs_define}; $self->_make_top(); $self->_run(logfile=>"$self->{obj_dir}/vcs_compile.log", fails=>$param{fails}, @@ -1003,6 +1016,7 @@ sub compile { ]); } elsif ($param{nc}) { + $param{tool_define} ||= $param{nc_define}; $self->_make_top(); my @more_args; if ($self->vhdl) { @@ -1024,6 +1038,7 @@ sub compile { ]); } elsif ($param{ms}) { + $param{tool_define} ||= $param{ms_define}; $self->_make_top(); $self->_run(logfile=>"$self->{obj_dir}/ms_compile.log", fails=>$param{fails}, @@ -1039,6 +1054,7 @@ sub compile { ]); } elsif ($param{iv}) { + $param{tool_define} ||= $param{iv_define}; $self->_make_top(); my @cmd = (($ENV{VERILATOR_IVERILOG}||"iverilog"), @{$param{iv_flags}}, @@ -1055,6 +1071,7 @@ sub compile { cmd=>\@cmd); } elsif ($param{xsim}) { + $param{tool_define} ||= $param{xsim_define}; $self->_make_top(); $self->_run(logfile=>"$self->{obj_dir}/xsim_compile.log", fails=>$param{fails}, @@ -1069,6 +1086,7 @@ sub compile { ]); } elsif ($param{vlt_all}) { + $param{tool_define} ||= $param{verilator_define}; if ($self->sc && !$self->have_sc) { $self->skip("Test requires SystemC; ignore error since not installed\n"); @@ -1166,7 +1184,9 @@ sub compile { if ($param{make_pli}) { $self->oprint("Compile vpi\n") if $self->{verbose}; - my @cmd = ($ENV{CXX}, @{$param{pli_flags}}, "-DIS_VPI", $ENV{CFLAGS}, + my @cmd = ($ENV{CXX}, @{$param{pli_flags}}, + "-D".$param{tool_define}, + "-DIS_VPI", ($ENV{CFLAGS}||''), "$self->{t_dir}/$self->{pli_filename}"); $self->_run(logfile=>"$self->{obj_dir}/pli_compile.log", diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h index 155d924f1..e783b9660 100644 --- a/test_regress/t/TestVpi.h +++ b/test_regress/t/TestVpi.h @@ -36,7 +36,11 @@ public: void release() { if (m_handle && m_freeit) { // Below not VL_DO_DANGLING so is portable +#ifdef IVERILOG + vpi_free_object(m_handle); +#else vpi_release_handle(m_handle); +#endif m_handle = NULL; } } diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index fea6e218d..f7b351642 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -35,9 +35,6 @@ #include "TestSimulator.h" #include "TestVpi.h" -#define TEST_MSG \ - if (0) printf - unsigned int main_time = 0; unsigned int callback_count_time1 = 3; unsigned int callback_count_time2 = 4; @@ -119,6 +116,10 @@ static int _time_cb2(p_cb_data cb_data) { } static int _start_of_sim_cb(p_cb_data cb_data) { +#ifdef TEST_VERBOSE + printf("-_start_of_sim_cb\n"); +#endif + t_cb_data cb_data_n1, cb_data_n2; bzero(&cb_data_n1, sizeof(cb_data_n1)); bzero(&cb_data_n2, sizeof(cb_data_n2)); diff --git a/test_regress/t/t_vpi_time_cb.v b/test_regress/t/t_vpi_time_cb.v index 846302d8a..1ac2d001f 100644 --- a/test_regress/t/t_vpi_time_cb.v +++ b/test_regress/t/t_vpi_time_cb.v @@ -8,14 +8,9 @@ module t (/*AUTOARG*/ // Inputs - input clk + clk ); - -`ifndef VERILATOR - reg clk_r = 0; - always #10 clk_r = ~clk_r; - assign clk = clk_r; -`endif + input clk; reg [31:0] count /*verilator public_flat_rd */; diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index 7127f2d47..b0e8cb0da 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -35,9 +35,6 @@ #include "TestSimulator.h" #include "TestVpi.h" -#define TEST_MSG \ - if (0) printf - unsigned int main_time = 0; unsigned int callback_count_zero_time = 0; unsigned int callback_count_start_of_sim = 0; @@ -62,6 +59,10 @@ static int _zero_time_cb(p_cb_data cb_data) { } static int _start_of_sim_cb(p_cb_data cb_data) { +#ifdef TEST_VERBOSE + printf("-_start_of_sim_cb\n"); +#endif + t_cb_data cb_data_n; bzero(&cb_data_n, sizeof(cb_data_n)); s_vpi_time t; diff --git a/test_regress/t/t_vpi_zero_time_cb.pl b/test_regress/t/t_vpi_zero_time_cb.pl index 7906bed68..d2e13ef9c 100755 --- a/test_regress/t/t_vpi_zero_time_cb.pl +++ b/test_regress/t/t_vpi_zero_time_cb.pl @@ -11,7 +11,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - make_top_shell => 0, make_main => 0, make_pli => 1, sim_time => 2100, diff --git a/test_regress/t/t_vpi_zero_time_cb.v b/test_regress/t/t_vpi_zero_time_cb.v index 846302d8a..1ac2d001f 100644 --- a/test_regress/t/t_vpi_zero_time_cb.v +++ b/test_regress/t/t_vpi_zero_time_cb.v @@ -8,14 +8,9 @@ module t (/*AUTOARG*/ // Inputs - input clk + clk ); - -`ifndef VERILATOR - reg clk_r = 0; - always #10 clk_r = ~clk_r; - assign clk = clk_r; -`endif + input clk; reg [31:0] count /*verilator public_flat_rd */; From 99afffa949b74abe1dab6574a86606a655162468 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 19:38:44 -0500 Subject: [PATCH 37/79] Tests: Add some verbose statements. --- test_regress/t/t_vpi_module.cpp | 4 ++++ test_regress/t/t_vpi_module.v | 4 ++-- test_regress/t/t_vpi_var.cpp | 4 ++++ test_regress/t/t_vpi_var.v | 4 ++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 0d9922f51..6f76bd5a6 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -80,6 +80,10 @@ void modDump(const TestVpiHandle& it, int n) { extern "C" { int mon_check() { +#ifdef TEST_VERBOSE + printf("-mon_check()\n"); +#endif + TestVpiHandle it = vpi_iterate(vpiModule, NULL); CHECK_RESULT_NZ(it); // Uncomment to see what other simulators return diff --git a/test_regress/t/t_vpi_module.v b/test_regress/t/t_vpi_module.v index 3ef25ea4b..8d29e6622 100644 --- a/test_regress/t/t_vpi_module.v +++ b/test_regress/t/t_vpi_module.v @@ -43,10 +43,10 @@ extern "C" int mon_check(); status = $c32("mon_check()"); `endif `ifdef IVERILOG - status = $mon_check(); + status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI - status = mon_check(); + status = mon_check(); `endif if (status!=0) begin $write("%%Error: t_vpi_module.cpp:%0d: C Test failed\n", status); diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index b8af76d23..e33072b2f 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -633,6 +633,10 @@ int _mon_check_vlog_info() { int mon_check() { // Callback from initial block in monitor +#ifdef TEST_VERBOSE + printf("-mon_check()\n"); +#endif + if (int status = _mon_check_mcd()) return status; if (int status = _mon_check_callbacks()) return status; if (int status = _mon_check_value_callbacks()) return status; diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 88c9612a6..ea2345b87 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -60,10 +60,10 @@ extern "C" int mon_check(); status = $c32("mon_check()"); `endif `ifdef IVERILOG - status = $mon_check(); + status = $mon_check(); `endif `ifndef USE_VPI_NOT_DPI - status = mon_check(); + status = mon_check(); `endif if (status!=0) begin $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); From 36eb952b60239e0f42a055622b8273cabc6e1c84 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Feb 2021 19:43:29 -0500 Subject: [PATCH 38/79] Tests: Fix mising init --- test_regress/t/TestVpi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h index e783b9660..bf9d1460f 100644 --- a/test_regress/t/TestVpi.h +++ b/test_regress/t/TestVpi.h @@ -25,7 +25,8 @@ public: : m_handle(NULL) , m_freeit(true) {} TestVpiHandle(vpiHandle h) - : m_handle(h) {} + : m_handle(h) + , m_freeit(true) {} ~TestVpiHandle() { release(); } operator vpiHandle() const { return m_handle; } inline TestVpiHandle& operator=(vpiHandle h) { From 2b72218dd82d922d08b9c890539b3a52e51bbf7c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 13 Feb 2021 17:06:53 -0500 Subject: [PATCH 39/79] Fix examples not flushing vcd (#2787). --- Changes | 2 ++ examples/make_hello_c/sim_main.cpp | 2 +- examples/make_protect_lib/sim_main.cpp | 3 ++- examples/make_tracing_c/sim_main.cpp | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 33999c758..3bb344cc4 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix $fread extra semicolon inside statements. [Leendert van Doorn] +**** Fix examples not flushing vcd (#2787). [Richard E George] + * Verilator 4.108 2021-01-10 diff --git a/examples/make_hello_c/sim_main.cpp b/examples/make_hello_c/sim_main.cpp index e95be4fa6..b2c76c84a 100644 --- a/examples/make_hello_c/sim_main.cpp +++ b/examples/make_hello_c/sim_main.cpp @@ -38,5 +38,5 @@ int main(int argc, char** argv, char** env) { delete top; // Return good completion status - exit(0); + return 0; } diff --git a/examples/make_protect_lib/sim_main.cpp b/examples/make_protect_lib/sim_main.cpp index c7762ba54..4d15ea360 100644 --- a/examples/make_protect_lib/sim_main.cpp +++ b/examples/make_protect_lib/sim_main.cpp @@ -71,5 +71,6 @@ int main(int argc, char** argv, char** env) { top = nullptr; // Return good completion status - exit(0); + // Don't use exit() or destructor won't get called + return 0; } diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index bcd853162..08fa60098 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -102,5 +102,6 @@ int main(int argc, char** argv, char** env) { #endif // Return good completion status - exit(0); + // Don't use exit() or destructor won't get called + return 0; } From 20b3f0efa0c04d80b81d2a5ed3f690f5187680de Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 13 Feb 2021 17:29:34 -0500 Subject: [PATCH 40/79] Fix class extends with VM_PARALLEL_BUILDS (#2775). --- Changes | 2 ++ src/V3EmitC.cpp | 7 +++++++ test_regress/t/t_class_extends.pl | 1 + 3 files changed, 10 insertions(+) diff --git a/Changes b/Changes index 3bb344cc4..6471e8a93 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix $fread extra semicolon inside statements. [Leendert van Doorn] +**** Fix class extends with VM_PARALLEL_BUILDS (#2775). [Iru Cai] + **** Fix examples not flushing vcd (#2787). [Richard E George] diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 16936bb2d..99f1f7361 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -3080,6 +3080,13 @@ void EmitCImp::emitIntTop(AstNodeModule*) { void EmitCImp::emitInt(AstNodeModule* modp) { puts("\n//==========\n\n"); + + if (AstClass* classp = VN_CAST(modp, Class)) { + if (classp->extendsp()) + puts("#include \"" + prefixNameProtect(classp->extendsp()->classp()->classOrPackagep()) + + ".h\"\n"); + } + emitModCUse(modp, VUseType::INT_INCLUDE); // Declare foreign instances up front to make C++ happy diff --git a/test_regress/t/t_class_extends.pl b/test_regress/t/t_class_extends.pl index aabcde63e..696e24d17 100755 --- a/test_regress/t/t_class_extends.pl +++ b/test_regress/t/t_class_extends.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + make_flags => 'VM_PARALLEL_BUILDS=1', # bug2775 ); execute( From 43cf5693d1f772a9d33c9d46ef77caf9e408ac17 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 14 Feb 2021 11:15:12 -0500 Subject: [PATCH 41/79] Fix shifts by > 32 bit values (#2785). --- Changes | 2 + include/verilated.h | 33 +++++- src/V3Ast.h | 2 +- src/V3AstNodes.h | 8 +- test_regress/t/t_math_shift.v | 207 ++++++++++++++++++++++++++-------- 5 files changed, 197 insertions(+), 55 deletions(-) diff --git a/Changes b/Changes index 6471e8a93..b4dff84d3 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix class extends with VM_PARALLEL_BUILDS (#2775). [Iru Cai] +**** Fix shifts by > 32 bit values (#2785). [qrq992] + **** Fix examples not flushing vcd (#2787). [Richard E George] diff --git a/include/verilated.h b/include/verilated.h index 6abb68521..2188f124b 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -2145,6 +2145,12 @@ static inline WDataOutP VL_SHIFTL_WWW(int obits, int lbits, int rbits, WDataOutP } return VL_SHIFTL_WWI(obits, lbits, 32, owp, lwp, rwp[0]); } +static inline WDataOutP VL_SHIFTL_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp, + QData rd) VL_MT_SAFE { + WData rwp[VL_WQ_WORDS_E]; + VL_SET_WQ(rwp, rd); + return VL_SHIFTL_WWW(obits, lbits, rbits, owp, lwp, rwp); +} static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more @@ -2153,6 +2159,11 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, WDataInP } return VL_CLEAN_II(obits, obits, lhs << rwp[0]); } +static inline IData VL_SHIFTL_IIQ(int obits, int lbits, int rbits, IData lhs, + QData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; + return VL_CLEAN_II(obits, obits, lhs << rhs); +} static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE { for (int i = 1; i < VL_WORDS_I(rbits); ++i) { if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more @@ -2162,6 +2173,11 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs << (static_cast(rwp[0]))); } +static inline QData VL_SHIFTL_QQQ(int obits, int lbits, int rbits, QData lhs, + QData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; + return VL_CLEAN_QQ(obits, obits, lhs << rhs); +} // EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean; // Important: Unlike most other funcs, the shift might well be a computed @@ -2223,6 +2239,14 @@ static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs, WDataInP // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast(rwp[0]))); } +static inline IData VL_SHIFTR_IIQ(int obits, int, int rbits, IData lhs, QData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; + return VL_CLEAN_QQ(obits, obits, lhs >> rhs); +} +static inline QData VL_SHIFTR_QQQ(int obits, int, int rbits, QData lhs, QData rhs) VL_MT_SAFE { + if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; + return VL_CLEAN_QQ(obits, obits, lhs >> rhs); +} // EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean; static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) VL_PURE { @@ -2277,7 +2301,7 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits, WDataOut WDataInP lwp, WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i]; - if (VL_UNLIKELY(overshift)) { + if (VL_UNLIKELY(overshift || rwp[0] >= obits)) { int lmsw = VL_WORDS_I(obits) - 1; EData sign = VL_SIGNONES_E(lbits, lwp[lmsw]); for (int j = 0; j <= lmsw; ++j) owp[j] = sign; @@ -2296,7 +2320,7 @@ static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i]; - if (VL_UNLIKELY(overshift)) { + if (VL_UNLIKELY(overshift || rwp[0] >= obits)) { IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative return VL_CLEAN_II(obits, obits, sign); } @@ -2306,13 +2330,14 @@ static inline QData VL_SHIFTRS_QQW(int obits, int lbits, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE { EData overshift = 0; // Huge shift 1>>32 or more for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i]; - if (VL_UNLIKELY(overshift)) { + if (VL_UNLIKELY(overshift || rwp[0] >= obits)) { QData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative return VL_CLEAN_QQ(obits, obits, sign); } return VL_SHIFTRS_QQI(obits, lbits, 32, lhs, rwp[0]); } -static inline IData VL_SHIFTRS_IIQ(int obits, int lbits, int rbits, IData lhs, QData rhs) VL_PURE { +static inline IData VL_SHIFTRS_IIQ(int obits, int lbits, int rbits, IData lhs, + QData rhs) VL_MT_SAFE { WData rwp[VL_WQ_WORDS_E]; VL_SET_WQ(rwp, rhs); return VL_SHIFTRS_IIW(obits, lbits, rbits, lhs, rwp); diff --git a/src/V3Ast.h b/src/V3Ast.h index 2295ff743..1718191e5 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1922,7 +1922,7 @@ public: virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV // For documentation on emitC format see EmitCStmts::emitOpName virtual string emitC() = 0; - virtual string emitSimpleOperator() { return ""; } + virtual string emitSimpleOperator() { return ""; } // "" means not ok to use virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS virtual bool cleanOut() const = 0; // True if output has extra upper bits zero // Someday we will generically support data types on every math node diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index feebe0714..eacbdbf8b 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -7305,7 +7305,9 @@ public: } virtual string emitVerilog() override { return "%k(%l %f<< %r)"; } virtual string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return "<<"; } + virtual string emitSimpleOperator() override { + return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<"; + } virtual bool cleanOut() const override { return false; } virtual bool cleanLhs() const override { return false; } virtual bool cleanRhs() const override { return true; } @@ -7327,7 +7329,9 @@ public: } virtual string emitVerilog() override { return "%k(%l %f>> %r)"; } virtual string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } - virtual string emitSimpleOperator() override { return ">>"; } + virtual string emitSimpleOperator() override { + return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>"; + } virtual bool cleanOut() const override { return false; } virtual bool cleanLhs() const override { return true; } virtual bool cleanRhs() const override { return true; } diff --git a/test_regress/t/t_math_shift.v b/test_regress/t/t_math_shift.v index cd071be78..e8f9379c4 100644 --- a/test_regress/t/t_math_shift.v +++ b/test_regress/t/t_math_shift.v @@ -24,30 +24,86 @@ module t (/*AUTOARG*/ localparam [3:0] PBIG29 = 4'b1 << 33'h100000000; // verilator lint_on WIDTH - reg [31:0] right; - reg [31:0] left; + reg [31:0] iright; + reg signed [31:0] irights; + reg [31:0] ileft; reg [P64-1:0] qright; + reg signed [P64-1:0] qrights; reg [P64-1:0] qleft; - reg [31:0] amt; + reg [95:0] wright; + reg signed [95:0] wrights; + reg [95:0] wleft; + + reg [31:0] q_iright; + reg signed [31:0] q_irights; + reg [31:0] q_ileft; + reg [P64-1:0] q_qright; + reg signed [P64-1:0] q_qrights; + reg [P64-1:0] q_qleft; + reg [95:0] q_wright; + reg signed [95:0] q_wrights; + reg [95:0] q_wleft; + + + reg [31:0] w_iright; + reg signed [31:0] w_irights; + reg [31:0] w_ileft; + reg [P64-1:0] w_qright; + reg signed [P64-1:0] w_qrights; + reg [P64-1:0] w_qleft; + reg [95:0] w_wright; + reg signed [95:0] w_wrights; + reg [95:0] w_wleft; + + reg [31:0] iamt; + reg [63:0] qamt; + reg [95:0] wamt; assign ign = {31'h0, clk} >>> 4'bx; // bug760 - assign ign2 = {amt[1:0] >> {22{amt[5:2]}}, amt[1:0] << (0 <<< amt[5:2])}; // bug1174 - assign ign3 = {amt[1:0] >> {22{amt[5:2]}}, - amt[1:0] >> {11{amt[5:2]}}, - $signed(amt[1:0]) >>> {22{amt[5:2]}}, - $signed(amt[1:0]) >>> {11{amt[5:2]}}, - amt[1:0] << {22{amt[5:2]}}, - amt[1:0] << {11{amt[5:2]}}}; + assign ign2 = {iamt[1:0] >> {22{iamt[5:2]}}, iamt[1:0] << (0 <<< iamt[5:2])}; // bug1174 + assign ign3 = {iamt[1:0] >> {22{iamt[5:2]}}, + iamt[1:0] >> {11{iamt[5:2]}}, + $signed(iamt[1:0]) >>> {22{iamt[5:2]}}, + $signed(iamt[1:0]) >>> {11{iamt[5:2]}}, + iamt[1:0] << {22{iamt[5:2]}}, + iamt[1:0] << {11{iamt[5:2]}}}; - wire [95:0] wamt = {amt,amt,amt}; - output wire [95:0] ign4 = wamt >> {11{amt[5:2]}}; - output wire signed [95:0] ign4s = $signed(wamt) >>> {11{amt[5:2]}}; + wire [95:0] wamtt = {iamt,iamt,iamt}; + output wire [95:0] ign4; + assign ign4 = wamtt >> {11{iamt[5:2]}}; + output wire signed [95:0] ign4s; + assign ign4s = $signed(wamtt) >>> {11{iamt[5:2]}}; always @* begin - right = 32'h819b018a >> amt; - left = 32'h819b018a << amt; - qright = 64'hf784bf8f_12734089 >> amt; - qleft = 64'hf784bf8f_12734089 >> amt; + iright = 32'h819b018a >> iamt; + irights = 32'sh819b018a >>> signed'(iamt); + ileft = 32'h819b018a << iamt; + qright = 64'hf784bf8f_12734089 >> iamt; + qrights = 64'shf784bf8f_12734089 >>> signed'(iamt); + qleft = 64'hf784bf8f_12734089 << iamt; + wright = 96'hf784bf8f_12734089_190abe48 >> iamt; + wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(iamt); + wleft = 96'hf784bf8f_12734089_190abe48 << iamt; + + q_iright = 32'h819b018a >> qamt; + q_irights = 32'sh819b018a >>> signed'(qamt); + q_ileft = 32'h819b018a << qamt; + q_qright = 64'hf784bf8f_12734089 >> qamt; + q_qrights = 64'shf784bf8f_12734089 >>> signed'(qamt); + q_qleft = 64'hf784bf8f_12734089 << qamt; + q_wright = 96'hf784bf8f_12734089_190abe48 >> qamt; + q_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(qamt); + q_wleft = 96'hf784bf8f_12734089_190abe48 << qamt; + + w_iright = 32'h819b018a >> wamt; + w_irights = 32'sh819b018a >>> signed'(wamt); + w_ileft = 32'h819b018a << wamt; + w_qright = 64'hf784bf8f_12734089 >> wamt; + w_qrights = 64'shf784bf8f_12734089 >>> signed'(wamt); + w_qleft = 64'hf784bf8f_12734089 << wamt; + w_wright = 96'hf784bf8f_12734089_190abe48 >> wamt; + w_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(wamt); + w_wleft = 96'hf784bf8f_12734089_190abe48 << wamt; end integer cyc; initial cyc=1; @@ -55,10 +111,12 @@ module t (/*AUTOARG*/ if (cyc!=0) begin cyc <= cyc + 1; `ifdef TEST_VERBOSE - $write("%d %x %x %x %x\n", cyc, left, right, qleft, qright); + $write("%d %x %x %x %x %x %x\n", cyc, ileft, iright, qleft, qright, wleft, wright); `endif if (cyc==1) begin - amt <= 32'd0; + iamt <= 0; + qamt <= 0; + wamt <= 0; if (P64 != 64) $stop; if (5'b10110>>2 != 5'b00101) $stop; if (5'b10110>>>2 != 5'b00101) $stop; // Note it cares about sign-ness @@ -72,57 +130,110 @@ module t (/*AUTOARG*/ if ((64'sh458c2de282e30f8b >> 68'sh4) !== 64'sh0458c2de282e30f8) $stop; end if (cyc==2) begin - amt <= 32'd28; - if (left != 32'h819b018a) $stop; - if (right != 32'h819b018a) $stop; - if (qleft != 64'hf784bf8f_12734089) $stop; - if (qright != 64'hf784bf8f_12734089) $stop; + iamt <= 28; + qamt <= 28; + wamt <= 28; + if (ileft != 32'h819b018a) $stop; + if (iright != 32'h819b018a) $stop; + if (irights != 32'h819b018a) $stop; + if (qleft != 64'hf784bf8f_12734089) $stop; + if (qright != 64'hf784bf8f_12734089) $stop; + if (qrights != 64'hf784bf8f_12734089) $stop; + if (wleft != 96'hf784bf8f12734089190abe48) $stop; + if (wright != 96'hf784bf8f12734089190abe48) $stop; + if (wrights != 96'hf784bf8f12734089190abe48) $stop; end if (cyc==3) begin - amt <= 32'd31; - if (left != 32'ha0000000) $stop; - if (right != 32'h8) $stop; - if (qleft != 64'h0000000f784bf8f1) $stop; + iamt <= 31; + qamt <= 31; + wamt <= 31; + if (ileft != 32'ha0000000) $stop; + if (iright != 32'h8) $stop; + if (irights != 32'hfffffff8) $stop; + if (qleft != 64'hf127340890000000) $stop; if (qright != 64'h0000000f784bf8f1) $stop; + if (qrights != 64'hffffffff784bf8f1) $stop; + if (wleft != 96'hf12734089190abe480000000) $stop; + if (wright != 96'h0000000f784bf8f127340891) $stop; + if (wrights != 96'hffffffff784bf8f127340891) $stop; end if (cyc==4) begin - amt <= 32'd32; - if (left != 32'h0) $stop; - if (right != 32'h1) $stop; - if (qleft != 64'h00000001ef097f1e) $stop; + iamt <= 32; + qamt <= 32; + wamt <= 32; + if (ileft != 32'h0) $stop; + if (iright != 32'h1) $stop; + if (qleft != 64'h8939a04480000000) $stop; if (qright != 64'h00000001ef097f1e) $stop; end if (cyc==5) begin - amt <= 32'd33; - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h00000000f784bf8f) $stop; + iamt <= 33; + qamt <= 33; + wamt <= 33; + if (ileft != 32'h0) $stop; + if (iright != 32'h0) $stop; + if (qleft != 64'h1273408900000000) $stop; if (qright != 64'h00000000f784bf8f) $stop; end if (cyc==6) begin - amt <= 32'd64; - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h000000007bc25fc7) $stop; + iamt <= 64; + qamt <= 64; + wamt <= 64; + if (ileft != 32'h0) $stop; + if (iright != 32'h0) $stop; + if (qleft != 64'h24e6811200000000) $stop; if (qright != 64'h000000007bc25fc7) $stop; end if (cyc==7) begin - amt <= 32'd128; - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; + iamt <= 128; + qamt <= 128; + wamt <= 128; + if (ileft != 32'h0) $stop; + if (iright != 32'h0) $stop; if (qleft != 64'h0) $stop; if (qright != 64'h0) $stop; end if (cyc==8) begin - if (left != 32'h0) $stop; - if (right != 32'h0) $stop; - if (qleft != 64'h0) $stop; - if (qright != 64'h0) $stop; + iamt <= 100; + qamt <= {32'h10, 32'h0}; + wamt <= {32'h10, 64'h0}; + if (ileft != '0) $stop; + if (iright != '0) $stop; + if (irights != '1) $stop; + if (qleft != '0) $stop; + if (qright != '0) $stop; + if (qrights != '1) $stop; + if (wleft != '0) $stop; + if (wright != '0) $stop; + if (wrights != '1) $stop; end - if (cyc==9) begin + if (cyc==19) begin $write("*-* All Finished *-*\n"); $finish; end + + // General rule to test all q's + if (cyc != 0) begin + if (ileft != q_ileft) $stop; + if (iright != q_iright) $stop; + if (irights != q_irights) $stop; + if (qleft != q_qleft) $stop; + if (qright != q_qright) $stop; + if (qrights != q_qrights) $stop; + if (wleft != q_wleft) $stop; + if (wright != q_wright) $stop; + if (wrights != q_wrights) $stop; + + if (ileft != w_ileft) $stop; + if (iright != w_iright) $stop; + if (irights != w_irights) $stop; + if (qleft != w_qleft) $stop; + if (qright != w_qright) $stop; + if (qrights != w_qrights) $stop; + if (wleft != w_wleft) $stop; + if (wright != w_wright) $stop; + if (wrights != w_wrights) $stop; + end end end endmodule From f2a7f30b09f1fe6883f2f786ea8b27b0d57ab819 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Mon, 15 Feb 2021 22:40:49 +0900 Subject: [PATCH 42/79] Commentary: In docs remove +I (#2789) --- bin/verilator | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/verilator b/bin/verilator index f88a03e14..6baaa81ac 100755 --- a/bin/verilator +++ b/bin/verilator @@ -455,11 +455,11 @@ ARGUMENTS"> for the detailed description of these arguments. +verilator+debug Enable debugging +verilator+debugi+ Enable debugging at a level +verilator+help Display help - +verilator+prof+threads+file+I Set profile filename - +verilator+prof+threads+start+I Set profile starting point - +verilator+prof+threads+window+I Set profile duration - +verilator+rand+reset+I Set random reset technique - +verilator+seed+I Set random seed + +verilator+prof+threads+file+ Set profile filename + +verilator+prof+threads+start+ Set profile starting point + +verilator+prof+threads+window+ Set profile duration + +verilator+rand+reset+ Set random reset technique + +verilator+seed+ Set random seed +verilator+noassert Disable assert checking +verilator+V Verbose version and config +verilator+version Show version and exit From e44563fddc3e689626a6a53006b093c8de4f5956 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 16 Feb 2021 20:14:13 -0500 Subject: [PATCH 43/79] Tests: Use vl_time_stamp64 where reasonable --- bin/verilator | 2 +- include/verilated_vcd_sc.h | 2 +- test_regress/driver.pl | 2 +- test_regress/t/t_clk_inp_init.cpp | 4 ++-- test_regress/t/t_dpi_var.cpp | 4 ++-- test_regress/t/t_trace_two_cc.cpp | 4 ++-- test_regress/t/t_vpi_cb_iter.cpp | 4 ++-- test_regress/t/t_vpi_cbs_called.cpp | 4 ++-- test_regress/t/t_vpi_get.cpp | 4 ++-- test_regress/t/t_vpi_memory.cpp | 4 ++-- test_regress/t/t_vpi_module.cpp | 4 ++-- test_regress/t/t_vpi_param.cpp | 4 ++-- test_regress/t/t_vpi_time_cb.cpp | 4 ++-- test_regress/t/t_vpi_unimpl.cpp | 4 ++-- test_regress/t/t_vpi_var.cpp | 4 ++-- test_regress/t/t_vpi_zero_time_cb.cpp | 4 ++-- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/bin/verilator b/bin/verilator index 6baaa81ac..e6c16fe2c 100755 --- a/bin/verilator +++ b/bin/verilator @@ -5250,7 +5250,7 @@ want all data to land in the same output file. topp->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("obj_dir/t_trace_ena_cc/simx.vcd"); ... - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += #; tfp->dump(main_time); } diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index 513344499..c18840541 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -53,7 +53,7 @@ public: // METHODS /// Called by SystemC simulate() virtual void cycle(bool delta_cycle) { - if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); } + if (!delta_cycle) this->dump(sc_time_stamp().to_double()); } private: diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 8f349fe52..779b64ed2 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1737,7 +1737,7 @@ sub _make_main { if (!$self->sc) { if ($self->{vl_time_stamp64}) { print $fh "vluint64_t main_time = 0;\n"; - print $fh "vluint64_t vl_time_stamp() { return main_time; }\n"; + print $fh "vluint64_t vl_time_stamp64() { return main_time; }\n"; } else { print $fh "double main_time = 0;\n"; print $fh "double sc_time_stamp() { return main_time; }\n"; diff --git a/test_regress/t/t_clk_inp_init.cpp b/test_regress/t/t_clk_inp_init.cpp index ffbd585c3..79c85635a 100644 --- a/test_regress/t/t_clk_inp_init.cpp +++ b/test_regress/t/t_clk_inp_init.cpp @@ -14,7 +14,7 @@ vluint64_t main_time; double sc_time_stamp() { return main_time; } void oneTest(int seed) { - double sim_time = 1000; + vluint64_t sim_time = 1000; #ifdef TEST_VERBOSE VL_PRINTF("== Seed=%d\n", seed); @@ -33,7 +33,7 @@ void oneTest(int seed) { topp->eval(); // Tick for a little bit - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { topp->clk = 0; topp->eval(); diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index bbab2e36c..16241b904 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -114,7 +114,7 @@ unsigned int main_time = 0; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); @@ -132,7 +132,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); topp->clk = !topp->clk; diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index 3cfd0ef46..3b4fc5f3d 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -33,7 +33,7 @@ vluint64_t main_time = 0; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); Verilated::traceEverOn(true); @@ -70,7 +70,7 @@ int main(int argc, char** argv, char** env) { ap->clk = false; main_time += 10; } - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { ap->clk = !ap->clk; bp->clk = ap->clk; ap->eval_step(); diff --git a/test_regress/t/t_vpi_cb_iter.cpp b/test_regress/t/t_vpi_cb_iter.cpp index a4a6641cb..b7372cb7a 100644 --- a/test_regress/t/t_vpi_cb_iter.cpp +++ b/test_regress/t/t_vpi_cb_iter.cpp @@ -169,7 +169,7 @@ static void register_filler_cb() { double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 100; + vluint64_t sim_time = 100; Verilated::commandArgs(argc, argv); Verilated::debug(0); @@ -184,7 +184,7 @@ int main(int argc, char** argv, char** env) { topp->eval(); topp->clk = 0; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; if (verbose) { VL_PRINTF("Sim Time %d got_error %d\n", main_time, got_error); } topp->clk = !topp->clk; diff --git a/test_regress/t/t_vpi_cbs_called.cpp b/test_regress/t/t_vpi_cbs_called.cpp index 8a8b929d3..2d19394a1 100644 --- a/test_regress/t/t_vpi_cbs_called.cpp +++ b/test_regress/t/t_vpi_cbs_called.cpp @@ -248,7 +248,7 @@ static int register_test_callback() { double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 100; + vluint64_t sim_time = 100; bool cbs_called; Verilated::commandArgs(argc, argv); @@ -262,7 +262,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 1; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { if (verbose) { VL_PRINTF("-- { Sim Time %d , Callback %s (%d) , Testcase State %d } --\n", main_time, cb_reason_to_string(*cb_iter), *cb_iter, *state_iter); diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 2fde87c6b..93193b483 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -234,7 +234,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; #else double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); @@ -258,7 +258,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 6478c4b58..51dcb3a57 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -245,7 +245,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); // we're going to be checking for these errors do don't crash out @@ -271,7 +271,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 6f76bd5a6..8bc9afe0e 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -171,7 +171,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); // we're going to be checking for these errors do don't crash out @@ -200,7 +200,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 64e54b36f..ea524311e 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -242,7 +242,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); // we're going to be checking for these errors do don't crash out @@ -268,7 +268,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index f7b351642..5e1c407f2 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -193,7 +193,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); @@ -233,7 +233,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 1; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 9c7e1ec3a..c9a6d3bda 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -186,7 +186,7 @@ int mon_check() { double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); // we're going to be checking for these errors do don't crash out @@ -212,7 +212,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); // VerilatedVpi::callValueCbs(); // Make sure can link without verilated_vpi.h included diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index e33072b2f..95853fd30 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -686,7 +686,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); @@ -710,7 +710,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 10; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index b0e8cb0da..0c500906c 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -116,7 +116,7 @@ void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; double sc_time_stamp() { return main_time; } int main(int argc, char** argv, char** env) { - double sim_time = 1100; + vluint64_t sim_time = 1100; Verilated::commandArgs(argc, argv); Verilated::debug(0); @@ -156,7 +156,7 @@ int main(int argc, char** argv, char** env) { topp->clk = 0; main_time += 1; - while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; topp->eval(); VerilatedVpi::callValueCbs(); From 95b0e9eef2eb3805a5a4d3284a11f5b6894cda2c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 16 Feb 2021 20:34:44 -0500 Subject: [PATCH 44/79] Tests: Add missing sc_time_stamp calls. --- test_regress/t/t_dpi_accessors.cpp | 2 ++ test_regress/t/t_func_rand.cpp | 2 ++ test_regress/t/t_math_imm2.cpp | 2 ++ test_regress/t/t_mem_slot.cpp | 2 ++ test_regress/t/t_multitop_sig.cpp | 2 ++ test_regress/t/t_order_multidriven.cpp | 2 ++ test_regress/t/t_param_public.cpp | 2 ++ test_regress/t/t_trace_c_api.cpp | 2 ++ test_regress/t/t_x_assign.cpp | 2 ++ 9 files changed, 18 insertions(+) diff --git a/test_regress/t/t_dpi_accessors.cpp b/test_regress/t/t_dpi_accessors.cpp index c20c81745..57b58a7df 100644 --- a/test_regress/t/t_dpi_accessors.cpp +++ b/test_regress/t/t_dpi_accessors.cpp @@ -26,6 +26,8 @@ using std::hex; using std::setfill; using std::setw; +double sc_time_stamp() { return 0; } + // Convenience function to check we didn't finish unexpectedly static void checkFinish(const char* msg) { if (Verilated::gotFinish()) { diff --git a/test_regress/t/t_func_rand.cpp b/test_regress/t/t_func_rand.cpp index 6a93db0ff..c3b43a385 100644 --- a/test_regress/t/t_func_rand.cpp +++ b/test_regress/t/t_func_rand.cpp @@ -9,6 +9,8 @@ #include #include "Vt_func_rand.h" +double sc_time_stamp() { return 0; } + int main(int argc, char* argv[]) { Vt_func_rand* topp = new Vt_func_rand; diff --git a/test_regress/t/t_math_imm2.cpp b/test_regress/t/t_math_imm2.cpp index 163e797b7..191b4eafa 100644 --- a/test_regress/t/t_math_imm2.cpp +++ b/test_regress/t/t_math_imm2.cpp @@ -6,6 +6,8 @@ #include #include "Vt_math_imm2.h" +double sc_time_stamp() { return 0; } + QData MaskVal(int lbit, int hbit) { QData val; for (val = 0; lbit <= hbit; lbit++) val |= (1ULL << lbit); diff --git a/test_regress/t/t_mem_slot.cpp b/test_regress/t/t_mem_slot.cpp index 501c9113f..02f228c9b 100644 --- a/test_regress/t/t_mem_slot.cpp +++ b/test_regress/t/t_mem_slot.cpp @@ -7,6 +7,8 @@ #include #include "Vt_mem_slot.h" +double sc_time_stamp() { return 0; } + unsigned int Array[3]; unsigned int StepSim(Vt_mem_slot* sim, unsigned int slot, unsigned int bit, unsigned int val, diff --git a/test_regress/t/t_multitop_sig.cpp b/test_regress/t/t_multitop_sig.cpp index e89b40853..4cdca1235 100644 --- a/test_regress/t/t_multitop_sig.cpp +++ b/test_regress/t/t_multitop_sig.cpp @@ -10,6 +10,8 @@ #include #include "Vt_multitop_sig.h" +double sc_time_stamp() { return 0; } + // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ diff --git a/test_regress/t/t_order_multidriven.cpp b/test_regress/t/t_order_multidriven.cpp index 5f6003e4b..9a5993967 100644 --- a/test_regress/t/t_order_multidriven.cpp +++ b/test_regress/t/t_order_multidriven.cpp @@ -8,6 +8,8 @@ #include "verilated.h" #include "verilated_vcd_c.h" +double sc_time_stamp() { return 0; } + Vt_order_multidriven* vcore; VerilatedVcdC* vcd; vluint64_t vtime; diff --git a/test_regress/t/t_param_public.cpp b/test_regress/t/t_param_public.cpp index f2e158a78..c206441e3 100644 --- a/test_regress/t/t_param_public.cpp +++ b/test_regress/t/t_param_public.cpp @@ -12,6 +12,8 @@ #include "Vt_param_public_p.h" #include "Vt_param_public_t.h" +double sc_time_stamp() { return 0; } + int main(int argc, char* argv[]) { Vt_param_public* topp = new Vt_param_public; diff --git a/test_regress/t/t_trace_c_api.cpp b/test_regress/t/t_trace_c_api.cpp index 5b8e5dbc7..d2d3f0921 100644 --- a/test_regress/t/t_trace_c_api.cpp +++ b/test_regress/t/t_trace_c_api.cpp @@ -11,6 +11,8 @@ #include VM_PREFIX_INCLUDE +double sc_time_stamp() { return 0; } + extern void vcdTestMain(const char* filenamep); int main(int argc, char** argv, char** env) { diff --git a/test_regress/t/t_x_assign.cpp b/test_regress/t/t_x_assign.cpp index 502301c7c..9ab268a4f 100644 --- a/test_regress/t/t_x_assign.cpp +++ b/test_regress/t/t_x_assign.cpp @@ -14,6 +14,8 @@ #include "verilated.h" #include VM_PREFIX_INCLUDE +double sc_time_stamp() { return 0; } + // clang-format off #if defined(T_X_ASSIGN_0) # define EXPECTED 0 From 64887bd92d46917e35b52e80aa37ab57fbe9de25 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 16 Feb 2021 20:40:16 -0500 Subject: [PATCH 45/79] Commentary --- src/V3Clock.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 04c174fa8..eb5cd526c 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -101,6 +101,7 @@ private: // BOTHEDGE: var ^ var_last // HIGHEDGE: var // LOWEDGE: ~var + // ANYEDGE: var ^ var_last AstNode* newp = nullptr; if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) { nodep->v3warn(E_UNSUPPORTED, From 2b2fe13e79dbb9106076946de314c8a8820c82bf Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 16 Feb 2021 22:31:30 -0500 Subject: [PATCH 46/79] Tests: Add unsupported test for interface typedef (#2783) --- src/verilog.y | 2 +- test_regress/t/t_interface_typedef.out | 7 ++++ test_regress/t/t_interface_typedef.pl | 23 +++++++++++ test_regress/t/t_interface_typedef.v | 56 ++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_interface_typedef.out create mode 100755 test_regress/t/t_interface_typedef.pl create mode 100644 test_regress/t/t_interface_typedef.v diff --git a/src/verilog.y b/src/verilog.y index bdf07ddb9..d11620541 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2209,7 +2209,7 @@ type_declaration: // ==IEEE: type_declaration AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } // // - | yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' + | yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); } // // Allow redeclaring same typedef again // // Alternative is use of idAny below, but this will cause conflicts with ablve diff --git a/test_regress/t/t_interface_typedef.out b/test_regress/t/t_interface_typedef.out new file mode 100644 index 000000000..73fe2430f --- /dev/null +++ b/test_regress/t/t_interface_typedef.out @@ -0,0 +1,7 @@ +%Error-UNSUPPORTED: t/t_interface_typedef.v:46:4: Unsupported: SystemVerilog 2005 typedef in this context + 46 | typedef ifc_if.struct_t struct_t; + | ^~~~~~~ +%Error: t/t_interface_typedef.v:51:16: syntax error, unexpected IDENTIFIER + 51 | struct_t substruct; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_interface_typedef.pl b/test_regress/t/t_interface_typedef.pl new file mode 100755 index 000000000..3a6c0a6d3 --- /dev/null +++ b/test_regress/t/t_interface_typedef.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_interface_typedef.v b/test_regress/t/t_interface_typedef.v new file mode 100644 index 000000000..a8faecb9b --- /dev/null +++ b/test_regress/t/t_interface_typedef.v @@ -0,0 +1,56 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +interface ifc + #( + parameter int unsigned WIDTH + ) (); + typedef struct { + logic [WIDTH-1:0] data; + } struct_t; +endinterface + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + ifc #(10) i_ifc10(); + ifc #(20) i_ifc20(); + + sub #(10) u_sub10 (.clk, .ifc_if(i_ifc10)); + sub #(20) u_sub20 (.clk, .ifc_if(i_ifc20)); + + integer cyc = 1; + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc==20) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule + +module sub #( + parameter int EXP_WIDTH) + ( + input logic clk, + ifc ifc_if); + typedef ifc_if.struct_t struct_t; + + wire [EXP_WIDTH-1:0] expval = '1; + + initial begin + struct_t substruct; + substruct.data = '1; + `checkh(substruct.data, expval); + end + +endmodule From c5e5be8e9929937296ac6e556e5b3829030d0477 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 16 Feb 2021 22:40:21 -0500 Subject: [PATCH 47/79] Commentary --- test_regress/t/t_EXAMPLE.pl | 2 +- test_regress/t/t_EXAMPLE.v | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test_regress/t/t_EXAMPLE.pl b/test_regress/t/t_EXAMPLE.pl index 9a15dd2cc..2cb5eeaff 100755 --- a/test_regress/t/t_EXAMPLE.pl +++ b/test_regress/t/t_EXAMPLE.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2019 by Wilson Snyder. This program is free software; you +# Copyright 2021 by Wilson Snyder. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 3a7373cc0..032785ac5 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -13,7 +13,7 @@ // please note it here, otherwise:** // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2020 by ____YOUR_NAME_HERE____. +// any use, without warranty, 2021 by ____YOUR_NAME_HERE____. // SPDX-License-Identifier: CC0-1.0 module t(/*AUTOARG*/ From d559190e9ecbad96229ca962ba5e0293ea086769 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 17 Feb 2021 22:57:52 -0500 Subject: [PATCH 48/79] Tests for future concat select (#2721) --- test_regress/t/t_concat_sel.out | 43 +++++++++++++++++++ ...math_concat_sel_bad.pl => t_concat_sel.pl} | 11 +++-- ...t_math_concat_sel_bad.v => t_concat_sel.v} | 15 +++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_concat_sel.out rename test_regress/t/{t_math_concat_sel_bad.pl => t_concat_sel.pl} (72%) rename test_regress/t/{t_math_concat_sel_bad.v => t_concat_sel.v} (75%) diff --git a/test_regress/t/t_concat_sel.out b/test_regress/t/t_concat_sel.out new file mode 100644 index 000000000..8df3350c0 --- /dev/null +++ b/test_regress/t/t_concat_sel.out @@ -0,0 +1,43 @@ +%Error-UNSUPPORTED: t/t_concat_sel.v:22:28: Unsupported: Select of concatenation + 22 | wire [3:0] out1 = {a,b}[2 +: 4]; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:23:28: Unsupported: Select of concatenation + 23 | wire [3:0] out2 = {a,b}[5 -: 4]; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:24:28: Unsupported: Select of concatenation + 24 | wire [3:0] out3 = {a,b}[5 : 2]; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:25:28: Unsupported: Select of concatenation + 25 | wire [0:0] out4 = {a,b}[2]; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:31:21: Unsupported: Select of concatenation + 31 | if ({16'h1234}[0] != 1'b0) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:32:21: Unsupported: Select of concatenation + 32 | if ({16'h1234}[2] != 1'b1) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:33:21: Unsupported: Select of concatenation + 33 | if ({16'h1234}[11:4] != 8'h23) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:34:21: Unsupported: Select of concatenation + 34 | if ({16'h1234}[4+:8] != 8'h23) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:35:21: Unsupported: Select of concatenation + 35 | if ({16'h1234}[11-:8] != 8'h23) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:36:25: Unsupported: Select of concatenation + 36 | if ({8'h12, 8'h34}[0] != 1'b0) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:37:25: Unsupported: Select of concatenation + 37 | if ({8'h12, 8'h34}[2] != 1'b1) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:38:25: Unsupported: Select of concatenation + 38 | if ({8'h12, 8'h34}[11:4] != 8'h23) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:39:25: Unsupported: Select of concatenation + 39 | if ({8'h12, 8'h34}[4+:8] != 8'h23) $stop; + | ^ +%Error-UNSUPPORTED: t/t_concat_sel.v:40:25: Unsupported: Select of concatenation + 40 | if ({8'h12, 8'h34}[11-:8] != 8'h23) $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_math_concat_sel_bad.pl b/test_regress/t/t_concat_sel.pl similarity index 72% rename from test_regress/t/t_math_concat_sel_bad.pl rename to test_regress/t/t_concat_sel.pl index f3e3b1181..40f69d41d 100755 --- a/test_regress/t/t_math_concat_sel_bad.pl +++ b/test_regress/t/t_concat_sel.pl @@ -8,11 +8,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(linter => 1); +scenarios(simulator => 1); -lint( - fails => 1, +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, ); +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + ok(1); 1; diff --git a/test_regress/t/t_math_concat_sel_bad.v b/test_regress/t/t_concat_sel.v similarity index 75% rename from test_regress/t/t_math_concat_sel_bad.v rename to test_regress/t/t_concat_sel.v index 88620ca3d..33dc12a99 100644 --- a/test_regress/t/t_math_concat_sel_bad.v +++ b/test_regress/t/t_concat_sel.v @@ -27,6 +27,21 @@ module t (/*AUTOARG*/ // Aggregate outputs into a single result vector wire [63:0] result = {51'h0, out4, out3, out2, out1}; + initial begin + if ({16'h1234}[0] != 1'b0) $stop; + if ({16'h1234}[2] != 1'b1) $stop; + if ({16'h1234}[11:4] != 8'h23) $stop; + if ({16'h1234}[4+:8] != 8'h23) $stop; + if ({16'h1234}[11-:8] != 8'h23) $stop; + if ({8'h12, 8'h34}[0] != 1'b0) $stop; + if ({8'h12, 8'h34}[2] != 1'b1) $stop; + if ({8'h12, 8'h34}[11:4] != 8'h23) $stop; + if ({8'h12, 8'h34}[4+:8] != 8'h23) $stop; + if ({8'h12, 8'h34}[11-:8] != 8'h23) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + // Test loop always @ (posedge clk) begin `ifdef TEST_VERBOSE From 22e299e78e82b01206980fd8bd4c7722b89ee97f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 17 Feb 2021 23:03:47 -0500 Subject: [PATCH 49/79] Support concat selection (#2721). --- Changes | 2 ++ src/V3LinkResolve.cpp | 6 ++--- test_regress/t/t_concat_sel.out | 43 --------------------------------- test_regress/t/t_concat_sel.pl | 4 +-- 4 files changed, 5 insertions(+), 50 deletions(-) delete mode 100644 test_regress/t/t_concat_sel.out diff --git a/Changes b/Changes index b4dff84d3..b3fa6ab1d 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.109 devel +**** Support concat selection (#2721). + **** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi] **** Fix $fread extra semicolon inside statements. [Leendert van Doorn] diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index f2d1dbb6a..976d2768d 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -235,11 +235,9 @@ private: fromp->cloneTree(false))); } else if (VN_IS(basefromp, Replicate)) { // From {...}[...] syntax in IEEE 2017 - if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); } - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Select of concatenation"); - nodep = nullptr; + if (basefromp) UINFO(1, " Related node: " << basefromp << endl); } else { - if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); } + if (basefromp) UINFO(1, " Related node: " << basefromp << endl); nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from"); } } diff --git a/test_regress/t/t_concat_sel.out b/test_regress/t/t_concat_sel.out deleted file mode 100644 index 8df3350c0..000000000 --- a/test_regress/t/t_concat_sel.out +++ /dev/null @@ -1,43 +0,0 @@ -%Error-UNSUPPORTED: t/t_concat_sel.v:22:28: Unsupported: Select of concatenation - 22 | wire [3:0] out1 = {a,b}[2 +: 4]; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:23:28: Unsupported: Select of concatenation - 23 | wire [3:0] out2 = {a,b}[5 -: 4]; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:24:28: Unsupported: Select of concatenation - 24 | wire [3:0] out3 = {a,b}[5 : 2]; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:25:28: Unsupported: Select of concatenation - 25 | wire [0:0] out4 = {a,b}[2]; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:31:21: Unsupported: Select of concatenation - 31 | if ({16'h1234}[0] != 1'b0) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:32:21: Unsupported: Select of concatenation - 32 | if ({16'h1234}[2] != 1'b1) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:33:21: Unsupported: Select of concatenation - 33 | if ({16'h1234}[11:4] != 8'h23) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:34:21: Unsupported: Select of concatenation - 34 | if ({16'h1234}[4+:8] != 8'h23) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:35:21: Unsupported: Select of concatenation - 35 | if ({16'h1234}[11-:8] != 8'h23) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:36:25: Unsupported: Select of concatenation - 36 | if ({8'h12, 8'h34}[0] != 1'b0) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:37:25: Unsupported: Select of concatenation - 37 | if ({8'h12, 8'h34}[2] != 1'b1) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:38:25: Unsupported: Select of concatenation - 38 | if ({8'h12, 8'h34}[11:4] != 8'h23) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:39:25: Unsupported: Select of concatenation - 39 | if ({8'h12, 8'h34}[4+:8] != 8'h23) $stop; - | ^ -%Error-UNSUPPORTED: t/t_concat_sel.v:40:25: Unsupported: Select of concatenation - 40 | if ({8'h12, 8'h34}[11-:8] != 8'h23) $stop; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_concat_sel.pl b/test_regress/t/t_concat_sel.pl index 40f69d41d..9a15dd2cc 100755 --- a/test_regress/t/t_concat_sel.pl +++ b/test_regress/t/t_concat_sel.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; From c1b6faff6d3d582769a2d4f53593faf4c66f32f3 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Thu, 18 Feb 2021 19:28:30 +0900 Subject: [PATCH 50/79] Add more patterns to t_const_opt_red.v (#2792) --- test_regress/t/t_const_opt_red.v | 100 +++++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 12 deletions(-) diff --git a/test_regress/t/t_const_opt_red.v b/test_regress/t/t_const_opt_red.v index d36faf72b..ee5d9fd06 100644 --- a/test_regress/t/t_const_opt_red.v +++ b/test_regress/t/t_const_opt_red.v @@ -24,19 +24,39 @@ module t(/*AUTOARG*/ logic a3; // From test of Test.v logic a4; // From test of Test.v logic a5; // From test of Test.v + logic a6; // From test of Test.v + logic a7; // From test of Test.v + logic a8; // From test of Test.v + logic a9; // From test of Test.v + logic a10; // From test of Test.v + logic a11; // From test of Test.v logic o1; // From test of Test.v logic o2; // From test of Test.v logic o3; // From test of Test.v logic o4; // From test of Test.v logic o5; // From test of Test.v + logic o6; // From test of Test.v + logic o7; // From test of Test.v + logic o8; // From test of Test.v + logic o9; // From test of Test.v + logic o10; // From test of Test.v + logic o11; // From test of Test.v logic x1; // From test of Test.v logic x2; // From test of Test.v logic x3; // From test of Test.v logic x4; // From test of Test.v logic x5; // From test of Test.v + logic x6; // From test of Test.v + logic x7; // From test of Test.v + logic x8; // From test of Test.v + logic x9; // From test of Test.v logic z1; // From test of Test.v logic z2; // From test of Test.v logic z3; // From test of Test.v + logic z4; // From test of Test.v + logic z5; // From test of Test.v + logic z6; // From test of Test.v + logic z7; // From test of Test.v // End of automatics wire [31:0] i = crc[31:0]; @@ -48,37 +68,57 @@ module t(/*AUTOARG*/ .a3 (a3), .a4 (a4), .a5 (a5), + .a6 (a6), + .a7 (a7), + .a8 (a8), + .a9 (a9), + .a10 (a10), + .a11 (a11), .o1 (o1), .o2 (o2), .o3 (o3), .o4 (o4), .o5 (o5), + .o6 (o6), + .o7 (o7), + .o8 (o8), + .o9 (o9), + .o10 (o10), + .o11 (o11), .x1 (x1), .x2 (x2), .x3 (x3), .x4 (x4), .x5 (x5), + .x6 (x6), + .x7 (x7), + .x8 (x8), + .x9 (x9), .z1 (z1), .z2 (z2), .z3 (z3), + .z4 (z4), + .z5 (z5), + .z6 (z6), + .z7 (z7), // Inputs .clk (clk), .i (i[31:0])); // Aggregate outputs into a single result vector // verilator lint_off WIDTH - wire [63:0] result = {a1,a2,a3,a4,a5, - o1,o2,o3,o4,o5, - x1,x2,x3,x4,x5}; + wire [63:0] result = {a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11, + o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11, + x1,x2,x3,x4,x5,x6,x7,x8,x9}; // verilator lint_on WIDTH // Test loop always @ (posedge clk) begin `ifdef TEST_VERBOSE $write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result); - $display("a %b %b %b %b %b", a1, a2, a3, a4, a5); - $display("o %b %b %b %b %b", o1, o2, o3, o4, o5); - $display("x %b %b %b %b %b", x1, x2, x3, x4, x5); + $display("a %b %b %b %b %b %b %b %b %b %b %b", a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); + $display("o %b %b %b %b %b %b %b %b %b %b %b", o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11); + $display("x %b %b %b %b %b %b %b %b %b", x1, x2, x3, x4, x5, x6, x7, x8, x9); `endif cyc <= cyc + 1; crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; @@ -96,23 +136,33 @@ module t(/*AUTOARG*/ if (a1 != a3) $stop; if (a1 != a4) $stop; if (a1 != a5) $stop; + if (a6 != a7) $stop; + if (a8 != a9) $stop; if (o1 != o2) $stop; if (o1 != o3) $stop; if (o1 != o4) $stop; if (o1 != o5) $stop; + if (o6 != o7) $stop; + if (o8 != o9) $stop; if (x1 != x2) $stop; if (x1 != x3) $stop; if (x1 != x4) $stop; if (x1 != x5) $stop; + if (x1 != x6) $stop; + if (x1 != x7) $stop; if (z1 != '0) $stop; if (z2 != '1) $stop; if (z3 != '0) $stop; + if (z4 != '0) $stop; + if (z5 != '1) $stop; + if (z6 != '1) $stop; + if (z7 != '0) $stop; end else begin $write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'hd7bd9c247dc7243c +`define EXPECTED_SUM 64'he9b854d521ebb8b6 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -123,7 +173,10 @@ endmodule module Test(/*AUTOARG*/ // Outputs - a1, a2, a3, a4, a5, o1, o2, o3, o4, o5, x1, x2, x3, x4, x5, z1, z2, z3, + a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11, + x1, x2, x3, x4, x5, x6, x7, x8, x9, + z1, z2, z3, z4, z5, z6, z7, // Inputs clk, i ); @@ -131,10 +184,13 @@ module Test(/*AUTOARG*/ input clk; input [31:0] i; - output logic a1, a2, a3, a4, a5; - output logic o1, o2, o3, o4, o5; - output logic x1, x2, x3, x4, x5; - output logic z1, z2, z3; + output logic a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11; + output logic o1, o2, o3, o4, o5, o6, o7, o8, o9, o10, o11; + output logic x1, x2, x3, x4, x5, x6, x7, x8, x9; + output logic z1, z2, z3, z4, z5, z6, z7; + + logic [127:0] d; + always_ff @(posedge clk) d <= {i, ~i, ~i, i}; always_ff @(posedge clk) begin a1 <= (i[5] & ~i[3] & i[1]); @@ -142,23 +198,43 @@ module Test(/*AUTOARG*/ a3 <= &{i[5], ~i[3], i[1]}; a4 <= ((i & 32'b101010) == 32'b100010); a5 <= ((i & 32'b001010) == 32'b000010) & i[5]; + a6 <= &i[5:3]; + a7 <= i[5] & i[4] & i[3] & i[5] & i[4]; + a8 <= &(~i[5:3]); + a9 <= ~i[5] & !i[4] & !i[3] && ~i[5] && !i[4]; + a10 <= ~(i[5] & ~d[3]) & (!i[5] & d[1]); // cannot be optimized + a11 <= d[0] & d[33] & d[66] & d[99] & !d[31] & !d[62] & !d[93] & !d[124]; // o1 <= (~i[5] | i[3] | ~i[1]); o2 <= (i[5]!=1 | i[3]!=0 | i[1]!=1); o3 <= |{~i[5], i[3], ~i[1]}; o4 <= ((i & 32'b101010) != 32'b100010); o5 <= ((i & 32'b001010) != 32'b000010) | !i[5]; + o6 <= |i[5:3]; + o7 <= i[5] | i[4] | i[3] | i[5] | i[4]; + o8 <= |(~i[5:3]); + o9 <= ~i[5] | !i[4] | ~i[3] || !i[5] || ~i[4]; + o10 <= ~(~i[5] | d[3]) | (i[5] | ~d[1]); // cannot be optimized + o11 <= d[0] | d[33] | d[66] | d[99] | !d[31] | !d[62] | !d[93] | !d[124]; // x1 <= (i[5] ^ ~i[3] ^ i[1]); x2 <= (i[5]==1 ^ i[3]==0 ^ i[1]==1); x3 <= ^{i[5], ~i[3], i[1]}; x4 <= ^((i & 32'b101010) ^ 32'b001000); x5 <= ^((i & 32'b001010) ^ 32'b001000) ^ i[5]; + x6 <= i[5] ^ ~i[3] ^ i[1] ^ i[3] ^ !i[1] ^ i[3] ^ ~i[1]; + x7 <= i[5] ^ (^((i & 32'b001010) ^ 32'b001000)); + x8 <= ~(~i[5] ^ d[3]) ^ (i[5] ^ ~d[1]); + x9 <= d[0] ^ d[33] ^ d[66] ^ d[99] ^ !d[31] ^ !d[62] ^ !d[93] ^ !d[124]; // // All zero/all one cases z1 <= (i[5] & ~i[3] & ~i[5]); z2 <= (~i[5] | i[3] | i[5]); z3 <= (i[5] ^ ~i[3] ^ ~i[5] ^ i[3]); + z4 <= &(i[0] && !i[0]); + z5 <= |(i[1] || !i[1]); + z6 <= ^(i[2] ^ !i[2]); + z7 <= ^(i[2] ^ i[2]); end endmodule From 120322df3e265e69ae969266b916223143446b87 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Thu, 18 Feb 2021 19:28:49 +0900 Subject: [PATCH 51/79] Remove redundant AND with 1 (#2791) --- src/V3Const.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index b9d81fef4..2d3f7e364 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -168,6 +168,34 @@ private: return (lp && VN_IS(lp->lhsp(), Const) && VN_IS(np->rhsp(), Const) && lp->width() == np->width()); } + bool matchRedundantClean(AstAnd* andp) { + // Remove And with constant one inserted by V3Clean + // 1 & (a == b) -> (IData)(a == b) + // When bool is casted to int, the value is either 0 or 1 + AstConst* constp = VN_CAST(andp->lhsp(), Const); + UASSERT_OBJ(constp && constp->isOne(), andp->lhsp(), "TRREEOPC must meet this condition"); + AstNode* rhsp = andp->rhsp(); + AstCCast* ccastp = nullptr; + auto isEqOrNeq + = [](AstNode* nodep) -> bool { return VN_IS(nodep, Eq) || VN_IS(nodep, Neq); }; + if (isEqOrNeq(rhsp)) { + ccastp = new AstCCast{andp->fileline(), rhsp->unlinkFrBack(), andp}; + } else if (AstCCast* tmpp = VN_CAST(rhsp, CCast)) { + if (isEqOrNeq(tmpp->lhsp())) { + if (tmpp->width() == andp->width()) { + tmpp->unlinkFrBack(); + ccastp = tmpp; + } else { + ccastp = new AstCCast{andp->fileline(), tmpp->lhsp()->unlinkFrBack(), andp}; + } + } + } + if (ccastp) { + andp->replaceWith(ccastp); + VL_DO_DANGLING(andp->deleteTree(), andp); + } + return ccastp; + } static bool operandAndOrSame(const AstNode* nodep) { // OR( AND(VAL,x), AND(VAL,y)) -> AND(VAL,OR(x,y)) @@ -2291,6 +2319,7 @@ private: TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1) TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y)) + TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b) // Trinary ops // Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump! TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)"); From aa998335808b6a72ff8897ecd903df73eeb7644d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 18 Feb 2021 19:20:43 -0500 Subject: [PATCH 52/79] Tests: Show (non-)per-instance coverage --- test_regress/t/t_assert_cover.v | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test_regress/t/t_assert_cover.v b/test_regress/t/t_assert_cover.v index dd90d552e..b80282802 100644 --- a/test_regress/t/t_assert_cover.v +++ b/test_regress/t/t_assert_cover.v @@ -19,6 +19,9 @@ module t (/*AUTOARG*/ .toggle (toggle), .cyc (cyc[31:0])); + Sub sub1 (.*); + Sub sub2 (.*); + always @ (posedge clk) begin if (cyc!=0) begin cyc <= cyc + 1; @@ -142,3 +145,14 @@ module Test `endif endmodule + +module Sub + ( + input clk, + input integer cyc + ); + + // Simple cover, per-instance + pi_sub: + cover property (@(posedge clk) cyc == 3); +endmodule From 62e877ebf018fc7b81379c578c6e10be422aa871 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 20 Feb 2021 23:16:55 +0900 Subject: [PATCH 53/79] Add transformation of '^(const ^ a)' -> '(^const) ^ (^a)' (#2800) * Add transformation of '^(const ^ a)' -> '(^const) ^ (^a)' * Use TREEOP instead of TREEOPC --- src/V3Const.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 2d3f7e364..54e2e3785 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2476,6 +2476,7 @@ private: TREEOPV("AstRedAnd{$lhsp.castExtend, $lhsp->width() > VN_CAST($lhsp,,Extend)->lhsp()->width()}", "replaceZero(nodep)"); // &{0,...} => 0 Prevents compiler limited range error TREEOPV("AstRedOr {$lhsp.castExtend}", "AstRedOr {$lhsp->castExtend()->lhsp()}"); TREEOPV("AstRedXor{$lhsp.castExtend}", "AstRedXor{$lhsp->castExtend()->lhsp()}"); + TREEOP ("AstRedXor{$lhsp.castXor, VN_IS(VN_CAST($lhsp,,Xor)->lhsp(),,Const)}", "AstXor{AstRedXor{$lhsp->castXor()->lhsp()}, AstRedXor{$lhsp->castXor()->rhsp()}}"); // ^(const ^ a) => (^const)^(^a) TREEOPV("AstOneHot{$lhsp.width1}", "replaceWLhs(nodep)"); TREEOPV("AstOneHot0{$lhsp.width1}", "replaceNum(nodep,1)"); // Binary AND/OR is faster than logical and/or (usually) From 975c1b39a97b802499c6ad6b039cda311d9dd6fc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Feb 2021 20:29:28 -0500 Subject: [PATCH 54/79] Fix little endian packed array pattern assignment (#2795). --- Changes | 2 ++ src/V3Width.cpp | 5 +++-- test_regress/t/t_array_packed_endian.v | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index b3fa6ab1d..c8148f4f3 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix examples not flushing vcd (#2787). [Richard E George] +**** Fix little endian packed array pattern assignment (#2795). [Alex Torregrosa] + * Verilator 4.108 2021-01-10 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 80324ec6a..1ee1972d6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3427,9 +3427,10 @@ private: void patternArray(AstPattern* nodep, AstNodeArrayDType* arrayDtp, AstPatMember* defaultp) { VNumRange range = arrayDtp->declRange(); PatVecMap patmap = patVectorMap(nodep, range); - UINFO(9, "ent " << range.hi() << " to " << range.lo() << endl); + UINFO(9, "ent " << range.left() << " to " << range.right() << endl); AstNode* newp = nullptr; - for (int ent = range.hi(); ent >= range.lo(); --ent) { + for (int entn = 0, ent = range.left(); entn < range.elements(); + ++entn, ent += range.leftToRightInc()) { AstPatMember* newpatp = nullptr; AstPatMember* patp = nullptr; const auto it = patmap.find(ent); diff --git a/test_regress/t/t_array_packed_endian.v b/test_regress/t/t_array_packed_endian.v index 6af307eea..5a4fa03f0 100644 --- a/test_regress/t/t_array_packed_endian.v +++ b/test_regress/t/t_array_packed_endian.v @@ -28,6 +28,13 @@ typedef struct packed { // verilator lint_on LITENDIAN } t2; +logic [2:0][31:0] test2l; +// verilator lint_off LITENDIAN +logic [0:2][31:0] test2b; +logic [0:2][31:0] test1b; +// verilator lint_on LITENDIAN +logic [2:0][31:0] test1l; + module t; t2 t; initial begin @@ -65,6 +72,23 @@ module t; t.dl[7] = 1'b1; `checkh(t, 80'h80_0002040000100800_01); + test1b = '{0, 1, 2}; + test1l = test1b; + test2l = '{2, 1, 0}; + test2b = test2l; + `checkh(test2l[0], 0); + `checkh(test2l[2], 2); + `checkh(test2l, {32'h2, 32'h1, 32'h0}); + `checkh(test2b[0], 2); + `checkh(test2b[2], 0); + `checkh(test2b, {32'h2, 32'h1, 32'h0}); + `checkh(test1b[0], 0); + `checkh(test1b[2], 2); + `checkh(test1b, {32'h0, 32'h1, 32'h2}); + `checkh(test1l[0], 2); + `checkh(test1l[2], 0); + `checkh(test1l, {32'h0, 32'h1, 32'h2}); + $write("*-* All Finished *-*\n"); $finish; end From 191f76dd90aa6309beb7fea5764a81bea791c726 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Feb 2021 20:55:38 -0500 Subject: [PATCH 55/79] Increase LINE_TOKEN_MAX (#2752). --- src/V3PreProc.h | 2 +- test_regress/t/t_pp_circ_subst_bad.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3PreProc.h b/src/V3PreProc.h index a51dab1bf..43d8f3a19 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -45,7 +45,7 @@ public: // CONSTANTS enum MiscConsts { DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error - LINE_TOKEN_MAX = 20000, // How many tokens on a line before an error + LINE_TOKEN_MAX = 40000, // How many tokens on a line before an error INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error // Streams deep (sometimes `def deep) before an error. // Set more than DEFINE_RECURSION_LEVEL_MAX or INCLUDE_DEPTH_MAX. diff --git a/test_regress/t/t_pp_circ_subst_bad.out b/test_regress/t/t_pp_circ_subst_bad.out index 657d44e8a..1f566721d 100644 --- a/test_regress/t/t_pp_circ_subst_bad.out +++ b/test_regress/t/t_pp_circ_subst_bad.out @@ -1,3 +1,3 @@ -%Error: t/t_pp_circ_subst_bad.v:8:40002: Too many preprocessor tokens on a line (>20000); perhaps recursive `define +%Error: t/t_pp_circ_subst_bad.v:8:80001: Too many preprocessor tokens on a line (>40000); perhaps recursive `define %Error: t/t_pp_circ_subst_bad.v:8:1: syntax error, unexpected IDENTIFIER %Error: Exiting due to From fd6edd90bc988980850fafc24f671c33752bea6f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Feb 2021 22:11:20 -0500 Subject: [PATCH 56/79] Fix little endian interface pin swizzling (#2475). --- Changes | 8 ++- src/V3Inst.cpp | 13 ++-- test_regress/t/t_mod_interface_array4.pl | 21 +++++++ test_regress/t/t_mod_interface_array4.v | 78 ++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_mod_interface_array4.pl create mode 100644 test_regress/t/t_mod_interface_array4.v diff --git a/Changes b/Changes index c8148f4f3..9c06d0728 100644 --- a/Changes +++ b/Changes @@ -7,17 +7,19 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support concat selection (#2721). +**** Fix little endian interface pin swizzling (#2475). [Don Owen] + **** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi] **** Fix $fread extra semicolon inside statements. [Leendert van Doorn] **** Fix class extends with VM_PARALLEL_BUILDS (#2775). [Iru Cai] -**** Fix shifts by > 32 bit values (#2785). [qrq992] +**** Fix shifts by > 32 bit values (#2785). [qrq992] -**** Fix examples not flushing vcd (#2787). [Richard E George] +**** Fix examples not flushing vcd (#2787). [Richard E George] -**** Fix little endian packed array pattern assignment (#2795). [Alex Torregrosa] +**** Fix little endian packed array pattern assignment (#2795). [Alex Torregrosa] * Verilator 4.108 2021-01-10 diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index fb950ae6c..bec64d058 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -396,7 +396,8 @@ private: AstNode* prevPinp = nullptr; // Clone the var referenced by the pin, and clone each var referenced by the varref // Clone pin varp: - for (int i = pinArrp->lo(); i <= pinArrp->hi(); ++i) { + for (int in = 0; in < pinArrp->elementsConst(); ++in) { + int i = pinArrp->left() + in * pinArrp->declRange().leftToRightInc(); string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__"; AstVar* varNewp = nullptr; @@ -429,16 +430,20 @@ private: newp->modVarp(varNewp); newp->name(newp->name() + "__BRA__" + cvtToStr(i) + "__KET__"); // And replace exprp with a new varxref - int offset = 0; const AstVarRef* varrefp = VN_CAST(newp->exprp(), VarRef); + int offset = 0; if (varrefp) { } else if (AstSliceSel* slicep = VN_CAST(newp->exprp(), SliceSel)) { varrefp = VN_CAST(slicep->fromp(), VarRef); UASSERT(VN_IS(slicep->rhsp(), Const), "Slices should be constant"); offset = VN_CAST(slicep->rhsp(), Const)->toSInt(); } - if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); } - string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__"; + int expr_i = i; + if (auto* exprArrp = VN_CAST(newp->exprp()->dtypep(), UnpackArrayDType)) + expr_i = exprArrp->left() + + (in + offset) * exprArrp->declRange().leftToRightInc(); + if (!varrefp) newp->exprp()->v3error("Unexpected connection to arrayed port"); + string newname = varrefp->name() + "__BRA__" + cvtToStr(expr_i) + "__KET__"; AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", VAccess::WRITE); newVarXRefp->varp(newp->modVarp()); diff --git a/test_regress/t/t_mod_interface_array4.pl b/test_regress/t/t_mod_interface_array4.pl new file mode 100755 index 000000000..2cb5eeaff --- /dev/null +++ b/test_regress/t/t_mod_interface_array4.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_mod_interface_array4.v b/test_regress/t/t_mod_interface_array4.v new file mode 100644 index 000000000..62ab2eebd --- /dev/null +++ b/test_regress/t/t_mod_interface_array4.v @@ -0,0 +1,78 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +interface intf (); + integer index; +endinterface + +module sub + ( + input logic clk, + input int cyc, + intf alh[1:2], + intf ahl[2:1], + intf blh[1:2], + intf bhl[2:1] + ); + + always @(posedge clk) begin + if (cyc == 5) begin + `checkh(alh[1].index, 2); + `checkh(alh[2].index, 1); + `checkh(ahl[1].index, 1); + `checkh(ahl[2].index, 2); + `checkh(blh[1].index, 1); + `checkh(blh[2].index, 2); + `checkh(bhl[1].index, 2); + `checkh(bhl[2].index, 1); + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module t + ( + clk + ); + input clk; + + intf ifa1_intf[2:1](); + intf ifa2_intf[2:1](); + intf ifb1_intf[1:2](); + intf ifb2_intf[1:2](); + + int cyc; + + sub sub + ( + .clk, + .cyc, + .alh(ifa1_intf), + .ahl(ifa2_intf), + .blh(ifb1_intf), + .bhl(ifb2_intf) + ); + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + ifa1_intf[1].index = 1; + ifa1_intf[2].index = 2; + ifa2_intf[1].index = 1; + ifa2_intf[2].index = 2; + ifb1_intf[1].index = 1; + ifb1_intf[2].index = 2; + ifb2_intf[1].index = 1; + ifb2_intf[2].index = 2; + end + end + +endmodule From bb5384bc5031eebc874cf26a83b671345036b33a Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 21 Feb 2021 18:11:33 +0900 Subject: [PATCH 57/79] Optimize bit op tree #2186, #2632, and #2633 (#2751) * Tests:Add some more signals to t_const_opt_red.v * Optimize bit op trees such as ~a[2] & a[1] & ~a[0] to 3'b010 == (3'111 & a) * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Apply clang-format * Don't edit and-or tree. * Call matchBitOpTree() after V3Expand does its job. * Internals: Rename newNodep -> newp. No functional change is intended. * Internals: Remove m_sels. No functional change is intended. * Internals: Remove stringstream. No functional change is intended. * Internals: Use V3Number::bitIs1(). No functional change is intended. * Internals: Use V3Number instead of std::map. Resolved laek. Result should be same. * Internals: Resolve overload of setPolarity. No functional change is intended. * Internals: Pass failure reason. No functional change is intended. * Internals: Add VNUser::toPtr(). No functional change is intended. * Internals: Use user4 instead of std::map. No functional change is intended. * Catch up with the AST style aftre V3Expand * Internals: Rename Context to VarInfo. No functional change is intended. * Add some more test case * tests:Add stats to tests Update stats in t_merge_cond.pl as matchBitopTree does some of them. * insert CCast if necessary * small optimization to remove redundant bit mask * No quick exit even when unoptimizable node is found. * Simplify removing redundant And * simplify * Revert "Internals: Add VNUser::toPtr(). No functional change is intended." This reverts commit f98dce10db5923c743ebe7e0392049f1dd39f2ab. * Consider AstWordSel and cleanup * Update test * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Update src/V3Const.cpp Co-authored-by: Wilson Snyder * Apply clang-format * Internals: rename variables. No functional change is intended. Co-authored-by: Wilson Snyder Co-authored-by: github action --- src/V3Const.cpp | 459 +++++++++++++++++++++++++++++- test_regress/t/t_const_opt_red.pl | 6 +- test_regress/t/t_func_crc.pl | 6 +- test_regress/t/t_gate_ormux.pl | 6 +- test_regress/t/t_merge_cond.pl | 4 +- 5 files changed, 474 insertions(+), 7 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 54e2e3785..096209936 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -29,9 +29,9 @@ #include "V3Ast.h" #include "V3Width.h" #include "V3Simulate.h" +#include "V3Stats.h" #include -#include //###################################################################### // Utilities @@ -76,6 +76,421 @@ public: bool found() const { return m_found; } }; +// This visitor can be used in the post-expanded Ast from V3Expand, where the Ast satisfies: +// - Constants are 64 bit at most (because words are accessed via AstWordSel) +// - Variables are scoped. +class ConstBitOpTreeVisitor final : public AstNVisitor { + // TYPES + + struct LeafInfo { // Leaf node (either AstConst or AstVarRef) + bool m_polarity = true; + int m_lsb = 0; + int m_wordIdx = -1; // -1 means AstWordSel is not used. + AstVarRef* m_refp = nullptr; + AstConst* m_constp = nullptr; + }; + // Collect information for each Variable to transform as below + class VarInfo final { + // MEMBERS + int m_constResult = -1; // -1: result is not constant, 0 or 1: result of this tree + ConstBitOpTreeVisitor* m_parentp; // ConstBitOpTreeVisitor that holds this VarInfo + AstVarRef* m_refp; // Points the variable that this VarInfo covers + V3Number m_bitPolarity; // Coefficient of each bit + static int widthOfRef(AstVarRef* refp) { + if (AstWordSel* selp = VN_CAST(refp->backp(), WordSel)) return selp->width(); + return refp->width(); + } + + public: + // METHODS + bool hasConstantResult() const { return m_constResult >= 0; } + void setPolarity(bool compBit, int bit) { + UASSERT_OBJ(!hasConstantResult(), m_refp, "Already has result of " << m_constResult); + if (m_bitPolarity.bitIsX(bit)) { // The bit is not yet set + m_bitPolarity.setBit(bit, compBit); + } else { // Priviously set the bit + const bool sameFlag = m_bitPolarity.bitIs1(bit) == compBit; + if (m_parentp->isXorTree()) { + // ^{x[0], ~x[0], x[2], x[3]} === ~^{x[2], x[3]} + UASSERT_OBJ(sameFlag, m_refp, "Only true is set in Xor tree"); + m_bitPolarity.setBit(bit, 'x'); + } else { // And, Or + // Can ignore this nodep as the bit is already registered + if (sameFlag) return; // a & a == a, b | b == b + // Otherwise result is constant + m_constResult = m_parentp->isAndTree() ? 0 : 1; + m_bitPolarity.setAllBitsX(); // The variable is not referred anymore + } + } + } + AstNode* getResult() const { + FileLine* fl = m_refp->fileline(); + AstNode* srcp = VN_CAST(m_refp->backp(), WordSel); + if (!srcp) srcp = m_refp; + const int width = widthOfRef(m_refp); + + if (hasConstantResult()) + return new AstConst{fl, + V3Number{srcp, width, static_cast(m_constResult)}}; + + AstConst* maskValuep = new AstConst{fl, V3Number{srcp, width, 0}}; + maskValuep->num().opBitsNonX(m_bitPolarity); // 'x' -> 0, 0->1, 1->1 + // Let AstConst be in lhs as it is the common convention + AstAnd* maskedp = new AstAnd{fl, maskValuep, srcp->cloneTree(false)}; + AstNode* resultp; + if (m_parentp->isXorTree()) { + resultp = new AstRedXor{fl, maskedp}; + resultp->dtypep()->widthForce(width, 1); + } else { + AstConst* compValuep = maskValuep->cloneTree(false); + compValuep->num().opBitsOne(m_bitPolarity); // 'x'->0, 0->0, 1->1 + if (m_parentp->isAndTree()) { + resultp = new AstEq{fl, compValuep, maskedp}; + } else { // Or + compValuep->num().opXor(V3Number{compValuep->num()}, maskValuep->num()); + resultp = new AstNeq{fl, compValuep, maskedp}; + } + } + return resultp; + } + + // CONSTRUCTORS + VarInfo(ConstBitOpTreeVisitor* parent, AstVarRef* refp) + : m_parentp(parent) + , m_refp(refp) + , m_bitPolarity(refp, widthOfRef(refp)) { + m_bitPolarity.setAllBitsX(); + } + }; + + // MEMBERS + bool m_failed = false; + bool m_polarity = true; // Flip when AstNot comes + int m_ops = 0; // Number of operations such as And, Or, Xor, Sel... + int m_lsb = 0; // Current LSB + LeafInfo* m_leafp = nullptr; // AstConst or AstVarRef that currently looking for + AstNode* m_rootp; // Root of this AST subtree + AstNode* m_curOpp = nullptr; // The node that should be added to m_frozenNodes + + AstUser4InUse m_inuser4; + std::vector m_frozenNodes; // Nodes that cannot be optimized + std::vector m_varInfos; // VarInfo for each variable, [0] is nullptr + + // NODE STATE + // AstVarRef::user4u -> Base index of m_varInfos that points VarInfo + // AstVarScope::user4u -> Same as AstVarRef::user4 + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + bool isAndTree() const { return VN_IS(m_rootp, And); } + bool isOrTree() const { return VN_IS(m_rootp, Or); } + bool isXorTree() const { return VN_IS(m_rootp, Xor) || VN_IS(m_rootp, RedXor); } + +#define CONST_BITOP_RETURN_IF(cond, nodep) \ + if (setFailed(cond, #cond, nodep, __LINE__)) return + +#define CONST_BITOP_SET_FAILED(reason, nodep) setFailed(true, reason, nodep, __LINE__) + + bool setFailed(bool fail, const char* reason, AstNode* nodep, int line) { + if (fail) { + UINFO(9, "cannot optimize " << m_rootp << " reason:" << reason << " called from line:" + << line << " when checking:" << nodep << std::endl); + // if (debug() >= 9) m_rootp->dumpTree(std::cout << "Root node:\n"); + } + m_failed |= fail; + return m_failed; + } + void incrOps(const AstNode* nodep, int line) { + ++m_ops; + UINFO(9, "Increment to " << m_ops << " " << nodep << " called from line " << line << "\n"); + } + VarInfo& getVarInfo(const LeafInfo& ref) { + UASSERT_OBJ(ref.m_refp, m_rootp, "null varref in And/Or/Xor optimization"); + AstNode* nodep = ref.m_refp->varScopep(); + if (!nodep) nodep = ref.m_refp->varp(); // Not scoped + int baseIdx = nodep->user4(); + if (baseIdx == 0) { // Not set yet + baseIdx = m_varInfos.size(); + const int numWords + = ref.m_refp->dtypep()->isWide() ? ref.m_refp->dtypep()->widthWords() : 1; + m_varInfos.resize(m_varInfos.size() + numWords, nullptr); + nodep->user4(baseIdx); + } + const size_t idx = baseIdx + std::max(0, ref.m_wordIdx); + VarInfo* varInfop = m_varInfos[idx]; + if (!varInfop) { + varInfop = new VarInfo{this, ref.m_refp}; + m_varInfos[idx] = varInfop; + } + return *varInfop; + } + + // Traverse down to see AstConst or AstVarRef + LeafInfo findLeaf(AstNode* nodep, bool expectConst) { + LeafInfo info; + { + VL_RESTORER(m_leafp); + m_leafp = &info; + iterate(nodep); + } + + bool ok = !m_failed; + if (expectConst) + ok &= !info.m_refp && info.m_constp; + else + ok &= info.m_refp && !info.m_constp; + return ok ? info : LeafInfo{}; + } + AstNode* combineTree(AstNode* lhsp, AstNode* rhsp) { + if (!lhsp) return rhsp; + if (isAndTree()) + return new AstAnd(m_rootp->fileline(), lhsp, rhsp); + else if (isOrTree()) + return new AstOr(m_rootp->fileline(), lhsp, rhsp); + else { + UASSERT_OBJ(isXorTree(), m_rootp, "must be either Xor or RedXor"); + return new AstXor(m_rootp->fileline(), lhsp, rhsp); + } + } + + // VISITORS + virtual void visit(AstNode* nodep) override { + CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); + } + virtual void visit(AstCCast* nodep) override { iterateChildren(nodep); } + virtual void visit(AstShiftR* nodep) override { + CONST_BITOP_RETURN_IF(!m_leafp, nodep); + AstConst* constp = VN_CAST(nodep->rhsp(), Const); + CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); + m_lsb += constp->toUInt(); + incrOps(nodep, __LINE__); + iterate(nodep->lhsp()); + m_lsb -= constp->toUInt(); + } + virtual void visit(AstNot* nodep) override { + CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep); + AstNode* lhsp = nodep->lhsp(); + CONST_BITOP_RETURN_IF(VN_IS(lhsp, And) || VN_IS(lhsp, Or) || VN_IS(lhsp, Const), lhsp); + incrOps(nodep, __LINE__); + m_polarity = !m_polarity; + iterateChildren(nodep); + // Don't restore m_polarity for Xor as it counts parity of the entire tree + if (!isXorTree()) m_polarity = !m_polarity; + } + virtual void visit(AstWordSel* nodep) override { + CONST_BITOP_RETURN_IF(!m_leafp, nodep); + AstConst* constp = VN_CAST(nodep->bitp(), Const); + CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); + UASSERT_OBJ(m_leafp->m_wordIdx == -1, nodep, "Unexpected nested WordSel"); + m_leafp->m_wordIdx = constp->toSInt(); + iterate(nodep->fromp()); + } + virtual void visit(AstVarRef* nodep) override { + CONST_BITOP_RETURN_IF(!m_leafp, nodep); + UASSERT_OBJ(!m_leafp->m_refp, nodep, m_leafp->m_refp << " is already set"); + m_leafp->m_refp = nodep; + m_leafp->m_polarity = m_polarity; + m_leafp->m_lsb = m_lsb; + } + virtual void visit(AstConst* nodep) override { + CONST_BITOP_RETURN_IF(!m_leafp, nodep); + UASSERT_OBJ(!m_leafp->m_constp, nodep, m_leafp->m_constp << " is already set"); + m_leafp->m_constp = nodep; + m_leafp->m_lsb = m_lsb; + } + + virtual void visit(AstRedXor* nodep) override { // Expect '^(mask & v)' + CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep); + AstAnd* andp = VN_CAST(nodep->lhsp(), And); + CONST_BITOP_RETURN_IF(!andp, nodep->lhsp()); + + auto mask = findLeaf(andp->lhsp(), true); + CONST_BITOP_RETURN_IF(!mask.m_constp || mask.m_lsb != 0, andp->lhsp()); + + LeafInfo leaf = findLeaf(andp->rhsp(), false); + CONST_BITOP_RETURN_IF(!leaf.m_refp, andp->rhsp()); + + incrOps(nodep, __LINE__); + incrOps(andp, __LINE__); + const V3Number& maskNum = mask.m_constp->num(); + VarInfo& varInfo = getVarInfo(leaf); + for (int i = 0; i < maskNum.width(); ++i) { + // Set true, m_treePolarity takes care of the entire parity + if (maskNum.bitIs1(i)) varInfo.setPolarity(true, i + leaf.m_lsb); + } + } + + virtual void visit(AstNodeBiop* nodep) override { + auto isConst = [](AstNode* nodep, vluint64_t v) -> bool { + AstConst* constp = VN_CAST(nodep, Const); + return constp && constp->toUQuad() == v; + }; + if (nodep->type() == m_rootp->type()) { // And, Or, Xor + CONST_BITOP_RETURN_IF(!m_polarity && isXorTree(), nodep); + incrOps(nodep, __LINE__); + VL_RESTORER(m_curOpp); + VL_RESTORER(m_leafp); + + for (int i = 0; i < 2; ++i) { + LeafInfo leafInfo; + m_leafp = &leafInfo; + m_curOpp = i == 0 ? nodep->lhsp() : nodep->rhsp(); + const size_t origFrozens = m_frozenNodes.size(); + const int origOps = m_ops; + const bool origFailed = m_failed; + iterate(m_curOpp); + if (leafInfo.m_constp || m_failed) { + // Rvert changes in leaf + if (m_frozenNodes.size() > origFrozens) m_frozenNodes.resize(origFrozens); + m_frozenNodes.push_back(m_curOpp); + m_ops = origOps; + m_failed = origFailed; + } else if (leafInfo.m_refp) { + VarInfo& varInfo = getVarInfo(leafInfo); + if (!varInfo.hasConstantResult()) { + varInfo.setPolarity(isXorTree() || leafInfo.m_polarity, leafInfo.m_lsb); + } + } + } + return; + } else if (VN_IS(m_rootp, Xor) && VN_IS(nodep, Eq) && isConst(nodep->lhsp(), 0) + && VN_IS(nodep->rhsp(), And)) { // 0 == (1 & RedXor) + AstAnd* andp = static_cast(nodep->rhsp()); // already checked above + CONST_BITOP_RETURN_IF(!isConst(andp->lhsp(), 1), andp->lhsp()); + AstRedXor* redXorp = VN_CAST(andp->rhsp(), RedXor); + CONST_BITOP_RETURN_IF(!redXorp, andp->rhsp()); + incrOps(nodep, __LINE__); + incrOps(andp, __LINE__); + m_polarity = !m_polarity; + iterate(redXorp); + return; + } else if (VN_IS(m_rootp, Xor) && VN_IS(nodep, And) && isConst(nodep->lhsp(), 1) + && (VN_IS(nodep->rhsp(), Xor) + || VN_IS(nodep->rhsp(), RedXor))) { // 1 & (v[3] ^ v[2]) + incrOps(nodep, __LINE__); + iterate(nodep->rhsp()); + return; + } else if ((isAndTree() && VN_IS(nodep, Eq)) || (isOrTree() && VN_IS(nodep, Neq))) { + CONST_BITOP_RETURN_IF(!m_polarity, nodep); + const bool maskFlip = isOrTree(); + LeafInfo comp = findLeaf(nodep->lhsp(), true); + CONST_BITOP_RETURN_IF(!comp.m_constp || comp.m_lsb != 0, nodep->lhsp()); + + AstAnd* andp = VN_CAST(nodep->rhsp(), And); // comp == (mask & v) + CONST_BITOP_RETURN_IF(!andp, nodep->rhsp()); + + LeafInfo mask = findLeaf(andp->lhsp(), true); + CONST_BITOP_RETURN_IF(!mask.m_constp || mask.m_lsb != 0, andp->lhsp()); + + LeafInfo ref = findLeaf(andp->rhsp(), false); + CONST_BITOP_RETURN_IF(!ref.m_refp, andp->rhsp()); + + VarInfo& varInfo = getVarInfo(ref); + + const V3Number maskNum = mask.m_constp->num(); + const V3Number compNum = comp.m_constp->num(); + for (int i = 0; i < maskNum.width() && !varInfo.hasConstantResult(); ++i) { + const int bit = i + ref.m_lsb; + if (maskNum.bitIs0(i)) continue; + varInfo.setPolarity(compNum.bitIs1(i) ^ maskFlip, bit); + } + incrOps(nodep, __LINE__); + incrOps(andp, __LINE__); + return; + } + CONST_BITOP_SET_FAILED("Mixture of different ops cannot be optimized", nodep); + } + + // CONSTRUCTORS + ConstBitOpTreeVisitor(AstNode* nodep, int ops) + : m_ops(ops) + , m_rootp(nodep) { + // Fill nullptr at [0] because AstVarScope::user4 is 0 by default + m_varInfos.push_back(nullptr); + CONST_BITOP_RETURN_IF(!isAndTree() && !isOrTree() && !isXorTree(), nodep); + AstNode::user4ClearTree(); + if (AstNodeBiop* biopp = VN_CAST(nodep, NodeBiop)) { + iterate(biopp); + } else { + incrOps(nodep, __LINE__); + iterateChildren(nodep); + } + UASSERT_OBJ(isXorTree() || m_polarity, nodep, "must be the original polarity"); + } + virtual ~ConstBitOpTreeVisitor() { + for (size_t i = 0; i < m_varInfos.size(); ++i) { + VL_DO_DANGLING(delete m_varInfos[i], m_varInfos[i]); + } + } +#undef CONST_BITOP_RETURN_IF +#undef CONST_BITOP_SET_FAILED + +public: + // Transform as below. + // v[0] & v[1] => 2'b11 == (2'b11 & v) + // v[0] | v[1] => 2'b00 != (2'b11 & v) + // v[0] ^ v[1] => ^{2'b11 & v} + // (3'b011 == (3'b011 & v)) & v[2] => 3'b111 == (3'b111 & v) + // (3'b000 != (3'b011 & v)) | v[2] => 3'b000 != (3'b111 & v) + // Reduction ops are transformed in the same way. + // &{v[0], v[1]} => 2'b11 == (2'b11 & v) + static AstNode* simplify(AstNode* nodep, int ops, VDouble0& reduction) { + ConstBitOpTreeVisitor visitor{nodep, ops}; + if (visitor.m_failed || visitor.m_varInfos.size() == 1) return nullptr; + + // Two ops for each varInfo. (And and Eq) + const int vars = visitor.m_varInfos.size() - 1; + int constTerms = 0; + for (const VarInfo* v : visitor.m_varInfos) { + if (v && v->hasConstantResult()) ++constTerms; + } + // Expected number of ops after this simplification + // e.g. (comp0 == (mask0 & var0)) & (comp1 == (mask1 & var1)) & .... + // e.g. redXor(mask1 & var0) ^ redXor(mask1 & var1) + // 2 ops per variables, numVars - 1 ops among variables + int expOps = 2 * (vars - constTerms) + vars - 1; + expOps += 2 * visitor.m_frozenNodes.size(); + if (visitor.isXorTree()) { + ++expOps; // AstRedXor::cleanOut() == false, so need 1 & redXor + if (!visitor.m_polarity) ++expOps; // comparison with 0 + } + if (visitor.m_ops <= expOps) return nullptr; // Unless benefitial, return + + reduction += visitor.m_ops - expOps; + + AstNode* resultp = nullptr; + // VarInfo in visitor.m_varInfos appears in deterministic order, + // so the optimized AST is deterministic too. + for (const VarInfo* varinfop : visitor.m_varInfos) { + if (!varinfop) continue; + AstNode* partialresultp = varinfop->getResult(); + resultp = visitor.combineTree(resultp, partialresultp); + } + AstNode* frozensp = nullptr; + for (AstNode* frozenp : visitor.m_frozenNodes) { + frozenp->unlinkFrBack(); + frozensp = visitor.combineTree(frozensp, frozenp); + } + if (frozensp) resultp = visitor.combineTree(resultp, frozensp); + + if (visitor.isXorTree()) { + // VL_REDXOR_N functions don't guarantee to return only 0/1 + const int width = resultp->width(); + FileLine* fl = nodep->fileline(); + resultp = new AstAnd{fl, new AstConst{fl, V3Number{nodep, width, 1}}, resultp}; + if (!visitor.m_polarity) { + resultp = new AstEq{fl, new AstConst{fl, V3Number{nodep, width, 0}}, resultp}; + resultp->dtypep()->widthForce(1, 1); + } + } + if (resultp->width() != nodep->width()) { + resultp = new AstCCast{resultp->fileline(), resultp, nodep}; + } + return resultp; + } +}; + //###################################################################### // Const state, as a visitor of each AstNode @@ -104,6 +519,7 @@ private: AstArraySel* m_selp = nullptr; // Current select AstNode* m_scopep = nullptr; // Current scope AstAttrOf* m_attrp = nullptr; // Current attribute + VDouble0 m_statBitOpReduction; // Ops reduced in ConstBitOpTreeVisitor // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -270,6 +686,36 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); return true; } + bool matchBitOpTree(AstNode* nodep) { + AstNode* newp = nullptr; + bool tried = false; + if (AstAnd* andp = VN_CAST(nodep, And)) { // 1 & BitOpTree + if (AstConst* bitMaskp = VN_CAST(andp->lhsp(), Const)) { + if (bitMaskp->num().toUQuad() != 1) return false; + newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), 1, m_statBitOpReduction); + tried = true; + } + } + if (!tried) { + // (comp == BitOpTree) & BitOpTree + // (comp != BitOpTree) | BitOpTree + newp = ConstBitOpTreeVisitor::simplify(nodep, 0, m_statBitOpReduction); + } + if (newp) { + UINFO(4, "Transformed leaf of bit tree to " << newp << std::endl); + if (debug() >= 9) { + static int c = 0; + std::cout << "Call matchBitOpTree[" << c << "]\n"; + nodep->dumpTree(std::cout); + std::cout << "\nResult:\n"; + newp->dumpTree(std::cout); + ++c; + } + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + return newp; + } static bool operandShiftSame(const AstNode* nodep) { const AstNodeBiop* np = VN_CAST_CONST(nodep, NodeBiop); { @@ -2477,6 +2923,7 @@ private: TREEOPV("AstRedOr {$lhsp.castExtend}", "AstRedOr {$lhsp->castExtend()->lhsp()}"); TREEOPV("AstRedXor{$lhsp.castExtend}", "AstRedXor{$lhsp->castExtend()->lhsp()}"); TREEOP ("AstRedXor{$lhsp.castXor, VN_IS(VN_CAST($lhsp,,Xor)->lhsp(),,Const)}", "AstXor{AstRedXor{$lhsp->castXor()->lhsp()}, AstRedXor{$lhsp->castXor()->rhsp()}}"); // ^(const ^ a) => (^const)^(^a) + TREEOPC("AstAnd {nodep->widthMin() == 1, $lhsp.castConst, $rhsp.castRedXor, matchBitOpTree(nodep)}", "DONE"); TREEOPV("AstOneHot{$lhsp.width1}", "replaceWLhs(nodep)"); TREEOPV("AstOneHot0{$lhsp.width1}", "replaceNum(nodep,1)"); // Binary AND/OR is faster than logical and/or (usually) @@ -2498,6 +2945,9 @@ private: TREEOP ("AstAnd {operandShiftSame(nodep)}", "replaceShiftSame(nodep)"); TREEOP ("AstOr {operandShiftSame(nodep)}", "replaceShiftSame(nodep)"); TREEOP ("AstXor {operandShiftSame(nodep)}", "replaceShiftSame(nodep)"); + TREEOPC("AstAnd {nodep->widthMin() == 1, matchBitOpTree(nodep)}", "DONE"); + TREEOPC("AstOr {nodep->widthMin() == 1, matchBitOpTree(nodep)}", "DONE"); + TREEOPC("AstXor {nodep->widthMin() == 1, matchBitOpTree(nodep)}", "DONE"); // Note can't simplify a extend{extends}, extends{extend}, as the sign // bits end up in the wrong places TREEOPV("AstExtend {$lhsp.castExtend}", "replaceExtend(nodep, VN_CAST(nodep->lhsp(), Extend)->lhsp())"); @@ -2595,7 +3045,12 @@ public: } // clang-format on } - virtual ~ConstVisitor() override = default; + virtual ~ConstVisitor() override { + if (m_doCpp) { + V3Stats::addStat("Optimizations, Const bit op reduction", m_statBitOpReduction); + } + } + AstNode* mainAcceptEdit(AstNode* nodep) { // Operate starting at a random place return iterateSubtreeReturnEdits(nodep); diff --git a/test_regress/t/t_const_opt_red.pl b/test_regress/t/t_const_opt_red.pl index b8d7ae067..573f3e618 100755 --- a/test_regress/t/t_const_opt_red.pl +++ b/test_regress/t/t_const_opt_red.pl @@ -11,12 +11,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2=>["-Wno-UNOPTTHREADS"], + verilator_flags2=>["-Wno-UNOPTTHREADS", "--stats"], ); execute( check_finished => 1, ); +if ($Self->{vlt}) { + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 135); +} + ok(1); 1; diff --git a/test_regress/t/t_func_crc.pl b/test_regress/t/t_func_crc.pl index 7d49cd2cd..6549284aa 100755 --- a/test_regress/t/t_func_crc.pl +++ b/test_regress/t/t_func_crc.pl @@ -11,12 +11,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--compiler msvc"], # We have deep expressions we want to test + verilator_flags2 => ["--compiler msvc", "--stats"], # We have deep expressions we want to test ); execute( check_finished => 1, ); +if ($Self->{vlt}) { + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 3888); +} + ok(1); 1; diff --git a/test_regress/t/t_gate_ormux.pl b/test_regress/t/t_gate_ormux.pl index a2b95b689..996e05170 100755 --- a/test_regress/t/t_gate_ormux.pl +++ b/test_regress/t/t_gate_ormux.pl @@ -15,9 +15,13 @@ $Self->{sim_time} = $Self->{cycles} * 10 + 1000; compile( v_flags2 => ["+define+SIM_CYCLES=$Self->{cycles}",], - verilator_flags2=>["-Wno-UNOPTTHREADS"], + verilator_flags2=>["-Wno-UNOPTTHREADS", "--stats"], ); +if ($Self->{vlt}) { + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 994); +} + execute( ); diff --git a/test_regress/t/t_merge_cond.pl b/test_regress/t/t_merge_cond.pl index 834265b01..51f97242d 100755 --- a/test_regress/t/t_merge_cond.pl +++ b/test_regress/t/t_merge_cond.pl @@ -21,9 +21,9 @@ execute( if ($Self->{vlt}) { # Note, with vltmt this might be split differently, so only checking vlt file_grep($Self->{stats}, qr/Optimizations, MergeCond merges\s+(\d+)/i, - 11); + 10); file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i, - 644); + 580); file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i, 64); } From 99c02419c096086303511fb2973282b3665169c6 Mon Sep 17 00:00:00 2001 From: Andreas Kuster <20418060+andreaskuster@users.noreply.github.com> Date: Sun, 21 Feb 2021 14:22:52 +0100 Subject: [PATCH 58/79] Commentary - contributors. (#2801) --- docs/CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 41124837f..f3de9d893 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -6,6 +6,7 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all. Ahmed El-Mahmoudy Alex Chadwick Àlex Torregrosa +Andreas Kuster Chris Randall Conor McCullough Dan Petrisko From 18f3df438ee5a6955bbb2969432f6a8558206d4c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Feb 2021 11:02:02 -0500 Subject: [PATCH 59/79] For generated --main, use unique_ptr. No functional change intended. --- src/V3EmitCMain.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 63e9abea6..768694416 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -55,8 +55,6 @@ private: puts("\n//======================\n\n"); - puts(topClassName() + "* topp;\n"); - puts("\n"); puts("// Requires -DVL_TIME_STAMP64\n"); v3Global.opt.addCFlags("-DVL_TIME_STAMP64"); puts("vluint64_t main_time = 0;\n"); @@ -67,10 +65,15 @@ private: puts("// Setup defaults and parse command line\n"); puts("Verilated::debug(0);\n"); puts("Verilated::commandArgs(argc, argv);\n"); + puts("\n"); + puts("// Construct the Verilated model, from Vtop.h generated from Verilating\n"); - puts("topp = new " + topClassName() + "(\"top\");\n"); + puts("const std::unique_ptr<" + topClassName() + "> topp{new " + topClassName() + "};\n"); + puts("\n"); + puts("// Evaluate initials\n"); puts("topp->eval(); // Evaluate\n"); + puts("\n"); puts("// Simulate until $finish\n"); puts("while (!Verilated::gotFinish()) {\n"); @@ -88,8 +91,7 @@ private: puts("// Final model cleanup\n"); puts("topp->final();\n"); - puts("VL_DO_DANGLING(delete topp, topp);\n"); - puts("exit(0);\n"); + puts("return 0;\n"); puts("}\n"); } }; From 3ae75926e465c9a45f7099e82c23d9b0d92d1624 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Feb 2021 12:12:11 -0500 Subject: [PATCH 60/79] Inline old VL_CTOR macros. --- include/verilated.h | 11 ----------- src/V3EmitC.cpp | 10 ++++++---- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index 2188f124b..9f761e209 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -272,17 +272,6 @@ public: #define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule // Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical) -/// Constructor, ala SC_CTOR -#define VL_CTOR(modname) modname(const char* __VCname = "") - -/// Constructor declaration for C++, ala SP_CTOR_IMPL -#define VL_CTOR_IMP(modname) \ - modname::modname(const char* __VCname) \ - : VerilatedModule(__VCname) - -/// Constructor declaration for SystemC, ala SP_CTOR_IMPL -#define VL_SC_CTOR_IMP(modname) modname::modname(sc_module_name) - //========================================================================= // Functions overridable by user defines // (Internals however must use VL_PRINTF_MT, which calls these.) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 99f1f7361..8a9ab194b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -2427,10 +2427,12 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { if (VN_IS(modp, Class)) { modp->v3fatalSrc("constructors should be AstCFuncs instead"); } else if (optSystemC() && modp->isTop()) { - puts("VL_SC_CTOR_IMP(" + prefixNameProtect(modp) + ")"); + puts(prefixNameProtect(modp) + "::" + prefixNameProtect(modp) + "(sc_module_name)"); } else { - puts("VL_CTOR_IMP(" + prefixNameProtect(modp) + ")"); - first = false; // VL_CTOR_IMP includes the first ':' + puts(prefixNameProtect(modp) + "::" + prefixNameProtect(modp) + + "(const char* __VCname)\n"); + puts(" : VerilatedModule(__VCname)\n"); + first = false; // printed the first ':' } emitVarCtors(&first); if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first); @@ -3184,7 +3186,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) { puts("virtual ~" + prefixNameProtect(modp) + "();\n"); } else if (optSystemC()) { ofp()->putsPrivate(false); // public: - puts("VL_CTOR(" + prefixNameProtect(modp) + ");\n"); + puts(prefixNameProtect(modp) + "(const char* __VCname = \"\");\n"); puts("~" + prefixNameProtect(modp) + "();\n"); } else { ofp()->putsPrivate(false); // public: From 9650aefa4234808df884af3b4845e102cc099274 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Feb 2021 21:25:21 -0500 Subject: [PATCH 61/79] Internals: Cleanup unneeded {}. No functional change --- include/verilated.cpp | 18 ++++++------- include/verilated.h | 16 ++++++------ include/verilated_cov.cpp | 2 +- include/verilated_fst_c.cpp | 2 +- include/verilated_trace.h | 2 +- include/verilated_vcd_c.cpp | 6 +++-- include/verilated_vcd_c.h | 2 +- include/verilated_vpi.cpp | 4 +-- src/V3Active.cpp | 4 +-- src/V3AssertPre.cpp | 2 +- src/V3Ast.cpp | 2 +- src/V3Ast.h | 8 +++--- src/V3AstNodes.cpp | 18 ++++++------- src/V3AstNodes.h | 30 +++++++++++----------- src/V3CCtors.cpp | 2 +- src/V3Case.cpp | 2 +- src/V3Cdc.cpp | 2 +- src/V3Clean.cpp | 8 +++--- src/V3Config.cpp | 2 +- src/V3Const.cpp | 6 ++--- src/V3Descope.cpp | 2 +- src/V3EmitC.cpp | 8 +++--- src/V3EmitCMake.cpp | 2 +- src/V3EmitCSyms.cpp | 4 +-- src/V3EmitMk.cpp | 10 ++++---- src/V3EmitV.cpp | 2 +- src/V3EmitXml.cpp | 4 +-- src/V3Error.h | 4 +-- src/V3File.cpp | 6 ++--- src/V3FileLine.cpp | 4 +-- src/V3Gate.cpp | 4 +-- src/V3Graph.cpp | 2 +- src/V3GraphAlg.cpp | 4 ++- src/V3GraphDfa.cpp | 2 +- src/V3GraphStream.h | 2 +- src/V3HierBlock.cpp | 2 +- src/V3Inline.cpp | 10 ++++---- src/V3Inst.cpp | 6 ++--- src/V3LifePost.cpp | 4 +-- src/V3LinkCells.cpp | 4 ++- src/V3LinkDot.cpp | 8 +++--- src/V3LinkResolve.cpp | 2 +- src/V3MergeCond.cpp | 6 +++-- src/V3Number.cpp | 16 ++++++------ src/V3Number_test.cpp | 2 +- src/V3Options.cpp | 4 +-- src/V3Order.cpp | 4 +-- src/V3Os.cpp | 2 +- src/V3ParseImp.cpp | 4 +-- src/V3ParseLex.cpp | 2 +- src/V3Partition.cpp | 24 ++++++++--------- src/V3PreProc.cpp | 2 +- src/V3ProtectLib.cpp | 4 +-- src/V3Slice.cpp | 2 +- src/V3SplitVar.cpp | 4 +-- src/V3TSP.cpp | 6 ++--- src/V3Table.cpp | 4 ++- src/V3Task.cpp | 2 +- src/V3Trace.cpp | 4 +-- src/V3Unroll.cpp | 10 ++++---- src/V3Width.cpp | 10 ++++---- src/V3WidthSel.cpp | 14 +++++----- src/VlcTop.cpp | 2 +- test_regress/t/t_dpi_accessors.cpp | 2 +- test_regress/t/t_dpi_arg_inout_unpack.cpp | 4 +-- test_regress/t/t_dpi_arg_input_unpack.cpp | 2 +- test_regress/t/t_dpi_arg_output_unpack.cpp | 2 +- test_regress/t/t_dpi_context_c.cpp | 2 +- test_regress/t/t_flag_fi.cpp | 2 +- test_regress/t/t_tri_gate.cpp | 2 +- test_regress/t/t_tri_inout.cpp | 2 +- test_regress/t/t_tri_pullup.cpp | 2 +- test_regress/t/t_tri_select.cpp | 2 +- test_regress/t/t_vpi_cb_iter.cpp | 12 ++++----- test_regress/t/t_vpi_cbs_called.cpp | 16 ++++++------ test_regress/t/t_vpi_get.cpp | 2 +- test_regress/t/t_vpi_param.cpp | 8 +++--- test_regress/t/t_vpi_var.cpp | 4 +-- 78 files changed, 218 insertions(+), 208 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index a56dcf5e0..c992d8cf7 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1510,19 +1510,19 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi IData entry = read_elements + start - array_lsb; if (width <= 8) { CData* datap = &(reinterpret_cast(memp))[entry]; - if (shift == start_shift) { *datap = 0; } + if (shift == start_shift) *datap = 0; *datap |= (c << shift) & VL_MASK_I(width); } else if (width <= 16) { SData* datap = &(reinterpret_cast(memp))[entry]; - if (shift == start_shift) { *datap = 0; } + if (shift == start_shift) *datap = 0; *datap |= (c << shift) & VL_MASK_I(width); } else if (width <= VL_IDATASIZE) { IData* datap = &(reinterpret_cast(memp))[entry]; - if (shift == start_shift) { *datap = 0; } + if (shift == start_shift) *datap = 0; *datap |= (c << shift) & VL_MASK_I(width); } else if (width <= VL_QUADSIZE) { QData* datap = &(reinterpret_cast(memp))[entry]; - if (shift == start_shift) { *datap = 0; } + if (shift == start_shift) *datap = 0; *datap |= ((static_cast(c) << static_cast(shift)) & VL_MASK_Q(width)); } else { WDataOutP datap = &(reinterpret_cast(memp))[entry * VL_WORDS_I(width)]; @@ -1909,19 +1909,19 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) { int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0')); if (m_bits <= 8) { CData* datap = reinterpret_cast(valuep); - if (!innum) { *datap = 0; } + if (!innum) *datap = 0; *datap = ((*datap << shift) + value) & VL_MASK_I(m_bits); } else if (m_bits <= 16) { SData* datap = reinterpret_cast(valuep); - if (!innum) { *datap = 0; } + if (!innum) *datap = 0; *datap = ((*datap << shift) + value) & VL_MASK_I(m_bits); } else if (m_bits <= VL_IDATASIZE) { IData* datap = reinterpret_cast(valuep); - if (!innum) { *datap = 0; } + if (!innum) *datap = 0; *datap = ((*datap << shift) + value) & VL_MASK_I(m_bits); } else if (m_bits <= VL_QUADSIZE) { QData* datap = reinterpret_cast(valuep); - if (!innum) { *datap = 0; } + if (!innum) *datap = 0; *datap = ((*datap << static_cast(shift)) + static_cast(value)) & VL_MASK_Q(m_bits); } else { @@ -2694,7 +2694,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_ if (!finalize) { // Need two passes so we know array size to create // Alternative is to dynamically stretch the array, which is more code, and slower. - if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum + 1; } + if (funcnum >= m_funcnumMax) m_funcnumMax = funcnum + 1; } else { if (VL_UNCOVERABLE(funcnum >= m_funcnumMax)) { VL_FATAL_MT(__FILE__, __LINE__, "", // LCOV_EXCL_LINE diff --git a/include/verilated.h b/include/verilated.h index 9f761e209..c0cddeaec 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -468,7 +468,7 @@ public: static bool gotFinish() VL_MT_SAFE { return s_s.s_gotFinish; } ///< Return if got a $finish /// Allow traces to at some point be enabled (disables some optimizations) static void traceEverOn(bool flag) VL_MT_SAFE { - if (flag) { calcUnusedSigs(flag); } + if (flag) calcUnusedSigs(flag); } /// Enable/disable assertions static void assertOn(bool flag) VL_MT_SAFE; @@ -577,7 +577,7 @@ public: /// Called at end of each thread mtask, before finishing eval static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { - if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) { endOfThreadMTaskGuts(evalMsgQp); } + if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp); } /// Called at end of eval loop static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { @@ -1257,7 +1257,7 @@ static inline IData VL_COUNTBITS_W(int lbits, int words, WDataInP lwp, IData ctr EData r = 0; IData wordLbits = 32; for (int i = 0; i < words; ++i) { - if (i == words - 1) { wordLbits = lbits % 32; } + if (i == words - 1) wordLbits = lbits % 32; r += VL_COUNTBITS_E(wordLbits, lwp[i], ctrl0, ctrl1, ctrl2); } return r; @@ -1330,7 +1330,7 @@ static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) VL_MT_SAFE { for (int i = words - 1; i >= 0; --i) { if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) { - if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) { return i * VL_EDATASIZE + bit + 1; } + if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) return i * VL_EDATASIZE + bit + 1; } // Can't get here - one bit must be set } @@ -1627,8 +1627,8 @@ static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp, WDataInP lwp, WData rwstore[VL_MULS_MAX_WORDS]; WDataInP ltup = lwp; WDataInP rtup = rwp; - if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); } - if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); } + if (lsign) ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); + if (rsign) rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); if ((lsign && !rsign) || (!lsign && rsign)) { WData qNoSign[VL_MULS_MAX_WORDS]; VL_DIV_WWW(lbits, qNoSign, ltup, rtup); @@ -1649,8 +1649,8 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp, WDataInP lwp, WData rwstore[VL_MULS_MAX_WORDS]; WDataInP ltup = lwp; WDataInP rtup = rwp; - if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); } - if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); } + if (lsign) ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); + if (rsign) rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); if (lsign) { // Only dividend sign matters for modulus WData qNoSign[VL_MULS_MAX_WORDS]; VL_MODDIV_WWW(lbits, qNoSign, ltup, rtup); diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index f351c3140..6d8e5a458 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -298,7 +298,7 @@ public: // Keys -> strings std::string keys[MAX_KEYS]; for (int i = 0; i < MAX_KEYS; ++i) { - if (ckeyps[i] && ckeyps[i][0]) { keys[i] = ckeyps[i]; } + if (ckeyps[i] && ckeyps[i][0]) keys[i] = ckeyps[i]; } // Ignore empty keys for (int i = 0; i < MAX_KEYS; ++i) { diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 8f2ba2cfd..c205ceda8 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -94,7 +94,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE { m_code2symbol.clear(); // Allocate string buffer for arrays - if (!m_strbuf) { m_strbuf = new char[maxBits() + 32]; } + if (!m_strbuf) m_strbuf = new char[maxBits() + 32]; } void VerilatedFst::close() { diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 7e938cf19..feb261606 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -74,7 +74,7 @@ public: // Non blocking get bool tryGet(T& result) { const VerilatedLockGuard lockGuard(m_mutex); - if (m_queue.empty()) { return false; } + if (m_queue.empty()) return false; result = m_queue.front(); m_queue.pop_front(); return true; diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 2d757bb11..c59468167 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -138,7 +138,9 @@ void VerilatedVcd::openNext(bool incFilename) { name[pos - 2] = '0'; if ((++(name[pos - 3])) > '9') { name[pos - 3] = '0'; - if ((++(name[pos - 4])) > '9') { name[pos - 4] = '0'; } + if ((++(name[pos - 4])) > '9') { // + name[pos - 4] = '0'; + } } } } @@ -164,7 +166,7 @@ void VerilatedVcd::openNext(bool incFilename) { } bool VerilatedVcd::preChangeDump() { - if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > m_rolloverMB)) { openNext(true); } + if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > m_rolloverMB)) openNext(true); return isOpen(); } diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 6c7408691..ec42fae9b 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -84,7 +84,7 @@ private: inline void bufferCheck() { // Flush the write buffer if there's not enough space left for new information // We only call this once per vector, so we need enough slop for a very wide "b###" line - if (VL_UNLIKELY(m_writep > m_wrFlushp)) { bufferFlush(); } + if (VL_UNLIKELY(m_writep > m_wrFlushp)) bufferFlush(); } void closePrev(); void closeErr(); diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index cb2a0c032..1ed63e9a0 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -742,7 +742,7 @@ PLI_INT32 VerilatedVpioReasonCb::dovpi_remove_cb() { VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE { VerilatedVpiImp::assertOneCheck(); - if (VL_UNLIKELY(!s_s.m_errorInfop)) { s_s.m_errorInfop = new VerilatedVpiError(); } + if (VL_UNLIKELY(!s_s.m_errorInfop)) s_s.m_errorInfop = new VerilatedVpiError(); return s_s.m_errorInfop; } @@ -1235,7 +1235,7 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { if (scopename.find('.') == std::string::npos) { // This is a toplevel, hence search in our TOP ports first. scopep = Verilated::scopeFind("TOP"); - if (scopep) { varp = scopep->varFind(baseNamep); } + if (scopep) varp = scopep->varFind(baseNamep); } if (!varp) { scopep = Verilated::scopeFind(scopename.c_str()); diff --git a/src/V3Active.cpp b/src/V3Active.cpp index a0d3de8fd..b918b7249 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -176,7 +176,7 @@ public: for (const auto& vrp : m_outputs) { LatchDetectGraphVertex* vertp = castVertexp(vrp->varp()->user1p()); vertp->user(true); // Identify the output vertex we are checking paths _to_ - if (!latchCheckInternal(castVertexp(verticesBeginp()))) { latch_detected = true; } + if (!latchCheckInternal(castVertexp(verticesBeginp()))) latch_detected = true; if (latch_detected && !latch_expected) { nodep->v3warn( LATCH, @@ -185,7 +185,7 @@ public: << " (not all control paths of combinational always assign a value)\n" << nodep->warnMore() << "... Suggest use of always_latch for intentional latches"); - if (debug() >= 9) { dumpDotFilePrefixed("latch_" + vrp->name()); } + if (debug() >= 9) dumpDotFilePrefixed("latch_" + vrp->name()); } vertp->user(false); // Clear again (see above) vrp->varp()->isLatched(latch_detected); diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 307081add..9049d6146 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -148,7 +148,7 @@ private: AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); - if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); } + if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); AstNode* past = new AstPast(fl, lhsp, nullptr); past->dtypeFrom(lhsp); diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 3c72a8d80..31f0b4d42 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1104,7 +1104,7 @@ void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) con os << indent << " "; dumpPtrs(os); } - if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); } + if (s_debugFileline >= 9) os << fileline()->warnContextSecondary(); if (maxDepth == 1) { if (op1p() || op2p() || op3p() || op4p()) os << indent << "1: ...(maxDepth)\n"; } else { diff --git a/src/V3Ast.h b/src/V3Ast.h index 1718191e5..258fb40c5 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1706,7 +1706,7 @@ public: } } void dtypeFrom(AstNode* fromp) { - if (fromp) { dtypep(fromp->dtypep()); } + if (fromp) dtypep(fromp->dtypep()); } void dtypeChgSigned(bool flag = true); void dtypeChgWidth(int width, int widthMin); @@ -2547,7 +2547,7 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstNodeArrayDType* asamep = static_cast(samep); @@ -2614,7 +2614,7 @@ class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { public: AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop{t, fl, lhsp, rhsp} { - if (lhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); } + if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); } ASTNODE_BASE_FUNCS(NodeStream) }; @@ -2811,7 +2811,7 @@ public: ASTNODE_BASE_FUNCS(NodeFTaskRef) virtual const char* broken() const override; virtual void cloneRelink() override { - if (m_taskp && m_taskp->clonep()) { m_taskp = m_taskp->clonep(); } + if (m_taskp && m_taskp->clonep()) m_taskp = m_taskp->clonep(); } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } // * = Var name diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 262b0421b..db091b09b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -50,7 +50,7 @@ const char* AstNodeVarRef::broken() const { } void AstNodeVarRef::cloneRelink() { - if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); } + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); } string AstNodeVarRef::hiernameProtect() const { @@ -99,7 +99,7 @@ void AstNodeCCall::dump(std::ostream& str) const { } } void AstNodeCCall::cloneRelink() { - if (m_funcp && m_funcp->clonep()) { m_funcp = m_funcp->clonep(); } + if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep(); } const char* AstNodeCCall::broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); @@ -1098,7 +1098,7 @@ void AstNode::dump(std::ostream& str) const { } else { str << " @dt=" << nodeAddr(dtypep()) << "@"; } - if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); } + if (AstNodeDType* dtp = dtypep()) dtp->dumpSmall(str); } else { // V3Broken will throw an error if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep()); } @@ -1230,9 +1230,9 @@ void AstEnumItemRef::dump(std::ostream& str) const { } void AstIfaceRefDType::dump(std::ostream& str) const { this->AstNode::dump(str); - if (cellName() != "") { str << " cell=" << cellName(); } - if (ifaceName() != "") { str << " if=" << ifaceName(); } - if (modportName() != "") { str << " mp=" << modportName(); } + if (cellName() != "") str << " cell=" << cellName(); + if (ifaceName() != "") str << " if=" << ifaceName(); + if (modportName() != "") str << " mp=" << modportName(); if (cellp()) { str << " -> "; cellp()->dump(str); @@ -1388,7 +1388,7 @@ void AstNodeDType::dump(std::ostream& str) const { void AstNodeDType::dumpSmall(std::ostream& str) const { str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "") << (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : ""); - if (!isDouble() && !isString()) { str << "w" << (widthSized() ? "" : "u") << width(); } + if (!isDouble() && !isString()) str << "w" << (widthSized() ? "" : "u") << width(); if (!widthSized()) str << "/" << widthMin(); str << ")"; } @@ -1640,7 +1640,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); str << " -> "; - if (dotted() != "") { str << ".=" << dotted() << " "; } + if (dotted() != "") str << ".=" << dotted() << " "; if (taskp()) { taskp()->dump(str); } else { @@ -1676,7 +1676,7 @@ void AstCoverDecl::dump(std::ostream& str) const { str << " -> "; this->dataDeclNullp()->dump(str); } else { - if (binNum()) { str << " bin" << std::dec << binNum(); } + if (binNum()) str << " bin" << std::dec << binNum(); } } void AstCoverInc::dump(std::ostream& str) const { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index eacbdbf8b..efaca0cec 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -539,8 +539,8 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } - if (m_keyDTypep && m_keyDTypep->clonep()) { m_keyDTypep = m_keyDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); + if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); @@ -641,7 +641,7 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); @@ -760,7 +760,7 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstNodeArrayDType* asamep = static_cast(samep); @@ -971,7 +971,7 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstConstDType* sp = static_cast(samep); @@ -1140,7 +1140,7 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstQueueDType* asamep = static_cast(samep); @@ -1217,8 +1217,8 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_typedefp && m_typedefp->clonep()) { m_typedefp = m_typedefp->clonep(); } - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep(); + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstRefDType* asamep = static_cast(samep); @@ -1486,7 +1486,7 @@ public: return nullptr; } virtual void cloneRelink() override { - if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } + if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } virtual bool same(const AstNode* samep) const override { const AstEnumDType* sp = static_cast(samep); @@ -2047,7 +2047,7 @@ public: , m_origName{name} { init(); combineType(type); - if (examplep->childDTypep()) { childDTypep(examplep->childDTypep()->cloneTree(true)); } + if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true)); dtypeFrom(examplep); m_declKwd = examplep->declKwd(); } @@ -2677,7 +2677,7 @@ public: } ASTNODE_NODE_FUNCS(MemberSel) virtual void cloneRelink() override { - if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); } + if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep(); } virtual const char* broken() const override { BROKEN_RTN(m_varp && !m_varp->brokeExists()); @@ -7294,7 +7294,7 @@ class AstShiftL final : public AstNodeBiop { public: AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { - if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ShiftL) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7318,7 +7318,7 @@ class AstShiftR final : public AstNodeBiop { public: AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { - if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ShiftR) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7346,7 +7346,7 @@ public: AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { // Important that widthMin be correct, as opExtend requires it after V3Expand - if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::SIGNED); } + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); } ASTNODE_NODE_FUNCS(ShiftRS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -9048,7 +9048,7 @@ public: , m_cleanOut{cleanOut} , m_pure{true} { addNOp1p(new AstText(fl, textStmt, true)); - if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } + if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(CMath) virtual bool isGateOptimizable() const override { return m_pure; } diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 49556d404..2aa30b2f7 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -81,7 +81,7 @@ public: m_tlFuncp->isStatic(false); m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path m_tlFuncp->argTypes(m_argsp); - if (stmt != "") { m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); } + if (stmt != "") m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); m_funcp = m_tlFuncp; m_modp->addStmtp(m_tlFuncp); } diff --git a/src/V3Case.cpp b/src/V3Case.cpp index d40c6eb0e..1b3122d7d 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -484,7 +484,7 @@ private: } //-------------------- virtual void visit(AstNode* nodep) override { - if (VN_IS(nodep, Always)) { m_alwaysp = nodep; } + if (VN_IS(nodep, Always)) m_alwaysp = nodep; iterateChildren(nodep); } diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 95b44887f..9139c5eb5 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -599,7 +599,7 @@ private: } } // If multiple domains need to do complicated optimizations - if (senedited) { senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); } + if (senedited) senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); if (traceDests) { vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that vertexp->dstDomainp(senoutp); diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 065f55197..ba0b91d6c 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -162,10 +162,10 @@ private: void operandQuadop(AstNodeQuadop* nodep) { iterateChildren(nodep); computeCppWidth(nodep); - if (nodep->cleanLhs()) { ensureClean(nodep->lhsp()); } - if (nodep->cleanRhs()) { ensureClean(nodep->rhsp()); } - if (nodep->cleanThs()) { ensureClean(nodep->thsp()); } - if (nodep->cleanFhs()) { ensureClean(nodep->fhsp()); } + if (nodep->cleanLhs()) ensureClean(nodep->lhsp()); + if (nodep->cleanRhs()) ensureClean(nodep->rhsp()); + if (nodep->cleanThs()) ensureClean(nodep->thsp()); + if (nodep->cleanFhs()) ensureClean(nodep->fhsp()); // no setClean.. must do it in each user routine. } diff --git a/src/V3Config.cpp b/src/V3Config.cpp index b0f035cd2..40b7985d7 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -61,7 +61,7 @@ public: T* resolve(const string& name) { // Lookup if it was resolved before, typically not auto it = m_mapResolved.find(name); - if (VL_UNLIKELY(it != m_mapResolved.end())) { return &it->second; } + if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second; T* newp = nullptr; // Cannot be resolved, create if matched diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 096209936..a8f7b5722 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2215,8 +2215,8 @@ private: if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true; if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false; // But might be same name with different scopes - if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) { return true; } - if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) { return false; } + if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) return true; + if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) return false; // Or rarely, different data types if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true; if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false; @@ -2602,7 +2602,7 @@ private: // Ignored, can eliminate early virtual void visit(AstSysIgnore* nodep) override { iterateChildren(nodep); - if (m_doNConst) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } + if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } // Simplify diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 237da3a1c..c9aa2bc88 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -60,7 +60,7 @@ private: int instances = 0; for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (VN_IS(stmtp, Scope)) { - if (++instances > 1) { return false; } + if (++instances > 1) return false; } } return (instances == 1); diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 8a9ab194b..89c6bc609 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -1035,8 +1035,8 @@ public: emitIQW(nodep); puts("OI("); puts(cvtToStr(nodep->widthMin())); - if (nodep->lhsp()) { puts("," + cvtToStr(nodep->lhsp()->widthMin())); } - if (nodep->rhsp()) { puts("," + cvtToStr(nodep->rhsp()->widthMin())); } + if (nodep->lhsp()) puts("," + cvtToStr(nodep->lhsp()->widthMin())); + if (nodep->rhsp()) puts("," + cvtToStr(nodep->rhsp()->widthMin())); puts(","); iterateAndNextNull(nodep->lhsp()); puts(", "); @@ -2026,7 +2026,7 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, nextComma = ","; needComma = false; } - if (pos[1] == ' ') { ++pos; } // Must do even if no nextComma + if (pos[1] == ' ') ++pos; // Must do even if no nextComma } else if (pos[0] == '%') { ++pos; bool detail = false; @@ -3877,7 +3877,7 @@ public: // Put out the file newOutCFile(0); - if (m_slow) { emitTraceSlow(); } + if (m_slow) emitTraceSlow(); iterate(v3Global.rootp()); diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index ebf8c07c9..e9097abde 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -58,7 +58,7 @@ class CMakeEmitter final { static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value, const string& cache_type = "", const string& docstring = "") { of << "set(" << name << " " << raw_value; - if (!cache_type.empty()) { of << " CACHE " << cache_type << " \"" << docstring << "\""; } + if (!cache_type.empty()) of << " CACHE " << cache_type << " \"" << docstring << "\""; of << ")\n"; } diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index d6392ef64..d9c0882b0 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -332,7 +332,7 @@ class EmitCSyms final : EmitCBaseVisitor { virtual void visit(AstVar* nodep) override { nameCheck(nodep); iterateChildren(nodep); - if (nodep->isSigUserRdPublic()) { m_modVars.emplace_back(make_pair(m_modp, nodep)); } + if (nodep->isSigUserRdPublic()) m_modVars.emplace_back(make_pair(m_modp, nodep)); } virtual void visit(AstCoverDecl* nodep) override { // Assign numbers to all bins, so we know how big of an array to use @@ -620,7 +620,7 @@ void EmitCSyms::emitSymImp() { + "& os) {\n"); puts("// LOCAL STATE\n"); // __Vm_namep presumably already correct - if (v3Global.opt.trace()) { puts("os" + op + "__Vm_activity;\n"); } + if (v3Global.opt.trace()) puts("os" + op + "__Vm_activity;\n"); puts("os" + op + "__Vm_didInit;\n"); puts("// SUBCELL STATE\n"); for (std::vector::iterator it = m_scopes.begin(); it != m_scopes.end(); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 6622d17e6..ab5ebabc2 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -101,10 +101,10 @@ public: // have them. } else if (support == 2 && !slow) { putMakeClassEntry(of, "verilated.cpp"); - if (v3Global.dpi()) { putMakeClassEntry(of, "verilated_dpi.cpp"); } - if (v3Global.opt.vpi()) { putMakeClassEntry(of, "verilated_vpi.cpp"); } - if (v3Global.opt.savable()) { putMakeClassEntry(of, "verilated_save.cpp"); } - if (v3Global.opt.coverage()) { putMakeClassEntry(of, "verilated_cov.cpp"); } + if (v3Global.dpi()) putMakeClassEntry(of, "verilated_dpi.cpp"); + if (v3Global.opt.vpi()) putMakeClassEntry(of, "verilated_vpi.cpp"); + if (v3Global.opt.savable()) putMakeClassEntry(of, "verilated_save.cpp"); + if (v3Global.opt.coverage()) putMakeClassEntry(of, "verilated_cov.cpp"); if (v3Global.opt.trace()) { putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp"); if (v3Global.opt.systemC()) { @@ -117,7 +117,7 @@ public: } } } - if (v3Global.opt.mtasks()) { putMakeClassEntry(of, "verilated_threads.cpp"); } + if (v3Global.opt.mtasks()) putMakeClassEntry(of, "verilated_threads.cpp"); } else if (support == 2 && slow) { } else { for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 026d48d16..238341569 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -815,7 +815,7 @@ public: AstSenTree* domainp, bool user3mark) : EmitVBaseVisitor{false, domainp} , m_formatter{os, prefix, flWidth} { - if (user3mark) { AstUser3InUse::check(); } + if (user3mark) AstUser3InUse::check(); iterate(nodep); } virtual ~EmitVPrefixedVisitor() override = default; diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 27770caa5..e02173e09 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -55,7 +55,7 @@ class EmitXmlFileVisitor final : public AstNVisitor { // XML methods void outputId(AstNode* nodep) { - if (!nodep->user1()) { nodep->user1(++m_id); } + if (!nodep->user1()) nodep->user1(++m_id); puts("\"" + cvtToStr(nodep->user1()) + "\""); } void outputTag(AstNode* nodep, const string& tagin) { @@ -336,7 +336,7 @@ private: } } virtual void visit(AstCell* nodep) override { - if (nodep->modp()->dead()) { return; } + if (nodep->modp()->dead()) return; if (!m_hasChildren) m_os << ">\n"; m_os << "fileline()->xml() << " " << nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\"" diff --git a/src/V3Error.h b/src/V3Error.h index 9f3b8daee..374bc4415 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -364,12 +364,12 @@ inline void v3errorEndFatal(std::ostringstream& sstr) { // Assertion without object, generally UOBJASSERT preferred #define UASSERT(condition, stmsg) \ do { \ - if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); } \ + if (VL_UNCOVERABLE(!(condition))) v3fatalSrc(stmsg); \ } while (false) // Assertion with object #define UASSERT_OBJ(condition, obj, stmsg) \ do { \ - if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); } \ + if (VL_UNCOVERABLE(!(condition))) (obj)->v3fatalSrc(stmsg); \ } while (false) // For use in V3Ast static functions only #define UASSERT_STATIC(condition, stmsg) \ diff --git a/src/V3File.cpp b/src/V3File.cpp index d04a70b8e..9b39bd425 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -320,7 +320,7 @@ void V3File::createMakeDir() { if (!created) { created = true; V3Os::createDir(v3Global.opt.makeDir()); - if (v3Global.opt.hierTop()) { V3Os::createDir(v3Global.opt.hierTopDataDir()); } + if (v3Global.opt.hierTop()) V3Os::createDir(v3Global.opt.hierTopDataDir()); } } @@ -787,11 +787,11 @@ void V3OutFormatter::puts(const char* strg) { wordstart = false; break; case 'e': - if (wordstart && m_lang == LA_VERILOG && tokenEnd(cp)) { indentDec(); } + if (wordstart && m_lang == LA_VERILOG && tokenEnd(cp)) indentDec(); wordstart = false; break; case 'm': - if (wordstart && m_lang == LA_VERILOG && tokenStart(cp, "module")) { indentInc(); } + if (wordstart && m_lang == LA_VERILOG && tokenStart(cp, "module")) indentInc(); wordstart = false; break; default: wordstart = false; break; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index aabcea844..272277948 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -338,7 +338,7 @@ void FileLine::modifyStateInherit(const FileLine* fromp) { // Any warnings that are off in "from", become off in "this". for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) { V3ErrorCode code = V3ErrorCode(codei); - if (fromp->warnIsOff(code)) { warnOff(code, true); } + if (fromp->warnIsOff(code)) warnOff(code, true); } } @@ -358,7 +358,7 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { } else if (!V3Error::errorContexted()) { nsstr << warnContextPrimary(); } - if (!m_waive) { V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str()); } + if (!m_waive) V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str()); V3Error::v3errorEnd(nsstr, lstr.str()); } diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e03443083..3c1a92e9e 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -264,7 +264,7 @@ private: virtual void visit(AstNode* nodep) override { // *** Special iterator if (!m_isSimple) return; // Fastpath - if (++m_ops > v3Global.opt.gateStmts()) { clearSimple("--gate-stmts exceeded"); } + if (++m_ops > v3Global.opt.gateStmts()) clearSimple("--gate-stmts exceeded"); if (!(m_dedupe ? nodep->isGateDedupable() : nodep->isGateOptimizable()) // || !nodep->isPure() || nodep->isBrancher()) { UINFO(5, "Non optimizable type: " << nodep << endl); @@ -282,7 +282,7 @@ public: // Iterate iterate(nodep); // Check results - if (!m_substTreep) { clearSimple("No assignment found\n"); } + if (!m_substTreep) clearSimple("No assignment found\n"); for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin(); it != m_rhsVarRefs.end(); ++it) { if (m_lhsVarRef && m_lhsVarRef->varScopep() == (*it)->varScopep()) { diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 76ab948b1..c4e28599d 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -377,7 +377,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { << (edgep->dotLabel() != "" ? edgep->dotLabel() : "") << "\"" << " weight=" << edgep->weight() << " color=" << edgep->dotColor(); if (edgep->dotStyle() != "") *logp << " style=" << edgep->dotStyle(); - // if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without + // if (edgep->cutable()) *logp << ",constraint=false"; // to rank without // following edges *logp << "];\n"; } diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index 7cc32dd55..f1e769f97 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -271,7 +271,9 @@ private: } for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { - if (!vertexp->user()) { vertexIterate(vertexp, 1); } + if (!vertexp->user()) { // + vertexIterate(vertexp, 1); + } } } diff --git a/src/V3GraphDfa.cpp b/src/V3GraphDfa.cpp index ad77d1c60..555c19d94 100644 --- a/src/V3GraphDfa.cpp +++ b/src/V3GraphDfa.cpp @@ -445,7 +445,7 @@ private: for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp; vertexp = nextp) { nextp = vertexp->verticesNextp(); - if (!vertexp->user()) { VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); } + if (!vertexp->user()) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); } } diff --git a/src/V3GraphStream.h b/src/V3GraphStream.h index 06e887699..b58ea458a 100644 --- a/src/V3GraphStream.h +++ b/src/V3GraphStream.h @@ -175,7 +175,7 @@ public: // Wrap curIt. Expect to wrap, and make another pass, to find // newly-ready elements that could have appeared ahead of the // m_last iterator - if (curIt == m_readyVertices.end()) { curIt = m_readyVertices.begin(); } + if (curIt == m_readyVertices.end()) curIt = m_readyVertices.begin(); } if (curIt != m_readyVertices.end()) { diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index 3f12fcfe4..3dd3f730e 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -224,7 +224,7 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const { for (const auto& hierblockp : m_children) *of << hierblockp->hierBlockArgs().front() << "\n"; // Hierarchical blocks should not use multi-threading, // but needs to be thread safe when top is multi-threaded. - if (v3Global.opt.threads() > 0) { *of << "--threads 1\n"; } + if (v3Global.opt.threads() > 0) *of << "--threads 1\n"; *of << v3Global.opt.allArgsStringForHierBlock(false) << "\n"; } diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index f9ea8c53d..e1ba954db 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -381,8 +381,8 @@ private: string name = m_cellp->name() + "__DOT__" + nodep->name(); if (!nodep->isFuncLocal() && !nodep->isClassMember()) nodep->inlineAttrReset(name); if (!m_cellp->isTrace()) nodep->trace(false); - if (debug() >= 9) { nodep->dumpTree(cout, "varchanged:"); } - if (debug() >= 9 && nodep->valuep()) { nodep->valuep()->dumpTree(cout, "varchangei:"); } + if (debug() >= 9) nodep->dumpTree(cout, "varchanged:"); + if (debug() >= 9 && nodep->valuep()) nodep->valuep()->dumpTree(cout, "varchangei:"); iterateChildren(nodep); } virtual void visit(AstNodeFTask* nodep) override { @@ -595,7 +595,7 @@ private: // Cleanup var names, etc, to not conflict { InlineRelinkVisitor(newmodp, m_modp, nodep); } // Move statements to top module - if (debug() >= 9) { newmodp->dumpTree(cout, "fixmod:"); } + if (debug() >= 9) newmodp->dumpTree(cout, "fixmod:"); AstNode* stmtsp = newmodp->stmtsp(); if (stmtsp) stmtsp->unlinkFrBackWithNext(); if (stmtsp) m_modp->addStmtp(stmtsp); @@ -603,7 +603,7 @@ private: VL_DO_DANGLING(newmodp->deleteTree(), newmodp); // Clear any leftover ports, etc nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); - if (debug() >= 9) { m_modp->dumpTree(cout, "donemod:"); } + if (debug() >= 9) m_modp->dumpTree(cout, "donemod:"); } } @@ -638,7 +638,7 @@ private: // VISITORS virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); } virtual void visit(AstModule* nodep) override { - if (nodep->isTop()) { iterateChildren(nodep); } + if (nodep->isTop()) iterateChildren(nodep); } virtual void visit(AstCell* nodep) override { VL_RESTORER(m_scope); diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index bec64d058..055c710ad 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -543,7 +543,7 @@ public: // Done. Constant. } else { // Make a new temp wire - // if (1 || debug() >= 9) { pinp->dumpTree(cout, "-in_pin:"); } + // if (1 || debug() >= 9) pinp->dumpTree(cout, "-in_pin:"); V3Inst::checkOutputShort(pinp); AstNode* pinexprp = pinp->exprp()->unlinkFrBack(); string newvarname @@ -575,8 +575,8 @@ public: pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, VAccess::READ)); } if (assignp) cellp->addNextHere(assignp); - // if (debug()) { pinp->dumpTree(cout, "- out:"); } - // if (debug()) { assignp->dumpTree(cout, "- aout:"); } + // if (debug()) pinp->dumpTree(cout, "- out:"); + // if (debug()) assignp->dumpTree(cout, "- aout:"); } return assignp; } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 1dc7865d6..c578335c7 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -110,8 +110,8 @@ public: bool operator<(const LifeLocation& b) const { unsigned a_id = mtaskp ? mtaskp->id() : 0; unsigned b_id = b.mtaskp ? b.mtaskp->id() : 0; - if (a_id < b_id) { return true; } - if (b_id < a_id) { return false; } + if (a_id < b_id) return true; + if (b_id < a_id) return false; return sequence < b.sequence; } }; diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index ef716e74f..0578e5bc7 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -453,7 +453,9 @@ private: nodep->hasIfaceVar(true); } } - if (nodep->modp()) { iterateChildren(nodep); } + if (nodep->modp()) { // + iterateChildren(nodep); + } UINFO(4, " Link Cell done: " << nodep << endl); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0c283904a..f6dafdc1b 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -369,7 +369,7 @@ public: symp->classOrPackagep(classOrPackagep); symp->fallbackp(abovep); nodep->user1p(symp); - if (name != "") { checkDuplicate(abovep, nodep, name); } + if (name != "") checkDuplicate(abovep, nodep, name); // Duplicates are possible, as until resolve generates might have 2 same cells under an if abovep->reinsert(name, symp); return symp; @@ -409,7 +409,7 @@ public: // Mark the given variable name as being allowed to be implicitly declared if (nodep) { const auto it = m_implicitNameSet.find(make_pair(nodep, varname)); - if (it == m_implicitNameSet.end()) { m_implicitNameSet.emplace(nodep, varname); } + if (it == m_implicitNameSet.end()) m_implicitNameSet.emplace(nodep, varname); } } bool implicitOk(AstNodeModule* nodep, const string& varname) { @@ -2107,7 +2107,7 @@ private: && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { m_ds.m_unlinkedScopep = nodep->lhsp(); } - if (VN_IS(nodep->lhsp(), LambdaArgRef)) { m_ds.m_unlinkedScopep = nodep->lhsp(); } + if (VN_IS(nodep->lhsp(), LambdaArgRef)) m_ds.m_unlinkedScopep = nodep->lhsp(); if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a // DOT(DOT(x,*here*),real-rhs) which we consider a RHS @@ -2152,7 +2152,7 @@ private: // Generally resolved during Primay, but might be at param time under AstUnlinkedRef UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep, "ParseRefs should no longer exist"); - if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); } + if (nodep->name() == "super") nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); DotStates lastStates = m_ds; bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed if (start) { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 976d2768d..f2f4c33a2 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -134,7 +134,7 @@ private: iterateChildren(nodep); } m_ftaskp = nullptr; - if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); } + if (nodep->dpiExport()) nodep->scopeNamep(new AstScopeName(nodep->fileline())); } virtual void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 873048ee1..0cb527c42 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -147,7 +147,7 @@ private: return condp; } else if (AstAnd* const andp = VN_CAST(rhsp, And)) { if (AstNodeCond* const condp = VN_CAST(andp->rhsp(), NodeCond)) { - if (VN_IS(andp->lhsp(), Const)) { return condp; } + if (VN_IS(andp->lhsp(), Const)) return condp; } } return nullptr; @@ -174,7 +174,9 @@ private: } else if (AstNodeCond* const condp = extractCond(rhsp)) { AstNode* const resp = condTrue ? condp->expr1p()->unlinkFrBack() : condp->expr2p()->unlinkFrBack(); - if (condp == rhsp) { return resp; } + if (condp == rhsp) { // + return resp; + } if (AstAnd* const andp = VN_CAST(rhsp, And)) { UASSERT_OBJ(andp->rhsp() == condp, rhsp, "Should not try to fold this"); return new AstAnd(andp->fileline(), andp->lhsp()->cloneTree(false), resp); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 819e47339..91a52ece2 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -401,7 +401,7 @@ V3Number& V3Number::setLongS(vlsint32_t value) { return *this; } V3Number& V3Number::setDouble(double value) { - if (VL_UNCOVERABLE(width() != 64)) { v3fatalSrc("Real operation on wrong sized number"); } + if (VL_UNCOVERABLE(width() != 64)) v3fatalSrc("Real operation on wrong sized number"); m_double = true; union { double d; @@ -951,10 +951,10 @@ bool V3Number::isAnyZ() const { bool V3Number::isLtXZ(const V3Number& rhs) const { // Include X/Z in comparisons for sort ordering for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { - if (this->bitIs1(bit) && rhs.bitIs0(bit)) { return true; } - if (rhs.bitIs1(bit) && this->bitIs0(bit)) { return false; } - if (this->bitIsXZ(bit)) { return true; } - if (rhs.bitIsXZ(bit)) { return false; } + if (this->bitIs1(bit) && rhs.bitIs0(bit)) return true; + if (rhs.bitIs1(bit) && this->bitIs0(bit)) return false; + if (this->bitIsXZ(bit)) return true; + if (rhs.bitIsXZ(bit)) return false; } return false; } @@ -1347,14 +1347,14 @@ V3Number& V3Number::opLogAnd(const V3Number& lhs, const V3Number& rhs) { loutc = 1; break; } - if (lhs.bitIsXZ(bit) && loutc == 0) { loutc = 'x'; } + if (lhs.bitIsXZ(bit) && loutc == 0) loutc = 'x'; } for (int bit = 0; bit < rhs.width(); bit++) { if (rhs.bitIs1(bit)) { routc = 1; break; } - if (rhs.bitIsXZ(bit) && routc == 0) { routc = 'x'; } + if (rhs.bitIsXZ(bit) && routc == 0) routc = 'x'; } char outc = 'x'; if (routc == 1 && loutc == 1) outc = 1; @@ -1528,7 +1528,7 @@ bool V3Number::isCaseEq(const V3Number& rhs) const { if (this->width() != rhs.width()) return false; for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { - if (this->bitIs(bit) != rhs.bitIs(bit)) { return false; } + if (this->bitIs(bit) != rhs.bitIs(bit)) return false; } return true; } diff --git a/src/V3Number_test.cpp b/src/V3Number_test.cpp index 74055f5c1..07ba971e8 100644 --- a/src/V3Number_test.cpp +++ b/src/V3Number_test.cpp @@ -110,7 +110,7 @@ void test(const string& lhss, const string& op, const string& rhss, const string V3Number ok(fl, 1); ok.opCaseEq(expnum, gotnum); - if (ok.toUInt() != 1) { v3fatalSrc("%Error:Test FAILED"); } + if (ok.toUInt() != 1) v3fatalSrc("%Error:Test FAILED"); free(l1); free(r1); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 5eebd637e..99f6489e2 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1370,7 +1370,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char string msg = sw + strlen("-Werror-"); V3ErrorCode code(msg.c_str()); if (code == V3ErrorCode::EC_ERROR) { - if (!isFuture(msg)) { fl->v3fatal("Unknown warning specified: " << sw); } + if (!isFuture(msg)) fl->v3fatal("Unknown warning specified: " << sw); } else { V3Error::pretendError(code, true); } @@ -1403,7 +1403,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char string msg = sw + strlen("-Wwarn-"); V3ErrorCode code(msg.c_str()); if (code == V3ErrorCode::EC_ERROR) { - if (!isFuture(msg)) { fl->v3fatal("Unknown warning specified: " << sw); } + if (!isFuture(msg)) fl->v3fatal("Unknown warning specified: " << sw); } else { FileLine::globalWarnOff(code, false); V3Error::pretendError(code, false); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index c8509fa72..4612cf44b 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -487,7 +487,7 @@ public: for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) { if (OrderLogicVertex* lvertexp = dynamic_cast(itp)) { T_MoveVertex* moveVxp = m_logic2move[lvertexp]; - if (moveVxp) { iterate(moveVxp, lvertexp, lvertexp->domainp()); } + if (moveVxp) iterate(moveVxp, lvertexp, lvertexp->domainp()); } } } @@ -1661,7 +1661,7 @@ void OrderVisitor::processMovePrepReady() { UINFO(5, " MovePrepReady\n"); for (OrderMoveVertex* vertexp = m_pomWaiting.begin(); vertexp;) { OrderMoveVertex* nextp = vertexp->pomWaitingNextp(); - if (vertexp->isWait() && vertexp->inEmpty()) { processMoveReadyOne(vertexp); } + if (vertexp->isWait() && vertexp->inEmpty()) processMoveReadyOne(vertexp); vertexp = nextp; } } diff --git a/src/V3Os.cpp b/src/V3Os.cpp index df66d97de..c3648025b 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -271,7 +271,7 @@ string V3Os::trueRandom(size_t size) { #if defined(_WIN32) || defined(__MINGW32__) NTSTATUS hr = BCryptGenRandom(nullptr, reinterpret_cast(data), size, BCRYPT_USE_SYSTEM_PREFERRED_RNG); - if (!BCRYPT_SUCCESS(hr)) { v3fatal("Could not acquire random data."); } + if (!BCRYPT_SUCCESS(hr)) v3fatal("Could not acquire random data."); #else std::ifstream is("/dev/urandom", std::ios::in | std::ios::binary); // This read uses the size of the buffer. diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index e19325194..349fd6cc3 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -178,7 +178,7 @@ void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) { string V3ParseImp::lexParseTag(const char* textp) { string tmp = textp + strlen("/*verilator tag "); string::size_type pos; - if ((pos = tmp.rfind("*/")) != string::npos) { tmp.erase(pos); } + if ((pos = tmp.rfind("*/")) != string::npos) tmp.erase(pos); return tmp; } @@ -468,7 +468,7 @@ void V3ParseImp::tokenPipeline() { V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead { size_t depth = tokenPipeScanParam(0); - if (tokenPeekp(depth)->token == yP_COLONCOLON) { token = yaID__CC; } + if (tokenPeekp(depth)->token == yP_COLONCOLON) token = yaID__CC; } yylval = curValue; } diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index eedae87c1..a53f3d569 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -64,7 +64,7 @@ void V3ParseImp::yylexReadTok() { void V3ParseImp::lexNew() { if (m_lexerp) delete m_lexerp; // Restart from clean slate. m_lexerp = new V3Lexer(); - if (debugFlex() >= 9) { m_lexerp->set_debug(~0); } + if (debugFlex() >= 9) m_lexerp->set_debug(~0); } void V3ParseImp::lexDestroy() { diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index bf3c0b410..d8a2c6e5b 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -749,8 +749,8 @@ public: || LogicMTask::pathExistsFrom(m_bp, m_ap, nullptr)); } bool operator<(const SiblingMC& other) const { - if (m_ap->id() < other.m_ap->id()) { return true; } - if (m_ap->id() > other.m_ap->id()) { return false; } + if (m_ap->id() < other.m_ap->id()) return true; + if (m_ap->id() > other.m_ap->id()) return false; return m_bp->id() < other.m_bp->id(); } }; @@ -1245,7 +1245,7 @@ private: for (SibpSet::iterator it = m_mtask2sibs[mtaskp].begin(); it != m_mtask2sibs[mtaskp].end(); ++it) { const SiblingMC* pairp = *it; - if (!pairp->removedFromSb()) { m_sb.removeElem(pairp); } + if (!pairp->removedFromSb()) m_sb.removeElem(pairp); LogicMTask* otherp = (pairp->bp() == mtaskp) ? pairp->ap() : pairp->bp(); size_t erased = m_mtask2sibs[otherp].erase(pairp); UASSERT_OBJ(erased > 0, otherp, "Expected existing mtask"); @@ -1409,7 +1409,7 @@ private: return 1 + edgeScore(edgep); } const SiblingMC* sibsp = dynamic_cast(pairp); - if (sibsp) { return siblingScore(sibsp); } + if (sibsp) return siblingScore(sibsp); v3fatalSrc("Failed to cast pairp to either MTaskEdge or SiblingMC in mergeCandidateScore"); return 0; } @@ -1472,10 +1472,10 @@ private: const LogicMTask* bp = *reinterpret_cast(vbp); uint32_t aCp = ap->critPathCost(*wp) + ap->stepCost(); uint32_t bCp = bp->critPathCost(*wp) + bp->stepCost(); - if (aCp < bCp) { return -1; } - if (aCp > bCp) { return 1; } - if (ap->id() < bp->id()) { return -1; } - if (ap->id() > bp->id()) { return 1; } + if (aCp < bCp) return -1; + if (aCp > bCp) return 1; + if (ap->id() < bp->id()) return -1; + if (ap->id() > bp->id()) return 1; return 0; } @@ -1534,7 +1534,7 @@ private: for (unsigned i = 0; i < chain_len; ++i) { LogicMTask* mtp = new LogicMTask(&mtasks, nullptr); mtp->setCost(1); - if (lastp) { new MTaskEdge(&mtasks, lastp, mtp, 1); } + if (lastp) new MTaskEdge(&mtasks, lastp, mtp, 1); lastp = mtp; } partInitCriticalPaths(&mtasks); @@ -1802,7 +1802,7 @@ private: ++it) { LogicMTask* mtaskp = *it; if (mergedp) { - if (mergedp->cost() < mtaskp->cost()) { mergedp = mtaskp; } + if (mergedp->cost() < mtaskp->cost()) mergedp = mtaskp; } else { mergedp = mtaskp; } @@ -1983,7 +1983,7 @@ public: for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { LogicMTask* mtaskp = dynamic_cast(vxp); - if (hasDpiHazard(mtaskp)) { tasksByRank[vxp->rank()].insert(mtaskp); } + if (hasDpiHazard(mtaskp)) tasksByRank[vxp->rank()].insert(mtaskp); } mergeSameRankTasks(&tasksByRank); } @@ -2415,7 +2415,7 @@ void V3Partition::go(V3Graph* mtasksp) { mtasksp->orderPreRanked(); int targetParFactor = v3Global.opt.threads(); - if (targetParFactor < 2) { v3fatalSrc("We should not reach V3Partition when --threads <= 1"); } + if (targetParFactor < 2) v3fatalSrc("We should not reach V3Partition when --threads <= 1"); // Set cpLimit to roughly totalGraphCost / nThreads // diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index c62eb7ec1..4fadcb2b8 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -953,7 +953,7 @@ int V3PreProcImp::getStateToken() { // Most states emit white space and comments between tokens. (Unless collecting a string) if (tok == VP_WHITE && state() != ps_STRIFY) return tok; - if (tok == VP_BACKQUOTE && state() != ps_STRIFY) { tok = VP_TEXT; } + if (tok == VP_BACKQUOTE && state() != ps_STRIFY) tok = VP_TEXT; if (tok == VP_COMMENT) { if (!m_off) { if (m_lexp->m_keepComments == KEEPCMT_SUB) { diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index af6e08918..2432ffada 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -205,7 +205,7 @@ private: m_tmpDeclsp = new AstTextBlock(fl); txtp->addNodep(m_tmpDeclsp); txtp->addText(fl, "\ntime last_combo_seqnum__V;\n"); - if (m_hasClk) { txtp->addText(fl, "time last_seq_seqnum__V;\n\n"); } + if (m_hasClk) txtp->addText(fl, "time last_seq_seqnum__V;\n\n"); // CPP hash value addComment(txtp, fl, "Hash value to make sure this file and the corresponding"); @@ -425,7 +425,7 @@ private: m_comboPortsp->addNodep(varp->cloneTree(false)); m_comboParamsp->addText(fl, varp->name() + "\n"); m_comboIgnorePortsp->addNodep(varp->cloneTree(false)); - if (m_hasClk) { m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); } + if (m_hasClk) m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cComboInsp->addText(fl, cInputConnection(varp)); m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index de7a4b362..231eb5fbe 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -141,7 +141,7 @@ class SliceVisitor final : public AstNVisitor { AstNode* newp = nodep->cloneType // AstNodeAssign (cloneAndSel(nodep->lhsp(), elements, offset), cloneAndSel(nodep->rhsp(), elements, offset)); - if (debug() >= 9) { newp->dumpTree(cout, "-new "); } + if (debug() >= 9) newp->dumpTree(cout, "-new "); newlistp = AstNode::addNextNull(newlistp, newp); } if (debug() >= 9) nodep->dumpTree(cout, " Deslice-Dn: "); diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index a3f0f4ef0..a6b33376b 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -853,7 +853,7 @@ public: // If this is AstVarRef and referred in the sensitivity list of always@, // return the sensitivity item AstSenItem* backSenItemp() const { - if (AstVarRef* refp = VN_CAST(m_nodep, VarRef)) { return VN_CAST(refp->backp(), SenItem); } + if (AstVarRef* refp = VN_CAST(m_nodep, VarRef)) return VN_CAST(refp->backp(), SenItem); return nullptr; } }; @@ -971,7 +971,7 @@ class SplitPackedVarVisitor final : public AstNVisitor, public SplitVarImpl { nodep->attrSplitVar(false); } else { // Finally find a good candidate const bool inserted = m_refs.insert(std::make_pair(nodep, PackedVarRef(nodep))).second; - if (inserted) { UINFO(3, nodep->prettyNameQ() << " is added to candidate list.\n"); } + if (inserted) UINFO(3, nodep->prettyNameQ() << " is added to candidate list.\n"); } } virtual void visit(AstVarRef* nodep) override { diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index e9f2503c6..f0666448d 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -379,7 +379,7 @@ public: for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { degree++; } - if (degree & 1) { result.push_back(tspvp->key()); } + if (degree & 1) result.push_back(tspvp->key()); } return result; } @@ -402,7 +402,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { // Make this TSP implementation work for graphs of size 0 or 1 // which, unfortunately, is a special case as the following // code assumes >= 2 nodes. - if (states.empty()) { return; } + if (states.empty()) return; if (states.size() == 1) { resultp->push_back(*(states.begin())); return; @@ -482,7 +482,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { while (i != max_cost_idx) { new_result.push_back((*resultp)[i]); i++; - if (i >= resultp->size()) { i = 0; } + if (i >= resultp->size()) i = 0; } new_result.push_back((*resultp)[i]); diff --git a/src/V3Table.cpp b/src/V3Table.cpp index cc68dba7c..37ef613e1 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -135,7 +135,9 @@ private: if (m_totalBytes > TABLE_TOTAL_BYTES) { chkvis.clearOptimizable(nodep, "Table out of memory"); } - if (!m_outWidth || !m_inWidth) { chkvis.clearOptimizable(nodep, "Table has no outputs"); } + if (!m_outWidth || !m_inWidth) { // + chkvis.clearOptimizable(nodep, "Table has no outputs"); + } UINFO(4, " Test: Opt=" << (chkvis.optimizable() ? "OK" : "NO") << ", Instrs=" << chkvis.instrCount() << " Data=" << chkvis.dataCount() << " inw=" << m_inWidth diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 1ba20e2fd..6e4e47b44 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -182,7 +182,7 @@ private: } // Likewise, all FTask->scope mappings for (AstNode* stmtp = nodep->blocksp(); stmtp; stmtp = stmtp->nextp()) { - if (AstNodeFTask* taskp = VN_CAST(stmtp, NodeFTask)) { taskp->user3p(nodep); } + if (AstNodeFTask* taskp = VN_CAST(stmtp, NodeFTask)) taskp->user3p(nodep); } iterateChildren(nodep); } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 70ede0bf8..bcbd89506 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -300,7 +300,7 @@ private: nextp = itp->verticesNextp(); if (TraceActivityVertex* const vtxp = dynamic_cast(itp)) { // Leave in the always vertex for later use. - if (vtxp != m_alwaysVtxp && !vtxp->outBeginp()) { vtxp->unlinkDelete(&m_graph); } + if (vtxp != m_alwaysVtxp && !vtxp->outBeginp()) vtxp->unlinkDelete(&m_graph); } } } @@ -646,7 +646,7 @@ private: } } ifp = new AstIf(flp, condp, nullptr, nullptr); - if (!always) { ifp->branchPred(VBranchPred::BP_UNLIKELY); } + if (!always) ifp->branchPred(VBranchPred::BP_UNLIKELY); subFuncp->addStmtsp(ifp); subStmts += EmitCBaseCounterVisitor(ifp).count(); prevActSet = &actSet; diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 28b96f230..57c49c552 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -365,10 +365,10 @@ private: } else { nodep->unlinkFrBack(); } - if (bodysp) { VL_DO_DANGLING(pushDeletep(bodysp), bodysp); } - if (precondsp) { VL_DO_DANGLING(pushDeletep(precondsp), precondsp); } - if (initp) { VL_DO_DANGLING(pushDeletep(initp), initp); } - if (incp && !incp->backp()) { VL_DO_DANGLING(pushDeletep(incp), incp); } + if (bodysp) VL_DO_DANGLING(pushDeletep(bodysp), bodysp); + if (precondsp) VL_DO_DANGLING(pushDeletep(precondsp), precondsp); + if (initp) VL_DO_DANGLING(pushDeletep(initp), initp); + if (incp && !incp->backp()) VL_DO_DANGLING(pushDeletep(incp), incp); if (debug() >= 9 && newbodysp) newbodysp->dumpTree(cout, "- _new: "); return true; } @@ -385,7 +385,7 @@ private: // Grab initial value AstNode* initp = nullptr; // Should be statement before the while. if (nodep->backp()->nextp() == nodep) initp = nodep->backp(); - if (initp) { VL_DO_DANGLING(V3Const::constifyEdit(initp), initp); } + if (initp) VL_DO_DANGLING(V3Const::constifyEdit(initp), initp); if (nodep->backp()->nextp() == nodep) initp = nodep->backp(); // Grab assignment AstNode* incp = nullptr; // Should be last statement diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1ee1972d6..f9a8fbe6c 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2669,7 +2669,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); newp->dtypeFrom(adtypep->subDTypep()); - if (!nodep->firstAbovep()) { newp->makeStatement(); } + if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { methodOkArguments(nodep, 0, 0); @@ -2762,7 +2762,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); newp->dtypeFrom(adtypep->subDTypep()); - if (!nodep->firstAbovep()) { newp->makeStatement(); } + if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; @@ -2876,7 +2876,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), nullptr); newp->dtypeFrom(adtypep->subDTypep()); - if (!nodep->firstAbovep()) { newp->makeStatement(); } + if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "push_back" || nodep->name() == "push_front") { methodOkArguments(nodep, 1, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -2894,7 +2894,7 @@ private: newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "r_" + nodep->name(), withp); newp->dtypeFrom(adtypep->subDTypep()); - if (!nodep->firstAbovep()) { newp->makeStatement(); } + if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; @@ -5593,7 +5593,7 @@ private: AstNodeBiop* replaceWithDVersion(AstNodeBiop* nodep) { // Given a signed/unsigned node type, create the opposite type // Return new node or nullptr if nothing - if (nodep->doubleFlavor()) { return nullptr; } + if (nodep->doubleFlavor()) return nullptr; FileLine* fl = nodep->fileline(); AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 1060f6310..665e5d543 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -313,7 +313,7 @@ private: nodep->replaceWith(fromp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); } + if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp); } virtual void visit(AstSelExtract* nodep) override { // Select of a range specified part of an array, i.e. "array[2:3]" @@ -458,9 +458,9 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } // delete whatever we didn't use in reconstruction - if (!fromp->backp()) { VL_DO_DANGLING(pushDeletep(fromp), fromp); } - if (!msbp->backp()) { VL_DO_DANGLING(pushDeletep(msbp), msbp); } - if (!lsbp->backp()) { VL_DO_DANGLING(pushDeletep(lsbp), lsbp); } + if (!fromp->backp()) VL_DO_DANGLING(pushDeletep(fromp), fromp); + if (!msbp->backp()) VL_DO_DANGLING(pushDeletep(msbp), msbp); + if (!lsbp->backp()) VL_DO_DANGLING(pushDeletep(lsbp), lsbp); } void replaceSelPlusMinus(AstNodePreSel* nodep) { @@ -563,9 +563,9 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } // delete whatever we didn't use in reconstruction - if (!fromp->backp()) { VL_DO_DANGLING(pushDeletep(fromp), fromp); } - if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); } - if (!widthp->backp()) { VL_DO_DANGLING(pushDeletep(widthp), widthp); } + if (!fromp->backp()) VL_DO_DANGLING(pushDeletep(fromp), fromp); + if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp); + if (!widthp->backp()) VL_DO_DANGLING(pushDeletep(widthp), widthp); } virtual void visit(AstSelPlus* nodep) override { replaceSelPlusMinus(nodep); } virtual void visit(AstSelMinus* nodep) override { replaceSelPlusMinus(nodep); } diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index b4969ed53..021e875c4 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -219,7 +219,7 @@ void VlcTop::annotateCalc() { for (int lni = start; start && lni <= end; ++lni) { source.incCount(lni, point.column(), point.count(), ok); } - if (!*covp) { break; } + if (!*covp) break; start = 0; // Prep for next end = 0; range = false; diff --git a/test_regress/t/t_dpi_accessors.cpp b/test_regress/t/t_dpi_accessors.cpp index 57b58a7df..54e7a9e18 100644 --- a/test_regress/t/t_dpi_accessors.cpp +++ b/test_regress/t/t_dpi_accessors.cpp @@ -56,7 +56,7 @@ static void logRegHex(int clk, const char* desc, int bitWidth, int val, const ch // Convenience function to check we got an expected result. Silent on success. static void checkResult(bool p, const char* msg_fail) { - if (!p) { vl_fatal(__FILE__, __LINE__, "dut", msg_fail); } + if (!p) vl_fatal(__FILE__, __LINE__, "dut", msg_fail); } // Main function instantiates the model and steps through the test. diff --git a/test_regress/t/t_dpi_arg_inout_unpack.cpp b/test_regress/t/t_dpi_arg_inout_unpack.cpp index 3e0b62d80..fffe3fcb1 100644 --- a/test_regress/t/t_dpi_arg_inout_unpack.cpp +++ b/test_regress/t/t_dpi_arg_inout_unpack.cpp @@ -91,7 +91,7 @@ void set_uint(svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { template bool compare(const T& act, const T& exp) { if (exp == act) { - if (VERBOSE_MESSAGE) { std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; } + if (VERBOSE_MESSAGE) std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; return true; } else { std::cout << "NG Exp:" << exp << " actual:" << act << std::endl; @@ -106,7 +106,7 @@ bool compare_scalar(const svScalar v0, sv_longint_unsigned_t val) { std::cout << "Mismatch at bit:" << 0 << " exp:" << exp_bit << " act:" << act_bit; return false; } - if (VERBOSE_MESSAGE) { std::cout << "OK " << val << " as expected " << std::endl; } + if (VERBOSE_MESSAGE) std::cout << "OK " << val << " as expected " << std::endl; return true; } diff --git a/test_regress/t/t_dpi_arg_input_unpack.cpp b/test_regress/t/t_dpi_arg_input_unpack.cpp index 08084ae57..2442f9578 100644 --- a/test_regress/t/t_dpi_arg_input_unpack.cpp +++ b/test_regress/t/t_dpi_arg_input_unpack.cpp @@ -77,7 +77,7 @@ const bool VERBOSE_MESSAGE = false; template bool compare(const T& act, const T& exp) { if (exp == act) { - if (VERBOSE_MESSAGE) { std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; } + if (VERBOSE_MESSAGE) std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; return true; } else { std::cout << "NG Exp:" << exp << " actual:" << act << std::endl; diff --git a/test_regress/t/t_dpi_arg_output_unpack.cpp b/test_regress/t/t_dpi_arg_output_unpack.cpp index 70fb6f542..918081f8e 100644 --- a/test_regress/t/t_dpi_arg_output_unpack.cpp +++ b/test_regress/t/t_dpi_arg_output_unpack.cpp @@ -175,7 +175,7 @@ void set_3d(svBitVecVal* v, int bitwidth) { template bool compare(const T& act, const T& exp) { if (exp == act) { - if (VERBOSE_MESSAGE) { std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; } + if (VERBOSE_MESSAGE) std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; return true; } else { std::cout << "NG Exp:" << exp << " actual:" << act << std::endl; diff --git a/test_regress/t/t_dpi_context_c.cpp b/test_regress/t/t_dpi_context_c.cpp index 359aa05b2..5c1060ed4 100644 --- a/test_regress/t/t_dpi_context_c.cpp +++ b/test_regress/t/t_dpi_context_c.cpp @@ -55,7 +55,7 @@ int dpic_line() { #ifdef VERILATOR static int didDump = 0; - if (didDump++ == 0) { Verilated::scopesDump(); } + if (didDump++ == 0) Verilated::scopesDump(); #endif const char* scopenamep = svGetNameFromScope(scope); diff --git a/test_regress/t/t_flag_fi.cpp b/test_regress/t/t_flag_fi.cpp index c977decf8..f91a5f303 100644 --- a/test_regress/t/t_flag_fi.cpp +++ b/test_regress/t/t_flag_fi.cpp @@ -26,7 +26,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); topp->eval(); - if (!gotit) { vl_fatal(__FILE__, __LINE__, "dut", "Never got call to myfunction"); } + if (!gotit) vl_fatal(__FILE__, __LINE__, "dut", "Never got call to myfunction"); topp->final(); VL_DO_DANGLING(delete topp, topp); diff --git a/test_regress/t/t_tri_gate.cpp b/test_regress/t/t_tri_gate.cpp index 89810bce7..f16ae0a45 100644 --- a/test_regress/t/t_tri_gate.cpp +++ b/test_regress/t/t_tri_gate.cpp @@ -44,7 +44,7 @@ int main() { for (tb->SEL = 0; tb->SEL < 2; tb->SEL++) { for (tb->A = 0; tb->A < 4; tb->A++) { tb->eval(); - if (!check()) { pass = false; } + if (!check()) pass = false; } } diff --git a/test_regress/t/t_tri_inout.cpp b/test_regress/t/t_tri_inout.cpp index 6156bfdbf..b3bd8aa46 100644 --- a/test_regress/t/t_tri_inout.cpp +++ b/test_regress/t/t_tri_inout.cpp @@ -43,7 +43,7 @@ int main() { for (tb->A = 0; tb->A < 2; tb->A++) { for (tb->B = 0; tb->B < 2; tb->B++) { tb->eval(); - if (!check()) { pass = false; } + if (!check()) pass = false; } } } diff --git a/test_regress/t/t_tri_pullup.cpp b/test_regress/t/t_tri_pullup.cpp index a85093968..12cbf9a1c 100644 --- a/test_regress/t/t_tri_pullup.cpp +++ b/test_regress/t/t_tri_pullup.cpp @@ -53,7 +53,7 @@ int main() { for (tb->OE = 0; tb->OE < 2; tb->OE++) { for (tb->A = 0; tb->A < 2; tb->A++) { tb->eval(); - if (!check()) { pass = false; } + if (!check()) pass = false; } } diff --git a/test_regress/t/t_tri_select.cpp b/test_regress/t/t_tri_select.cpp index b2efad8fa..c33f2c7cf 100644 --- a/test_regress/t/t_tri_select.cpp +++ b/test_regress/t/t_tri_select.cpp @@ -54,7 +54,7 @@ int main() { for (tb->A1 = 0; tb->A1 < 4; tb->A1++) { for (tb->A2 = 0; tb->A2 < 4; tb->A2++) { tb->eval(); - if (!check()) { pass = false; } + if (!check()) pass = false; } } } diff --git a/test_regress/t/t_vpi_cb_iter.cpp b/test_regress/t/t_vpi_cb_iter.cpp index b7372cb7a..7ef5df92d 100644 --- a/test_regress/t/t_vpi_cb_iter.cpp +++ b/test_regress/t/t_vpi_cb_iter.cpp @@ -76,7 +76,7 @@ static int the_rw_callback(p_cb_data cb_data) { static void reregister_value_cb() { if (vh_value_cb) { - if (verbose) { vpi_printf(const_cast("- Removing cbValueChange callback\n")); } + if (verbose) vpi_printf(const_cast("- Removing cbValueChange callback\n")); int ret = vpi_remove_cb(vh_value_cb); vh_value_cb.freed(); CHECK_RESULT(ret, 1); @@ -88,7 +88,7 @@ static void reregister_value_cb() { CHECK_RESULT_NE(main_time, last_value_cb_time); last_value_cb_time = main_time; } - if (verbose) { vpi_printf(const_cast("- Registering cbValueChange callback\n")); } + if (verbose) vpi_printf(const_cast("- Registering cbValueChange callback\n")); t_cb_data cb_data_testcase; bzero(&cb_data_testcase, sizeof(cb_data_testcase)); cb_data_testcase.cb_rtn = the_value_callback; @@ -109,7 +109,7 @@ static void reregister_value_cb() { static void reregister_rw_cb() { if (vh_rw_cb) { - if (verbose) { vpi_printf(const_cast("- Removing cbReadWriteSynch callback\n")); } + if (verbose) vpi_printf(const_cast("- Removing cbReadWriteSynch callback\n")); int ret = vpi_remove_cb(vh_rw_cb); vh_rw_cb.freed(); CHECK_RESULT(ret, 1); @@ -121,7 +121,7 @@ static void reregister_rw_cb() { CHECK_RESULT_NE(main_time, last_rw_cb_time); last_rw_cb_time = main_time; } - if (verbose) { vpi_printf(const_cast("- Registering cbReadWriteSynch callback\n")); } + if (verbose) vpi_printf(const_cast("- Registering cbReadWriteSynch callback\n")); t_cb_data cb_data_testcase; bzero(&cb_data_testcase, sizeof(cb_data_testcase)); cb_data_testcase.cb_rtn = the_rw_callback; @@ -186,12 +186,12 @@ int main(int argc, char** argv, char** env) { while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { main_time += 1; - if (verbose) { VL_PRINTF("Sim Time %d got_error %d\n", main_time, got_error); } + if (verbose) VL_PRINTF("Sim Time %d got_error %d\n", main_time, got_error); topp->clk = !topp->clk; topp->eval(); VerilatedVpi::callValueCbs(); VerilatedVpi::callCbs(cbReadWriteSynch); - if (got_error) { vl_stop(__FILE__, __LINE__, "TOP-cpp"); } + if (got_error) vl_stop(__FILE__, __LINE__, "TOP-cpp"); } if (!Verilated::gotFinish()) { diff --git a/test_regress/t/t_vpi_cbs_called.cpp b/test_regress/t/t_vpi_cbs_called.cpp index 2d19394a1..79d62e3ae 100644 --- a/test_regress/t/t_vpi_cbs_called.cpp +++ b/test_regress/t/t_vpi_cbs_called.cpp @@ -108,7 +108,7 @@ static int register_cb(const int next_state) { } // State of callback next time through loop - if (verbose) { vpi_printf(const_cast(" Updating callback for next loop:\n")); } + if (verbose) vpi_printf(const_cast(" Updating callback for next loop:\n")); switch (next_state) { case ACTIVE: { if (verbose) { @@ -141,7 +141,7 @@ static int register_cb(const int next_state) { break; } default: - if (verbose) { vpi_printf(const_cast(" - No change\n")); } + if (verbose) vpi_printf(const_cast(" - No change\n")); break; } @@ -161,7 +161,7 @@ static int test_callbacks(p_cb_data cb_data) { t_cb_data cb_data_testcase; bzero(&cb_data_testcase, sizeof(cb_data_testcase)); - if (verbose) { vpi_printf(const_cast(" Checking callback results\n")); } + if (verbose) vpi_printf(const_cast(" Checking callback results\n")); // Check results from previous loop int cb = *cb_iter; @@ -192,7 +192,7 @@ static int test_callbacks(p_cb_data cb_data) { } int ret = register_cb(next_state); - if (ret) { return ret; } + if (ret) return ret; // Update iterators for next loop ++state_iter; @@ -228,7 +228,7 @@ static int register_test_callback() { bzero(&cb_data, sizeof(cb_data)); s_vpi_time t1; - if (verbose) { vpi_printf(const_cast(" Registering test_cbs Timed callback\n")); } + if (verbose) vpi_printf(const_cast(" Registering test_cbs Timed callback\n")); cb_data.reason = cbAfterDelay; t1.type = vpiSimTime; @@ -254,7 +254,7 @@ int main(int argc, char** argv, char** env) { VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out - if (verbose) { VL_PRINTF("-- { Sim Time %d } --\n", main_time); } + if (verbose) VL_PRINTF("-- { Sim Time %d } --\n", main_time); register_test_callback(); @@ -279,7 +279,7 @@ int main(int argc, char** argv, char** env) { } else { cbs_called = VerilatedVpi::callCbs(i); } - if (verbose) { VL_PRINTF(" - any callbacks called? %s\n", cbs_called ? "YES" : "NO"); } + if (verbose) VL_PRINTF(" - any callbacks called? %s\n", cbs_called ? "YES" : "NO"); callbacks_called[i] = cbs_called; } @@ -287,7 +287,7 @@ int main(int argc, char** argv, char** env) { main_time = VerilatedVpi::cbNextDeadline(); if (main_time == -1 && !Verilated::gotFinish()) { - if (verbose) { VL_PRINTF("-- { Sim Time %d , No more testcases } --\n", main_time); } + if (verbose) VL_PRINTF("-- { Sim Time %d , No more testcases } --\n", main_time); if (got_error) { vl_stop(__FILE__, __LINE__, "TOP-cpp"); } else { diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 93193b483..451af15e3 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -123,7 +123,7 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int int vpidir = vpi_get(vpiDirection, handle); // Don't check port directions in verilator // see #681 - if (!TestSimulator::is_verilator()) { CHECK_RESULT(vpidir, direction); } + if (!TestSimulator::is_verilator()) CHECK_RESULT(vpidir, direction); } // check type of object diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index ea524311e..731aaf625 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -112,7 +112,7 @@ int check_param_int(std::string name, PLI_INT32 format, int exp_value, bool verb } // values - if (verbose) { vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); } + if (verbose) vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); value.value.integer = exp_value; vpi_put_value(param_h, &value, NULL, vpiNoDelay); CHECK_RESULT_NZ(vpi_chk_error(&e)); @@ -120,7 +120,7 @@ int check_param_int(std::string name, PLI_INT32 format, int exp_value, bool verb vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } - if (verbose) { vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); } + if (verbose) vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); vpi_get_value(param_h, &value); CHECK_RESULT_NZ(!vpi_chk_error(&e)); if (verbose && vpi_chk_error(&e)) { @@ -166,7 +166,7 @@ int check_param_str(std::string name, PLI_INT32 format, std::string exp_value, b } // values - if (verbose) { vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); } + if (verbose) vpi_printf((PLI_BYTE8*)" Try writing value to %s ...\n", name.c_str()); value.value.str = (PLI_BYTE8*)exp_value.c_str(); vpi_put_value(param_h, &value, NULL, vpiNoDelay); CHECK_RESULT_NZ(vpi_chk_error(&e)); @@ -174,7 +174,7 @@ int check_param_str(std::string name, PLI_INT32 format, std::string exp_value, b vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } - if (verbose) { vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); } + if (verbose) vpi_printf((PLI_BYTE8*)" Try reading value of %s ...\n", name.c_str()); vpi_get_value(param_h, &value); CHECK_RESULT_NZ(!vpi_chk_error(&e)); if (verbose && vpi_chk_error(&e)) { diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 95853fd30..3698d0751 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -475,7 +475,7 @@ int _mon_check_string() { v.format = vpiStringVal; vpi_get_value(vh1, &v); - if (vpi_chk_error(&e)) { printf("%%vpi_chk_error : %s\n", e.message); } + if (vpi_chk_error(&e)) printf("%%vpi_chk_error : %s\n", e.message); (void)vpi_chk_error(NULL); @@ -568,7 +568,7 @@ int _mon_check_putget_str(p_cb_data cb_data) { TEST_MSG("new value\n"); for (int j = 0; j < 4; j++) { data[i].value.vector[j].aval = rand_r(&seed); - if (j == (words - 1)) { data[i].value.vector[j].aval &= mask; } + if (j == (words - 1)) data[i].value.vector[j].aval &= mask; TEST_MSG(" %08x\n", data[i].value.vector[j].aval); } v.value.vector = data[i].value.vector; From 0f8e494c765f2e241f6233bcfd7945e634c2b22d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Feb 2021 21:49:55 -0500 Subject: [PATCH 62/79] Tests: Add t_verilated_legacy --- include/verilated.cpp | 4 +- include/verilated.h | 7 +- test_regress/t/t_verilated_legacy.cpp | 105 ++++++++++++++++++++ test_regress/t/t_verilated_legacy.pl | 24 +++++ test_regress/t/t_verilated_legacy.v | 24 +++++ test_regress/t/t_verilated_legacy_time64.pl | 27 +++++ 6 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 test_regress/t/t_verilated_legacy.cpp create mode 100755 test_regress/t/t_verilated_legacy.pl create mode 100644 test_regress/t/t_verilated_legacy.v create mode 100755 test_regress/t/t_verilated_legacy_time64.pl diff --git a/include/verilated.cpp b/include/verilated.cpp index c992d8cf7..180cc8d76 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2482,12 +2482,12 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { // VerilatedImp:: Constructors // verilated.o may exist both in protect-lib and main module. -// Both the main module and the protec-lib refer the same instance of +// Both the main module and the protect-lib refer the same instance of // static variables such as Verilated or VerilatedImplData. // This is important to share the state such as Verilated::gotFinish. // But the sharing may cause double-free error when shutting down because destructors // are called twice. -// 1st time:From protec-lib shared object on the way of unloading after exitting main() +// 1st time:From protect-lib shared object on the way of unloading after exiting main() // 2nd time:From main executable. // // To avoid the trouble, all member variables are enclosed in VerilatedImpU union. diff --git a/include/verilated.h b/include/verilated.h index c0cddeaec..657313e0f 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -564,22 +564,23 @@ public: static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; } static int exportFuncNum(const char* namep) VL_MT_SAFE; + // Internal: Serialization setup static constexpr size_t serialized1Size() VL_PURE { return sizeof(s_s); } static constexpr void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // For Serialize only static size_t serialized2Size() VL_PURE; static void* serialized2Ptr() VL_MT_UNSAFE; #ifdef VL_THREADED - /// Set the mtaskId, called when an mtask starts + /// Internal: Set the mtaskId, called when an mtask starts static void mtaskId(vluint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; } static vluint32_t mtaskId() VL_MT_SAFE { return t_s.t_mtaskId; } static void endOfEvalReqdInc() VL_MT_SAFE { ++t_s.t_endOfEvalReqd; } static void endOfEvalReqdDec() VL_MT_SAFE { --t_s.t_endOfEvalReqd; } - /// Called at end of each thread mtask, before finishing eval + /// Internal: Called at end of each thread mtask, before finishing eval static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp); } - /// Called at end of eval loop + /// Internal: Called at end of eval loop static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { // It doesn't work to set endOfEvalReqd on the threadpool thread // and then check it on the eval thread since it's thread local. diff --git a/test_regress/t/t_verilated_legacy.cpp b/test_regress/t/t_verilated_legacy.cpp new file mode 100644 index 000000000..5536d586d --- /dev/null +++ b/test_regress/t/t_verilated_legacy.cpp @@ -0,0 +1,105 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Wilson Snyder and Marlon James. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include VM_PREFIX_INCLUDE + +#include +#include +#include +#include + +bool got_error = false; + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ + got_error = true; \ + } +#define CHECK_RESULT_CSTR(got, exp) \ + if (strcmp((got), (exp))) { \ + printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", __FILE__, __LINE__, \ + (got) ? (got) : "", (exp) ? (exp) : ""); \ + return __LINE__; \ + } + +vluint64_t main_time = 0; + +#ifdef T_VERILATED_LEGACY_TIME64 +vluint64_t vl_time_stamp64() { return main_time; } +#endif +#ifdef T_VERILATED_LEGACY +double sc_time_stamp() { return main_time; } +#endif + +int main(int argc, char** argv, char** env) { + // Test that the old non-context Verilated:: calls all work + // (This test should never get updated to use context) + + // Many used only by git@github.com:djg/verilated-rs.git + + Verilated::commandArgs(argc, argv); // Commonly used + CHECK_RESULT_CSTR(Verilated::commandArgsPlusMatch("not-matching"), ""); + + Verilated::assertOn(true); + CHECK_RESULT(Verilated::assertOn(), true); + + Verilated::calcUnusedSigs(true); + CHECK_RESULT(Verilated::calcUnusedSigs(), true); + + Verilated::debug(9); // Commonly used + CHECK_RESULT(Verilated::debug(), 9); + Verilated::debug(0); + + Verilated::fatalOnVpiError(true); + CHECK_RESULT(Verilated::fatalOnVpiError(), true); + + Verilated::gotFinish(false); + CHECK_RESULT(Verilated::gotFinish(), false); // Commonly used + + Verilated::mkdir(VL_STRINGIFY(TEST_OBJ_DIR) "/mkdired"); + + Verilated::randReset(0); + CHECK_RESULT(Verilated::randReset(), 0); + + Verilated::traceEverOn(true); // Commonly used + + CHECK_RESULT_CSTR(Verilated::productName(), Verilated::productName()); + CHECK_RESULT_CSTR(Verilated::productVersion(), Verilated::productVersion()); + + VM_PREFIX* topp = new VM_PREFIX(); + + topp->eval(); + topp->clk = 0; + + VL_PRINTF("Starting\n"); + + vluint64_t sim_time = 100; + while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) { + CHECK_RESULT(VL_TIME_Q(), main_time); + CHECK_RESULT(VL_TIME_D(), main_time); + main_time += 1; + topp->clk = !topp->clk; + topp->eval(); + } + + topp->final(); + Verilated::flushCall(); + Verilated::runFlushCallbacks(); + + Verilated::internalsDump(); + Verilated::scopesDump(); + + VL_DO_DANGLING(delete topp, topp); + Verilated::runExitCallbacks(); + return got_error ? 10 : 0; +} diff --git a/test_regress/t/t_verilated_legacy.pl b/test_regress/t/t_verilated_legacy.pl new file mode 100755 index 000000000..293973bb4 --- /dev/null +++ b/test_regress/t/t_verilated_legacy.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder and Marlon James. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_verilated_legacy.v b/test_regress/t/t_verilated_legacy.v new file mode 100644 index 000000000..c6fd4a2e0 --- /dev/null +++ b/test_regress/t/t_verilated_legacy.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 Wilson Snyder and Marlon James. +// SPDX-License-Identifier: CC0-1.0 + + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + int count; + + always @(posedge clk) begin + count <= count + 1; + if (count == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule : t diff --git a/test_regress/t/t_verilated_legacy_time64.pl b/test_regress/t/t_verilated_legacy_time64.pl new file mode 100755 index 000000000..7319ca391 --- /dev/null +++ b/test_regress/t/t_verilated_legacy_time64.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder and Marlon James. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +top_filename("t/t_verilated_legacy.v"); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/t_verilated_legacy.cpp"], + make_flags => 'CPPFLAGS_ADD=-DVL_TIME_STAMP64', + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; From 48986ccdebdb6f954b4b95bc05e7d99b130f7088 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Feb 2021 21:56:43 -0500 Subject: [PATCH 63/79] Remove VL_TIME_I, rarely/never used and too little precision. --- docs/TODO | 2 -- include/verilated.h | 1 - 2 files changed, 3 deletions(-) diff --git a/docs/TODO b/docs/TODO index ce1b15083..341d51d42 100644 --- a/docs/TODO +++ b/docs/TODO @@ -96,8 +96,6 @@ Don't merge if any combining would form circ logic (out goes back to in) ** Multiple assignments each bit can become single assign with concat Make sure a SEL of a CONCAT can get the single bit back. -** Usually blocks/values - Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out ** Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching ** I-cache packing improvements (what/how?) ** Data cache organization (order of vars in class) diff --git a/include/verilated.h b/include/verilated.h index 657313e0f..c81241df8 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -857,7 +857,6 @@ inline vluint64_t vl_time_stamp64() { return static_cast(sc_time_sta # endif #endif -#define VL_TIME_I() (static_cast(vl_time_stamp64())) #define VL_TIME_Q() (static_cast(vl_time_stamp64())) #define VL_TIME_D() (static_cast(vl_time_stamp64())) From 9f381f761718ce049a77a83ccdfb7e0edbbf3d8f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 22 Feb 2021 22:26:45 -0500 Subject: [PATCH 64/79] Remove old SP_AUTO_COVER3 define --- include/verilated.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index c81241df8..2c6ee8cf5 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -265,7 +265,6 @@ public: #define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits #define VL_OUTW(name, msb, lsb, words) WData name[words] ///< Declare output signal, 65+ bits -#define VL_PIN_NOP(instname, pin, port) ///< Connect a pin, ala SP_PIN #define VL_CELL(instname, type) ///< Declare a cell, ala SP_CELL /// Declare a module, ala SC_MODULE @@ -879,10 +878,6 @@ double vl_time_multiplier(int scale); # define VL_DEBUG_IF(text) do {} while (false) #endif -/// Collect coverage analysis for this line -#ifndef SP_AUTO_COVER3 -# define SP_AUTO_COVER3(what,file,line) -#endif // clang-format on //========================================================================= From 6ada513fa5351fb7c11ed5f8d21a017a39beaff2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 22 Feb 2021 22:29:06 -0500 Subject: [PATCH 65/79] Internal: Don't serialize debug, turn on each run. --- include/verilated.cpp | 3 +-- include/verilated.h | 25 +++++++++++++------------ include/verilated_imp.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 180cc8d76..880297a0a 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -265,7 +265,6 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE { // Overall class init Verilated::Serialized::Serialized() { - s_debug = 0; s_calcUnusedSigs = false; s_gotFinish = false; s_assertOn = true; @@ -2216,7 +2215,7 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix, void Verilated::debug(int level) VL_MT_SAFE { const VerilatedLockGuard lock(s_mutex); - s_s.s_debug = level; + s_ns.s_debug = level; if (level) { #ifdef VL_DEBUG VL_DEBUG_IF(VL_DBG_MSGF("- Verilated::debug is on." diff --git a/include/verilated.h b/include/verilated.h index 2c6ee8cf5..1c90643db 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -364,7 +364,6 @@ class Verilated final { static struct Serialized { // All these members serialized/deserialized // Fast path - int s_debug; ///< See accessors... only when VL_DEBUG set bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated bool s_gotFinish; ///< A $finish statement executed bool s_assertOn; ///< Assertions are enabled @@ -384,6 +383,7 @@ class Verilated final { static struct NonSerialized { // Non-serialized information // These are reloaded from on command-line settings, so do not need to persist // Fast path + int s_debug = 0; ///< See accessors... only when VL_DEBUG set vluint64_t s_profThreadsStart = 1; ///< +prof+threads starting time vluint32_t s_profThreadsWindow = 2; ///< +prof+threads window size // Slow path @@ -426,6 +426,18 @@ private: public: // METHODS - User called + /// Enable debug of internal verilated code + static void debug(int level) VL_MT_SAFE; +#ifdef VL_DEBUG + /// Return debug level + /// When multithreaded this may not immediately react to another thread + /// changing the level (no mutex) + static inline int debug() VL_MT_SAFE { return s_ns.s_debug; } +#else + /// Return constant 0 debug level, so C++'s optimizer rips up + static constexpr int debug() VL_PURE { return 0; } +#endif + /// Select initial value of otherwise uninitialized signals. //// /// 0 = Set to zeros @@ -439,17 +451,6 @@ public: /// Random seed extended to 64 bits, and defaulted if user seed==0 static vluint64_t randSeedDefault64() VL_MT_SAFE; - /// Enable debug of internal verilated code - static void debug(int level) VL_MT_SAFE; -#ifdef VL_DEBUG - /// Return debug level - /// When multithreaded this may not immediately react to another thread - /// changing the level (no mutex) - static inline int debug() VL_MT_SAFE { return s_s.s_debug; } -#else - /// Return constant 0 debug level, so C++'s optimizer rips up - static constexpr int debug() VL_PURE { return 0; } -#endif /// Enable calculation of unused signals static void calcUnusedSigs(bool flag) VL_MT_SAFE; static bool calcUnusedSigs() VL_MT_SAFE { ///< Return calcUnusedSigs value diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 6102425f9..9287cf26e 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -235,7 +235,7 @@ protected: VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap - /// Map the represents scope hierarchy + /// Map that represents scope hierarchy VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); // Slow - somewhat static: From 8c2ee6c5ab87c1fca380c2d2bbcb8275d474425b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 22 Feb 2021 22:59:23 -0500 Subject: [PATCH 66/79] With -DVL_NO_LEGACY hide all outdated API routines --- include/verilated.h | 2 ++ include/verilated_vpi.cpp | 2 ++ include/verilatedos.h | 39 ++++++++++++++-------- test_regress/t/t_flag_main.pl | 2 ++ test_regress/t/t_flag_main.v | 2 +- test_regress/t/t_scope_map.cpp | 3 -- test_regress/t/t_verilated_legacy.cpp | 3 ++ test_regress/t/t_vpi_release_dup_bad_c.cpp | 5 +++ 8 files changed, 41 insertions(+), 17 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index 1c90643db..ac43160ed 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -496,7 +496,9 @@ public: static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE; static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE; static void runFlushCallbacks() VL_MT_SAFE; +#ifndef VL_NO_LEGACY static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated +#endif /// Callbacks to run prior to termination static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE; static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE; diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 1ed63e9a0..e48809e54 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -2112,10 +2112,12 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) { return _error_info_p->level; // return error severity level } +#ifndef VL_NO_LEGACY PLI_INT32 vpi_free_object(vpiHandle object) { // vpi_free_object is IEEE deprecated, use vpi_release_handle return vpi_release_handle(object); } +#endif PLI_INT32 vpi_release_handle(vpiHandle object) { VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_release_handle %p\n", object);); diff --git a/include/verilatedos.h b/include/verilatedos.h index d4625e643..b83d5f1bc 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -39,6 +39,7 @@ # define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1))) # define VL_ATTR_PURE __attribute__((pure)) # define VL_ATTR_UNUSED __attribute__((unused)) +# define VL_ATTR_WEAK __attribute__((weak)) # define VL_FUNC __func__ # if defined(__clang__) && defined(VL_THREADED) # define VL_ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__))) @@ -87,6 +88,9 @@ #ifndef VL_ATTR_UNUSED # define VL_ATTR_UNUSED ///< Function that may be never used #endif +#ifndef VL_ATTR_WEAK +# define VL_ATTR_WEAK ///< Function external that is optionally defined +#endif #ifndef VL_FUNC # define VL_FUNC "__func__" ///< Name of current function for error macros #endif @@ -133,8 +137,10 @@ # define VL_THREAD_LOCAL ///< Use new C++ static local thread #endif -#define VL_THREAD ///< Deprecated -#define VL_STATIC_OR_THREAD static ///< Deprecated +#ifndef VL_NO_LEGACY +# define VL_THREAD ///< Deprecated +# define VL_STATIC_OR_THREAD static ///< Deprecated +#endif #define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE) #define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED @@ -144,7 +150,9 @@ #define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, ///< protected to make sure single-caller -#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated) +#ifndef VL_NO_LEGACY +# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated) +#endif // This is not necessarily the same as #UL, depending on what the IData typedef is. #define VL_UL(c) (static_cast(c##UL)) ///< Add appropriate suffix to 32-bit constant @@ -184,16 +192,18 @@ // C++-2011 #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK) +# ifndef VL_NO_LEGACY // These are deprecated historical defines. We leave them in case users referenced them. -# define VL_EQ_DELETE = delete -# define vl_unique_ptr std::unique_ptr -# define vl_unordered_map std::unordered_map -# define vl_unordered_set std::unordered_set -# define VL_INCLUDE_UNORDERED_MAP -# define VL_INCLUDE_UNORDERED_SET -# define VL_FINAL final -# define VL_MUTABLE mutable -# define VL_OVERRIDE override +# define VL_EQ_DELETE = delete +# define vl_unique_ptr std::unique_ptr +# define vl_unordered_map std::unordered_map +# define vl_unordered_set std::unordered_set +# define VL_INCLUDE_UNORDERED_MAP +# define VL_INCLUDE_UNORDERED_SET +# define VL_FINAL final +# define VL_MUTABLE mutable +# define VL_OVERRIDE override +# endif #else # error "Verilator requires a C++11 or newer compiler" #endif @@ -358,12 +368,15 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type #define VL_BYTESIZE 8 ///< Bits in a CData / byte #define VL_SHORTSIZE 16 ///< Bits in a SData / short #define VL_IDATASIZE 32 ///< Bits in a IData / word -#define VL_WORDSIZE VL_IDATASIZE ///< Legacy define #define VL_QUADSIZE 64 ///< Bits in a QData / quadword #define VL_EDATASIZE 32 ///< Bits in a EData (WData entry) #define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE) #define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment) +#ifndef VL_NO_LEGACY +# define VL_WORDSIZE VL_IDATASIZE ///< Legacy define +#endif + /// Bytes this number of bits needs (1 bit=1 byte) #define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE) /// Words/EDatas this number of bits needs (1 bit=1 word) diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl index 397fea235..381004460 100755 --- a/test_regress/t/t_flag_main.pl +++ b/test_regress/t/t_flag_main.pl @@ -15,6 +15,8 @@ compile( verilator_make_cmake => 0, verilator_make_gmake => 0, make_main => 0, + # Check that code --main produces uses only most modern API features + make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY', ); execute( diff --git a/test_regress/t/t_flag_main.v b/test_regress/t/t_flag_main.v index ef63ab8ca..cfbfe9164 100644 --- a/test_regress/t/t_flag_main.v +++ b/test_regress/t/t_flag_main.v @@ -6,7 +6,7 @@ module t(/*AUTOARG*/); initial begin - $write("[%0t] Hello", $time); // Check timestamp works + $write("[%0t] Hello\n", $time); // Check timestamp works $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index b27cb4c97..912150699 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -115,9 +115,6 @@ int main(int argc, char** argv, char** env) { tfp->dump((unsigned int)(main_time)); ++main_time; - // Code coverage of historical flush function - Verilated::flushCall(); - for (VerilatedScopeNameMap::const_iterator it = scopeMapp->begin(); it != scopeMapp->end(); ++it) { VerilatedVarNameMap* varNameMap = it->second->varsp(); diff --git a/test_regress/t/t_verilated_legacy.cpp b/test_regress/t/t_verilated_legacy.cpp index 5536d586d..b46f6c296 100644 --- a/test_regress/t/t_verilated_legacy.cpp +++ b/test_regress/t/t_verilated_legacy.cpp @@ -76,6 +76,9 @@ int main(int argc, char** argv, char** env) { CHECK_RESULT_CSTR(Verilated::productName(), Verilated::productName()); CHECK_RESULT_CSTR(Verilated::productVersion(), Verilated::productVersion()); + if (Verilated::timeunit()) {} + if (Verilated::timeprecision()) {} + VM_PREFIX* topp = new VM_PREFIX(); topp->eval(); diff --git a/test_regress/t/t_vpi_release_dup_bad_c.cpp b/test_regress/t/t_vpi_release_dup_bad_c.cpp index 2d05cb61d..1ade9eaac 100644 --- a/test_regress/t/t_vpi_release_dup_bad_c.cpp +++ b/test_regress/t/t_vpi_release_dup_bad_c.cpp @@ -23,6 +23,11 @@ void dpii_check() { // Verilated::scopesDump(); mod = vpi_handle_by_name((PLI_BYTE8*)"top.t", NULL); if (!mod) vpi_printf(const_cast("-- Cannot vpi_find module\n")); +#ifdef VL_NO_LEGACY + vpi_release_handle(mod); + vpi_release_handle(mod); +#else vpi_free_object(mod); // using vpi_free_object instead of vpi_release_handle for coverage vpi_free_object(mod); // error: double free +#endif } From a886f28c85d3c5e52da917090f69ab72fddd65a3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 Feb 2021 19:02:04 -0500 Subject: [PATCH 67/79] Internals: Use static_assert --- include/verilated.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 880297a0a..122f56943 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -45,18 +45,12 @@ constexpr unsigned VL_VALUE_STRING_MAX_WIDTH = 8192; //=========================================================================== -// Static sanity checks (when get C++11 can use static_assert) +// Static sanity checks -typedef union { - // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint8_incorrect[(sizeof(vluint8_t) == 1) ? 1 : -1]; - // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint16_incorrect[(sizeof(vluint16_t) == 2) ? 1 : -1]; - // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint32_incorrect[(sizeof(vluint32_t) == 4) ? 1 : -1]; - // cppcheck-suppress unusedStructMember // Unused as is assertion - char vluint64_incorrect[(sizeof(vluint64_t) == 8) ? 1 : -1]; -} vl_static_checks_t; +static_assert(sizeof(vluint8_t) == 1, "vluint8_t is missized"); +static_assert(sizeof(vluint16_t) == 2, "vluint8_t is missized"); +static_assert(sizeof(vluint32_t) == 4, "vluint8_t is missized"); +static_assert(sizeof(vluint64_t) == 8, "vluint8_t is missized"); //=========================================================================== // Global variables From c95e606c0a832636d4b9b21951a8777a0121385a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Feb 2021 18:21:13 -0500 Subject: [PATCH 68/79] Fix range inheritance on port without data type (#2753). --- Changes | 2 + src/verilog.y | 6 +- test_regress/t/t_var_port_xml.out | 129 ++++++++++++++++++++++++++++++ test_regress/t/t_var_port_xml.pl | 25 ++++++ test_regress/t/t_var_port_xml.v | 59 ++++++++++++++ 5 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_var_port_xml.out create mode 100755 test_regress/t/t_var_port_xml.pl create mode 100644 test_regress/t/t_var_port_xml.v diff --git a/Changes b/Changes index 9c06d0728..9b127722c 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix little endian interface pin swizzling (#2475). [Don Owen] +**** Fix range inheritance on port without data type (#2753). [Embedded Go] + **** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi] **** Fix $fread extra semicolon inside statements. [Leendert van Doorn] diff --git a/src/verilog.y b/src/verilog.y index d11620541..e887c3a3d 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1380,9 +1380,9 @@ portDirNetE: // IEEE: part of port, optional net type and/or direction /* empty */ { } // // Per spec, if direction given default the nettype. // // The higher level rule may override this VARDTYPE with one later in the parse. - | port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr/*default_nettype*/); } - | port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr/*default_nettype*/); } // net_type calls VARDECL - | net_type { } // net_type calls VARDECL + | port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr); } + | port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL + | net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL ; port_declNetE: // IEEE: part of port_declaration, optional net type diff --git a/test_regress/t/t_var_port_xml.out b/test_regress/t/t_var_port_xml.out new file mode 100644 index 000000000..b2e6f9f4f --- /dev/null +++ b/test_regress/t/t_var_port_xml.out @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_var_port_xml.pl b/test_regress/t/t_var_port_xml.pl new file mode 100755 index 000000000..acd3ab33d --- /dev/null +++ b/test_regress/t/t_var_port_xml.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +compile( + verilator_flags2 => ['--xml-only'], + verilator_make_gmake => 0, + make_top_shell => 0, + make_main => 0, + ); + +files_identical($out_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_var_port_xml.v b/test_regress/t/t_var_port_xml.v new file mode 100644 index 000000000..88418b19c --- /dev/null +++ b/test_regress/t/t_var_port_xml.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// This checks IEEE ports work correctly, we use XML output to make it easy to +// see all attributes are propagated + +// verilator lint_off MULTITOP + +`ifndef VERILATOR +module mh0 (wire x_inout_wire_logic); +endmodule +module mh1 (integer x_inout_wire_integer); +endmodule +`endif +module mh2 (inout integer x_inout_wire_integer); +endmodule +`ifndef VERILATOR +module mh3 ([5:0] x_inout_wire_logic_p6); +endmodule +`endif +module mh5 (input x_input_wire_logic); +endmodule +module mh6 (input var x_input_var_logic); +endmodule +module mh7 (input var integer x_input_var_integer); +endmodule +module mh8 (output x_output_wire_logic); +endmodule +module mh9 (output var x_output_var_logic); +endmodule +module mh10(output signed [5:0] x_output_wire_logic_signed_p6); +endmodule +module mh11(output integer x_output_var_integer); +endmodule +module mh12(ref [5:0] x_ref_logic_p6); +endmodule +module mh13(ref x_ref_var_logic_u6 [5:0]); +endmodule +`ifndef VERILATOR +module mh14(wire x_inout_wire_logic, y_inout_wire_logic_p8 [7:0]); +endmodule +module mh15(integer x_inout_wire_integer, signed [5:0] y_inout_wire_logic_signed6); +endmodule +module mh16([5:0] x_inout_wire_logic_p6, wire y_inout_wire_logic); +endmodule +`endif +module mh17(input var integer x_input_var_integer, wire y_input_wire_logic); +endmodule +module mh18(output var x_output_var_logic, input y_input_wire_logic); +endmodule +module mh19(output signed [5:0] x_output_wire_logic_signed_p6, integer y_output_var_integer); +endmodule +module mh20(ref [5:0] x_ref_var_logic_p6, y_ref_var_logic_p6); +endmodule +module mh21(ref ref_var_logic_u6 [5:0], y_ref_var_logic); +endmodule From 1a5f599626240e4ebdc3d2c0d4d2a49e15da9d98 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Feb 2021 18:32:15 -0500 Subject: [PATCH 69/79] Commentary --- Changes | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Changes b/Changes index 9b127722c..f4a370e46 100644 --- a/Changes +++ b/Changes @@ -5,14 +5,24 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.109 devel +*** Optimize bit operations and others (#2186) (#2632) (#2633) (#2751) (#2800) [Yutetsu TAKATSUKASA] + **** Support concat selection (#2721). +**** Support struct scopes when dumping structs to VCD (#2776) [Alex Torregrosa] + +**** Generate SELRANGE for potentially unreachable code (#2625) (#2754) [Pierre-Henri Horrein] + +**** For --flatten, override inlining of public and no_inline modules (#2761) [James Hanlon] + **** Fix little endian interface pin swizzling (#2475). [Don Owen] **** Fix range inheritance on port without data type (#2753). [Embedded Go] **** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi] +**** Fix to exclude strings from toggle coverage (#2766) (#2767) [Paul Wright] + **** Fix $fread extra semicolon inside statements. [Leendert van Doorn] **** Fix class extends with VM_PARALLEL_BUILDS (#2775). [Iru Cai] From 30c34e4975a7ec6f8e3fd31b2443391125878b88 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Feb 2021 19:21:02 -0500 Subject: [PATCH 70/79] Internals: Avoid extra typedef. No functional change. --- include/verilated.cpp | 6 +++++- include/verilated.h | 9 +-------- include/verilated_imp.h | 2 +- include/verilated_syms.h | 8 +++++--- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 122f56943..e9d84974c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2465,7 +2465,11 @@ void Verilated::endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAF VerilatedThreadMsgQueue::flush(evalMsgQp); } -void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { +void Verilated::endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { + // It doesn't work to set endOfEvalReqd on the threadpool thread + // and then check it on the eval thread since it's thread local. + // It should be ok to call into endOfEvalGuts, it returns immediately + // if there are no transactions. VL_DEBUG_IF(VL_DBG_MSGF("End-of-eval cleanup\n");); evalMsgQp->process(); } diff --git a/include/verilated.h b/include/verilated.h index ac43160ed..badf3d82d 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -583,19 +583,12 @@ public: if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp); } /// Internal: Called at end of eval loop - static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE { - // It doesn't work to set endOfEvalReqd on the threadpool thread - // and then check it on the eval thread since it's thread local. - // It should be ok to call into endOfEvalGuts, it returns immediately - // if there are no transactions. - endOfEvalGuts(evalMsgQp); - } + static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE; #endif private: #ifdef VL_THREADED static void endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE; - static void endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE; #endif }; diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 9287cf26e..e9f343a16 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -417,7 +417,7 @@ public: // But only for verilated*.cpp const VerilatedLockGuard lock(s_s.v.m_hierMapMutex); VerilatedHierarchyMap& map = s_s.v.m_hierMap; if (map.find(fromp) == map.end()) return; - VerilatedScopeVector& scopes = map[fromp]; + auto& scopes = map[fromp]; const auto it = find(scopes.begin(), scopes.end(), top); if (it != scopes.end()) scopes.erase(it); } diff --git a/include/verilated_syms.h b/include/verilated_syms.h index 295bcc1b8..191ad5014 100644 --- a/include/verilated_syms.h +++ b/include/verilated_syms.h @@ -43,6 +43,7 @@ struct VerilatedCStrCmp { }; /// Map of sorted scope names to find associated scope class +// This is a class instead of typedef/using to allow forward declaration in verilated.h class VerilatedScopeNameMap final : public std::map { public: @@ -51,16 +52,17 @@ public: }; /// Map of sorted variable names to find associated variable class +// This is a class instead of typedef/using to allow forward declaration in verilated.h class VerilatedVarNameMap final : public std::map { public: VerilatedVarNameMap() = default; ~VerilatedVarNameMap() = default; }; -typedef std::vector VerilatedScopeVector; - +/// Map of parent scope to vector of children scopes +// This is a class instead of typedef/using to allow forward declaration in verilated.h class VerilatedHierarchyMap final - : public std::unordered_map { + : public std::unordered_map> { public: VerilatedHierarchyMap() = default; ~VerilatedHierarchyMap() = default; From 206bd416aa808c06602ee5d7396d3b0d0b7d11c7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Feb 2021 22:13:24 -0500 Subject: [PATCH 71/79] Internals: Cleanup some RANDOM functions. --- include/verilated.cpp | 26 +++++++++----------------- include/verilated.h | 5 ++++- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index e9d84974c..17949a17c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -321,19 +321,16 @@ vluint64_t vl_rand64() VL_MT_SAFE { return result; } +#ifndef VL_NO_LEGACY // VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility // LCOV_EXCL_START WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { - for (int i = 0; i < VL_WORDS_I(obits); ++i) { - if (i < (VL_WORDS_I(obits) - 1)) { - outwp[i] = vl_rand64(); - } else { - outwp[i] = vl_rand64() & VL_MASK_E(obits); - } - } + for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = vl_rand64(); + outwp[VL_WORDS_I(obits) - 1] = vl_rand64() & VL_MASK_E(obits); return outwp; } // LCOV_EXCL_STOP +#endif IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE { Verilated::randSeed(static_cast(seed)); @@ -359,13 +356,8 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE { return data; } WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE { - for (int i = 0; i < VL_WORDS_I(obits); ++i) { - if (i < (VL_WORDS_I(obits) - 1)) { - outwp[i] = VL_RAND_RESET_I(32); - } else { - outwp[i] = VL_RAND_RESET_I(32) & VL_MASK_E(obits); - } - } + for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32); + outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits); return outwp; } @@ -2114,7 +2106,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary // Helper function for conversion of timescale strings // Converts (1|10|100)(s|ms|us|ns|ps|fs) to power of then -int VL_TIME_STR_CONVERT(const char* strp) { +int VL_TIME_STR_CONVERT(const char* strp) VL_PURE { int scale = 0; if (!strp) return 0; if (*strp++ != '1') return 0; @@ -2135,14 +2127,14 @@ int VL_TIME_STR_CONVERT(const char* strp) { if (*strp) return 0; return scale; } -static const char* vl_time_str(int scale) { +static const char* vl_time_str(int scale) VL_PURE { static const char* const names[] = {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"}; if (VL_UNLIKELY(scale > 2 || scale < -15)) scale = 0; return names[2 - scale]; } -double vl_time_multiplier(int scale) { +double vl_time_multiplier(int scale) VL_PURE { // Return timescale multipler -18 to +18 // For speed, this does not check for illegal values if (scale < 0) { diff --git a/include/verilated.h b/include/verilated.h index badf3d82d..b78c3ad21 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -640,7 +640,9 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE; extern vluint64_t vl_rand64() VL_MT_SAFE; inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); } inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); } +#ifndef VL_NO_LEGACY extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signal +#endif extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE; inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) { vluint64_t rnd = vl_rand64(); @@ -860,8 +862,9 @@ inline vluint64_t vl_time_stamp64() { return static_cast(sc_time_sta // Can't use multiply in Q flavor, as might lose precision #define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast(scale)) #define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast(scale)) + /// Time imported from units to time precision -double vl_time_multiplier(int scale); +double vl_time_multiplier(int scale) VL_PURE; /// Evaluate expression if debug enabled #ifdef VL_DEBUG From 00c3bafe7d1b459494a60a76af8b068c9385b7e7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 19:20:11 -0500 Subject: [PATCH 72/79] Tests: With --gdbsim build with ggdb --- test_regress/driver.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 779b64ed2..48650baa1 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -896,6 +896,7 @@ sub compile_vlt_flags { unshift @verilator_flags, "--trace-threads 1" if $param{vltmt} && $checkflags =~ /-trace /; unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /; unshift @verilator_flags, "--debug-partition" if $param{vltmt}; + unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim; unshift @verilator_flags, "-CFLAGS -fsanitize=address -LDFLAGS -fsanitize=address" if $param{sanitize}; unshift @verilator_flags, "--make gmake" if $param{verilator_make_gmake}; unshift @verilator_flags, "--make cmake" if $param{verilator_make_cmake}; From 2f8fa756916ff26781fe3235390cf7511704092e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 19:24:41 -0500 Subject: [PATCH 73/79] Tests: On format make tests executable --- Makefile.in | 6 +++++- test_regress/t/t_module_class_static_method.pl | 0 test_regress/t/t_randomize_method.pl | 0 test_regress/t/t_randomize_method_bad.pl | 0 test_regress/t/t_randomize_method_types_unsup.pl | 0 test_regress/t/t_randomize_method_unsup.pl | 0 test_regress/t/t_xml_flat_no_inline_mod.pl | 0 test_regress/t/t_xml_flat_pub_mod.pl | 0 8 files changed, 5 insertions(+), 1 deletion(-) mode change 100644 => 100755 test_regress/t/t_module_class_static_method.pl mode change 100644 => 100755 test_regress/t/t_randomize_method.pl mode change 100644 => 100755 test_regress/t/t_randomize_method_bad.pl mode change 100644 => 100755 test_regress/t/t_randomize_method_types_unsup.pl mode change 100644 => 100755 test_regress/t/t_randomize_method_unsup.pl mode change 100644 => 100755 test_regress/t/t_xml_flat_no_inline_mod.pl mode change 100644 => 100755 test_regress/t/t_xml_flat_pub_mod.pl diff --git a/Makefile.in b/Makefile.in index 1f069f909..fdf0ef90e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -463,7 +463,7 @@ analyzer-include: -rm -rf examples/*/obj* scan-build $(MAKE) -k examples -format: clang-format yapf +format: clang-format yapf format-pl-exec CLANGFORMAT = clang-format CLANGFORMAT_FLAGS = -i @@ -495,6 +495,10 @@ YAPF_FILES = \ yapf: $(YAPF) $(YAPF_FLAGS) $(YAPF_FILES) +format-pl-exec: + -chmod a+x test_regress/t/*.pl + + ftp: info install-msg: diff --git a/test_regress/t/t_module_class_static_method.pl b/test_regress/t/t_module_class_static_method.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_randomize_method.pl b/test_regress/t/t_randomize_method.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_randomize_method_bad.pl b/test_regress/t/t_randomize_method_bad.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_randomize_method_types_unsup.pl b/test_regress/t/t_randomize_method_types_unsup.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_randomize_method_unsup.pl b/test_regress/t/t_randomize_method_unsup.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_xml_flat_no_inline_mod.pl b/test_regress/t/t_xml_flat_no_inline_mod.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_xml_flat_pub_mod.pl b/test_regress/t/t_xml_flat_pub_mod.pl old mode 100644 new mode 100755 From 57d1404f402e72da96e7387ea579de01c99d8518 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 19:26:36 -0500 Subject: [PATCH 74/79] Tests: Cleanup to return instead of exit --- test_regress/driver.pl | 4 ++-- test_regress/t/t_cover_lib_c.cpp | 2 +- test_regress/t/t_dpi_var.cpp | 2 +- test_regress/t/t_math_imm2.cpp | 2 +- test_regress/t/t_runflag_uninit_bad.cpp | 2 +- test_regress/t/t_savable_open_bad2.cpp | 2 +- test_regress/t/t_trace_two_cc.cpp | 2 +- test_regress/t/t_trace_two_sc.cpp | 2 +- test_regress/t/t_var_overwidth_bad.cpp | 2 +- test_regress/t/t_vpi_cb_iter.cpp | 2 +- test_regress/t/t_vpi_cbs_called.cpp | 2 +- test_regress/t/t_vpi_get.cpp | 2 +- test_regress/t/t_vpi_memory.cpp | 2 +- test_regress/t/t_vpi_module.cpp | 2 +- test_regress/t/t_vpi_param.cpp | 2 +- test_regress/t/t_vpi_time_cb.cpp | 2 +- test_regress/t/t_vpi_unimpl.cpp | 2 +- test_regress/t/t_vpi_var.cpp | 9 ++++++++- test_regress/t/t_vpi_zero_time_cb.cpp | 2 +- 19 files changed, 27 insertions(+), 20 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 48650baa1..48fd12a05 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1845,7 +1845,7 @@ sub _make_main { $fh->print(" if (sc_time_stamp() == save_time && save_time) {\n"); $fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n"); $fh->print(" printf(\"Exiting after save_model\\n\");\n"); - $fh->print(" exit(0);\n"); + $fh->print(" return 0;\n"); $fh->print(" }\n"); } _print_advance_time($self, $fh, 1, $action); @@ -1870,7 +1870,7 @@ sub _make_main { $fh->print("\n"); print $fh " topp.reset();\n"; - print $fh " exit(0L);\n"; + print $fh " return 0;\n"; print $fh "}\n"; $fh->close(); } diff --git a/test_regress/t/t_cover_lib_c.cpp b/test_regress/t/t_cover_lib_c.cpp index a9168e483..cce1893b6 100644 --- a/test_regress/t/t_cover_lib_c.cpp +++ b/test_regress/t/t_cover_lib_c.cpp @@ -49,5 +49,5 @@ int main() { VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); printf("*-* All Finished *-*\n"); - exit(failure ? 10 : 0); + return (failure ? 10 : 0); } diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index 16241b904..f62388ccb 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -144,5 +144,5 @@ int main(int argc, char** argv, char** env) { topp->final(); VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_math_imm2.cpp b/test_regress/t/t_math_imm2.cpp index 191b4eafa..1238fff1f 100644 --- a/test_regress/t/t_math_imm2.cpp +++ b/test_regress/t/t_math_imm2.cpp @@ -54,6 +54,6 @@ int main(int argc, char* argv[]) { exit(10); } else { printf("*-* All Finished *-*\n"); - exit(0); + return 0; } } diff --git a/test_regress/t/t_runflag_uninit_bad.cpp b/test_regress/t/t_runflag_uninit_bad.cpp index 2a389c6e1..e1484272f 100644 --- a/test_regress/t/t_runflag_uninit_bad.cpp +++ b/test_regress/t/t_runflag_uninit_bad.cpp @@ -24,5 +24,5 @@ int main(int argc, char* argv[]) { // We aren't calling Verilated::commandArgs(argc, argv) topp->eval(); - exit(0); + return 0; } diff --git a/test_regress/t/t_savable_open_bad2.cpp b/test_regress/t/t_savable_open_bad2.cpp index 0e4c383cc..1fb06a851 100644 --- a/test_regress/t/t_savable_open_bad2.cpp +++ b/test_regress/t/t_savable_open_bad2.cpp @@ -44,5 +44,5 @@ int main(int argc, char* argv[]) { CHECK_RESULT_HEX(os.isOpen(), false); } - exit(0); + return 0; } diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index 3b4fc5f3d..87c7ebb5f 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -94,5 +94,5 @@ int main(int argc, char** argv, char** env) { VL_DO_DANGLING(delete ap, ap); VL_DO_DANGLING(delete bp, bp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_trace_two_sc.cpp b/test_regress/t/t_trace_two_sc.cpp index ebfffc68d..6d0c0e125 100644 --- a/test_regress/t/t_trace_two_sc.cpp +++ b/test_regress/t/t_trace_two_sc.cpp @@ -67,5 +67,5 @@ int sc_main(int argc, char** argv) { VL_DO_DANGLING(delete ap, ap); VL_DO_DANGLING(delete bp, bp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_var_overwidth_bad.cpp b/test_regress/t/t_var_overwidth_bad.cpp index 30573b0b4..2aa7d801a 100644 --- a/test_regress/t/t_var_overwidth_bad.cpp +++ b/test_regress/t/t_var_overwidth_bad.cpp @@ -34,5 +34,5 @@ int main(int argc, char** argv, char** env) { topp->final(); VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_vpi_cb_iter.cpp b/test_regress/t/t_vpi_cb_iter.cpp index 7ef5df92d..b71f33ff6 100644 --- a/test_regress/t/t_vpi_cb_iter.cpp +++ b/test_regress/t/t_vpi_cb_iter.cpp @@ -200,5 +200,5 @@ int main(int argc, char** argv, char** env) { topp->final(); VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_vpi_cbs_called.cpp b/test_regress/t/t_vpi_cbs_called.cpp index 79d62e3ae..3b81b1840 100644 --- a/test_regress/t/t_vpi_cbs_called.cpp +++ b/test_regress/t/t_vpi_cbs_called.cpp @@ -308,5 +308,5 @@ int main(int argc, char** argv, char** env) { topp->final(); VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 451af15e3..ba97e83fb 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -278,7 +278,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 51dcb3a57..c420baebc 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -291,7 +291,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 8bc9afe0e..7c00dcbf5 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -220,7 +220,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 731aaf625..ac6275b15 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -288,7 +288,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index 5e1c407f2..e3f9748a5 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -258,7 +258,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index c9a6d3bda..5706be271 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -233,5 +233,5 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 3698d0751..d9ec774b2 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -67,6 +67,12 @@ bool verbose = false; return __LINE__; \ } +#define CHECK_RESULT_Z(got) \ + if ((got)) { \ + printf("%%Error: %s:%d: GOT = !NULL EXP = NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ @@ -624,6 +630,7 @@ int _mon_check_vlog_info() { CHECK_RESULT_CSTR(vlog_info.argv[1], "+PLUS"); CHECK_RESULT_CSTR(vlog_info.argv[2], "+INT=1234"); CHECK_RESULT_CSTR(vlog_info.argv[3], "+STRSTR"); + CHECK_RESULT_Z(vlog_info.argv[4]); if (TestSimulator::is_verilator()) { CHECK_RESULT_CSTR(vlog_info.product, "Verilator"); CHECK_RESULT(strlen(vlog_info.version) > 0, 1); @@ -734,7 +741,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index 0c500906c..1c1f15e5d 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -180,7 +180,7 @@ int main(int argc, char** argv, char** env) { #endif VL_DO_DANGLING(delete topp, topp); - exit(0L); + return 0; } #endif From 0b501df959bff20d0da6a98505520b2359da4c78 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 20:05:54 -0500 Subject: [PATCH 75/79] Tests: Rename --- .../t/{t_verilated_legacy.cpp => t_wrapper_legacy.cpp} | 4 ++-- test_regress/t/{t_verilated_legacy.pl => t_wrapper_legacy.pl} | 0 test_regress/t/{t_verilated_legacy.v => t_wrapper_legacy.v} | 0 ..._verilated_legacy_time64.pl => t_wrapper_legacy_time64.pl} | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename test_regress/t/{t_verilated_legacy.cpp => t_wrapper_legacy.cpp} (98%) rename test_regress/t/{t_verilated_legacy.pl => t_wrapper_legacy.pl} (100%) rename test_regress/t/{t_verilated_legacy.v => t_wrapper_legacy.v} (100%) rename test_regress/t/{t_verilated_legacy_time64.pl => t_wrapper_legacy_time64.pl} (85%) diff --git a/test_regress/t/t_verilated_legacy.cpp b/test_regress/t/t_wrapper_legacy.cpp similarity index 98% rename from test_regress/t/t_verilated_legacy.cpp rename to test_regress/t/t_wrapper_legacy.cpp index b46f6c296..d93356a6a 100644 --- a/test_regress/t/t_verilated_legacy.cpp +++ b/test_regress/t/t_wrapper_legacy.cpp @@ -34,10 +34,10 @@ bool got_error = false; vluint64_t main_time = 0; -#ifdef T_VERILATED_LEGACY_TIME64 +#ifdef T_WRAPPER_LEGACY_TIME64 vluint64_t vl_time_stamp64() { return main_time; } #endif -#ifdef T_VERILATED_LEGACY +#ifdef T_WRAPPER_LEGACY double sc_time_stamp() { return main_time; } #endif diff --git a/test_regress/t/t_verilated_legacy.pl b/test_regress/t/t_wrapper_legacy.pl similarity index 100% rename from test_regress/t/t_verilated_legacy.pl rename to test_regress/t/t_wrapper_legacy.pl diff --git a/test_regress/t/t_verilated_legacy.v b/test_regress/t/t_wrapper_legacy.v similarity index 100% rename from test_regress/t/t_verilated_legacy.v rename to test_regress/t/t_wrapper_legacy.v diff --git a/test_regress/t/t_verilated_legacy_time64.pl b/test_regress/t/t_wrapper_legacy_time64.pl similarity index 85% rename from test_regress/t/t_verilated_legacy_time64.pl rename to test_regress/t/t_wrapper_legacy_time64.pl index 7319ca391..ad170fa1e 100755 --- a/test_regress/t/t_verilated_legacy_time64.pl +++ b/test_regress/t/t_wrapper_legacy_time64.pl @@ -10,12 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); -top_filename("t/t_verilated_legacy.v"); +top_filename("t/t_wrapper_legacy.v"); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/t_verilated_legacy.cpp"], + verilator_flags2 => ["--exe $Self->{t_dir}/t_wrapper_legacy.cpp"], make_flags => 'CPPFLAGS_ADD=-DVL_TIME_STAMP64', ); From e1a48dcb070c838a56b324ca44eacd81762e269e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 20:11:51 -0500 Subject: [PATCH 76/79] Fix spacing --- src/V3EmitC.cpp | 4 ++-- src/V3Task.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 89c6bc609..00fe1eeeb 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -693,7 +693,7 @@ public: iterateAndNextNull(nodep->offset()); puts(","); iterateAndNextNull(nodep->operation()); - puts(")==-1?-1:0)"); + puts(") == -1 ? -1 : 0)"); } virtual void visit(AstFTell* nodep) override { puts("VL_FTELL_I("); @@ -703,7 +703,7 @@ public: virtual void visit(AstFRewind* nodep) override { puts("(VL_FSEEK_I("); iterateAndNextNull(nodep->filep()); - puts(", 0, 0)==-1?-1:0)"); + puts(", 0, 0) == -1 ? -1 : 0)"); } virtual void visit(AstFRead* nodep) override { puts("VL_FREAD_I("); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 6e4e47b44..b58cc0c78 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -786,7 +786,7 @@ private: // Static doesn't need save-restore as if below will re-fill proper value stmt += "static int __Vfuncnum = -1;\n"; // First time init (faster than what the compiler does if we did a singleton - stmt += "if (VL_UNLIKELY(__Vfuncnum==-1)) { __Vfuncnum = Verilated::exportFuncNum(\"" + stmt += "if (VL_UNLIKELY(__Vfuncnum == -1)) { __Vfuncnum = Verilated::exportFuncNum(\"" + nodep->cname() + "\"); }\n"; // If the find fails, it will throw an error stmt += "const VerilatedScope* __Vscopep = Verilated::dpiScope();\n"; From dad86b9a849cbd1fe4435e3b5d8f2ac4f7ad3c87 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 20:38:38 -0500 Subject: [PATCH 77/79] Tests: Fix leak found by previous commit --- src/V3Task.cpp | 4 ++-- test_regress/t/t_trace_two_cc.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index b58cc0c78..8f0663b1e 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -786,8 +786,8 @@ private: // Static doesn't need save-restore as if below will re-fill proper value stmt += "static int __Vfuncnum = -1;\n"; // First time init (faster than what the compiler does if we did a singleton - stmt += "if (VL_UNLIKELY(__Vfuncnum == -1)) { __Vfuncnum = Verilated::exportFuncNum(\"" - + nodep->cname() + "\"); }\n"; + stmt += "if (VL_UNLIKELY(__Vfuncnum == -1)) __Vfuncnum = Verilated::exportFuncNum(\"" + + nodep->cname() + "\");\n"; // If the find fails, it will throw an error stmt += "const VerilatedScope* __Vscopep = Verilated::dpiScope();\n"; // If dpiScope is fails and is null; the exportFind function throws and error diff --git a/test_regress/t/t_trace_two_cc.cpp b/test_regress/t/t_trace_two_cc.cpp index 87c7ebb5f..4b445b8ed 100644 --- a/test_regress/t/t_trace_two_cc.cpp +++ b/test_regress/t/t_trace_two_cc.cpp @@ -90,6 +90,7 @@ int main(int argc, char** argv, char** env) { #ifdef TEST_HDR_TRACE if (tfp) tfp->close(); + VL_DO_DANGLING(delete tfp, tfp); #endif VL_DO_DANGLING(delete ap, ap); From ce78d6e438fbf56d0d7689f5eb1425c476666f12 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 21:19:37 -0500 Subject: [PATCH 78/79] Fix flexfix to directly run with python. --- src/Makefile_obj.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 0b38c2108..4562bcd7d 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -340,7 +340,7 @@ V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS) ${LEX} ${LFLAGS} -o$@ $< V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX) - $(PERL) $(FLEXFIX) V3PreLex <$< >$@ + $(PYTHON3) $(FLEXFIX) V3PreLex <$< >$@ .SUFFIXES: From 17b75c6428a7e06961d24784ade3e47611838983 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 25 Feb 2021 21:43:33 -0500 Subject: [PATCH 79/79] Version bump --- Changes | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index f4a370e46..cf1962931 100644 --- a/Changes +++ b/Changes @@ -3,7 +3,7 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! -* Verilator 4.109 devel +* Verilator 4.110 2021-02-25 *** Optimize bit operations and others (#2186) (#2632) (#2633) (#2751) (#2800) [Yutetsu TAKATSUKASA] diff --git a/configure.ac b/configure.ac index 0ef39b109..5cbb6ffe0 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.109 devel], +AC_INIT([Verilator],[4.110 2021-02-25], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file