diff --git a/.travis.yml b/.travis.yml index aeb2146eb..a06929f60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,12 +41,21 @@ install: before_script: # ccache maintenance - ./ci/travis-ccache-maint.bash + # Don't produce core dumps (esp. on FreeBSD) + - ulimit -c 0 # On Focal, set the SystemC installation location - | - if [ "$TRAVIS_DIST" = "focal" ]; then + if [ "$TRAVIS_DIST" = "focal" ] && [ "$M32" != "1" ]; then export SYSTEMC_INCLUDE=/usr/include export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu fi + # Override compiler for M32 + - | + if [ "$M32" = "1" ]; then + export CC="$CC -m32" + export CXX="$CXX -m32" + unset M32 # verilated.mk actually references $(M32) so unset + fi before_cache: - ccache -s -z @@ -70,6 +79,12 @@ jobs: - {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}} # Coverage build - {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1} + # 32-bit build + - {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc-m32, paths: .}}, env: M32=1} + # OS X build + - {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}} + # FreeBSD build + - {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}} ############################################################################ # Jobs in the 'test' stage ############################################################################ @@ -109,6 +124,21 @@ jobs: - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1} - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2} - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3} + # 32-bit tests + - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-0]} + - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-1]} + - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-0]} + - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-1]} + # OS X tests + - {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-0} + - {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-1} + - {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0} + - {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1} + # FreeBSD tests + - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0} + - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1} + - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0} + - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1} notifications: email: diff --git a/Changes b/Changes index f0ab90451..2d2cf87fe 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,34 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.038 2020-07-11 + +** Versions 4.038 and 4.040 are planned to be the final versions that will + support pre-C++11 compilers. Please move to C++11 or newer compilers. + +*** Support VPI access to parameters and localparam. [Ludwig Rogiers] + +*** Support parsing (not elaboration, yet) of UVM. + +**** Add new UNSUPPORTED error code to replace most previous Unsupported: messages. + +**** With --bbox-unsup continue parsing on many (not all) UVM constructs. + +**** Support for-loop increments with commas. + +**** Support $swrite with arbitrary arguments. + +**** Support $writememb (#2450). [Fan Shupei] + +**** Fix OS X, Free BSD, and -m32 portability issues. [Geza Lore] + +**** Fix to flush FST trace on termination due to $stop or assertion failure. + +**** Fix part select error when multipling by power-of-two (#2413). [Conor McCullough] + +**** Fix division exception (#2460) [Kuoping Hsu] + + * Verilator 4.036 2020-06-06 ** OPT_FAST is now -Os by default. See the BENCHMARKING & OPTIMIZATION part diff --git a/Makefile.in b/Makefile.in index b49baf8ae..f1b09115a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -425,6 +425,9 @@ CPPCHECK_CPP = $(wildcard \ CPPCHECK_H = $(wildcard \ $(srcdir)/include/*.h \ $(srcdir)/src/*.h ) +CPPCHECK_YL = $(wildcard \ + $(srcdir)/src/*.y \ + $(srcdir)/src/*.l ) CPPCHECK = src/cppcheck_filtered CPPCHECK_FLAGS = --enable=all --inline-suppr \ --suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \ @@ -462,7 +465,7 @@ CLANGFORMAT_FLAGS = -i clang-format: @$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \ || echo "*** You are not using clang-format 10.0, indents may differ from master's ***" - $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) + $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) ftp: info diff --git a/bin/verilator b/bin/verilator index b8d345107..83712deca 100755 --- a/bin/verilator +++ b/bin/verilator @@ -224,6 +224,7 @@ __END__ Verilator - Translate and simulate SystemVerilog code using C++/SystemC + =head1 SYNOPSIS verilator --help @@ -232,31 +233,43 @@ Verilator - Translate and simulate SystemVerilog code using C++/SystemC verilator --sc [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so] verilator --lint-only -Wall [source_files.v]... + =head1 DESCRIPTION -Verilator converts synthesizable (generally not behavioral) Verilog code, -plus some Synthesis, SystemVerilog and a small subset of Verilog AMS into -C++ or SystemC code. It is not a traditional simulator, but a compiler. +The "Verilator" package converts all synthesizable, and many behavioral, +Verilog and SystemVerilog designs into a C++ or SystemC model that after +compiling can be executed. Verilator is not a traditional simulator, but a +compiler. -Verilator is invoked with parameters similar to GCC, Cadence -Verilog-XL/NC-Verilog, or Synopsys's VCS. It reads the specified Verilog -code, lints it, and optionally adds coverage and waveform tracing code. -For C++ and SystemC formats, it outputs .cpp and .h files. +Verilator is typically used as follows: -The files created by Verilator are then compiled with C++. The user writes -a little C++ wrapper file, which instantiates the top level module, and -passes this filename on the command line. These C files are compiled in -C++, and linked with the Verilated files. +1. The C executable is invoked with parameters similar to GCC, +Cadence Verilog-XL/NC-Verilog, or Synopsys VCS. C reads the +specified user's SystemVerilog code, lints it, optionally adds coverage and +waveform tracing support, and compiles the design into a source level C++ +or SystemC "model". The resulting model's C++ or SystemC code is output as +.cpp and .h files. This is referred to as "verilating" and the process is +"to verilate"; the output is a "verilated" model. -The resulting executable will perform the actual simulation. +2. For simulation, a small user written C++ wrapper file is required, the +"wrapper". This wrapper defines the C++ function `main()` which +instantiates the Verilated model as a C++/SystemC object. -To get started, jump down to "EXAMPLE C++ EXECUTION". +3. The user main wrapper, the files created by Verilator, a "runtime +library" provided by Verilator, and if applicable the SystemC libraries are +then compiled using a C++ compiler to create a simulation executable. + +4. The resulting executable will perform the actual simulation, during +"simulation runtime". + +To get started, jump down to the L section. =head1 ARGUMENT SUMMARY -This is a short summary of the arguments to Verilator itself. See the -detailed descriptions in L for more information. +This is a short summary of the arguments to the "verilator" executable. +See L for the detailed descriptions of these +arguments. {file.v} Verilog package, module and top module filenames {file.c/cc/cpp} Optional C++ files to compile in @@ -275,7 +288,7 @@ detailed descriptions in L for more information. --bbox-unsup Blackbox unsupported language features --bin Override Verilator binary --build Build model executable/library after Verilation - -CFLAGS C++ Compiler flags for makefile + -CFLAGS C++ compiler flags for makefile --cc Create C++ output --cdc Clock domain crossing analysis --clk Mark specified signal as clock @@ -308,7 +321,7 @@ detailed descriptions in L for more information. -f Parse options from a file -FI Force include of a file --flatten Force inlining of all modules, tasks and functions - -G= Overwrite toplevel parameter + -G= Overwrite top-level parameter --gdb Run Verilator under GDB interactively --gdbbt Run Verilator under GDB for backtrace --generate-key Create random key for --protect-key @@ -342,9 +355,9 @@ detailed descriptions in L for more information. -O Selectable optimizations -o Name of final executable --no-order-clock-delay Disable ordering clock enable assignments - --no-verilate Skip verilation and just compile previously verilated code. + --no-verilate Skip verilation and just compile previously Verilated code. --output-split Split .cpp files into pieces - --output-split-cfuncs Split .cpp functions + --output-split-cfuncs Split model functions --output-split-ctrace Split tracing functions -P Disable line numbers and blanks with -E --pins-bv Specify types for top level ports @@ -417,9 +430,9 @@ detailed descriptions in L for more information. --xml-output XML output filename -y Directory to search for modules -This is a short summary of the arguments to simulation runtime Verilated -arguments. detailed descriptions in L for -more information. +This is a short summary of the simulation runtime arguments, i.e. for the +final Verilated simulation runtime models. See L for the detailed description of these arguments. +verilator+debug Enable debugging +verilator+debugi+ Enable debugging at a level @@ -436,7 +449,8 @@ more information. =head1 VERILATION ARGUMENTS -The following are the arguments that may be passed to Verilator itself. +The following are the arguments that may be passed to the "verilator" +executable. =over 4 @@ -446,16 +460,13 @@ Specifies the Verilog file containing the top module to be Verilated. =item {file.c/.cc/.cpp/.cxx} -Specifies optional C++ files to be linked in with the Verilog code. The -file path should either be absolute, or relative to where the make will be -executed from, or add to your makefile's VPATH the appropriate directory to -find the file. +Used with --exe to specify optional C++ files to be linked in with the +Verilog code. The file path should either be absolute, or relative to +where the make will be executed from, or add to your makefile's VPATH the +appropriate directory to find the file. -If any C++ files are specified in this way, Verilator will include a make -rule that generates a I executable. Without any C++ files, -Verilator will stop at the I__ALL.a library, and presume you'll -continue linking with make rules you write yourself. See also the -CFLAGS -option. +See also the -CFLAGS and -LDFLAGS options, which are useful when the C++ +files need special compiler flags. =item {file.a/.o/.so} @@ -503,9 +514,10 @@ preferable option is to edit the code to repair new keywords, or add appropriate C<`begin_keywords>. B C<`begin_keywords> is a SystemVerilog construct, which specifies -I which the set of keywords is to be recognized. Whatever set is -chosen, the semantics will be those of SystemVerilog. By contrast -C<+1364-1995ext+> etc. specify both the syntax I semantics to be used. +I the set of keywords to be recognized. This also controls some error +messages that vary between language standards. Note at present Verilator +tends to be overly permissive, e.g. it will accept many grammar and other +semantic extensions which might not be legal when set to an older standard. =item --assert @@ -514,15 +526,15 @@ Enable all assertions. =item --autoflush After every $display or $fdisplay, flush the output stream. This ensures -that messages will appear immediately but may reduce performance; for best -performance call "fflush(stdout)" occasionally in the main C loop. -Defaults off, which will buffer output as provided by the normal C stdio -calls. +that messages will appear immediately but may reduce performance. For best +performance call "fflush(stdout)" occasionally in the C++ main loop. +Defaults to off, which will buffer output as provided by the normal C/C++ +standard library IO. =item --bbox-sys -Black box any unknown $system task or function calls. System tasks will be -simply become no-operations, and system functions will be replaced by +Black box any unknown $system task or function calls. System tasks will +simply become no-operations, and system functions will be replaced with unsized zero. Arguments to such functions will be parsed, but not otherwise checked. This prevents errors when linting in the presence of company specific PLI calls. @@ -560,7 +572,7 @@ the shell (C<-CFLAGS "-a -b">), or use multiple -CFLAGS arguments (C<-CFLAGS -a -CFLAGS -b>). When make is run on the generated makefile these will be passed to the C++ -compiler (gcc/g++/msvc++). +compiler (g++/clang++/msvc++). =item --cc @@ -568,10 +580,10 @@ Specifies C++ without SystemC output mode; see also --sc. =item --cdc -Experimental. Perform some clock domain crossing checks and issue related -warnings (CDCRSTLOGIC) and then exit; if warnings other than CDC warnings -are needed make a second run with --lint-only. Additional warning -information is also written to the file {prefix}__cdc.txt. +Permanently experimental. Perform some clock domain crossing checks and +issue related warnings (CDCRSTLOGIC) and then exit; if warnings other than +CDC warnings are needed make a second run with --lint-only. Additional +warning information is also written to the file {prefix}__cdc.txt. Currently only checks some items that other CDC tools missed; if you have interest in adding more traditional CDC checks, please contact the authors. @@ -611,14 +623,16 @@ using --build. =item --compiler I -Enables tunings and workarounds for the specified C++ compiler. +Enables workarounds for the specified C++ compiler, either C, +C, or C. Currently this does not change any performance tuning +flags, but it may in the future. =over 4 =item clang Tune for clang. This may reduce execution speed as it enables several -workarounds to avoid silly hardcoded limits in clang. This includes +workarounds to avoid silly hard-coded limits in clang. This includes breaking deep structures as for msvc as described below. =item gcc @@ -629,7 +643,7 @@ compliant C++ compiler. Currently the default. =item msvc Tune for Microsoft Visual C++. This may reduce execution speed as it -enables several workarounds to avoid silly hardcoded limits in MSVC++. +enables several workarounds to avoid silly hard-coded limits in MSVC++. This includes breaking deeply nested parenthesized expressions into sub-expressions to avoid error C1009, and breaking deep blocks into functions to avoid error C1061. @@ -650,10 +664,9 @@ Enables all forms of coverage, alias for "--coverage-line --coverage-toggle Specifies basic block line coverage analysis code should be inserted. -Coverage analysis adds statements at each code flow change point, which are -the branches of IF and CASE statements, a super-set of normal Verilog Line -Coverage. At each such branch a unique counter is incremented. At the end -of a test, the counters along with the filename and line number +Coverage analysis adds statements at each code flow change point (e.g. at +branches). At each such branch a unique counter is incremented. At the +end of a test, the counters along with the filename and line number corresponding to each counter are written into logs/coverage.dat. Verilator automatically disables coverage of branches that have a $stop in @@ -717,13 +730,13 @@ the comment "DefaultClock": =item -DI=I -Defines the given preprocessor symbol, without allowing. Similar to -+define; +define is fairly standard across Verilog tools while -D is an -alias for GCC compatibility. +Defines the given preprocessor symbol. Similar to +define, but does not +allow multiple definitions with a single option using plus signs. +define +is fairly standard across Verilog tools while -D is similar to GCC. =item --debug -Select the debug built image of Verilator (if available), and enable more +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 to C<--dump-treei 3>). @@ -735,15 +748,15 @@ changing debug verbosity. Enabled automatically when --debug specified. =item --no-debug-leak -In --debug mode, by default Verilator intentionally leaks AstNode's +In --debug mode, by default Verilator intentionally leaks AstNode instances instead of freeing them, so that each node pointer is unique in the resulting tree files and dot files. This option disables the leak. This may avoid out-of-memory errors when Verilating large models in --debug mode. -Outside of --debug mode, AstNode's should never be leaked and this option -has no effect. +Outside of --debug mode, AstNode instances should never be leaked and this +option has no effect. =item --debugi I @@ -778,13 +791,14 @@ then the latest SystemVerilog language (IEEE 1800-2017) is used. =item +define+I=I+I=I... Defines the given preprocessor symbol, or multiple symbols if separated by -plusses. Similar to -D; +define is fairly standard across Verilog tools -while -D is an alias for GCC compatibility. +plus signs. Similar to -D; +define is fairly standard across Verilog tools +while -D is similar to GCC. =item --dpi-hdr-only Only generate the DPI header file. This option has no effect on the name -or location of the file. +or location of the emitted DPI header file, it is output in C<--Mdir> as it +would be without this option. =item --dump-defines @@ -810,7 +824,7 @@ large and not desired. Rarely needed - for developer use. Set internal tree dumping level globally to a specific dumping level or set the specified Verilator source file to the specified tree dumping level (e.g. C<--dump-treei-V3Order 9>). -Level 0 disbles dumps and is equivalent to "--no-dump-tree". Level 9 +Level 0 disables dumps and is equivalent to "--no-dump-tree". Level 9 enables dumping of every stage. =item --dump-tree-addrids @@ -880,7 +894,7 @@ to basic data literals: =item Verilog integer literals -The standard verilog integer literals are supported, so values like 32'h8, +The standard Verilog integer literals are supported, so values like 32'h8, 2'b00, 4 etc. are allowed. Care must be taken that the single quote (I') is properly escaped in an interactive shell, e.g., as -GWIDTH=8\'hx. @@ -893,13 +907,13 @@ octal (0..) or binary (0b..) notation. Double literals must be one of the following styles: - contains a dot (.) (e.g. 1.23) - - contains an expornent (e/E) (e.g. 12e3) + - contains an exponent (e/E) (e.g. 12e3) - contains p/P for hexadecimal floating point in C99 (e.g. 0x123.ABCp1) =item Strings -String must in double quotes (""). On the command line it is required to escape -them properly, e.g. as -GSTR="\"My String\"" or -GSTR='"My String"'. +Strings must be in double quotes (""). They must be escaped properly on the +command line, e.g. as -GSTR="\"My String\"" or -GSTR='"My String"'. =back @@ -963,7 +977,7 @@ Tune the inlining of modules. The default value of 2000 specifies that up to 2000 new operations may be added to the model by inlining, if more than this number of operations would result, the module is not inlined. Larger values, or a value < 1 will inline everything, will lead to longer compile -times, but potentially faster simulation runtimes. This setting is ignored +times, but potentially faster simulation speed. This setting is ignored for very small modules; they will always be inlined, if allowed. =item -j @@ -1037,7 +1051,7 @@ Defaults to 64K. Enable/disable creation of .d dependency files, used for make dependency detection, similar to gcc -MMD option. By default this option is enabled -for --cc or --sp modes. +for --cc or --sc modes. =item --MP @@ -1062,7 +1076,7 @@ Prevent the specified signal from being marked as clock. See C<--clk>. =item --no-decoration -When creating output Verilated code, minimize comments, whitespace, symbol +When creating output Verilated code, minimize comments, white space, symbol names and other decorative items, at the cost of greatly reduced readability. This may assist C++ compile times. This will not typically change the ultimate model's performance, but may in some cases. @@ -1092,7 +1106,7 @@ with extra loads and stores to handle the (imaginary) aliasing. Using only Rarely needed. Disables or enables skipping execution of Verilator if all source files are identical, and all output files exist with newer dates. -By default this option is enabled for --cc or --sp modes only. +By default this option is enabled for --cc or --sc modes only. =item +notimingchecks @@ -1106,7 +1120,7 @@ Disables optimization of the model. Enables slow optimizations for the code Verilator itself generates (as opposed to "-CFLAGS -O3" which effects the C compiler's optimization. -O3 -may reduce simulation runtimes at the cost of compile time. This currently +may improve simulation performance at the cost of compile time. This currently sets --inline-mult -1. =item -OI @@ -1144,13 +1158,12 @@ value of 0. =item --output-split-cfuncs I -Enables splitting functions in the output .cpp files into multiple -functions. When a generated function exceeds the specified number of -operations, a new function will be created. With --output-split, this will -enable GCC to compile faster, at a small loss in performance that gets -worse with decreasing split values. Note that this option is stronger than ---output-split in the sense that --output-split will not split inside a -function. +Enables splitting functions in the output .cpp files into multiple functions. +When a generated function exceeds the specified number of operations, a new +function will be created. With --output-split, this will enable the C++ +compiler to compile faster, at a small loss in performance that gets worse with +decreasing split values. Note that this option is stronger than --output-split +in the sense that --output-split will not split inside a function. Defaults to the value of --output-split, unless explicitly specified. @@ -1201,16 +1214,17 @@ Likewise pins of width 9-16 will use uint16_t instead of uint32_t. =item --pipe-filter I -Rarely needed and experimental. Verilator will spawn the specified command -as a subprocess pipe, to allow the command to perform custom edits on the -Verilog code before it reaches Verilator. +Rarely needed. Verilator will spawn the specified command as a subprocess +pipe, to allow the command to perform custom edits on the Verilog code +before it reaches Verilator. Before reading each Verilog file, Verilator will pass the file name to the -subprocess' stdin with 'read_verilog ""'. The filter may then -read the file and perform any filtering it desires, and feeds the new file -contents back to Verilator on stdout with 'Content-Length'. Output to -stderr from the filter feeds through to Verilator's stdout and if the -filter exits with non-zero status Verilator terminates. See the +subprocess' stdin with 'read ""'. The filter may then read the file +and perform any filtering it desires, and feeds the new file contents back to +Verilator on stdout by first emitting a line defining the length in bytes of +the filtered output 'Content-Length: ', followed by the new filtered +contents. Output to stderr from the filter feeds through to Verilator's stdout +and if the filter exits with non-zero status Verilator terminates. See the t/t_pipe_filter test for an example. To debug the output of the filter, try using the -E option to see @@ -1323,12 +1337,12 @@ inlining. This will also turn off inlining as if all modules had a =item --public-flat-rw Declares all variables, ports and wires public as if they had /*verilator -public_flat_rw*/ comments. This will make them VPI accessible by their -flat name, but not turn off module inlining. This is particularly useful -in combination with --vpi. This may also in some rare cases result in -mis-simulation of generated clocks. Instead of this global switch, marking -only those signals that need public_flat_rw is typically significantly -better performing. +public_flat_rw @ ()*/ comments. This will +make them VPI accessible by their flat name, but not turn off module +inlining. This is particularly useful in combination with --vpi. This may +also in some rare cases result in mis-simulation of generated clocks. +Instead of this global switch, marking only those signals that need +public_flat_rw is typically significantly better performing. =item -pvalue+I=I @@ -1367,6 +1381,11 @@ printing. For example: will generate a PDF Vt_unoptflat_simple_2_35_unoptflat.dot.pdf from the DOT file. +As an alternative, the I command can be used to view DOT files +interactively: + + xdot Vt_unoptflat_simple_2_35_unoptflat.dot + =item --rr Run Verilator and record with rr. See: rr-project.org. @@ -1442,7 +1461,8 @@ L. =item --threads-dpi pure -When using --dpi with --threads, control what DPI tasks are thread safe. +When using --threads, controls which DPI imported tasks and functions are +considered thread safe. With --threads-dpi all, enable Verilator to assume all DPI imports are threadsafe, and to use thread-local storage for communication with DPI, @@ -1483,9 +1503,9 @@ precision of 1fs. =item --top-module I When the input Verilog contains more than one top level module, specifies -the name of the top level Verilog module to become the top, and sets the -default for if --prefix is not used. This is not needed with standard -designs with only one top. See also the MULTITOP warning section. +the name of the Verilog module to become the top level module, and sets the +default for --prefix if not explicitly specified. This is not needed with +standard designs with only one top. See also the MULTITOP warning section. =item --trace @@ -1495,12 +1515,12 @@ C<--trace-fst>. Verilator will generate additional {prefix}__Trace*.cpp files that will need to be compiled. In addition verilated_vcd_sc.cpp (for SystemC traces) or verilated_vcd_c.cpp (for both) must be compiled and linked in. If using -the Verilator generated Makefiles, these files will be added as source -targets for you. If you're not using the Verilator makefiles, you will +the Verilator generated Makefiles, these files will be added to the source +file lists for you. If you are not using the Verilator Makefiles, you will need to add these to your Makefile manually. Having tracing compiled in may result in some small performance losses, -even when waveforms are not turned on during model execution. +even when tracing is not turned on during model execution. See also C<--trace-threads>. @@ -1514,14 +1534,14 @@ already visible. The added signal will be a 32-bit value which will increment on each coverage occurrence. Due to this, this option may greatly increase trace -file sizes and simulation runtime. +file sizes and reduce simulation speed. =item --trace-depth I Specify the number of levels deep to enable tracing, for example --trace-level 1 to only see the top level's signals. Defaults to the entire model. Using a small number will decrease visibility, but greatly -improve simulation runtime and trace file size. +improve simulation performance and trace file size. =item --trace-fst @@ -1598,9 +1618,9 @@ Note -v is fairly standard across Verilog tools. =item --no-verilate -When using --build, disable generation of C++/SC code, and execute only the -build. This can be useful for rebuilding verilated code produced by a previous -invocation of Verilator. +When using --build, disable generation of C++/SystemC code, and execute only +the build. This can be useful for rebuilding Verilated code produced by a +previous invocation of Verilator. =item +verilog1995ext+I @@ -1619,7 +1639,7 @@ Enable use of VPI and linking against the verilated_vpi.cpp files. =item --waiver-output Generate a waiver file which contains all waiver statements to suppress the -warnings emitted during this Verilator run. This is in particular useful as +warnings emitted during this Verilator run. This in particular is useful as a starting point for solving linter warnings or suppressing them systematically. @@ -1630,12 +1650,12 @@ standard file extension is .vlt. =item -Wall Enable all code style warnings, including code style warnings that are -normally disabled by default. Equivelent to "-Wwarn-lint -Wwarn-style". +normally disabled by default. Equivalent to "-Wwarn-lint -Wwarn-style". Excludes some specialty warnings, i.e. IMPERFECTSCH. =item -Werror-I -Convert the specified warning message into an error message. This is +Promote the specified warning message into an error message. This is generally to discourage users from violating important site-wide rules, for example C<-Werror-NOUNOPTFLAT>. @@ -1649,20 +1669,19 @@ supports which the older version does not support. =item -Wno-I -Disable the specified warning message, or in some cases where noted here -disable an error. This will override any lint_on directives in the source, -i.e. the warning will still not be printed. +Disable the specified warning/error message. This will override any lint_on +directives in the source, i.e. the warning will still not be printed. =item -Wno-context Disable showing the suspected context of the warning message by quoting the -source text at the suspected location. This is used to appease tools which -process the error messages may get confused by lines from the original +source text at the suspected location. This can be used to appease tools which +process the warning messages but may get confused by lines from the original source. =item -Wno-fatal -When warnings are detected, print them, but do not exit the simulator. +When warnings are detected, print them, but do not terminate Verilator. Having warning messages in builds is sloppy. It is strongly recommended you cleanup your code, use inline lint_off, or use -Wno-... flags rather @@ -1692,8 +1711,8 @@ already disabled). This is equivalent to "-Wno-DECLFILENAME -Wno-DEFPARAM Warn on any construct demanded by IEEE, and disable all Verilator extensions that may interfere with IEEE compliance to the standard defined -with --language (etc). Similar to GCC's -Wpedantic. Rarely used, and -intended only for strict compliance tests. +with --default-language (etc). Similar to GCC's -Wpedantic. Rarely used, +and intended only for strict compliance tests. =item -Wwarn-I @@ -1723,23 +1742,26 @@ Enable all code style related warning messages. This is equivalent to =item --x-assign unique -Controls the two-state value that is replaced when an assignment to X is -encountered. C<--x-assign fast>, the default, converts all Xs to whatever is -best for performance. C<--x-assign 0> converts all Xs to 0s, and is also fast. -C<--x-assign 1> converts all Xs to 1s, this is nearly as fast as 0, but more -likely to find reset bugs as active high logic will fire. C<--x-assign unique> -will call a function to determine the value, this allows randomization of -all Xs to find reset bugs and is the slowest, but safest for finding reset -bugs in code. +Controls the two-state value that is substituted when an explicit X value is +encountered in the source. C<--x-assign fast>, the default, converts all Xs to +whatever is best for performance. C<--x-assign 0> converts all Xs to 0s, and +is also fast. C<--x-assign 1> converts all Xs to 1s, this is nearly as fast as +0, but more likely to find reset bugs as active high logic will fire. Using +C<--x-assign unique> will result in all explicit Xs being replaced by a +constant value determined at runtime. The value is determined by calling a +function at initialization time. This enables randomization of Xs with +different seeds on different executions. This method is the slowest, but safest +for finding reset bugs. -If using --x-assign unique, you may want to seed your random number -generator such that each regression run gets a different randomization -sequence. Use the system's srand48() or for Windows srand() function to do -this. You'll probably also want to print any seeds selected, and code to -enable rerunning with that same seed so you can reproduce bugs. +If using --x-assign unique, you may want to seed your random number generator +such that each regression run gets a different randomization sequence. The +simplest is to use the +verilator+seed runtime option. Alternatively use the +system's srand48() or for Windows srand() function to do this. You'll probably +also want to print any seeds selected, and code to enable rerunning with that +same seed so you can reproduce bugs. -B This option applies only to variables which are explicitly assigned -to X in the Verilog source code. Initial values of clocks are set to 0 unless +B This option applies only to values which are explicitly written as +X in the Verilog source code. Initial values of clocks are set to 0 unless --x-initial-edge is specified. Initial values of all other state holding variables are controlled with --x-initial. @@ -1812,8 +1834,8 @@ Filename for XML output file. Using this option automatically sets Add the directory to the list of directories that should be searched for include files or libraries. The three flags -y, +incdir and -I have -similar effect; +incdir and +y are fairly standard across Verilog tools while -I -is an alias for GCC compatibility. +similar effect; +incdir and +y are fairly standard across Verilog tools while +-I is used by many C++ compilers. Verilator defaults to the current directory ("-y .") and any specified --Mdir, though these default paths are used after any user specified @@ -1854,20 +1876,21 @@ Display help and exit. =item +verilator+prof+threads+file+I -When using --prof-threads at simulation runtime, the filename to dump to. -Defaults to "profile_threads.dat". +When a model was Verilated using --prof-threads, sets the simulation runtime +filename to dump to. Defaults to "profile_threads.dat". =item +verilator+prof+threads+start+I -When using --prof-threads at simulation runtime, Verilator will wait until -$time is at this value (expressed in units of the time precision), then -start the profiling warmup, then capturing. Generally this should be set to -some time that is well within the normal operation of the simulation, -i.e. outside of reset. If 0, the dump is disabled. Defaults to 1. +When a model was Verilated using --prof-threads, the simulation runtime will +wait until $time is at this value (expressed in units of the time +precision), then start the profiling warmup, then capturing. Generally this +should be set to some time that is well within the normal operation of the +simulation, i.e. outside of reset. If 0, the dump is disabled. Defaults to +1. =item +verilator+prof+threads+window+I -When using --prof-threads at simulation runtime, after $time reaches +When a model was Verilated using --prof-threads, after $time reaches +verilator+prof+threads+start, Verilator will warm up the profiling for this number of eval() calls, then will capture the profiling of this number of eval() calls. Defaults to 2, which makes sense for a @@ -1928,8 +1951,8 @@ We'll compile this example into C++. EOF See the README in the source kit for various ways to install or point to -Verilator binaries. In brief, if you are running Verilator that came from -your operating system (as an RPM), or did a "make install" to place +Verilator binaries. In brief, if you installed Verilator using the package +manager of your operating system, or did a "make install" to place Verilator into your default path, you do not need anything special in your environment, and should not have VERILATOR_ROOT set. However, if you installed Verilator from sources and want to run Verilator out of where you @@ -1998,8 +2021,8 @@ This is an example similar to the above, but using SystemC. EOF See the README in the source kit for various ways to install or point to -Verilator binaries. In brief, if you are running Verilator that came from -your operating system (as an RPM), or did a "make install" to place +Verilator binaries. In brief, if you installed Verilator using the package +manager of your operating system, or did a "make install" to place Verilator into your default path, you do not need anything special in your environment, and should not have VERILATOR_ROOT set. However, if you installed Verilator from sources and want to run Verilator out of where you @@ -2047,14 +2070,14 @@ the examples directory in the distribution. =head1 EVALUATION LOOP -When using SystemC, when Verilator is evaluated is managed by the SystemC +When using SystemC, evaluation of the Verilated model is managed by the SystemC kernel, and for the most part can be ignored. When using C++, the user must call eval(), or eval_step() and eval_end_step(). -1. When there is a single design instantiated at the C++ level that need to +1. When there is a single design instantiated at the C++ level that needs to evaluate, just call designp->eval(). -2. When there are multiple designs instantiated each at the C++ level that +2. When there are multiple designs instantiated at the C++ level that need to evaluate, call first_designp->eval_step() then ->eval_step() on all other designs. Then call ->eval_end_step() on the first design then all other designs. If there is only a single design, you would call @@ -2067,7 +2090,7 @@ evaluates related sequential always blocks, such as computing always_ff @ Note combinatorial logic is not computed before sequential always blocks are computed (for speed reasons). Therefore it is best to set any non-clock -inputs up with a separate eval() call before changing clocks(). +inputs up with a separate eval() call before changing clocks. Alternatively, if all always_ff statements use only the posedge of clocks, or all inputs go directly to always_ff statements, as is typical, then you @@ -2112,8 +2135,8 @@ applies to slow-path code, which executes rarely, often only once at the beginning or end of simulation. Note that OPT_SLOW is ignored if VM_PARALLEL_BUILDS is not 1, in which case all generated code will be compiled in a single compilation unit using OPT_FAST. See also the C<--output-split> -option. The OPT_GLOBAL variable applies to common code in the run-time library -used by verilated models (shipped in $VERILATOR_ROOT/include). Additional C++ +option. The OPT_GLOBAL variable applies to common code in the runtime library +used by Verilated models (shipped in $VERILATOR_ROOT/include). Additional C++ files passed on the verilator command line use OPT_FAST. The OPT variable applies to all compilation units in addition to the specific OPT_* variables described above. @@ -2133,8 +2156,8 @@ controlled by OPT_SLOW have little effect on performance and therefore OPT_SLOW is empty by default (equivalent to "-O0") for improved compilation speed. In common use-cases there should be little benefit in changing OPT_SLOW. OPT_GLOBAL is set to "-Os" by default and there should rarely be a need to -change it. As the run-time library is small in comparison to a lot of verilated -models, disabling optimization on the run-time library should not have a +change it. As the runtime library is small in comparison to a lot of Verilated +models, disabling optimization on the runtime library should not have a serious effect on overall compilation time, but may have detrimental effect on simulation speed, especially with tracing. In addition to the above, for best results use OPT="-march=native", the latest Clang compiler (about 10% faster @@ -2176,8 +2199,8 @@ how Verilator compares, and may be able to suggest additional improvements. =head1 FILES -All output files are placed in the output directory name specified with the --Mdir option, or "obj_dir" if not specified. +All output files are placed in the output directory specified with the +C<--Mdir> option, or "obj_dir" if not specified. Verilator creates the following files in the output directory: @@ -2216,7 +2239,7 @@ In certain debug and other modes, it also creates: It also creates internal files that can be mostly ignored: - {mod_prefix}_{each_verilog_module}{__n}.vpp // Post-processed verilog + {mod_prefix}_{each_verilog_module}{__n}.vpp // Pre-processed verilog {prefix}__ver.d // Make dependencies (-MMD) {prefix}__verFiles.dat // Timestamps for skip-identical {prefix}{misc}.dot // Debugging graph files (--debug) @@ -2316,22 +2339,23 @@ Specifies the directory containing the distribution kit. This is used to find the executable, Perl library, and include files. If not specified, it will come from a default optionally specified at configure time (before Verilator was compiled). It should not be specified if using a pre-compiled -Verilator RPM as the hardcoded value should be correct. +Verilator package as the hard-coded value should be correct. =back =head1 CONNECTING TO C++ -Verilator creates a .h and .cpp file for the top level module and all -modules under it. See the examples directory in the kit for examples. +Verilator creates a I.h and I.cpp file for the top level +module, together with additional .h and .cpp files for internals. See the +examples directory in the kit for examples. -After the modules are completed, there will be a I.mk file that may -be used with Make to produce a I__ALL.a file with all required -objects in it. This is then linked with the user's top level to create the -simulation executable. +After the model is created, there will be a I.mk file that may +be used with Make to produce a I__ALL.a file with all required +objects in it. This is then linked with the user's C++ main loop to +create the simulation executable. -The user must write the top level of the simulation. Here's a simple +The user must write the C++ main loop of the simulation. Here is a simple example: #include // Defines common routines @@ -2377,9 +2401,9 @@ example: delete top; } -Note signals are read and written as member variables of the lower module. +Note signals are read and written as member variables of the model. You call the eval() method to evaluate the model. When the simulation is -complete call the final() method to wrap up any SystemVerilog final blocks, +complete call the final() method to execute any SystemVerilog final blocks, and complete any assertions. See L. @@ -2410,7 +2434,7 @@ the original Synopsys-only DPI. In the SYSTEMC example above, if you wanted to import C++ functions into Verilog, put in our.v: - import "DPI-C" function integer add (input integer a, input integer b); + import "DPI-C" function int add (input int a, input int b); initial begin $display("%x + %x = %x", 1, 2, add(1,2)); @@ -2451,7 +2475,7 @@ called from C++: Then after Verilating, Verilator will create a file Vour__Dpi.h with the prototype to call this function: - extern bool publicSetBool(bool in_bool); + extern void publicSetBool(svBit in_bool); From the sc_main.cpp file, you'd then: @@ -2476,9 +2500,9 @@ respect to that top level module, then the scope could be set with #include "svdpi.h" ... - svSetScope(svGetScopeFromName("dut")); + svSetScope(svGetScopeFromName("TOP.dut")); -(Remember that Verilator adds a "V" to the top of the module hierarchy.) +(Remember that Verilator adds a "TOP" to the top of the module hierarchy.) Scope can also be set from within a DPI imported C function that has been called from Verilog by querying the scope of that function. See the @@ -2729,9 +2753,9 @@ the SystemC include an library path. (same as above). - When using Accellera's SystemC with CMake support, a CMake target is -available that will easen above steps. This will only work if the SystemC -installation can be found by CMake. This can be configured by setting the -CMAKE_PREFIX_PATH variable during CMake configuration. +available that simplifies the above steps. This will only work if the +SystemC installation can be found by CMake. This can be configured by +setting the CMAKE_PREFIX_PATH variable during CMake configuration. Don't forget to set the same C++ standard for the Verilated sources as the SystemC library. This can be specified using the SYSTEMC_CXX_FLAGS environment @@ -2745,15 +2769,15 @@ Name of a target created by add_executable or add_library. =item SOURCES -List of verilog files to Verilate. Must have at least one file. +List of Verilog files to Verilate. Must have at least one file. =item PREFIX Optional. Sets the Verilator output prefix. Defaults to the name of the -first hdl source with a "V" prepended. Must be unique in each call to +first source file with a "V" prepended. Must be unique in each call to verilate(), so this is necessary if you build a module multiple times with different parameters. Must be a valid C++ identifier, i.e. contains no -whitespace and only characters A-Z, a-z, 0-9 or _. +white space and only characters A-Z, a-z, 0-9 or _. =item TOP_MODULE @@ -2791,7 +2815,7 @@ Optional. Set compiler flags for the fast path. =item OPT_GLOBAL -Optional. Set compiler flags for the common run-time library used by verilated +Optional. Set compiler flags for the common runtime library used by Verilated models. =item DIRECTORY @@ -2806,30 +2830,10 @@ here, use DIRECTORY or PREFIX. =back -=head2 Cadence NC-SystemC Models - -Similar to compiling Verilated designs with gcc, Verilated designs may be -compiled inside other simulators that support C++ or SystemC models. One -such simulator is Cadence's NC-SystemC, part of their Incisive Verification -Suite. (Highly recommended.) - -Using the example files above, the following command will build the model -underneath NC: - - cd obj_dir - ncsc_run \ - sc_main.cpp \ - Vour__ALL.cpp \ - verilated.cpp - -For larger designs you'll want to automate this using makefiles, which pull -the names of the .cpp files to compile in from the make variables generated -in obj_dir/Vour_classes.mk. - =head1 MULTITHREADING -Verilator experimentally supports multithreading. +Verilator supports multithreaded simulation models. With --no-threads, the default, the model is not thread safe, and any use of more than one thread calling into one or even different Verilated models @@ -2913,7 +2917,7 @@ If using --coverage, the coverage routines are fully thread safe. If using --dpi, Verilator assumes pure DPI imports are thread safe, balancing performance versus safety. See --threads-dpi. -If using --savable, the save/restore classes are not multithreaded and are +If using --savable, the save/restore classes are not multithreaded and must be called only by the eval thread. If using --sc, the SystemC kernel is not thread safe, therefore the eval @@ -2928,6 +2932,7 @@ thread. =back + =head1 CONFIGURATION FILES In addition to the command line, warnings and other features may be @@ -2940,13 +2945,13 @@ extension. An example: This disables WIDTH warnings globally, and CASEX for a specific file. -Configuration files are parsed after the normal Verilog preprocessing, so -`ifdefs, `defines, and comments may be used as if it were normal Verilog -code. +Configuration files are fed through the normal Verilog preprocessor prior to +parsing, so `ifdefs, `defines, and comments may be used as if it were normal +Verilog code. Note that file or line-specific configuration only applies to files read after the configuration file. It is therefore recommended to pass the -configuration file to Verilator as first file. +configuration file to Verilator as the first file. The grammar of configuration commands is as follows: @@ -2983,7 +2988,7 @@ enabled/disabled. This will override all later lint warning enables for the specified region. If -match is set the linter warnings are matched against this (wildcard) -string and are waived in case they match iff rule and file (with wildcard) +string and are waived in case they match and iff rule and file (with wildcard) also match. In previous versions -rule was named -msg. The latter is deprecated, but @@ -3046,15 +3051,9 @@ print an "Assertion failed" error message. =item inline -module "" -Specifies the module may be inlined into any modules that use this -module. This is useful to speed up simulation runtime with some small -loss of trace visibility and modularity. Note signals under inlined -submodules will be named I__DOT__I as C++ does -not allow "." in signal names. When tracing such signals the tracing -routines will replace the __DOT__ with the period. - -Same as /*verilator inline_module*/, see L for -more information. +Specifies the module may be inlined into any modules that use this module. +Same as /*verilator inline_module*/, and see that under L for more information. =item isolate_assignments -module "" [-task ""] -var "" @@ -3072,13 +3071,9 @@ EXTENSIONS"> for more information. =item no_inline -module "" -Specifies the module should not be inlined into any modules that use -this module. This is useful especially at the top level module to -reduce the size of the interface class, to aid compile time at a small -performance loss. - -Same as /*verilator no_inline_module*/, see L -for more information. +Specifies the module should not be inlined into any modules that use this +module. Same as /*verilator no_inline_module*/, and see that under +L for more information. =item no_inline [-module ""] -task "" @@ -3093,27 +3088,37 @@ outside the task itself. Same as /*verilator no_inline_task*/, see L for more information. +=item public [-module ""] [-task/-function ""] + -var "" + +=item public_flat [-module ""] [-task/-function ""] + -var "" + +=item public_flat_rd [-module ""] [-task/-function ""] + -var "" + +=item public_flat_rw [-module ""] [-task/-function ""] + -var "" "@(edge)" + +Sets the variable to be public. Same as /*verilator public*/ or +/*verilator public_flat*/ etc, see those under L +for more information. + =item sc_bv -module "" [-task ""] -var "" =item sc_bv -module "" [-function ""] -var "" Sets the port to be of sc_bv> type, instead of bool, vluint32_t or -vluint64_t. This may be useful if the port width is parameterized and -different of such modules interface a templated module (such as a transactor) -or for other reasons. In general you should avoid using this attribute when -not necessary as with increasing usage of sc_bv the performance decreases -significantly. - -Same as /*verilator sc_bv*/, see L for more -information. +vluint64_t. Same as /*verilator sc_bv*/, see that under L for more information. =item sformat [-module ""] [-task ""] -var "" =item sformat [-module ""] [-function ""] -var "" -Final input of a function or task "input string" to indicate the -function or task should pass all remaining arguments through -$sformatf. This allows creation of DPI functions with $display like +Must be applied to the final argument of type "input string" of a function or +task to indicate the function or task should pass all remaining arguments +through $sformatf. This allows creation of DPI functions with $display like behavior. See the test_regress/t/t_dpi_display.v file for an example. Same as /*verilator sformat*/, see L for more @@ -3258,12 +3263,13 @@ each different output width. Format arguments may use C fprintf sizes after the % escape. Per the Verilog standard, %x prints a number with the natural width, and %0x prints a number with minimum width. Verilator extends this so %5x prints 5 digits -per the C standard (it's unspecified in Verilog). +per the C standard (this is unspecified in Verilog, but was incorporated +into the 1800-2009). =item `coverage_block_off Specifies the entire begin/end block should be ignored for coverage -analysis. Must be inside a basic block, e.g. within a begin/end pair. +analysis. Must be inside a code block, e.g. within a begin/end pair. Same as /* verilator coverage_block_off */ and C in L. @@ -3327,7 +3333,7 @@ default when --language is 1800-*. =item `verilator3 The VERILATOR, verilator and verilator3 defines are set by default so you -may `ifdef around compiler specific constructs. +may `ifdef around tool specific constructs. =item `verilator_config @@ -3394,11 +3400,9 @@ appropriate --coverage flags are passed) after being disabled earlier with =item /*verilator inline_module*/ Specifies the module the comment appears in may be inlined into any modules -that use this module. This is useful to speed up simulation runtime with some -small loss of trace visibility and modularity. Note signals under inlined -submodules will be named I__DOT__I as C++ does not -allow "." in signal names. When tracing such signals the tracing routines -will replace the __DOT__ with the period. +that use this module. This is useful to speed up simulation runtime. Note +if using "--public" that signals under inlined submodules will be named +I__DOT__I as C++ does not allow "." in signal names. Same as C in configuration files, see L for more information. @@ -3473,9 +3477,7 @@ and if it was off before the lint_off it will remain off. =item /*verilator no_inline_module*/ Specifies the module the comment appears in should not be inlined into any -modules that use this module. This is useful especially at the top level -module to reduce the size of the interface class, to aid compile time at a -small performance loss. +modules that use this module. Same as C in configuration files, see L for more information. @@ -3597,21 +3599,21 @@ clock pins to be sc_clocks and this is no longer needed. =item /*verilator sc_bv*/ Used after a port declaration. It sets the port to be of sc_bv> -type, instead of bool, vluint32_t or vluint64_t. This may be useful if -the port width is parameterized and different of such modules interface -a templated module (such as a transactor) or for other reasons. In general -you should avoid using this attribute when not necessary as with increasing -usage of sc_bv the performance decreases significantly. +type, instead of bool, vluint32_t or vluint64_t. This may be useful if the +port width is parameterized and the instantiating C++ code wants to always +have a sc_bv so it can accept any width. In general you should avoid using +this attribute when not necessary as with increasing usage of sc_bv the +performance decreases significantly. Same as C in configuration files, see L for more information. =item /*verilator sformat*/ -Attached to the final input of a function or task "input string" to +Attached to the final argument of type "input string" of a function or task to indicate the function or task should pass all remaining arguments through -$sformatf. This allows creation of DPI functions with $display like -behavior. See the test_regress/t/t_dpi_display.v file for an example. +$sformatf. This allows creation of DPI functions with $display like behavior. +See the test_regress/t/t_dpi_display.v file for an example. Same as C in configuration files, see L for more information. @@ -3634,13 +3636,13 @@ To: logic [7:0] x__BRA__1__KET__ /*verilator split_var*/; Note that the generated packed variables retain the split_var metacomment -because they may be split into further smaller pieces accorting to the +because they may be split into further smaller pieces according to the access patterns. This only supports unpacked arrays, packed arrays, and packed structs of integer types (reg, logic, bit, byte, int...); otherwise if a split was requested but cannot occur a SPLITVAR warning is issued. Splitting large -arrays may slow donw the Verilation speed, so use this only on variables +arrays may slow down the Verilation speed, so use this only on variables that require it. Same as C in configuration files, see L @@ -3704,24 +3706,20 @@ path. =head2 Class Verilator class support is limited but in active development. Verilator -supports members, and methods. Verilator doe not support class static +supports members, and methods. Verilator does not support class static members, class extend, or class parameters. =head2 Dotted cross-hierarchy references Verilator supports dotted references to variables, functions and tasks in -different modules. However, references into named blocks and function-local -variables are not supported. The portion before the dot must have a -constant value; for example a[2].b is acceptable, while a[x].b is not. +different modules. The portion before the dot must have a constant value; +for example a[2].b is acceptable, while a[x].b is generally not. References into generated and arrayed instances use the instance names specified in the Verilog standard; arrayed instances are named {cellName}[{instanceNumber}] in Verilog, which becomes {cellname}__BRA__{instanceNumber}__KET__ inside the generated C++ code. -If you are having trouble determining where a dotted path goes wrong, note -that Verilator will print a list of known scopes to help your debugging. - =head2 Latches Verilator is optimized for edge sensitive (flop based) designs. It will @@ -3730,7 +3728,7 @@ optimizations will be disabled around the latch. =head2 Structures and Unions -Verilator only presently supports packed structs and packed unions. Rand +Presently Verilator only supports packed structs and packed unions. Rand and randc tags on members are simply ignored. All structures and unions are represented as a single vector, which means that generating one member of a structure from blocking, and another from non-blocking assignments is @@ -3746,28 +3744,31 @@ Verilator is mostly a two state simulator, not a four state simulator. However, it has two features which uncover most initialization bugs (including many that a four state simulator will miss.) -Identity comparisons (=== or !==) are converted to standard ==/!== when -neither side is a constant. This may make the expression result differ -from a four state simulator. An === comparison to X will always be false, -so that Verilog code which checks for uninitialized logic will not fire. +Identity comparisons (=== or !==) are converted to standard ==/!= when neither +side is a constant. This may make the expression yield a different result +compared to a four state simulator. An === comparison to X will always be +false, so that Verilog code which checks for uninitialized logic will not fire. -Assigning a variable to a X will actually assign the variable to a random -value (see the --x-assign switch and +verilator+rand+reset simulation -runtime switch.) Thus if the value is actually used, the random value -should cause downstream errors. Integers also randomize, even though the -Verilog 2001 specification says they initialize to zero. +Assigning X to a variable will actually assign a constant value as +determined by the --x-assign switch. This allows runtime randomization, +thus if the value is actually used, the random value should cause +downstream errors. Integers also get randomized, even though the Verilog +2001 specification says they initialize to zero. Note however that +randomization happens at initialization time and hence during a single +simulation run, the same constant (but random) value will be used every +time the assignment is executed. All variables, depending on --x-initial setting, are typically randomly initialized using a function. By running several random simulation runs -you can determine that reset is working correctly. On the first run, the -function initializes variables to zero. On the second, have it initialize +you can determine that reset is working correctly. On the first run, have the +function initialize variables to zero. On the second, have it initialize variables to one. On the third and following runs have it initialize them randomly. If the results match, reset works. (Note this is what the hardware will really do.) In practice, just setting all variables to one at startup finds most problems (since typically control signals are active-high). ---x-assign applies to variables explicitly initialized or assigned to +--x-assign applies to variables explicitly initialized or assigned an X. Uninitialized clocks are initialized to zero, while all other state holding variables are initialized to a random value. Event driven simulators will generally trigger an edge on a transition from X to 1 @@ -3816,7 +3817,7 @@ different.) =head2 Generated Clocks -Verilator attempts to deal with generated and enabled clocks correctly, +Verilator attempts to deal with generated and gated clocks correctly, however some cases cause problems in the scheduling algorithm which is optimized for performance. The safest option is to have all clocks as primary inputs to the model, or wires directly attached to primary inputs. @@ -3894,9 +3895,8 @@ Generally supported. =item ++, -- operators -Increment/decrement can only be used as standalone statements or in for -loops. They cannot be used as side effect operators inside more complicate -expressions ("a = b++;"). +Increment/decrement can only be used as standalone statements or in certain +limited cases. =item '{} operator @@ -3963,7 +3963,7 @@ $dumpfile or $dumpports will create a VCD or FST file (which is based on the --trace argument given when the model was Verilated). This will take effect starting at the next eval() call. If you have multiple Verilated designs under the same C model, then this will dump signals only from the -design containing the $dumpvar. +design containing the $dumpvars. $dumpvars and $dumpports module identifier is ignored; the traced instances will always start at the top of the design. The levels argument is also @@ -3980,14 +3980,9 @@ $dumplimit/$dumpportlimit are currently ignored. The rarely used optional parameter to $finish and $stop is ignored. =item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets, -$fscanf, $fwrite +$fscanf, $fwrite, $fscanf, $sscanf -File descriptors passed to the file PLI calls must be file descriptors, not -MCDs, which includes the mode parameter to $fopen being mandatory. - -=item $fscanf, $sscanf - -The formats %r, %v, and %z are not supported. +Generally supported. =item $fullskew, $hold, $nochange, $period, $recovery, $recrem, $removal, $setup, $setuphold, $skew, $timeskew, $width @@ -4027,7 +4022,7 @@ $value$plusargs. Warnings may be disabled in three ways. First, when the warning is printed it will include a warning code. Simply surround the offending -line with a warn_off/warn_on pair: +line with a lint_off/lint_on pair: // verilator lint_off UNSIGNED if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop; @@ -4055,7 +4050,7 @@ Digital Equipment Corporation). Some errors or warning have a code attached, with meanings described below. Some errors also have a filename, line number and optional column number (starting at column 1 to match GCC). -Following an the error message, Verilator will typically show the user's +Following the error message, Verilator will typically show the user's source code corresponding to the error, prefixed by the line number and a " | ". Following this is typically an arrow and ~ pointing at the error on the source line directly above. @@ -4103,7 +4098,7 @@ default as a code style warning. =item BLKANDNBLK -BLKANDNBLK is an error that a variable comes from a mix of blocked and +BLKANDNBLK is an error that a variable comes from a mix of blocking and non-blocking assignments. Generally, this is caused by a register driven by both combo logic and a flop: @@ -4122,7 +4117,7 @@ may make Verilator simulations differ from other simulators. It is generally safe to disable this error (with a "// verilator lint_off BLKANDNBLK" metacomment or the -Wno-BLKANDNBLK option) when one of the -assignments is inside a public task, or when the blocked and non-blocking +assignments is inside a public task, or when the blocking and non-blocking assignments have non-overlapping bits and structure members. =item BLKSEQ @@ -4170,7 +4165,7 @@ simulators. Warns that a backslash is followed by a space then a newline. Likely the intent was to have a backslash directly followed by a newline (e.g. when -making a `define) and there's accidentally whitespace at the end of the +making a `define) and there's accidentally white space at the end of the line. If the space is not accidental, suggest removing the backslash in the code as it serves no function. @@ -4316,10 +4311,10 @@ For example: This code will toggle forever, and thus to prevent an infinite loop, the executable will give the didn't converge error. -To debug this, first is to review any UNOPTFLAT warnings that were ignored. +To debug this, first review any UNOPTFLAT warnings that were ignored. Though typically it is safe to ignore UNOPTFLAT (at a performance cost), at -the time of issuing a UNOPTFLAT Verilator didn't know if they would -eventually converge and assumed the would. +the time of issuing a UNOPTFLAT Verilator did not know if the logic would +eventually converge and assumed it would. Next, run Verilator with --prof-cfuncs. Run make on the generated files with "CPP_FLAGS=-DVL_DEBUG", to allow enabling simulation runtime debug @@ -4349,23 +4344,17 @@ correctly. =item GENCLK -Warns that the specified signal is generated, but is also being used as a -clock. Verilator needs to evaluate sequential logic multiple times in this -situation. In somewhat contrived cases having any generated clock can -reduce performance by almost a factor of two. For fastest results, -generate ALL clocks outside in C++/SystemC and make them primary inputs to -your Verilog model. (However once need to you have even one, don't sweat -additional ones.) - -Ignoring this warning may make Verilator simulations differ from other -simulators. +Deprecated and no longer used as a warning. Used to indicate that the +specified signal was is generated inside the model, and also being used as +a clock. =item IFDEPTH Warns that if/if else statements have exceeded the depth specified with ---if-depth, as they are likely to result in slow priority encoders. Unique -and priority if statements are ignored. Solutions include changing the -code to a case statement, or a SystemVerilog 'unique if' or 'priority if'. +--if-depth, as they are likely to result in slow priority encoders. Statements +below unique and priority if statements are ignored. Solutions include +changing the code to a case statement, or a SystemVerilog 'unique if' or +'priority if'. Disabled by default as this is a code style warning; it will simulate correctly. @@ -4426,7 +4415,7 @@ simulators. Warns that an `include filename specifies an absolute path. This means the code will not work on any other system with a different file system layout. Instead of using absolute paths, relative paths (preferably without any -directory specified whatever) should be used, and +incdir used on the +directory specified whatsoever) should be used, and +incdir used on the command line to specify the top include source directories. Disabled by default as this is a code style warning; it will simulate @@ -4435,10 +4424,10 @@ correctly. =item INFINITELOOP Warns that a while or for statement has a condition that is always true. -and thus result in an infinite loop if the statement ever executes. +and thus results in an infinite loop if the statement ever executes. This might be unintended behavior if the loop body contains statements that -in other statements that would make time pass, which Verilator is ignoring +in other simulators would make time pass, which Verilator is ignoring due to e.g. STMTDLY warnings being disabled. Ignoring this warning will only suppress the lint check, it will simulate @@ -4521,7 +4510,7 @@ removed as part of the Verilog module elaboration process.) 3. Multiple modules are intended to be design tops, e.g. when linting a library file. As multiple modules are desired, disable the MULTITOP warning. All input/outputs will go uniquely to each module, with any -conflicting and identical signal names being uniquified by adding a prefix +conflicting and identical signal names being made unique by adding a prefix based on the top module name followed by __02E (a Verilator-encoded ASCII ".'). This renaming is done even if the two modules' signals seem identical, e.g. multiple modules with a "clk" input. @@ -4629,7 +4618,7 @@ interface. * The variable is a parameter, localparam, genvar, or queue. -* The variable is tirstate or bidirectional. (e.g. inout or ref). +* The variable is tristate or bidirectional. (e.g. inout or ref). =item STMTDLY @@ -4644,7 +4633,7 @@ simulators. =item SYMRSVDWORD Warning that a symbol matches a C++ reserved word and using this as a symbol -name would result in odd C compiler errors. You may disable this warning, +name would result in odd C++ compiler errors. You may disable this warning, but the symbol will be renamed by Verilator to avoid the conflict. =item SYNCASYNCNET @@ -4707,8 +4696,8 @@ unexpected timescale. =item UNDRIVEN -Warns that the specified signal is never sourced. Verilator is fairly -liberal in the usage calculations; making a signal public, or loading only +Warns that the specified signal has no source. Verilator is fairly +liberal in the usage calculations; making a signal public, or setting only a single array element marks the entire signal as driven. Disabled by default as this is a code style warning; it will simulate @@ -4718,7 +4707,7 @@ correctly. Warns that due to some construct, optimization of the specified signal or block is disabled. The construct should be cleaned up to improve -simulation runtime. +simulation performance. A less obvious case of this is when a module instantiates two submodules. Inside submodule A, signal I is input and signal O is output. Likewise in @@ -4734,12 +4723,12 @@ correctly. =item UNOPTFLAT Warns that due to some construct, optimization of the specified signal is -disabled. The signal specified includes a complete scope to the signal; it +disabled. The signal reported includes a complete scope to the signal; it may be only one particular usage of a multiply instantiated block. The -construct should be cleaned up to improve simulation runtime; two times better -performance may be possible by fixing these warnings. +construct should be cleaned up to improve simulation performance; two times +better performance may be possible by fixing these warnings. -Unlike the UNOPT warning, this occurs after netlist flattening, and +Unlike the UNOPT warning, this occurs after flattening the netlist, and indicates a more basic problem, as the less obvious case described under UNOPT does not apply. @@ -4818,17 +4807,25 @@ Warns that unpacked structs and unions are not supported. Ignoring this warning will make Verilator treat the structure as packed, which may make Verilator simulations differ from other simulators. This downgrading may also result what would normally be a legal unpacked -struct/array inside an unpacked struct/array becomming an illegal unpacked +struct/array inside an unpacked struct/array becoming an illegal unpacked struct/array inside a packed struct/array. =item UNSIGNED Warns that you are comparing a unsigned value in a way that implies it is -signed, for example "X < 0" will always be true when X is unsigned. +signed, for example "X < 0" will always be false when X is unsigned. Ignoring this warning will only suppress the lint check, it will simulate correctly. +=item UNSUPPORTED + +UNSUPPORTED is an error that the construct might be legal according to IEEE +but is not currently supported. + +This error may be ignored with --bbox-unsup, however this will make the +design simulate incorrectly; see the details under --bbox-unsup. + =item UNUSED Warns that the specified signal is never used/consumed. Verilator is @@ -4851,9 +4848,9 @@ The reduction AND and constant zeros mean the net will always be zero, so won't use simulation runtime. The redundant leading and trailing zeros avoid syntax errors if there are no signals between them. The magic name "unused" (-unused-regexp) is recognized by Verilator and suppresses -warnings; if using other lint tools, either teach to tool to ignore signals -with "unused" in the name, or put the appropriate lint_off around the wire. -Having unused signals in one place makes it easy to find what is unused, +warnings; if using other lint tools, either teach it to the tool to ignore +signals with "unused" in the name, or put the appropriate lint_off around the +wire. Having unused signals in one place makes it easy to find what is unused, and reduces the number of lint_off pragmas, reducing bugs. =item USERINFO, USERWARN, USERERROR, USERFATAL @@ -4938,14 +4935,14 @@ The following deprecated items are scheduled for future removal: =item Pre-C++11 compiler support Verilator supports pre-C++11 compilers for non-threaded models when -configured with --enable-prec11. This flag will be removed and C++11 -compilers will be required for both compiling Verilator and compiling -Verilated models no sooner than September 2020. +configured with --enable-prec11/--enable-prec11-final. This flag will be +removed and C++11 compilers will be required for both compiling Verilator +and compiling Verilated models no sooner than September 2020. =item SystemC 2.2 and earlier support Support for SystemC versions 2.2 and earlier including the related sc_clock -variable attribute will be removed no sooner than August 2020. The +variable attribute will be removed no sooner than September 2020. The supported versions will be SystemC 2.3.0 (SYSTEMC_VERSION 20111121) and later (presently 2.3.0, 2.3.1, 2.3.2, 2.3.3). @@ -4968,18 +4965,19 @@ for removal no sooner than January 2021. =item Can I contribute? -Please contribute! Just file an issue asking for a merge, or ask on the -forums if looking for something to help on. For more information see our +Please contribute! Just submit a pull request, or raise an issue to discuss +if looking for something to help on. For more information see our contributor agreement. -=item How commonly is Verilator used? +=item How widely is Verilator used? -Verilator is used by many of the largest silicon design companies, and all -the way down to college projects. Verilator is a "big 4" simulator, +Verilator is used by many of the largest silicon design companies, and all the +way down to college projects. Verilator is one of the "big 4" simulators, meaning one of the 4 main SystemVerilog simulators available, namely the -commercial products Synopsys' VCS (tm), Mentor's ModelSim (tm), Cadence -Incisive/NC-Verilog/NC-Sim, and the open-source Verilator. The three -commercial choices are commonly collectively called the "big 3" simulators. +commercial products Synopsys VCS (tm), Mentor Questa/ModelSim (tm), Cadence +Xcelium/Incisive/NC-Verilog/NC-Sim (tm), and the open-source Verilator. The +three commercial offerings are often collectively called the "big 3" +simulators. =item Does Verilator run under Windows? @@ -4988,28 +4986,27 @@ C++, but this is not tested every release. =item Can you provide binaries? -Verilator is available as a RPM for Debian/Ubuntu, SuSE, Fedora, and other -distributions; this is done by porters and may slightly lag the primary -distribution. If there isn't a binary build for your distribution, how -about you set one up? Please contact the authors for assistance. - -Note people sometimes request binaries when they are having problems with -their C++ compiler. Alas, binaries won't help this, as in the end a fully -working C++ compiler is required to compile the output of Verilator. +You can install Verilator via the system package manager (apt, yum, etc.) on +many Linux distributions, including Debian, Ubuntu, SuSE, Fedora, and others. +These packages are provided by the Linux distributions and generally will lag +the version of the mainline Verilator repository. If no binary package is +available for your distribution, how about you set one up? Please contact the +authors for assistance. =item How can it be faster than (name-a-big-3-closed-source-simulator)? -Generally, the implied part is of the question is "... with all of the +Generally, the implied part of the question is "... with all of the manpower they can put into developing it." -Most simulators have to be Verilog compliant, meaning event driven. This -prevents them from being able to reorder blocks and make netlist-style +Most simulators have to be compliant with the complete IEEE 1364 (Verilog) and +IEEE 1800 (SystemVerilog) standards, meaning they have to be event driven. +This prevents them from being able to reorder blocks and make netlist-style optimizations, which are where most of the gains come from. -Non-compliance shouldn't be scary. Your synthesis program isn't compliant, -so your simulator shouldn't have to be -- and Verilator is closer to the -synthesis interpretation, so this is a good thing for getting working -silicon. +You should not be scared by non-compliance. Your synthesis tool isn't +compliant with the whole standard to start with, so your simulator need not be +either. Verilator is closer to the synthesis interpretation, so this is a good +thing for getting working silicon. =item Will Verilator output remain under my own license? @@ -5022,7 +5019,7 @@ However, Verilator output (the Verilated code) only "include"s the licensed files, and so you are NOT required to release any output from Verilator. You also have the option of using the Perl Artistic License, which again -does not require you release your Verilog or generated code, and also +does not require you to release your Verilog or generated code, and also allows you to modify Verilator for internal use without distributing the modified version. But please contribute back to the community! @@ -5038,13 +5035,11 @@ and large tests under the LGPL/Artistic, unless requested otherwise. =item Why is running Verilator (to create a model) so slow? Verilator needs more memory than the resulting simulator will require, as -Verilator creates internally all of the state of the resulting generated -simulator in order to optimize it. If it takes more than a minute or so -(and you're not using --debug since debug is disk bound), see if your +Verilator internally creates all of the state of the resulting generated +simulator in order to optimize it. If it takes more than a few minutes or +so (and you're not using --debug since debug mode is disk bound), see if your machine is paging; most likely you need to run it on a machine with more -memory. Verilator is a full 64-bit application and may use more than 4GB, -but about 1GB is the maximum typically needed, and very large designs have -topped 16GB. +memory. Very large designs are known to have topped 16GB resident set size. =item How do I generate waveforms (traces) in C++? @@ -5108,7 +5103,7 @@ Note you can also call ->trace on multiple Verilated objects with the same trace file if you want all data to land in the same output file. When using SystemC 2.3, the SystemC library must have been built with the -experiemntal simulation phase callback based tracing disabled. This is +experimental simulation phase callback based tracing disabled. This is disabled by default when building SystemC with its configure based build system, but when building SystemC with CMake, you must pass -DENABLE_PHASE_CALLBACKS_TRACING=OFF to disable this feature. @@ -5129,16 +5124,19 @@ system, but when building SystemC with CMake, you must pass =item How do I generate FST waveforms (traces) in C++? -FST a format by GTKWave. This version provides a basic FST support. To -dump FST format, add the --trace-fst switch to Verilator and either A. use -$dumpfile/$dumpvars in Verilog as described in the VCD example above, or -B. in C++ change the include described in the VCD example above: +FST is a trace file format developed by GTKWave. Verilator provides basic FST +support. To dump traces in FST format, add the --trace-fst switch to Verilator +and either A. use $dumpfile/$dumpvars in Verilog as described in the VCD +example above, or B. in C++ change the include described in the VCD example +above: #include "verilated_fst_c.h" VerilatedFstC* tfp = new VerilatedFstC; Note that currently supporting both FST and VCD in a single simulation is -impossible, but such requirement should be rare. +impossible, but such requirement should be rare. You can however ifdef +around the trace format in your C++ main loop, and select VCD or FST at +build time, should you require. =item How do I generate FST waveforms (aka dumps or traces) in SystemC? @@ -5147,34 +5145,39 @@ format instead. =item How do I view waveforms (aka dumps or traces)? -Verilator makes standard VCD (Value Change Dump) and FST files. VCD files -are viewable with the public domain GTKWave (recommended) or Dinotrace -(legacy) programs, or any of the many closed-source offerings; FST is -supported by GTKWave only. +Verilator creates standard VCD (Value Change Dump) and FST files. VCD files +are viewable with the open source GTKWave (recommended) or Dinotrace (legacy) +programs, or any of the many closed-source offerings; FST is supported only by +GTKWave. =item How do I reduce the size of large waveform (trace) files? First, instead of calling VerilatedVcdC->open at the beginning of time, -delay calling it until the time stamp where you want to tracing to begin. +delay calling it until the time stamp where you want tracing to begin. Likewise you can also call VerilatedVcdC->open before the end of time -(perhaps a short period after you detect a verification error.) +(perhaps a short period after you detect a verification error). Next, add /*verilator tracing_off*/ to any very low level modules you never want to trace (such as perhaps library cells). Finally, use the --trace-depth option to limit the depth of tracing, for example --trace-depth 1 to see only the top level signals. -Also be sure you write your trace files to a local solid-state disk, -instead of to a network disk. Network disks are generally far slower. +Also be sure you write your trace files to a local solid-state drive, +instead of to a network drive. Network drives are generally far slower. + +You can also consider using FST tracing instead of VCD. FST dumps are a +fraction of the size of the equivalent VCD. FST tracing can be slower than +VCD tracing, but it might be the only option if the VCD file size is +prohibitively large. =item How do I do coverage analysis? Verilator supports both block (line) coverage and user inserted functional coverage. -First, run verilator with the --coverage option. If you're using your own +First, run verilator with the --coverage option. If you are using your own makefile, compile the model with the GCC flag -DVM_COVERAGE (if using -Verilator's, it will do this for you.) +the makefile provided by Verilator, it will do this for you). At the end of your test, call VerilatedCov::write passing the name of the coverage data file (typically "logs/coverage.dat"). @@ -5182,8 +5185,8 @@ coverage data file (typically "logs/coverage.dat"). Run each of your tests in different directories. Each test will create a logs/coverage.dat file. -After running all of your tests, verilator_coverage is executed. -Verilator_coverage reads the logs/coverage.dat file(s), and creates an +After running all of your tests, execute the verilator_coverage tool. The +verilator_coverage tool reads the logs/coverage.dat file(s), and creates an annotated source code listing showing code coverage details. For an example, after running 'make test' in the Verilator distribution, @@ -5207,9 +5210,10 @@ the "VERILATOR" define for you, so just wrap the code in an ifndef region: Most synthesis tools similarly define SYNTHESIS for you. -=item Why do I get "unexpected `do'" or "unexpected `bit'" errors? +=item Why do I get "unexpected C" or "unexpected C" errors? -Do, bit, ref, return, and other words are now SystemVerilog keywords. You +The words C, C, C, C, and others are reserved keywords +in SystemVerilog. Older Verilog code might use these as identifiers. You should change your code to not use them to ensure it works with newer tools. Alternatively, surround them by the Verilog 2005/SystemVerilog begin_keywords pragma to indicate Verilog 2001 code. @@ -5218,14 +5222,8 @@ begin_keywords pragma to indicate Verilog 2001 code. integer bit; initial bit = 1; `end_keywords -If you want the whole file to be parsed as Verilog 2001, just create a -file with - - `begin_keywords "1364-2001" - -and add it before other Verilog files on the command line. (Note this will -also change the default for --prefix, so if you're not using --prefix, you -will now need to.) +If you want the whole design to be parsed as Verilog 2001, please see the +C<--default-language> option. =item How do I prevent my assertions from firing during reset? @@ -5295,16 +5293,23 @@ uses one large symbol table, as that results in 2-3 less assembly instructions for each signal access. This makes the execution time 10-15% faster, but can result in more compilations when something changes. -=item How do I access functions/tasks in C? +=item How do I access Verilog functions/tasks in C? Use the SystemVerilog Direct Programming Interface. You write a Verilog function or task with input/outputs that match what you want to call in -with C. Then mark that function as an external function. See the DPI -chapter in the manual. +with C. Then mark that function as a DPI export function. See the DPI +chapter in the IEEE Standard. + +=item How do I access C++ functions/tasks in Verilog? + +Use the SystemVerilog Direct Programming Interface. You write a Verilog +function or task with input/outputs that match what you want to call in +with C. Then mark that function as a DPI import function. See the DPI +chapter in the IEEE Standard. =item How do I access signals in C? -The best thing is to make a SystemVerilog "export DPI task" or function +The best thing to do is to make a SystemVerilog "export DPI" task or function that accesses that signal, as described in the DPI chapter in the manual and DPI tutorials on the web. This will allow Verilator to better optimize the model and should be portable across simulators. @@ -5369,7 +5374,7 @@ SystemC module *may* be faster.) =head1 BUGS -First, check the coding limitations section. +First, check the L section. Next, try the --debug switch. This will enable additional internal assertions, and may help identify the problem. @@ -5382,7 +5387,7 @@ follows: cp -p t/t_EXAMPLE.pl t/t_BUG.pl cp -p t/t_EXAMPLE.v t/t_BUG.v -There are many hits on how to write a good test in the driver.pl +There are many hints on how to write a good test in the driver.pl documentation which can be seen by running: cd $VERILATOR_ROOT # Need the original distribution kit @@ -5560,6 +5565,7 @@ released as Creative Commons Public Domain (CC0). Many example files and test files are likewise released under CC0 into effectively the Public Domain as described in the files themselves. + =head1 SEE ALSO L, L, L, L, @@ -5571,3 +5577,6 @@ and docs/internals.adoc in the distribution. =cut ###################################################################### +# Local Variables: +# fill-column: 75 +# End: diff --git a/ci/travis-install.bash b/ci/travis-install.bash index 6fb552ca5..f4c89c9bd 100755 --- a/ci/travis-install.bash +++ b/ci/travis-install.bash @@ -25,11 +25,21 @@ fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } +if [ "$TRAVIS_OS_NAME" = "linux" ]; then + MAKE=make +elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + MAKE=make +elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then + MAKE=gmake +else + fatal "Unknown os: '$TRAVIS_OS_NAME'" +fi + install-vcddiff() { TMP_DIR="$(mktemp -d)" git clone https://github.com/veripool/vcddiff "$TMP_DIR" git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c - make -C "${TMP_DIR}" + "$MAKE" -C "${TMP_DIR}" sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin } @@ -39,12 +49,20 @@ if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then # build Verilator if [ "$TRAVIS_OS_NAME" = "linux" ]; then - time sudo apt-get update + sudo apt-get update sudo apt-get install libfl-dev sudo apt-get install libgoogle-perftools-dev if [ "$COVERAGE" = 1 ]; then yes yes | sudo cpan -fi Unix::Processors Parallel::Forker fi + if [ "$M32" = 1 ]; then + sudo apt-get install gcc-multilib g++-multilib + fi + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + brew update + brew install ccache perl gperftools + elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then + sudo pkg install -y autoconf bison ccache gmake perl5 else fatal "Unknown os: '$TRAVIS_OS_NAME'" fi @@ -59,9 +77,23 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then if [ "$TRAVIS_DIST" = "focal" ]; then sudo apt-get install libsystemc-dev fi + if [ "$M32" = 1 ]; then + sudo apt-get install lib32z1-dev gcc-multilib g++-multilib + fi yes yes | sudo cpan -fi Unix::Processors Parallel::Forker # Not listing Bit::Vector as slow to install, and only skips one test install-vcddiff + elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + brew update + # brew cask install gtkwave # fst2vcd hangs at launch, so don't bother + brew install ccache perl + yes yes | sudo cpan -fi Unix::Processors Parallel::Forker + install-vcddiff + elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then + # fst2vcd fails with "Could not open '', exiting." + sudo pkg install -y ccache gmake perl5 python3 + yes yes | sudo cpan -fi Unix::Processors Parallel::Forker + install-vcddiff else fatal "Unknown os: '$TRAVIS_OS_NAME'" fi diff --git a/ci/travis-script.bash b/ci/travis-script.bash index e87e62429..c80443053 100755 --- a/ci/travis-script.bash +++ b/ci/travis-script.bash @@ -22,77 +22,110 @@ fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } +if [ "$TRAVIS_OS_NAME" = "linux" ]; then + export MAKE=make + NPROC=$(nproc) +elif [ "$TRAVIS_OS_NAME" = "osx" ]; then + export MAKE=make + NPROC=$(sysctl -n hw.logicalcpu) +elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then + export MAKE=gmake + NPROC=$(sysctl -n hw.ncpu) +else + fatal "Unknown os: '$TRAVIS_OS_NAME'" +fi + if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then ############################################################################## # Build verilator - if [ "$TRAVIS_OS_NAME" = "linux" ]; then - if [ "$COVERAGE" != 1 ]; then - autoconf - ./configure --enable-longtests --enable-ccwarn - make -j $(nproc) - else - nodist/code_coverage --stages 1-2 + if [ "$COVERAGE" != 1 ]; then + autoconf + ./configure --enable-longtests --enable-ccwarn + "$MAKE" -j "$NPROC" + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + file bin/verilator_bin + file bin/verilator_bin_dbg + md5 bin/verilator_bin + md5 bin/verilator_bin_dbg + stat bin/verilator_bin + stat bin/verilator_bin_dbg fi else - fatal "Unknown os: '$TRAVIS_OS_NAME'" + nodist/code_coverage --stages 1-2 fi elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then ############################################################################## # Run tests - if [ "$TRAVIS_OS_NAME" = "linux" ]; then - # Run the specified test - case $TESTS in - dist-vlt-0) - make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2 - ;; - dist-vlt-1) - make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2 - ;; - vltmt-0) - make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 - ;; - vltmt-1) - make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2 - ;; - coverage-dist) - nodist/code_coverage --stages 3- --scenarios=--dist - ;; - coverage-vlt-0) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4 - ;; - coverage-vlt-1) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4 - ;; - coverage-vlt-2) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4 - ;; - coverage-vlt-3) - nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4 - ;; - coverage-vltmt-0) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4 - ;; - coverage-vltmt-1) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4 - ;; - coverage-vltmt-2) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4 - ;; - coverage-vltmt-3) - nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4 - ;; - *) - fatal "Unknown test: $TESTS" - ;; - esac - # Upload coverage data to codecov.io - if [[ $TESTS == coverage-* ]]; then - bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info - fi - else - fatal "Unknown os: '$TRAVIS_OS_NAME'" + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X + export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg + # export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd + file bin/verilator_bin + file bin/verilator_bin_dbg + md5 bin/verilator_bin + md5 bin/verilator_bin_dbg + stat bin/verilator_bin + stat bin/verilator_bin_dbg + # For some reason, the dbg exe is corrupted by this point ('file' reports + # it as data rather than a Mach-O). Unclear if this is an OS X issue or + # one for Travis. Remove the file and re-link... + rm bin/verilator_bin_dbg + "$MAKE" -j "$NPROC" + elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then + export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run + export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable + fi + + # Run the specified test + case $TESTS in + dist-vlt-0) + "$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2 + ;; + dist-vlt-1) + "$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2 + ;; + vltmt-0) + "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 + ;; + vltmt-1) + "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2 + ;; + coverage-dist) + nodist/code_coverage --stages 3- --scenarios=--dist + ;; + coverage-vlt-0) + nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4 + ;; + coverage-vlt-1) + nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4 + ;; + coverage-vlt-2) + nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4 + ;; + coverage-vlt-3) + nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4 + ;; + coverage-vltmt-0) + nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4 + ;; + coverage-vltmt-1) + nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4 + ;; + coverage-vltmt-2) + nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4 + ;; + coverage-vltmt-3) + nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4 + ;; + *) + fatal "Unknown test: $TESTS" + ;; + esac + # Upload coverage data to codecov.io + if [[ $TESTS == coverage-* ]]; then + bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info fi else ############################################################################## diff --git a/configure.ac b/configure.ac index 809200482..6a866b524 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.036 2020-06-06], +AC_INIT([Verilator],[4.038 2020-07-11], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file @@ -114,25 +114,25 @@ AC_MSG_RESULT($CFG_WITH_LONGTESTS) # CFG_WITH_PREC11 AC_MSG_CHECKING(whether allow pre-C++11) -AC_ARG_ENABLE([prec11], - [AS_HELP_STRING([--enable-prec11], +AC_ARG_ENABLE([prec11-final], + [AS_HELP_STRING([--enable-prec11-final], [enable pre-C++11 compilers for Verilator binary and Verilated makefiles])], [case "${enableval}" in yes) CFG_WITH_PREC11=yes ;; no) CFG_WITH_PREC11=no ;; - *) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11]) ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11-final]) ;; esac], [CFG_WITH_PREC11=no;] ) AC_SUBST(CFG_WITH_PREC11) AC_MSG_RESULT($CFG_WITH_PREC11) -# Compiler flags -CFLAGS+=" -I${includedir}" -CPPFLAGS+=" -I${includedir}" -CXXFLAGS+=" -I${includedir}" -LDFLAGS+=" -L${libdir}" +# Compiler flags (ensure they are not empty to avoid configure defaults) +CFLAGS+=" " +CPPFLAGS+=" " +CXXFLAGS+=" " +LDFLAGS+=" " # Checks for programs. AC_PROG_CC @@ -153,14 +153,20 @@ AC_PATH_PROG(PERL,perl) if test "x$PERL" = "x" ; then AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it]) fi + AC_PATH_PROG(LEX,flex) if test "x$LEX" = "x" ; then AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it]) fi +flex_version=$($LEX --version | head -1) +AC_MSG_RESULT([$LEX --version = $flex_version]) + AC_PATH_PROG(YACC,bison) if test "x$YACC" = "x" ; then AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it]) fi +bison_version=$($YACC --version | head -1) +AC_MSG_RESULT([$YACC --version = $bison_version]) AC_CHECK_PROG(OBJCACHE,ccache,ccache) if test "x$OBJCACHE" != "x" ; then @@ -427,12 +433,11 @@ if test "$CFG_WITH_THREADED" = "no" ; then AC_MSG_NOTICE([[]]) AC_MSG_ERROR([[the $CXX compiler appears to not support C++11. -Verilator plans to require a C++11 or newer compiler in a future release, -unless sufficient people report problems. Therefore, if you do not have a -C++11 compiler, please post a message to -https://www.veripool.org/boards/3/topics/2580-Verilator-Requiring-C-11-compiler -indicating your OS and when you think C++11 might be ok, and then rerun -configure with the --enable-prec11 argument. Thanks.]]) +Verilator will require a C++11 or newer compiler for all releases starting +September 2020. Please investigate a C++11 build environment now so you +will be ready. Until then you may rerun configure with the +--enable-prec11-final argument to enable reduced functionality with such +older compilers. Thanks.]]) fi fi @@ -447,14 +452,18 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec], # - If not found or not system-wide, user can set SYSTEMC_INCLUDE. # AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work. AC_MSG_CHECKING([whether SystemC is found (in system path)]) -AC_COMPILE_IFELSE( +ACO_SAVE_LIBS="$LIBS" +LIBS="$LIBS -lsystemc" +AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include - ]],[])], + extern "C" int sc_main(int argc, char* argv[]) {} + ]],[[sc_version()]])], [_my_result=yes - AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])], + AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])], [_my_result=no]) AC_MSG_RESULT($_my_result) -AC_SUBST(HAVE_SYSTEMC_H) +LIBS="$ACO_SAVE_LIBS" +AC_SUBST(HAVE_SYSTEMC) # Checks for system services diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 4426b7e75..cc00fe3a1 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -6,15 +6,18 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all. Ahmed El-Mahmoudy Alex Chadwick Chris Randall +Conor McCullough Dan Petrisko David Horton David Stanford Driss Hafdi Eric Rippey +Fan Shupei Garrett Smith Geza Lore Gianfranco Costamagna Glen Gibb +Harald Heckmann Howard Su Huang Rui Iztok Jeras diff --git a/docs/install.adoc b/docs/install.adoc index a61171896..d3b13b244 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -39,7 +39,7 @@ brief: #sudo apt-get install libfl2 # Ubuntu only (ignore if gives error) #sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) -git clone https://git.veripool.org/git/verilator # Only first time +git clone https://github.com/verilator/verilator # Only first time ## Note the URL above is not a page you can see with a browser, it's for git only # Every time you need to build: @@ -89,7 +89,7 @@ To build or run the following are optional but should be installed for good performance: sudo apt-get install ccache # If present at build, needed for run - sudo apt-get install libgoogle-perftools-dev numactl + sudo apt-get install libgoogle-perftools-dev numactl perl-doc To build Verilator you will need to install these packages; these do not need to be present to run Verilator: @@ -128,7 +128,7 @@ Downloads]; we presume you know how to use it, and is not described here.) Get the sources from the repository: (You need do this only once, ever.) - git clone https://git.veripool.org/git/verilator # Only first time + git clone https://github.com/verilator/verilator # Only first time ## Note the URL above is not a page you can see with a browser, it's for git only Enter the checkout and determine what version/branch to use: diff --git a/docs/internals.adoc b/docs/internals.adoc index d5c41a954..22dbd1ad4 100644 --- a/docs/internals.adoc +++ b/docs/internals.adoc @@ -777,9 +777,10 @@ output, for example: You can then print a.ps. You may prefer gif format, which doesn't get scaled so can be more useful with large graphs. -For dynamic graph viewing consider +For interactive graph viewing consider +https://github.com/jrfonseca/xdot.py[xdot] or http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of -better viewers let us know; ZGRViewer isn't great for large graphs. +better viewers (especially for large graphs) please let us know. === .tree Output diff --git a/examples/make_protect_lib/Makefile b/examples/make_protect_lib/Makefile index 8a82d9372..319ce5c4a 100644 --- a/examples/make_protect_lib/Makefile +++ b/examples/make_protect_lib/Makefile @@ -68,7 +68,7 @@ run: @echo " library (libverilated_secret.a) generated from the previous" @echo " step" @echo "---------------------------------------------------------------" - $(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp + $(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '../obj_dir_secret/libverilated_secret.a' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp @echo @echo "-- COMPILE entire design --------------------------------------" diff --git a/include/gtkwave/fst_config.h b/include/gtkwave/fst_config.h index 29a6c5d98..43fbd90ee 100644 --- a/include/gtkwave/fst_config.h +++ b/include/gtkwave/fst_config.h @@ -3,7 +3,7 @@ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have and it should be used (not on Ultrix). */ -#if !defined(__MINGW32__) +#if !defined(__MINGW32__) && !defined(__FreeBSD__) # define HAVE_ALLOCA_H 1 #endif diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index 8540587bb..d311c756d 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -794,6 +794,7 @@ pthread_t thread; pthread_attr_t thread_attr; struct fstWriterContext *xc_parent; #endif +unsigned in_pthread : 1; size_t fst_orig_break_size; size_t fst_orig_break_add_size; @@ -1806,10 +1807,9 @@ static void *fstWriterFlushContextPrivate1(void *ctx) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +pthread_mutex_lock(&(xc->xc_parent->mutex)); fstWriterFlushContextPrivate2(xc); -pthread_mutex_unlock(&(xc->xc_parent->mutex)); - #ifdef FST_REMOVE_DUPLICATE_VC free(xc->curval_mem); #endif @@ -1818,6 +1818,9 @@ free(xc->vchg_mem); tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); free(xc); +xc->xc_parent->in_pthread = 0; +pthread_mutex_unlock(&(xc->xc_parent->mutex)); + return(NULL); } @@ -1865,7 +1868,15 @@ if(xc->parallel_enabled) xc->section_header_only = 0; xc->secnum++; + while (xc->in_pthread) + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + }; + pthread_mutex_lock(&xc->mutex); + xc->in_pthread = 1; + pthread_mutex_unlock(&xc->mutex); pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2); } @@ -1947,6 +1958,12 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) #ifdef FST_WRITER_PARALLEL pthread_mutex_lock(&xc->mutex); pthread_mutex_unlock(&xc->mutex); + + while (xc->in_pthread) + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + }; #endif } } diff --git a/include/verilated.cpp b/include/verilated.cpp index c8582ab77..72f3e97c9 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -31,6 +31,8 @@ #include #include #include // mkdir +#include +#include // clang-format off #if defined(_WIN32) || defined(__MINGW32__) @@ -59,7 +61,6 @@ typedef union { // Slow path variables VerilatedMutex Verilated::m_mutex; -VerilatedVoidCb Verilated::s_flushCb = NULL; // Keep below together in one cache line Verilated::Serialized Verilated::s_s; @@ -83,7 +84,8 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE if (Verilated::gotFinish()) { VL_PRINTF( // Not VL_PRINTF_MT, already on main thread "- %s:%d: Second verilog $finish, exiting\n", filename, linenum); - Verilated::flushCall(); + Verilated::runFlushCallbacks(); + Verilated::runExitCallbacks(); exit(0); } Verilated::gotFinish(true); @@ -93,7 +95,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE #ifndef VL_USER_STOP ///< Define this to override this function void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { Verilated::gotFinish(true); - Verilated::flushCall(); + Verilated::runFlushCallbacks(); vl_fatal(filename, linenum, hier, "Verilog $stop"); } #endif @@ -108,10 +110,15 @@ void vl_fatal(const char* filename, int linenum, const char* hier, const char* m } else { VL_PRINTF("%%Error: %s\n", msg); } - Verilated::flushCall(); + Verilated::runFlushCallbacks(); VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread - Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush + + // Second flush in case VL_PRINTF does something needing a flush + Verilated::runFlushCallbacks(); + + // Callbacks prior to termination + Verilated::runExitCallbacks(); abort(); } #endif @@ -1700,7 +1707,7 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_ static const char* memhFormat(int nBits) { assert((nBits >= 1) && (nBits <= 32)); - static char buf[32]; + static VL_THREAD_LOCAL char buf[32]; switch ((nBits - 1) / 4) { case 0: VL_SNPRINTF(buf, 32, "%%01x"); break; case 1: VL_SNPRINTF(buf, 32, "%%02x"); break; @@ -1715,6 +1722,18 @@ static const char* memhFormat(int nBits) { return buf; } +static const char* formatBinary(int nBits, vluint32_t bits) { + assert((nBits >= 1) && (nBits <= 32)); + + static VL_THREAD_LOCAL char buf[64]; + for (int i = 0; i < nBits; i++) { + bool isOne = bits & (1 << (nBits - 1 - i)); + buf[i] = (isOne ? '1' : '0'); + } + buf[nBits] = '\0'; + return buf; +} + VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end) : m_hex(hex) , m_bits(bits) @@ -1852,14 +1871,9 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) { } VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end) - : m_bits(bits) + : m_hex(hex) + , m_bits(bits) , m_addr(0) { - if (VL_UNLIKELY(!hex)) { - VL_FATAL_MT(filename.c_str(), 0, "", - "Unsupported: $writemem binary format (suggest hex format)"); - return; - } - if (VL_UNLIKELY(start > end)) { VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range"); return; @@ -1886,23 +1900,40 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) { m_addr = addr + 1; if (m_bits <= 8) { const CData* datap = reinterpret_cast(valuep); - fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); - fprintf(m_fp, "\n"); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); + fprintf(m_fp, "\n"); + } else { + fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap)); + } } else if (m_bits <= 16) { const SData* datap = reinterpret_cast(valuep); - fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); - fprintf(m_fp, "\n"); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); + fprintf(m_fp, "\n"); + } else { + fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap)); + } } else if (m_bits <= 32) { const IData* datap = reinterpret_cast(valuep); - fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); - fprintf(m_fp, "\n"); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap); + fprintf(m_fp, "\n"); + } else { + fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap)); + } } else if (m_bits <= 64) { const QData* datap = reinterpret_cast(valuep); vluint64_t value = VL_MASK_Q(m_bits) & *datap; vluint32_t lo = value & 0xffffffff; vluint32_t hi = value >> 32; - fprintf(m_fp, memhFormat(m_bits - 32), hi); - fprintf(m_fp, "%08x\n", lo); + if (m_hex) { + fprintf(m_fp, memhFormat(m_bits - 32), hi); + fprintf(m_fp, "%08x\n", lo); + } else { + fprintf(m_fp, "%s", formatBinary(m_bits - 32, hi)); + fprintf(m_fp, "%s\n", formatBinary(32, lo)); + } } else { WDataInP datap = reinterpret_cast(valuep); // output as a sequence of VL_EDATASIZE'd words @@ -1915,9 +1946,17 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) { if (first) { data &= VL_MASK_E(m_bits); int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1; - fprintf(m_fp, memhFormat(top_word_nbits), data); + if (m_hex) { + fprintf(m_fp, memhFormat(top_word_nbits), data); + } else { + fprintf(m_fp, "%s", formatBinary(top_word_nbits, data)); + } } else { - fprintf(m_fp, "%08x", data); + if (m_hex) { + fprintf(m_fp, "%08x", data); + } else { + fprintf(m_fp, "%s", formatBinary(32, data)); + } } word_idx--; first = false; @@ -2242,29 +2281,60 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim return strp; } -void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - if (s_flushCb == cb) { // Ok - don't duplicate - } else if (!s_flushCb) { - s_flushCb = cb; - } else { // LCOV_EXCL_LINE - // Someday we may allow multiple callbacks ala atexit(), but until then - VL_FATAL_MT("unknown", 0, "", // LCOV_EXCL_LINE - "Verilated::flushCb called twice with different callbacks"); - } +//========================================================================= +// Flush and exit callbacks + +// Keeping these out of class Verilated to avoid having to include +// in verilated.h (for compilation speed) +typedef std::list > VoidPCbList; +static VoidPCbList g_flushCbs; +static VoidPCbList g_exitCbs; + +static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) { + std::pair pair(cb, datap); + cbs.remove(pair); // Just in case it's a duplicate + cbs.push_back(pair); +} +static void removeCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) { + std::pair pair(cb, datap); + cbs.remove(pair); +} +static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE { + for (VoidPCbList::iterator it = cbs.begin(); it != cbs.end(); ++it) { it->first(it->second); } } -// When running internal code coverage (gcc --coverage, as opposed to -// verilator --coverage), dump coverage data to properly cover failing -// tests. -void Verilated::flushCall() VL_MT_SAFE { +void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE { const VerilatedLockGuard lock(m_mutex); - if (s_flushCb) (*s_flushCb)(); + addCb(cb, datap, g_flushCbs); +} +void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE { + const VerilatedLockGuard lock(m_mutex); + removeCb(cb, datap, g_flushCbs); +} +void Verilated::runFlushCallbacks() VL_MT_SAFE { + const VerilatedLockGuard lock(m_mutex); + runCallbacks(g_flushCbs); fflush(stderr); fflush(stdout); + // When running internal code coverage (gcc --coverage, as opposed to + // verilator --coverage), dump coverage data to properly cover failing + // tests. VL_GCOV_FLUSH(); } +void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE { + const VerilatedLockGuard lock(m_mutex); + addCb(cb, datap, g_exitCbs); +} +void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE { + const VerilatedLockGuard lock(m_mutex); + removeCb(cb, datap, g_exitCbs); +} +void Verilated::runExitCallbacks() VL_MT_SAFE { + const VerilatedLockGuard lock(m_mutex); + runCallbacks(g_exitCbs); +} + const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; } const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; } @@ -2565,7 +2635,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_ } } -void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, +void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam, VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE { // Grab dimensions // In the future we may just create a large table at emit time and @@ -2573,7 +2643,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, if (!finalize) return; if (!m_varsp) m_varsp = new VerilatedVarNameMap(); - VerilatedVar var(namep, datap, vltype, static_cast(vlflags), dims); + VerilatedVar var(namep, datap, vltype, static_cast(vlflags), dims, isParam); va_list ap; va_start(ap, dims); diff --git a/include/verilated.h b/include/verilated.h index 5e25d2f35..f9cb28fbe 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -84,10 +84,6 @@ typedef EData WData; ///< Verilated pack data, >64 bits, as an array typedef const WData* WDataInP; ///< Array input to a function typedef WData* WDataOutP; ///< Array output from a function -typedef void (*VerilatedVoidCb)(void); - -class SpTraceVcd; -class SpTraceVcdCFile; class VerilatedEvalMsgQueue; class VerilatedScopeNameMap; class VerilatedVar; @@ -339,8 +335,8 @@ public: // But internals only - called from VerilatedModule's void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE; void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE; - void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, - int vlflags, int dims, ...) VL_MT_UNSAFE; + void varInsert(int finalize, const char* namep, void* datap, bool isParam, + VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE; // ACCESSORS const char* name() const { return m_namep; } const char* identifier() const { return m_identifierp; } @@ -376,8 +372,6 @@ class Verilated { // Slow path variables static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED - static VerilatedVoidCb s_flushCb; ///< Flush callback function - static struct Serialized { // All these members serialized/deserialized // Fast path int s_debug; ///< See accessors... only when VL_DEBUG set @@ -501,9 +495,15 @@ public: static void profThreadsFilenamep(const char* flagp) VL_MT_SAFE; static const char* profThreadsFilenamep() VL_MT_SAFE { return s_ns.s_profThreadsFilenamep; } - /// Flush callback for VCD waves - static void flushCb(VerilatedVoidCb cb) VL_MT_SAFE; - static void flushCall() VL_MT_SAFE; + typedef void (*VoidPCb)(void*); // Callback type for below + /// Callbacks to run on global flush + 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; + /// 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; + static void runExitCallbacks() VL_MT_SAFE; /// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs, /// and for parsing +verilator+ run-time arguments. @@ -843,7 +843,7 @@ inline vluint64_t vl_time_stamp64() { return static_cast(sc_time_sta // Optimized assuming scale is always constant. // 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() * (1.0 / (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); @@ -1571,24 +1571,30 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP static inline IData VL_DIVS_III(int lbits, IData lhs, IData rhs) VL_PURE { if (VL_UNLIKELY(rhs == 0)) return 0; + // -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE + if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0; vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs); vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs); return lhs_signed / rhs_signed; } static inline QData VL_DIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE { if (VL_UNLIKELY(rhs == 0)) return 0; + // -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE + if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0; vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs); vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs); return lhs_signed / rhs_signed; } static inline IData VL_MODDIVS_III(int lbits, IData lhs, IData rhs) VL_PURE { if (VL_UNLIKELY(rhs == 0)) return 0; + if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0; vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs); vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs); return lhs_signed % rhs_signed; } static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE { if (VL_UNLIKELY(rhs == 0)) return 0; + if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0; vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs); vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs); return lhs_signed % rhs_signed; diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index d09aed228..65459998d 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -220,20 +220,19 @@ private: } static void selftest() VL_MT_SAFE { // Little selftest -#define VL_CST_CHECK(got, exp) \ +#define SELF_CHECK(got, exp) \ do { \ if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \ } while (0) - - VL_CST_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c"); - VL_CST_CHECK(combineHier("a.b.c", "a.b"), "a.b*"); - VL_CST_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c"); - VL_CST_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c"); - VL_CST_CHECK(combineHier("z", "a"), "*"); - VL_CST_CHECK(combineHier("q.a", "q.b"), "q.*"); - VL_CST_CHECK(combineHier("q.za", "q.zb"), "q.z*"); - VL_CST_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a"); -#undef VL_CST_CHECK + SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c"); + SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*"); + SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c"); + SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c"); + SELF_CHECK(combineHier("z", "a"), "*"); + SELF_CHECK(combineHier("q.a", "q.b"), "q.*"); + SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*"); + SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a"); +#undef SELF_CHECK } void clearGuts() VL_REQUIRES(m_mutex) { for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) { diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 6cc3e20de..a006bd6fa 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -133,8 +133,6 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV VerilatedTrace::declCode(code, bits, false); - std::pair p - = m_code2symbol.insert(std::make_pair(code, static_cast(NULL))); std::istringstream nameiss(name); std::istream_iterator beg(nameiss); std::istream_iterator end; @@ -174,11 +172,13 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV fstEnumHandle enumNum = m_local2fstdtype[dtypenum]; fstWriterEmitEnumTableRef(m_fst, enumNum); } - if (p.second) { // New - p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0); - assert(p.first->second); + + Code2SymbolType::const_iterator it = m_code2symbol.find(code); + if (it == m_code2symbol.end()) { // New + m_code2symbol[code] + = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0); } else { // Alias - fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second); + fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second); } } diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 03df61629..2241bf8d1 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -62,6 +62,7 @@ public: }; class VlWriteMem { + bool m_hex; // Hex format int m_bits; // Bit width of values FILE* m_fp; // File handle for filename QData m_addr; // Next address to write diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 0260a4154..78007b096 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -487,8 +487,8 @@ public: // But only for verilated*.cpp const VerilatedLockGuard lock(s_s.m_fdMutex); if (s_s.m_fdFree.empty()) { // Need to create more space in m_fdps and m_fdFree - const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size()); - const size_t excess = 10; + const std::size_t start = std::max(31UL + 1UL + 3UL, s_s.m_fdps.size()); + const std::size_t excess = 10; s_s.m_fdps.resize(start + excess); std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0); s_s.m_fdFree.resize(excess); diff --git a/include/verilated_save.cpp b/include/verilated_save.cpp index 0972f513f..e571e9cf8 100644 --- a/include/verilated_save.cpp +++ b/include/verilated_save.cpp @@ -129,7 +129,7 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE { // cppcheck-suppress duplicateExpression m_fd = ::open(filenamep, O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666); - if (m_fd < 0) { + if (VL_UNLIKELY(m_fd < 0)) { // User code can check isOpen() m_isOpen = false; return; @@ -151,7 +151,7 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE { } else { // cppcheck-suppress duplicateExpression m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666); - if (m_fd < 0) { + if (VL_UNLIKELY(m_fd < 0)) { // User code can check isOpen() m_isOpen = false; return; diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index e95b67ad6..51d154e18 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -232,13 +232,15 @@ class VerilatedVar : public VerilatedVarProps { void* m_datap; // Location of data const char* m_namep; // Name - slowpath protected: + bool m_isParam; friend class VerilatedScope; // CONSTRUCTORS VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype, - VerilatedVarFlags vlflags, int dims) + VerilatedVarFlags vlflags, int dims, bool isParam) : VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)) , m_datap(datap) - , m_namep(namep) {} + , m_namep(namep) + , m_isParam(isParam) {} public: ~VerilatedVar() {} @@ -247,6 +249,7 @@ public: const VerilatedRange& range() const { return packed(); } // Deprecated const VerilatedRange& array() const { return unpacked(); } // Deprecated const char* name() const { return m_namep; } + bool isParam() const { return m_isParam; } }; #endif // Guard diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 8a99bf07d..ab854d9fd 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -158,6 +158,11 @@ private: // to access duck-typed functions to avoid a virtual function call. T_Derived* self() { return static_cast(this); } + // Flush any remaining data for this file + static void onFlush(void* selfp) VL_MT_UNSAFE_ONE; + // Close the file on termination + static void onExit(void* selfp) VL_MT_UNSAFE_ONE; + #ifdef VL_TRACE_THREADED // Number of total trace buffers that have been allocated vluint32_t m_numTraceBuffers; diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index 507b3b3ab..3980a984c 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -258,6 +258,19 @@ template <> void VerilatedTrace::flush() { #endif } +//============================================================================= +// Callbacks to run on global events + +template <> void VerilatedTrace::onFlush(void* selfp) { + // Note this calls 'flush' on the derived class + reinterpret_cast(selfp)->flush(); +} + +template <> void VerilatedTrace::onExit(void* selfp) { + // Note this calls 'close' on the derived class + reinterpret_cast(selfp)->close(); +} + //============================================================================= // VerilatedTrace @@ -282,6 +295,8 @@ VerilatedTrace::VerilatedTrace() template <> VerilatedTrace::~VerilatedTrace() { if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); + Verilated::removeFlushCb(VerilatedTrace::onFlush, this); + Verilated::removeExitCb(VerilatedTrace::onExit, this); #ifdef VL_TRACE_THREADED close(); #endif @@ -318,6 +333,10 @@ template <> void VerilatedTrace::traceInit() VL_MT_UNSAFE { // holding previous signal values. if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()]; + // Set callback so flush/abort will flush this file + Verilated::addFlushCb(VerilatedTrace::onFlush, this); + Verilated::addExitCb(VerilatedTrace::onExit, this); + #ifdef VL_TRACE_THREADED // Compute trace buffer size. we need to be able to store a new value for // each signal, which is 'nextCode()' entries after the init callbacks diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index 2387275a5..e38f507cf 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -66,47 +66,6 @@ #include "verilated_trace_imp.cpp" #undef VL_DERIVED_T -//============================================================================= -// VerilatedVcdImp -/// Base class to hold some static state -/// This is an internally used class - -class VerilatedVcdSingleton { -private: - typedef std::vector VcdVec; - struct Singleton { - VerilatedMutex s_vcdMutex; ///< Protect the singleton - VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces - }; - static Singleton& singleton() { - static Singleton s; - return s; - } - -public: - static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { - const VerilatedLockGuard lock(singleton().s_vcdMutex); - singleton().s_vcdVecp.push_back(vcdp); - } - static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { - const VerilatedLockGuard lock(singleton().s_vcdMutex); - VcdVec::iterator pos - = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp); - if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); } - } - static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE { - // Thread safety: Although this function is protected by a mutex so - // perhaps in the future we can allow tracing in separate threads, - // vcdp->flush() assumes call from single thread - const VerilatedLockGuard lock(singleton().s_vcdMutex); - for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin(); - it != singleton().s_vcdVecp.end(); ++it) { - VerilatedVcd* vcdp = *it; - vcdp->flush(); - } - } -}; - //============================================================================= //============================================================================= //============================================================================= @@ -152,13 +111,7 @@ void VerilatedVcd::open(const char* filename) { // Set member variables m_filename = filename; // "" is ok, as someone may overload open - VerilatedVcdSingleton::pushVcd(this); - // SPDIFF_OFF - // Set callback so an early exit will flush us - Verilated::flushCb(&flush_all); - - // SPDIFF_ON openNext(m_rolloverMB != 0); if (!isOpen()) return; @@ -266,7 +219,6 @@ VerilatedVcd::~VerilatedVcd() { if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL); deleteNameMap(); if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL); - VerilatedVcdSingleton::removeVcd(this); } void VerilatedVcd::closePrev() { @@ -823,11 +775,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) { #endif // VL_TRACE_VCD_OLD_API -//====================================================================== -// Static members - -void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); } - //====================================================================== //====================================================================== //====================================================================== diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index 781183c23..24f10ab7d 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -105,9 +105,6 @@ private: void finishLine(vluint32_t code, char* writep); - /// Flush any remaining data from all files - static void flush_all() VL_MT_UNSAFE_ONE; - // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcd); diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index e4c5a2c20..e19c332e4 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -139,6 +139,32 @@ public: vlsint32_t num() const { return m_num; } }; +class VerilatedVpioParam : public VerilatedVpio { + const VerilatedVar* m_varp; + const VerilatedScope* m_scopep; + +public: + VerilatedVpioParam(const VerilatedVar* varp, const VerilatedScope* scopep) + : m_varp(varp) + , m_scopep(scopep) {} + + virtual ~VerilatedVpioParam() {} + + static inline VerilatedVpioParam* castp(vpiHandle h) { + return dynamic_cast(reinterpret_cast(h)); + } + virtual vluint32_t type() const { return vpiParameter; } + const VerilatedVar* varp() const { return m_varp; } + void* varDatap() const { return m_varp->datap(); } + const VerilatedScope* scopep() const { return m_scopep; } + virtual const char* name() const { return m_varp->name(); } + virtual const char* fullname() const { + static VL_THREAD_LOCAL std::string out; + out = std::string(m_scopep->name()) + "." + name(); + return out.c_str(); + } +}; + class VerilatedVpioRange : public VerilatedVpio { const VerilatedRange* m_range; vlsint32_t m_iteration; @@ -938,52 +964,52 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE { return names[(vpiVal <= vpiIsProtected) ? vpiVal : 0]; } -#define CHECK_RESULT_CSTR(got, exp) \ +#define SELF_CHECK_RESULT_CSTR(got, exp) \ if (0 != strcmp((got), (exp))) { \ std::string msg \ = std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \ VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \ } -#define CHECK_ENUM_STR(fn, enum) \ +#define SELF_CHECK_ENUM_STR(fn, enum) \ do { \ const char* strVal = VerilatedVpiError::fn(enum); \ - CHECK_RESULT_CSTR(strVal, #enum); \ + SELF_CHECK_RESULT_CSTR(strVal, #enum); \ } while (0) void VerilatedVpi::selfTest() VL_MT_UNSAFE_ONE { VerilatedVpiError::selfTest(); } void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE { VerilatedVpiImp::assertOneCheck(); - CHECK_ENUM_STR(strFromVpiVal, vpiBinStrVal); - CHECK_ENUM_STR(strFromVpiVal, vpiRawFourStateVal); + SELF_CHECK_ENUM_STR(strFromVpiVal, vpiBinStrVal); + SELF_CHECK_ENUM_STR(strFromVpiVal, vpiRawFourStateVal); - CHECK_ENUM_STR(strFromVpiObjType, vpiAlways); - CHECK_ENUM_STR(strFromVpiObjType, vpiWhile); - CHECK_ENUM_STR(strFromVpiObjType, vpiAttribute); - CHECK_ENUM_STR(strFromVpiObjType, vpiUdpArray); - CHECK_ENUM_STR(strFromVpiObjType, vpiContAssignBit); - CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar); + SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAlways); + SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiWhile); + SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAttribute); + SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUdpArray); + SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiContAssignBit); + SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar); - CHECK_ENUM_STR(strFromVpiMethod, vpiCondition); - CHECK_ENUM_STR(strFromVpiMethod, vpiStmt); + SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiCondition); + SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiStmt); - CHECK_ENUM_STR(strFromVpiCallbackReason, cbValueChange); - CHECK_ENUM_STR(strFromVpiCallbackReason, cbAtEndOfSimTime); + SELF_CHECK_ENUM_STR(strFromVpiCallbackReason, cbValueChange); + SELF_CHECK_ENUM_STR(strFromVpiCallbackReason, cbAtEndOfSimTime); - CHECK_ENUM_STR(strFromVpiProp, vpiType); - CHECK_ENUM_STR(strFromVpiProp, vpiProtected); - CHECK_ENUM_STR(strFromVpiProp, vpiDirection); - CHECK_ENUM_STR(strFromVpiProp, vpiTermIndex); - CHECK_ENUM_STR(strFromVpiProp, vpiConstType); - CHECK_ENUM_STR(strFromVpiProp, vpiAutomatic); - CHECK_ENUM_STR(strFromVpiProp, vpiOffset); - CHECK_ENUM_STR(strFromVpiProp, vpiStop); - CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiType); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiProtected); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiDirection); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiTermIndex); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiConstType); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiAutomatic); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiOffset); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiStop); + SELF_CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected); } -#undef CHECK_ENUM_STR -#undef CHECK_RESULT_CSTR +#undef SELF_CHECK_ENUM_STR +#undef SELF_CHECK_RESULT_CSTR //====================================================================== // callback related @@ -1096,7 +1122,12 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { } } if (!varp) return NULL; - return (new VerilatedVpioVar(varp, scopep))->castVpiHandle(); + + if (varp->isParam()) { + return (new VerilatedVpioParam(varp, scopep))->castVpiHandle(); + } else { + return (new VerilatedVpioVar(varp, scopep))->castVpiHandle(); + } } vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) { @@ -1327,583 +1358,506 @@ void vpi_get_delays(vpiHandle /*object*/, p_vpi_delay /*delay_p*/) { _VL_VPI_UNI void vpi_put_delays(vpiHandle /*object*/, p_vpi_delay /*delay_p*/) { _VL_VPI_UNIMP(); } // value processing +bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const char* fullname, + bool isGetValue) { + bool status = true; + if ((valuep->format == vpiVectorVal) || (valuep->format == vpiBinStrVal) + || (valuep->format == vpiOctStrVal) || (valuep->format == vpiHexStrVal)) { + switch (varp->vltype()) { + case VLVT_UINT8: + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: return status; + default: status = false; + } + } else if (valuep->format == vpiDecStrVal) { + switch (varp->vltype()) { + case VLVT_UINT8: + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: return status; + default: status = false; + } + } else if (valuep->format == vpiStringVal) { + switch (varp->vltype()) { + case VLVT_UINT8: + case VLVT_UINT16: + case VLVT_UINT32: + case VLVT_UINT64: + case VLVT_WDATA: return status; + case VLVT_STRING: + if (isGetValue) { + return status; + } else { + status = false; + break; + } + default: status = false; + } + } else if (valuep->format == vpiIntVal) { + switch (varp->vltype()) { + case VLVT_UINT8: + case VLVT_UINT16: + case VLVT_UINT32: return status; + default: status = false; + } + } else if (valuep->format == vpiSuppressVal) { + return status; + } else { + status = false; + } + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(valuep->format), fullname); + return status; +} -void vpi_get_value(vpiHandle object, p_vpi_value value_p) { +void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep, + const char* fullname) { + if (!vl_check_format(varp, valuep, fullname, true)) return; // Maximum required size is for binary string, one byte per bit plus null termination static VL_THREAD_LOCAL char outStr[1 + VL_MULS_MAX_WORDS * 32]; // cppcheck-suppress variableScope static VL_THREAD_LOCAL int outStrSz = sizeof(outStr) - 1; + // We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal + // This may cause backward compatibility issues with older code. + if (valuep->format == vpiVectorVal) { + // Vector pointer must come from our memory pool + // It only needs to persist until the next vpi_get_value + static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS * 2]; + valuep->value.vector = out; + if (varp->vltype() == VLVT_UINT8) { + out[0].aval = *(reinterpret_cast(varDatap)); + out[0].bval = 0; + return; + } else if (varp->vltype() == VLVT_UINT16) { + out[0].aval = *(reinterpret_cast(varDatap)); + out[0].bval = 0; + return; + } else if (varp->vltype() == VLVT_UINT32) { + out[0].aval = *(reinterpret_cast(varDatap)); + out[0].bval = 0; + return; + } else if (varp->vltype() == VLVT_UINT64) { + QData data = *(reinterpret_cast(varDatap)); + out[1].aval = static_cast(data >> 32ULL); + out[1].bval = 0; + out[0].aval = static_cast(data); + out[0].bval = 0; + return; + } else if (varp->vltype() == VLVT_WDATA) { + int words = VL_WORDS_I(varp->packed().elements()); + if (VL_UNCOVERABLE(words >= VL_MULS_MAX_WORDS)) { + VL_FATAL_MT( + __FILE__, __LINE__, "", + "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile"); + } + WDataInP datap = (reinterpret_cast(varDatap)); + for (int i = 0; i < words; ++i) { + out[i].aval = datap[i]; + out[i].bval = 0; + } + return; + } + } else if (valuep->format == vpiBinStrVal) { + valuep->value.str = outStr; + int bits = varp->packed().elements(); + CData* datap = (reinterpret_cast(varDatap)); + int i; + if (bits > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + bits = outStrSz; + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_MULS_MAX_WORDS, bits); + } + for (i = 0; i < bits; ++i) { + char val = (datap[i >> 3] >> (i & 7)) & 1; + outStr[bits - i - 1] = val ? '1' : '0'; + } + outStr[i] = '\0'; + return; + } else if (valuep->format == vpiOctStrVal) { + valuep->value.str = outStr; + int chars = (varp->packed().elements() + 2) / 3; + int bytes = VL_BYTES_I(varp->packed().elements()); + CData* datap = (reinterpret_cast(varDatap)); + int i; + if (chars > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_MULS_MAX_WORDS, chars); + chars = outStrSz; + } + for (i = 0; i < chars; ++i) { + div_t idx = div(i * 3, 8); + int val = datap[idx.quot]; + if ((idx.quot + 1) < bytes) { + // if the next byte is valid or that in + // for when the required 3 bits straddle adjacent bytes + val |= datap[idx.quot + 1] << 8; + } + // align so least significant 3 bits represent octal char + val >>= idx.rem; + if (i == (chars - 1)) { + // most signifcant char, mask off non existant bits when vector + // size is not a multiple of 3 + unsigned int rem = varp->packed().elements() % 3; + if (rem) { + // generate bit mask & zero non existant bits + val &= (1 << rem) - 1; + } + } + outStr[chars - i - 1] = '0' + (val & 7); + } + outStr[i] = '\0'; + return; + } else if (valuep->format == vpiDecStrVal) { + valuep->value.str = outStr; + // outStrSz does not include NULL termination so add one + if (varp->vltype() == VLVT_UINT8) { + VL_SNPRINTF(outStr, outStrSz + 1, "%hhu", + static_cast(*(reinterpret_cast(varDatap)))); + return; + } else if (varp->vltype() == VLVT_UINT16) { + VL_SNPRINTF(outStr, outStrSz + 1, "%hu", + static_cast(*(reinterpret_cast(varDatap)))); + return; + } else if (varp->vltype() == VLVT_UINT32) { + VL_SNPRINTF(outStr, outStrSz + 1, "%u", + static_cast(*(reinterpret_cast(varDatap)))); + return; + } else if (varp->vltype() == VLVT_UINT64) { + VL_SNPRINTF(outStr, outStrSz + 1, "%llu", + static_cast(*(reinterpret_cast(varDatap)))); + return; + } + } else if (valuep->format == vpiHexStrVal) { + valuep->value.str = outStr; + int chars = (varp->packed().elements() + 3) >> 2; + CData* datap = (reinterpret_cast(varDatap)); + int i; + if (chars > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_MULS_MAX_WORDS, chars); + chars = outStrSz; + } + for (i = 0; i < chars; ++i) { + char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15; + if (i == (chars - 1)) { + // most signifcant char, mask off non existant bits when vector + // size is not a multiple of 4 + unsigned int rem = varp->packed().elements() & 3; + if (rem) { + // generate bit mask & zero non existant bits + val &= (1 << rem) - 1; + } + } + outStr[chars - i - 1] = "0123456789abcdef"[static_cast(val)]; + } + outStr[i] = '\0'; + return; + } else if (valuep->format == vpiStringVal) { + if (varp->vltype() == VLVT_STRING) { + valuep->value.str = reinterpret_cast(varDatap); + return; + } else { + valuep->value.str = outStr; + int bytes = VL_BYTES_I(varp->packed().elements()); + CData* datap = (reinterpret_cast(varDatap)); + int i; + if (bytes > outStrSz) { + // limit maximum size of output to size of buffer to prevent overrun. + _VL_VPI_WARNING( + __FILE__, __LINE__, + "%s: Truncating string value of %s for %s" + " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_MULS_MAX_WORDS, bytes); + bytes = outStrSz; + } + for (i = 0; i < bytes; ++i) { + char val = datap[bytes - i - 1]; + // other simulators replace [leading?] zero chars with spaces, replicate here. + outStr[i] = val ? val : ' '; + } + outStr[i] = '\0'; + return; + } + } else if (valuep->format == vpiIntVal) { + if (varp->vltype() == VLVT_UINT8) { + valuep->value.integer = *(reinterpret_cast(varDatap)); + return; + } else if (varp->vltype() == VLVT_UINT16) { + valuep->value.integer = *(reinterpret_cast(varDatap)); + return; + } else if (varp->vltype() == VLVT_UINT32) { + valuep->value.integer = *(reinterpret_cast(varDatap)); + return; + } + } else if (valuep->format == vpiSuppressVal) { + return; + } + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", VL_FUNC, + VerilatedVpiError::strFromVpiVal(valuep->format), fullname); + return; +} + +void vpi_get_value(vpiHandle object, p_vpi_value valuep) { VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_value %p\n", object);); VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); - if (VL_UNLIKELY(!value_p)) return; + if (VL_UNLIKELY(!valuep)) return; + if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { - // We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal - // This may cause backward compatability issues with older code. - if (value_p->format == vpiVectorVal) { - // Vector pointer must come from our memory pool - // It only needs to persist until the next vpi_get_value - static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS * 2]; - value_p->value.vector = out; - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - out[0].aval = *(reinterpret_cast(vop->varDatap())); - out[0].bval = 0; - return; - case VLVT_UINT16: - out[0].aval = *(reinterpret_cast(vop->varDatap())); - out[0].bval = 0; - return; - case VLVT_UINT32: - out[0].aval = *(reinterpret_cast(vop->varDatap())); - out[0].bval = 0; - return; - case VLVT_WDATA: { - int words = VL_WORDS_I(vop->varp()->packed().elements()); - if (VL_UNCOVERABLE(words >= VL_MULS_MAX_WORDS)) { - VL_FATAL_MT( - __FILE__, __LINE__, "", - "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile"); - } - WDataInP datap = (reinterpret_cast(vop->varDatap())); - for (int i = 0; i < words; ++i) { - out[i].aval = datap[i]; - out[i].bval = 0; - } - return; - } - case VLVT_UINT64: { - QData data = *(reinterpret_cast(vop->varDatap())); - out[1].aval = static_cast(data >> 32ULL); - out[1].bval = 0; - out[0].aval = static_cast(data); - out[0].bval = 0; - return; - } - default: { - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return; - } - } - } else if (value_p->format == vpiBinStrVal) { - value_p->value.str = outStr; - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int bits = vop->varp()->packed().elements(); - CData* datap = (reinterpret_cast(vop->varDatap())); - int i; - if (bits > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - bits = outStrSz; - _VL_VPI_WARNING( - __FILE__, __LINE__, - "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bits); - } - for (i = 0; i < bits; ++i) { - char val = (datap[i >> 3] >> (i & 7)) & 1; - outStr[bits - i - 1] = val ? '1' : '0'; - } - outStr[i] = '\0'; - return; - } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return; - } - } else if (value_p->format == vpiOctStrVal) { - value_p->value.str = outStr; - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements() + 2) / 3; - int bytes = VL_BYTES_I(vop->varp()->packed().elements()); - CData* datap = (reinterpret_cast(vop->varDatap())); - int i; - if (chars > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - _VL_VPI_WARNING( - __FILE__, __LINE__, - "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); - chars = outStrSz; - } - for (i = 0; i < chars; ++i) { - div_t idx = div(i * 3, 8); - int val = datap[idx.quot]; - if ((idx.quot + 1) < bytes) { - // if the next byte is valid or that in - // for when the required 3 bits straddle adjacent bytes - val |= datap[idx.quot + 1] << 8; - } - // align so least significant 3 bits represent octal char - val >>= idx.rem; - if (i == (chars - 1)) { - // most signifcant char, mask off non existant bits when vector - // size is not a multiple of 3 - unsigned int rem = vop->varp()->packed().elements() % 3; - if (rem) { - // generate bit mask & zero non existant bits - val &= (1 << rem) - 1; - } - } - outStr[chars - i - 1] = '0' + (val & 7); - } - outStr[i] = '\0'; - return; - } - default: - strcpy(outStr, "0"); - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return; - } - } else if (value_p->format == vpiDecStrVal) { - value_p->value.str = outStr; - switch (vop->varp()->vltype()) { - // outStrSz does not include NULL termination so add one - case VLVT_UINT8: - VL_SNPRINTF( - outStr, outStrSz + 1, "%hhu", - static_cast(*(reinterpret_cast(vop->varDatap())))); - return; - case VLVT_UINT16: - VL_SNPRINTF( - outStr, outStrSz + 1, "%hu", - static_cast(*(reinterpret_cast(vop->varDatap())))); - return; - case VLVT_UINT32: - VL_SNPRINTF( - outStr, outStrSz + 1, "%u", - static_cast(*(reinterpret_cast(vop->varDatap())))); - return; - case VLVT_UINT64: - VL_SNPRINTF( - outStr, outStrSz + 1, "%llu", - static_cast(*(reinterpret_cast(vop->varDatap())))); - return; - default: - strcpy(outStr, "-1"); - _VL_VPI_ERROR(__FILE__, __LINE__, - "%s: Unsupported format (%s) for %s, maximum limit is 64 bits", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); - return; - } - } else if (value_p->format == vpiHexStrVal) { - value_p->value.str = outStr; - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements() + 3) >> 2; - CData* datap = (reinterpret_cast(vop->varDatap())); - int i; - if (chars > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - _VL_VPI_WARNING( - __FILE__, __LINE__, - "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, chars); - chars = outStrSz; - } - for (i = 0; i < chars; ++i) { - char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15; - if (i == (chars - 1)) { - // most signifcant char, mask off non existant bits when vector - // size is not a multiple of 4 - unsigned int rem = vop->varp()->packed().elements() & 3; - if (rem) { - // generate bit mask & zero non existant bits - val &= (1 << rem) - 1; - } - } - outStr[chars - i - 1] = "0123456789abcdef"[static_cast(val)]; - } - outStr[i] = '\0'; - return; - } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return; - } - } else if (value_p->format == vpiStringVal) { - value_p->value.str = outStr; - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int bytes = VL_BYTES_I(vop->varp()->packed().elements()); - CData* datap = (reinterpret_cast(vop->varDatap())); - int i; - if (bytes > outStrSz) { - // limit maximum size of output to size of buffer to prevent overrun. - _VL_VPI_WARNING( - __FILE__, __LINE__, - "%s: Truncating string value of %s for %s" - " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname(), outStrSz, VL_MULS_MAX_WORDS, bytes); - bytes = outStrSz; - } - for (i = 0; i < bytes; ++i) { - char val = datap[bytes - i - 1]; - // other simulators replace [leading?] zero chars with spaces, replicate here. - outStr[i] = val ? val : ' '; - } - outStr[i] = '\0'; - return; - } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return; - } - } else if (value_p->format == vpiIntVal) { - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - value_p->value.integer = *(reinterpret_cast(vop->varDatap())); - return; - case VLVT_UINT16: - value_p->value.integer = *(reinterpret_cast(vop->varDatap())); - return; - case VLVT_UINT32: - value_p->value.integer = *(reinterpret_cast(vop->varDatap())); - return; - case VLVT_WDATA: // FALLTHRU - case VLVT_UINT64: // FALLTHRU - default: - value_p->value.integer = 0; - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return; - } - } else if (value_p->format == vpiSuppressVal) { - return; - } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname()); + return; + } else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) { + vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname()); return; } else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { - if (value_p->format == vpiIntVal) { - value_p->value.integer = vop->num(); + if (valuep->format == vpiIntVal) { + valuep->value.integer = vop->num(); return; } _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname()); return; } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object); } -vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time_p*/, +vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_p*/, PLI_INT32 /*flags*/) { - VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value %p %p\n", object, value_p);); + VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value %p %p\n", object, valuep);); VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); - if (VL_UNLIKELY(!value_p)) { + if (VL_UNLIKELY(!valuep)) { _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value with NULL value pointer"); return 0; } if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) { VL_DEBUG_IF_PLI( VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(), - value_p->format, value_p->value.integer); + valuep->format, valuep->value.integer); VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap());); + if (VL_UNLIKELY(!vop->varp()->isPublicRW())) { _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_put_value to signal marked read-only," - " use public_flat_rw instead: ", + " use public_flat_rw instead: %s", vop->fullname()); return 0; } - if (value_p->format == vpiVectorVal) { - if (VL_UNLIKELY(!value_p->value.vector)) return NULL; - switch (vop->varp()->vltype()) { - case VLVT_UINT8: + if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return 0; + if (valuep->format == vpiVectorVal) { + if (VL_UNLIKELY(!valuep->value.vector)) return NULL; + if (vop->varp()->vltype() == VLVT_UINT8) { *(reinterpret_cast(vop->varDatap())) - = value_p->value.vector[0].aval & vop->mask(); + = valuep->value.vector[0].aval & vop->mask(); return object; - case VLVT_UINT16: + } else if (vop->varp()->vltype() == VLVT_UINT16) { *(reinterpret_cast(vop->varDatap())) - = value_p->value.vector[0].aval & vop->mask(); + = valuep->value.vector[0].aval & vop->mask(); return object; - case VLVT_UINT32: + } else if (vop->varp()->vltype() == VLVT_UINT32) { *(reinterpret_cast(vop->varDatap())) - = value_p->value.vector[0].aval & vop->mask(); + = valuep->value.vector[0].aval & vop->mask(); return object; - case VLVT_WDATA: { + } else if (vop->varp()->vltype() == VLVT_UINT64) { + *(reinterpret_cast(vop->varDatap())) = _VL_SET_QII( + valuep->value.vector[1].aval & vop->mask(), valuep->value.vector[0].aval); + return object; + } else if (vop->varp()->vltype() == VLVT_WDATA) { int words = VL_WORDS_I(vop->varp()->packed().elements()); WDataOutP datap = (reinterpret_cast(vop->varDatap())); for (int i = 0; i < words; ++i) { - datap[i] = value_p->value.vector[i].aval; + datap[i] = valuep->value.vector[i].aval; if (i == (words - 1)) datap[i] &= vop->mask(); } return object; } - case VLVT_UINT64: { - *(reinterpret_cast(vop->varDatap())) = _VL_SET_QII( - value_p->value.vector[1].aval & vop->mask(), value_p->value.vector[0].aval); - return object; - } - default: { - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return NULL; - } - } - } else if (value_p->format == vpiBinStrVal) { - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int bits = vop->varp()->packed().elements(); - int len = strlen(value_p->value.str); - CData* datap = (reinterpret_cast(vop->varDatap())); - for (int i = 0; i < bits; ++i) { - char set = (i < len) ? (value_p->value.str[len - i - 1] == '1') : 0; - // zero bits 7:1 of byte when assigning to bit 0, else - // or in 1 if bit set - if (i & 7) { - datap[i >> 3] |= set << (i & 7); - } else { - datap[i >> 3] = set; - } + } else if (valuep->format == vpiBinStrVal) { + int bits = vop->varp()->packed().elements(); + int len = strlen(valuep->value.str); + CData* datap = (reinterpret_cast(vop->varDatap())); + for (int i = 0; i < bits; ++i) { + char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0; + // zero bits 7:1 of byte when assigning to bit 0, else + // or in 1 if bit set + if (i & 7) { + datap[i >> 3] |= set << (i & 7); + } else { + datap[i >> 3] = set; } - return object; } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return 0; - } - } else if (value_p->format == vpiOctStrVal) { - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements() + 2) / 3; - int bytes = VL_BYTES_I(vop->varp()->packed().elements()); - int len = strlen(value_p->value.str); - CData* datap = (reinterpret_cast(vop->varDatap())); - div_t idx; - datap[0] = 0; // reset zero'th byte - for (int i = 0; i < chars; ++i) { - union { - char byte[2]; - short half; - } val; - idx = div(i * 3, 8); - if (i < len) { - // ignore illegal chars - char digit = value_p->value.str[len - i - 1]; - if (digit >= '0' && digit <= '7') { - val.half = digit - '0'; - } else { - _VL_VPI_WARNING( - __FILE__, __LINE__, - "%s: Non octal character '%c' in '%s' as value %s for %s", VL_FUNC, - digit, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); - val.half = 0; - } + return object; + } else if (valuep->format == vpiOctStrVal) { + int chars = (vop->varp()->packed().elements() + 2) / 3; + int bytes = VL_BYTES_I(vop->varp()->packed().elements()); + int len = strlen(valuep->value.str); + CData* datap = (reinterpret_cast(vop->varDatap())); + div_t idx; + datap[0] = 0; // reset zero'th byte + for (int i = 0; i < chars; ++i) { + union { + char byte[2]; + short half; + } val; + idx = div(i * 3, 8); + if (i < len) { + // ignore illegal chars + char digit = valuep->value.str[len - i - 1]; + if (digit >= '0' && digit <= '7') { + val.half = digit - '0'; } else { + _VL_VPI_WARNING(__FILE__, __LINE__, + "%s: Non octal character '%c' in '%s' as value %s for %s", + VL_FUNC, digit, valuep->value.str, + VerilatedVpiError::strFromVpiVal(valuep->format), + vop->fullname()); val.half = 0; } - // align octal character to position within vector, note that - // the three bits may straddle a byte bounday so two byte wide - // assignments are made to adjacent bytes - but not if the least - // signifcant byte of the aligned value is the most significant - // byte of the destination. - val.half <<= idx.rem; - datap[idx.quot] |= val.byte[0]; // or in value - if ((idx.quot + 1) < bytes) { - datap[idx.quot + 1] = val.byte[1]; // this also resets - // all bits to 0 prior to or'ing above - } + } else { + val.half = 0; } - // mask off non existant bits in the most significant byte - if (idx.quot == (bytes - 1)) { - datap[idx.quot] &= vop->mask_byte(idx.quot); - } else if (idx.quot + 1 == (bytes - 1)) { - datap[idx.quot + 1] &= vop->mask_byte(idx.quot + 1); + // align octal character to position within vector, note that + // the three bits may straddle a byte boundary so two byte wide + // assignments are made to adjacent bytes - but not if the least + // significant byte of the aligned value is the most significant + // byte of the destination. + val.half <<= idx.rem; + datap[idx.quot] |= val.byte[0]; // or in value + if ((idx.quot + 1) < bytes) { + datap[idx.quot + 1] = val.byte[1]; // this also resets + // all bits to 0 prior to or'ing above } - // zero off remaining top bytes - for (int i = idx.quot + 2; i < bytes; ++i) datap[i] = 0; - return object; } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return 0; + // mask off non-existent bits in the most significant byte + if (idx.quot == (bytes - 1)) { + datap[idx.quot] &= vop->mask_byte(idx.quot); + } else if (idx.quot + 1 == (bytes - 1)) { + datap[idx.quot + 1] &= vop->mask_byte(idx.quot + 1); } - } else if (value_p->format == vpiDecStrVal) { + // zero off remaining top bytes + for (int i = idx.quot + 2; i < bytes; ++i) datap[i] = 0; + return object; + } else if (valuep->format == vpiDecStrVal) { char remainder[16]; unsigned long long val; - int success = sscanf(value_p->value.str, "%30llu%15s", &val, remainder); + int success = sscanf(valuep->value.str, "%30llu%15s", &val, remainder); if (success < 1) { _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s", - VL_FUNC, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + VL_FUNC, valuep->value.str, + VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname()); return 0; } if (success > 1) { - _VL_VPI_WARNING( - __FILE__, __LINE__, "%s: Trailing garbage '%s' in '%s' as value %s for %s", - VL_FUNC, remainder, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + _VL_VPI_WARNING(__FILE__, __LINE__, + "%s: Trailing garbage '%s' in '%s' as value %s for %s", VL_FUNC, + remainder, valuep->value.str, + VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname()); } - switch (vop->varp()->vltype()) { - case VLVT_UINT8: + if (vop->varp()->vltype() == VLVT_UINT8) { *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); - break; - case VLVT_UINT16: + return object; + } else if (vop->varp()->vltype() == VLVT_UINT16) { *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); - break; - case VLVT_UINT32: + return object; + } else if (vop->varp()->vltype() == VLVT_UINT32) { *(reinterpret_cast(vop->varDatap())) = val & vop->mask(); - break; - case VLVT_UINT64: + return object; + } else if (vop->varp()->vltype() == VLVT_UINT64) { *(reinterpret_cast(vop->varDatap())) = val; (reinterpret_cast(vop->varDatap()))[1] &= vop->mask(); - break; - case VLVT_WDATA: - default: - _VL_VPI_ERROR(__FILE__, __LINE__, - "%s: Unsupported format (%s) for %s, maximum limit is 64 bits", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); - return 0; + return object; } - return object; - } else if (value_p->format == vpiHexStrVal) { - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int chars = (vop->varp()->packed().elements() + 3) >> 2; - CData* datap = (reinterpret_cast(vop->varDatap())); - char* val = value_p->value.str; - // skip hex ident if one is detected at the start of the string - if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2; - int len = strlen(val); - for (int i = 0; i < chars; ++i) { - char hex; - // compute hex digit value - if (i < len) { - char digit = val[len - i - 1]; - if (digit >= '0' && digit <= '9') { - hex = digit - '0'; - } else if (digit >= 'a' && digit <= 'f') { - hex = digit - 'a' + 10; - } else if (digit >= 'A' && digit <= 'F') { - hex = digit - 'A' + 10; - } else { - _VL_VPI_WARNING( - __FILE__, __LINE__, - "%s: Non hex character '%c' in '%s' as value %s for %s", VL_FUNC, - digit, value_p->value.str, - VerilatedVpiError::strFromVpiVal(value_p->format), - vop->fullname()); - hex = 0; - } + } else if (valuep->format == vpiHexStrVal) { + int chars = (vop->varp()->packed().elements() + 3) >> 2; + CData* datap = (reinterpret_cast(vop->varDatap())); + char* val = valuep->value.str; + // skip hex ident if one is detected at the start of the string + if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2; + int len = strlen(val); + for (int i = 0; i < chars; ++i) { + char hex; + // compute hex digit value + if (i < len) { + char digit = val[len - i - 1]; + if (digit >= '0' && digit <= '9') { + hex = digit - '0'; + } else if (digit >= 'a' && digit <= 'f') { + hex = digit - 'a' + 10; + } else if (digit >= 'A' && digit <= 'F') { + hex = digit - 'A' + 10; } else { + _VL_VPI_WARNING(__FILE__, __LINE__, + "%s: Non hex character '%c' in '%s' as value %s for %s", + VL_FUNC, digit, valuep->value.str, + VerilatedVpiError::strFromVpiVal(valuep->format), + vop->fullname()); hex = 0; } - // assign hex digit value to destination - if (i & 1) { - datap[i >> 1] |= hex << 4; - } else { - datap[i >> 1] = hex; // this also resets all - // bits to 0 prior to or'ing above of the msb - } + } else { + hex = 0; } - // apply bit mask to most significant byte - datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1); - return object; - } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return 0; - } - } else if (value_p->format == vpiStringVal) { - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - case VLVT_UINT16: - case VLVT_UINT32: - case VLVT_UINT64: - case VLVT_WDATA: { - int bytes = VL_BYTES_I(vop->varp()->packed().elements()); - int len = strlen(value_p->value.str); - CData* datap = (reinterpret_cast(vop->varDatap())); - for (int i = 0; i < bytes; ++i) { - // prepend with 0 values before placing string the least signifcant bytes - datap[i] = (i < len) ? value_p->value.str[len - i - 1] : 0; + // assign hex digit value to destination + if (i & 1) { + datap[i >> 1] |= hex << 4; + } else { + datap[i >> 1] = hex; // this also resets all + // bits to 0 prior to or'ing above of the msb } - return object; } - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return 0; + // apply bit mask to most significant byte + datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1); + return object; + } else if (valuep->format == vpiStringVal) { + int bytes = VL_BYTES_I(vop->varp()->packed().elements()); + int len = strlen(valuep->value.str); + CData* datap = (reinterpret_cast(vop->varDatap())); + for (int i = 0; i < bytes; ++i) { + // prepend with 0 values before placing string the least significant bytes + datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0; } - } else if (value_p->format == vpiIntVal) { - switch (vop->varp()->vltype()) { - case VLVT_UINT8: - *(reinterpret_cast(vop->varDatap())) - = vop->mask() & value_p->value.integer; + return object; + } else if (valuep->format == vpiIntVal) { + if (vop->varp()->vltype() == VLVT_UINT8) { + *(reinterpret_cast(vop->varDatap())) = vop->mask() & valuep->value.integer; return object; - case VLVT_UINT16: - *(reinterpret_cast(vop->varDatap())) - = vop->mask() & value_p->value.integer; + } else if (vop->varp()->vltype() == VLVT_UINT16) { + *(reinterpret_cast(vop->varDatap())) = vop->mask() & valuep->value.integer; return object; - case VLVT_UINT32: - *(reinterpret_cast(vop->varDatap())) - = vop->mask() & value_p->value.integer; + } else if (vop->varp()->vltype() == VLVT_UINT32) { + *(reinterpret_cast(vop->varDatap())) = vop->mask() & valuep->value.integer; return object; - case VLVT_WDATA: // FALLTHRU - case VLVT_UINT64: // FALLTHRU - default: - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); - return 0; } } _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", - VL_FUNC, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname()); return NULL; + } else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s", + VL_FUNC, vop->fullname()); + return 0; + } else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) { + _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s", + VL_FUNC, vop->fullname()); + return 0; } - _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for ??", VL_FUNC, - VerilatedVpiError::strFromVpiVal(value_p->format)); + _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object); return NULL; } @@ -2005,7 +1959,7 @@ PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8* format, va_list ap) { PLI_INT32 vpi_flush(void) { VerilatedVpiImp::assertOneCheck(); _VL_VPI_ERROR_RESET(); - Verilated::flushCall(); + Verilated::runFlushCallbacks(); return 0; } diff --git a/include/verilatedos.h b/include/verilatedos.h index 357ee8654..027276558 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -435,7 +435,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type // Performance counters /// The vluint64_t argument is loaded with a high-performance counter for profiling -/// or 0x0 if not implemeted on this platform +/// or 0x0 if not implemented on this platform #if defined(__i386__) || defined(__x86_64__) #define VL_RDTSC(val) \ { \ diff --git a/nodist/code_coverage.dat b/nodist/code_coverage.dat index df768a0ab..3e298fd4f 100644 --- a/nodist/code_coverage.dat +++ b/nodist/code_coverage.dat @@ -53,6 +53,7 @@ exclude_line_regexp(qr/(\bv3fatalSrc\b |\bUINFO\b)/x); # Exclude for branch coverage only -exclude_branch_regexp(qr/(\bdebug\(\))/x); +exclude_branch_regexp(qr/(\bdebug\(\) + |\bSELF_CHECK)/x); 1; diff --git a/src/Makefile.in b/src/Makefile.in index e8bb467c3..91c60b76a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -69,16 +69,17 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj +ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit + ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users +GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD + endif +endif + prefiles:: prefiles:: config_rev.h -ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users # This output goes into srcdir if locally configured, as we need to distribute it as part of the kit. -config_rev.h: ${srcdir}/config_rev.pl ${srcdir}/../.git/logs/HEAD +config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP) $(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@ -else -config_rev.h: ${srcdir}/config_rev.pl - $(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@ -endif maintainer-copy:: clean mostlyclean distclean maintainer-clean:: diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 0cd331087..0c2ed579c 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -278,7 +278,6 @@ V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS))) $(TGT): $(PREDEP_H) $(OBJS) @echo " Linking $@..." - -rm -rf $@ $@.exe ${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS} V3Number_test: V3Number_test.o diff --git a/src/V3Active.cpp b/src/V3Active.cpp index eb24b00d7..26cf3f3aa 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -316,10 +316,8 @@ private: if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*) if (combo && sequent) { - if (!v3Global.opt.bboxUnsup()) { - nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity " - "(no edge) sensitive activity list"); - } + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Mixed edge (pos/negedge) and activity " + "(no edge) sensitive activity list"); sequent = false; } @@ -378,14 +376,6 @@ private: // if (debug() >= 9) nodep->dumpTree(cout, " Alw: "); visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS); } - virtual void visit(AstSenGate* nodep) VL_OVERRIDE { - AstSenItem* subitemp = nodep->sensesp(); - UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE - || subitemp->edgeType() == VEdgeType::ET_POSEDGE - || subitemp->edgeType() == VEdgeType::ET_NEGEDGE, - nodep, "Strange activity type under SenGate"); - iterateChildren(nodep); - } virtual void visit(AstSenItem* nodep) VL_OVERRIDE { if (nodep->varrefp()) { if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) { @@ -405,8 +395,9 @@ private: } else if (nodep->varrefp()) { // V3LinkResolve should have cleaned most of these up if (!nodep->varrefp()->width1()) { - nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: " - << nodep->varrefp()->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Non-single bit wide signal pos/negedge sensitivity: " + << nodep->varrefp()->prettyNameQ()); } m_itemSequent = true; nodep->varrefp()->varp()->usedClock(true); diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index 933ba26fa..07f7741d2 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -54,7 +54,7 @@ private: // VISITORS virtual void visit(AstTopScope* nodep) VL_OVERRIDE { m_topscopep = nodep; - m_finder.main(m_topscopep); + m_finder.init(m_topscopep); iterateChildren(nodep); m_topscopep = NULL; } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index c23e1bd75..6448d0eab 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -34,11 +34,11 @@ private: // NODE STATE/TYPES // STATE // Reset each module: - AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock) + AstSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock) // Reset each assertion: - AstNodeSenItem* m_senip; // Last sensitivity + AstSenItem* m_senip; // Last sensitivity // Reset each always: - AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always + AstSenItem* m_seniAlwaysp; // Last sensitivity in always // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -47,11 +47,11 @@ private: // Create sentree based on clocked or default clock // Return NULL for always AstSenTree* newp = NULL; - AstNodeSenItem* senip = m_senip; + AstSenItem* senip = m_senip; if (!senip) senip = m_seniDefaultp; if (!senip) senip = m_seniAlwaysp; if (!senip) { - nodep->v3error("Unsupported: Unclocked assertion"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion"); newp = new AstSenTree(nodep->fileline(), NULL); } else { newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true)); @@ -97,7 +97,8 @@ private: virtual void visit(AstPropClocked* nodep) VL_OVERRIDE { // No need to iterate the body, once replace will get iterated iterateAndNextNull(nodep->sensesp()); - if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion"); + if (m_senip) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion"); // Block is the new expression to evaluate AstNode* blockp = nodep->propp()->unlinkFrBack(); if (nodep->disablep()) { diff --git a/src/V3Ast.h b/src/V3Ast.h index c2ab16559..674c393f9 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -117,6 +117,9 @@ public: inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; } inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; } inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { + return os << rhs.ascii(); +} //###################################################################### @@ -1809,6 +1812,8 @@ public: virtual bool hasDType() const { return false; } // Iff has a non-null childDTypep(), as generic node function virtual AstNodeDType* getChildDTypep() const { return NULL; } + // Iff has a non-null child2DTypep(), as generic node function + virtual AstNodeDType* getChild2DTypep() const { return NULL; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc. virtual bool maybePointedTo() const { return false; } virtual const char* broken() const { return NULL; } @@ -2241,19 +2246,6 @@ public: void addNotParallelp(AstNode* nodep) { setOp3p(nodep); } }; -class AstNodeSenItem : public AstNode { - // An AstSenItem or AstSenGate -public: - AstNodeSenItem(AstType t, FileLine* fl) - : AstNode(t, fl) {} - ASTNODE_BASE_FUNCS(NodeSenItem) - virtual bool isClocked() const = 0; - virtual bool isCombo() const = 0; - virtual bool isInitial() const = 0; - virtual bool isSettle() const = 0; - virtual bool isNever() const = 0; -}; - class AstNodeVarRef : public AstNodeMath { // An AstVarRef or AstVarXRef private: @@ -2264,29 +2256,26 @@ private: string m_name; // Name of variable string m_hiername; // Scope converted into name-> for emitting bool m_hierThis; // Hiername points to "this" function - void init(); public: AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue) : AstNodeMath(t, fl) , m_lvalue(lvalue) - , m_varp(NULL) , m_varScopep(NULL) , m_packagep(NULL) , m_name(name) , m_hierThis(false) { - init(); + this->varp(NULL); } AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue) : AstNodeMath(t, fl) , m_lvalue(lvalue) - , m_varp(varp) , m_varScopep(NULL) , m_packagep(NULL) , m_name(name) , m_hierThis(false) { // May have varp==NULL - init(); + this->varp(varp); } ASTNODE_BASE_FUNCS(NodeVarRef) virtual bool hasDType() const { return true; } @@ -2298,7 +2287,7 @@ public: bool lvalue() const { return m_lvalue; } void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - void varp(AstVar* varp) { m_varp = varp; } + void varp(AstVar* varp); AstVarScope* varScopep() const { return m_varScopep; } void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } string hiername() const { return m_hiername; } @@ -2636,6 +2625,7 @@ private: bool m_taskPublic : 1; // Public task bool m_attrIsolateAssign : 1; // User isolate_assignments attribute bool m_classMethod : 1; // Class method + bool m_extern : 1; // Extern prototype bool m_prototype : 1; // Just a prototype bool m_dpiExport : 1; // DPI exported bool m_dpiImport : 1; // DPI imported @@ -2644,6 +2634,8 @@ private: bool m_dpiTask : 1; // DPI import task (vs. void function) bool m_isConstructor : 1; // Class constructor bool m_pure : 1; // DPI import pure (vs. virtual pure) + bool m_pureVirtual : 1; // Pure virtual + bool m_virtual : 1; // Virtual method in class VLifetime m_lifetime; // Lifetime public: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) @@ -2653,6 +2645,7 @@ public: , m_taskPublic(false) , m_attrIsolateAssign(false) , m_classMethod(false) + , m_extern(false) , m_prototype(false) , m_dpiExport(false) , m_dpiImport(false) @@ -2660,7 +2653,9 @@ public: , m_dpiOpenChild(false) , m_dpiTask(false) , m_isConstructor(false) - , m_pure(false) { + , m_pure(false) + , m_pureVirtual(false) + , m_virtual(false) { addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } @@ -2693,6 +2688,8 @@ public: bool attrIsolateAssign() const { return m_attrIsolateAssign; } void classMethod(bool flag) { m_classMethod = flag; } bool classMethod() const { return m_classMethod; } + void isExtern(bool flag) { m_extern = flag; } + bool isExtern() const { return m_extern; } void prototype(bool flag) { m_prototype = flag; } bool prototype() const { return m_prototype; } void dpiExport(bool flag) { m_dpiExport = flag; } @@ -2709,6 +2706,10 @@ public: bool isConstructor() const { return m_isConstructor; } void pure(bool flag) { m_pure = flag; } bool pure() const { return m_pure; } + void pureVirtual(bool flag) { m_pureVirtual = flag; } + bool pureVirtual() const { return m_pureVirtual; } + void isVirtual(bool flag) { m_virtual = flag; } + bool isVirtual() const { return m_virtual; } void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } }; @@ -2926,8 +2927,9 @@ inline bool AstNode::sameGateTree(const AstNode* node2p) const { return sameTreeIter(this, node2p, true, true); } -inline void AstNodeVarRef::init() { - if (m_varp) dtypep(m_varp->dtypep()); +inline void AstNodeVarRef::varp(AstVar* varp) { + m_varp = varp; + dtypeFrom(varp); } inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 78f710b73..d5ee54c8d 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -22,6 +22,7 @@ #include "V3Global.h" #include "V3Graph.h" #include "V3PartitionGraph.h" // Just for mtask dumping +#include "V3String.h" // For VString::parseDouble #include "V3EmitCBase.h" #include @@ -225,6 +226,36 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode return newp; } +AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) { + bool success = false; + if (literal[0] == '"') { + // This is a string + string v = literal.substr(1, literal.find('"', 1) - 1); + return new AstConst(fl, AstConst::VerilogStringLiteral(), v); + } else if (literal.find_first_of(".eEpP") != string::npos) { + // This may be a real + double v = VString::parseDouble(literal, &success); + if (success) return new AstConst(fl, AstConst::RealDouble(), v); + } + if (!success) { + // This is either an integer or an error + // We first try to convert it as C literal. If strtol returns + // 0 this is either an error or 0 was parsed. But in any case + // we will try to parse it as a verilog literal, hence having + // the false negative for 0 is okay. If anything remains in + // the string after the number, this is invalid C and we try + // the Verilog literal parser. + char* endp; + int v = strtol(literal.c_str(), &endp, 0); + if ((v != 0) && (endp[0] == 0)) { // C literal + return new AstConst(fl, AstConst::WidthedValue(), 32, v); + } else { // Try a Verilog literal (fatals if not) + return new AstConst(fl, AstConst::StringToParse(), literal.c_str()); + } + } + return NULL; +} + void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) { VTimescale prec = v3Global.opt.timeComputePrec(value); if (prec.isNone() || prec == m_timeprecision) { @@ -495,8 +526,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const { } if (isWide()) { if (forReturn) { - v3error("Unsupported: Public functions with >64 bit outputs; " - "make an output of a public task instead"); + v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; " + "make an output of a public task instead"); } arg += " (& " + name(); arg += ")[" + cvtToStr(widthWords()) + "]"; @@ -784,28 +815,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const { bool AstSenTree::hasClocked() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) { if (senp->isClocked()) return true; } return false; } bool AstSenTree::hasSettle() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) { if (senp->isSettle()) return true; } return false; } bool AstSenTree::hasInitial() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) { if (senp->isInitial()) return true; } return false; } bool AstSenTree::hasCombo() const { UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it"); - for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { + for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) { if (senp->isCombo()) return true; } return false; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4f9c1d99a..bb055fb6c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -170,6 +170,9 @@ public: virtual int instrCount() const { return widthInstrs(); } bool isEqAllOnes() const { return num().isEqAllOnes(width()); } bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); } + // Parse string and create appropriate type of AstConst. + // May return NULL on parse failure. + static AstConst* parseParamLiteral(FileLine* fl, const string& literal); }; class AstRange : public AstNodeRange { @@ -231,33 +234,23 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; -class AstAssocRange : public AstNodeRange { - // Associative array range specification - // Only for early parsing - becomes AstAssocDType +class AstBracketRange : public AstNodeRange { + // Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range, + // unknown until lhsp type is determined public: - AstAssocRange(FileLine* fl, AstNodeDType* dtp) + AstBracketRange(FileLine* fl, AstNode* elementsp) : ASTGEN_SUPER(fl) { - setOp1p(dtp); + setOp1p(elementsp); } - ASTNODE_NODE_FUNCS(AssocRange) - virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const { return V3Hash(); } - virtual bool same(const AstNode* samep) const { return true; } - AstNodeDType* keyDTypep() const { return VN_CAST(op1p(), NodeDType); } -}; - -class AstQueueRange : public AstNodeRange { - // Queue range specification - // Only for early parsing - becomes AstQueueDType -public: - explicit AstQueueRange(FileLine* fl) - : ASTGEN_SUPER(fl) {} - ASTNODE_NODE_FUNCS(QueueRange) + ASTNODE_NODE_FUNCS(BracketRange) virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual V3Hash sameHash() const { return V3Hash(); } virtual bool same(const AstNode* samep) const { return true; } + // Will be removed in V3Width, which relies on this + // being a child not a dtype pointed node + virtual bool maybePointedTo() const { return false; } + AstNode* elementsp() const { return op1p(); } }; class AstUnsizedRange : public AstNodeRange { @@ -311,6 +304,7 @@ class AstClass : public AstNodeModule { // MEMBERS MemberNameMap m_members; // Members or method children AstClassPackage* m_packagep; // Class package this is under + bool m_virtual; // Virtual class void insertCache(AstNode* nodep); public: @@ -343,6 +337,8 @@ public: MemberNameMap::const_iterator it = m_members.find(name); return (it == m_members.end()) ? NULL : it->second; } + bool isVirtual() const { return m_virtual; } + void isVirtual(bool flag) { m_virtual = flag; } }; class AstClassExtends : public AstNode { @@ -541,8 +537,9 @@ public: virtual string prettyDTypeName() const; virtual void dumpSmall(std::ostream& str) const; virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } + virtual AstNodeDType* getChildDTypep() const { return childDTypep(); } + virtual AstNodeDType* getChild2DTypep() const { return keyChildDTypep(); } virtual bool isHeavy() const { return true; } - AstNodeDType* getChildDTypep() const { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -567,6 +564,36 @@ public: virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } }; +class AstBracketArrayDType : public AstNodeDType { + // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" + // only for early parsing then becomes another data type + // Children: DTYPE (moved to refDTypep() in V3Width) + // Children: DTYPE (the key) +public: + AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp) + : ASTGEN_SUPER(fl) { + setOp1p(dtp); // Only for parser + setOp2p(elementsp); // Only for parser + } + ASTNODE_NODE_FUNCS(BracketArrayDType) + virtual bool similarDType(AstNodeDType* samep) const { V3ERROR_NA_RETURN(false); } + // op1 = Range of variable + AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } + virtual AstNodeDType* subDTypep() const { return childDTypep(); } + // op2 = Range of variable + AstNode* elementsp() const { return op2p(); } + // METHODS + // Will be removed in V3Width, which relies on this + // being a child not a dtype pointed node + virtual bool maybePointedTo() const { return false; } + virtual AstBasicDType* basicp() const { return NULL; } + virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } + virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } + virtual int widthAlignBytes() const { V3ERROR_NA_RETURN(0); } + virtual int widthTotalBytes() const { V3ERROR_NA_RETURN(0); } +}; + class AstDynArrayDType : public AstNodeDType { // Dynamic array data type, ie "[]" // Children: DTYPE (moved to refDTypep() in V3Width) @@ -1539,6 +1566,25 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; +class AstSelLoopVars : public AstNode { + // Parser only concept "[id, id, id]" for a foreach statement + // Unlike normal selects elements is a list +public: + AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) + : ASTGEN_SUPER(fl) { + setOp1p(fromp); + addNOp2p(elementsp); + } + ASTNODE_NODE_FUNCS(SelLoopVars) + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } + virtual bool maybePointedTo() const { return false; } + AstNode* fromp() const { return op1p(); } + AstNode* elementsp() const { return op2p(); } +}; + class AstSelExtract : public AstNodePreSel { // Range extraction, gets replaced with AstSel public: @@ -2972,11 +3018,26 @@ public: void cname(const string& cname) { m_cname = cname; } }; +class AstWith : public AstNodeStmt { +public: + AstWith(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* argsp) + : ASTGEN_SUPER(fl) { + statement(stmt); + setOp1p(funcrefp); + addNOp2p(argsp); + } + ASTNODE_NODE_FUNCS(With) + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } + // + AstNode* funcrefp() const { return op1p(); } +}; + //###################################################################### -class AstSenItem : public AstNodeSenItem { +class AstSenItem : public AstNode { // Parents: SENTREE - // Children: (optional) VARREF SENGATE + // Children: (optional) VARREF private: VEdgeType m_edgeType; // Edge type public: @@ -3026,41 +3087,15 @@ public: return VN_CAST(op1p(), NodeVarRef); } // op1 = Signal sensitized // - virtual bool isClocked() const { return edgeType().clockedStmt(); } - virtual bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } - virtual bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } - virtual bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } - virtual bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } - virtual bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } + bool isClocked() const { return edgeType().clockedStmt(); } + bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; } + bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; } + bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; } + bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; } + bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; } bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } }; -class AstSenGate : public AstNodeSenItem { - // Parents: SENTREE - // Children: SENITEM expr - // AND as applied to a sensitivity list and a gating expression - // Performing this gating is optional; it may be removed by later optimizations -public: - AstSenGate(FileLine* fl, AstSenItem* sensesp, AstNode* rhsp) - : ASTGEN_SUPER(fl) { - dtypeSetLogicBool(); - addOp1p(sensesp); - setOp2p(rhsp); - } - ASTNODE_NODE_FUNCS(SenGate) - virtual string emitVerilog() { return "(%l) %f&& (%r)"; } - AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } - AstNode* rhsp() const { return op2p(); } - void sensesp(AstSenItem* nodep) { addOp1p(nodep); } - void rhsp(AstNode* nodep) { setOp2p(nodep); } - // - virtual bool isClocked() const { return true; } - virtual bool isCombo() const { return false; } - virtual bool isInitial() const { return false; } - virtual bool isSettle() const { return false; } - virtual bool isNever() const { return false; } -}; - class AstSenTree : public AstNode { // A list of senitems // Parents: MODULE | SBLOCK @@ -3068,7 +3103,7 @@ class AstSenTree : public AstNode { private: bool m_multi; // Created from combo logic by ORing multiple clock domains public: - AstSenTree(FileLine* fl, AstNodeSenItem* sensesp) + AstSenTree(FileLine* fl, AstSenItem* sensesp) : ASTGEN_SUPER(fl) , m_multi(false) { addNOp1p(sensesp); @@ -3079,8 +3114,8 @@ public: virtual V3Hash sameHash() const { return V3Hash(); } bool isMulti() const { return m_multi; } // op1 = Sensitivity list - AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } - void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); } + AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } + void addSensesp(AstSenItem* nodep) { addOp1p(nodep); } void multi(bool flag) { m_multi = true; } // METHODS bool hasClocked() const; // Includes a clocked statement @@ -3116,6 +3151,7 @@ public: // virtual void dump(std::ostream& str) const; AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list + void sensesp(AstSenTree* nodep) { setOp1p(nodep); } VAlwaysKwd keyword() const { return m_keyword; } }; @@ -3548,10 +3584,11 @@ public: addNOp1p(exprsp); addNOp2p(NULL); } - AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd') + AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', + bool hidden = true) : ASTGEN_SUPER(fl) , m_text("") - , m_hidden(true) + , m_hidden(hidden) , m_hasFormat(false) , m_missingArgChar(missingArgChar) { dtypeSetString(); @@ -3708,6 +3745,11 @@ public: setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setOp3p(lhsp); } + AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') + : ASTGEN_SUPER(fl) { + setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); + setOp3p(lhsp); + } ASTNODE_NODE_FUNCS(SFormat) virtual const char* broken() const { BROKEN_RTN(!fmtp()); @@ -4088,8 +4130,9 @@ public: class AstWriteMem : public AstNodeReadWriteMem { public: - AstWriteMem(FileLine* fl, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, true, filenamep, memp, lsbp, msbp) {} + AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, + AstNode* msbp) + : ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(WriteMem) virtual string verilogKwd() const { return (isHex() ? "$writememh" : "$writememb"); } virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; } @@ -4196,15 +4239,13 @@ public: class AstForeach : public AstNodeStmt { public: - AstForeach(FileLine* fl, AstNode* arrayp, AstNode* varsp, AstNode* bodysp) + AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) : ASTGEN_SUPER(fl) { setOp1p(arrayp); - addNOp2p(varsp); addNOp4p(bodysp); } ASTNODE_NODE_FUNCS(Foreach) - AstNode* arrayp() const { return op1p(); } // op1 = array - AstNode* varsp() const { return op2p(); } // op2 = variable index list + AstNode* arrayp() const { return op1p(); } // op1 = array and index vars AstNode* bodysp() const { return op4p(); } // op4 = body of loop virtual bool isGateOptimizable() const { return false; } virtual int instrCount() const { return instrCountBranch(); } @@ -4228,6 +4269,17 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; +class AstWait : public AstNodeStmt { +public: + AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) + : ASTGEN_SUPER(fl) { + setOp2p(condp); + addNOp3p(bodysp); + } + ASTNODE_NODE_FUNCS(Wait) + AstNode* bodysp() const { return op3p(); } // op3 = body of loop +}; + class AstWhile : public AstNodeStmt { public: AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp = NULL) @@ -4292,6 +4344,22 @@ public: } }; +class AstDisableFork : public AstNodeStmt { + // A "disable fork" statement +public: + AstDisableFork(FileLine* fl) + : ASTGEN_SUPER(fl) {} + ASTNODE_NODE_FUNCS(DisableFork) +}; + +class AstWaitFork : public AstNodeStmt { + // A "wait fork" statement +public: + AstWaitFork(FileLine* fl) + : ASTGEN_SUPER(fl) {} + ASTNODE_NODE_FUNCS(WaitFork) +}; + class AstReturn : public AstNodeStmt { public: explicit AstReturn(FileLine* fl, AstNode* lhsp = NULL) @@ -4798,6 +4866,26 @@ public: virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); } }; +class AstTimingControl : public AstNodeStmt { + // Parents: stmtlist +public: + AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) + : ASTGEN_SUPER(fl) { + setNOp1p(sensesp); + setNOp2p(stmtsp); + } + ASTNODE_NODE_FUNCS(TimingControl) + virtual string verilogKwd() const { return "@(%l) %r"; } + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool isPure() const { return false; } + virtual bool isOutputter() const { return false; } + virtual int instrCount() const { return 0; } + virtual V3Hash sameHash() const { return V3Hash(); } + AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } + AstNode* stmtsp() const { return op2p(); } +}; + class AstTimeFormat : public AstNodeStmt { // Parents: stmtlist public: @@ -5593,6 +5681,30 @@ public: AstNode* lhsp() const { return op1p(); } AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); } + virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } +}; + +class AstCastDynamic : public AstNodeBiop { +public: + AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) + : ASTGEN_SUPER(fl, lhsp, rhsp) {} + ASTNODE_NODE_FUNCS(CastDynamic) + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } + virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { + return new AstCastDynamic(this->fileline(), lhsp, rhsp); + } + virtual string emitVerilog() { return "%f$cast(%r, %l)"; } + // Non-existent filehandle returns EOF + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { return true; } + virtual bool cleanLhs() const { return true; } + virtual bool cleanRhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + virtual bool sizeMattersRhs() const { return false; } + virtual int instrCount() const { return widthInstrs() * 20; } + virtual bool isPure() const { return true; } }; class AstCastParse : public AstNode { @@ -7940,14 +8052,14 @@ class AstClocking : public AstNode { // Parents: MODULE // Children: Assertions public: - AstClocking(FileLine* fl, AstNodeSenItem* sensesp, AstNode* bodysp) + AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) : ASTGEN_SUPER(fl) { addOp1p(sensesp); addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(Clocking) // op1 = Sensitivity list - AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); } + AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } AstNode* bodysp() const { return op2p(); } // op2 = Body }; @@ -7959,7 +8071,7 @@ class AstPropClocked : public AstNode { // Parents: ASSERT|COVER (property) // Children: SENITEM, Properties public: - AstPropClocked(FileLine* fl, AstNodeSenItem* sensesp, AstNode* disablep, AstNode* propp) + AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) : ASTGEN_SUPER(fl) { addNOp1p(sensesp); addNOp2p(disablep); @@ -7967,9 +8079,7 @@ public: } ASTNODE_NODE_FUNCS(PropClocked) virtual bool hasDType() const { return true; } // Used under Cover, which expects a bool child - AstNodeSenItem* sensesp() const { - return VN_CAST(op1p(), NodeSenItem); - } // op1 = Sensitivity list + AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } // op1 = Sensitivity list AstNode* disablep() const { return op2p(); } // op2 = disable AstNode* propp() const { return op3p(); } // op3 = property }; diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index e47600fc0..7369d3b63 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -694,8 +694,6 @@ private: m_inDly = false; } virtual void visit(AstSenItem* nodep) VL_OVERRIDE { - // Note we look at only AstSenItems, not AstSenGate's - // The gating term of a AstSenGate is normal logic m_inSenItem = true; iterateChildren(nodep); m_inSenItem = false; @@ -705,11 +703,6 @@ private: // CDC doesn't care about public variables } virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } - virtual void visit(AstSenGate* nodep) VL_OVERRIDE { - // First handle the clock part will be handled in a minute by visit AstSenItem - // The logic gating term is dealt with as logic - iterateNewStmt(nodep); - } virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); } diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 331701260..a37b2f922 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -66,8 +66,8 @@ private: if (vscp->user1p()) return static_cast(vscp->user1p()); AstVar* varp = vscp->varp(); if (!varp->width1()) { - varp->v3error( - "Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ()); + varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: " + << varp->prettyNameQ()); } string newvarname = (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name()); @@ -103,10 +103,8 @@ private: // LOWEDGE: ~var AstNode* newp = NULL; if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) { - if (!v3Global.opt.bboxUnsup()) { - nodep->v3error( - "Unsupported: Complicated event expression in sensitive activity list"); - } + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Complicated event expression in sensitive activity list"); return NULL; } AstVarScope* clkvscp = nodep->varrefp()->varScopep(); @@ -138,23 +136,11 @@ private: } return newp; } - AstNode* createSenGateEquation(AstSenGate* nodep) { - AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()), - nodep->rhsp()->cloneTree(true)); - return newp; - } - AstNode* createSenseEquation(AstNodeSenItem* nodesp) { + AstNode* createSenseEquation(AstSenItem* nodesp) { // Nodep may be a list of elements; we need to walk it AstNode* senEqnp = NULL; - for (AstNodeSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) { - AstNode* senOnep = NULL; - if (AstSenItem* itemp = VN_CAST(senp, SenItem)) { - senOnep = createSenItemEquation(itemp); - } else if (AstSenGate* itemp = VN_CAST(senp, SenGate)) { - senOnep = createSenGateEquation(itemp); - } else { - senp->v3fatalSrc("Strange node under sentree"); - } + for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) { + AstNode* const senOnep = createSenItemEquation(senp); if (senEqnp) { // Add new OR to the sensitivity list equation senEqnp = new AstOr(senp->fileline(), senEqnp, senOnep); diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 4cf88e78b..aab3e6d62 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -158,19 +158,19 @@ typedef V3ConfigWildcardResolver V3ConfigFTaskResolver; class V3ConfigModule { typedef vl_unordered_set StringSet; + typedef std::set PragmaSet; V3ConfigFTaskResolver m_tasks; // Functions/tasks in module V3ConfigVarResolver m_vars; // Variables in module StringSet m_coverageOffBlocks; // List of block names for coverage_off + PragmaSet m_modPragmas; // List of Pragmas for modules bool m_inline; // Whether to force the inline bool m_inlineValue; // The inline value (on/off) - bool m_public; // Public module public: V3ConfigModule() : m_inline(false) - , m_inlineValue(false) - , m_public(false) {} + , m_inlineValue(false) {} void update(const V3ConfigModule& m) { m_tasks.update(m.m_tasks); @@ -183,7 +183,10 @@ public: m_inline = m.m_inline; m_inlineValue = m.m_inlineValue; } - if (!m_public) m_public = m.m_public; + for (PragmaSet::const_iterator it = m.m_modPragmas.begin(); it != m.m_modPragmas.end(); + ++it) { + m_modPragmas.insert(*it); + } } V3ConfigFTaskResolver& ftasks() { return m_tasks; } @@ -194,7 +197,7 @@ public: m_inline = true; m_inlineValue = set; } - void setPublic(bool set) { m_public = set; } + void addModulePragma(AstPragmaType pragma) { m_modPragmas.insert(pragma); } void apply(AstNodeModule* modp) { if (m_inline) { @@ -203,8 +206,8 @@ public: AstNode* nodep = new AstPragma(modp->fileline(), type); modp->addStmtp(nodep); } - if (m_public) { - AstNode* nodep = new AstPragma(modp->fileline(), AstPragmaType::PUBLIC_MODULE); + for (PragmaSet::const_iterator it = m_modPragmas.begin(); it != m_modPragmas.end(); ++it) { + AstNode* nodep = new AstPragma(modp->fileline(), *it); modp->addStmtp(nodep); } } @@ -408,6 +411,10 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int } } +void V3Config::addModulePragma(const string& module, AstPragmaType pragma) { + V3ConfigResolver::s().modules().at(module).addModulePragma(pragma); +} + void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) { if (ftask.empty()) { V3ConfigResolver::s().modules().at(module).setInline(on); @@ -439,7 +446,8 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas } else if (attr == AstAttrType::VAR_PUBLIC) { if (ftask.empty()) { // public module, this is the only exception from var here - V3ConfigResolver::s().modules().at(module).setPublic(true); + V3ConfigResolver::s().modules().at(module).addModulePragma( + AstPragmaType::PUBLIC_MODULE); } else { V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true); } diff --git a/src/V3Config.h b/src/V3Config.h index dd542192c..cc3a3a42f 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -34,6 +34,7 @@ public: static void addCoverageBlockOff(const string& module, const string& blockname); static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max); static void addWaiver(V3ErrorCode code, const string& filename, const string& message); + static void addModulePragma(const string& module, AstPragmaType pragma); static void addInline(FileLine* fl, const string& module, const string& ftask, bool on); static void addVarAttr(FileLine* fl, const string& module, const string& ftask, const string& signal, AstAttrType type, AstSenTree* nodep); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index fb3456d78..097562560 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -588,6 +588,7 @@ private: } return false; } + bool operandsSameSize(AstNode* lhsp, AstNode* rhsp) { return lhsp->width() == rhsp->width(); } //---------------------------------------- // Constant Replacement functions. @@ -1678,7 +1679,7 @@ private: // Not constant propagated (for today) because AstNodeMath::isOpaque is set // Someday if lower is constant, convert to quoted "string". - bool onlySenItemInSenTree(AstNodeSenItem* nodep) { + bool onlySenItemInSenTree(AstSenItem* nodep) { // Only one if it's not in a list return (!nodep->nextp() && nodep->backp()->nextp() != nodep); } @@ -1722,56 +1723,29 @@ private: "Null sensitivity variable"); } } - virtual void visit(AstSenGate* nodep) VL_OVERRIDE { - iterateChildren(nodep); - if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) { - if (constp->isZero()) { - UINFO(4, "SENGATE(...,0)->NEVER" << endl); - if (onlySenItemInSenTree(nodep)) { - nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never())); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - } else { - UINFO(4, "SENGATE(SENITEM,0)->ALWAYS SENITEM" << endl); - AstNode* senitemp = nodep->sensesp()->unlinkFrBack(); - nodep->replaceWith(senitemp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } - } - } struct SenItemCmp { - inline bool operator()(AstNodeSenItem* lhsp, AstNodeSenItem* rhsp) const { + inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const { if (lhsp->type() < rhsp->type()) return true; if (lhsp->type() > rhsp->type()) return false; - const AstSenItem* litemp = VN_CAST_CONST(lhsp, SenItem); - const AstSenItem* ritemp = VN_CAST_CONST(rhsp, SenItem); - if (litemp && ritemp) { - // Looks visually better if we keep sorted by name - if (!litemp->varrefp() && ritemp->varrefp()) return true; - if (litemp->varrefp() && !ritemp->varrefp()) return false; - if (litemp->varrefp() && ritemp->varrefp()) { - if (litemp->varrefp()->name() < ritemp->varrefp()->name()) return true; - if (litemp->varrefp()->name() > ritemp->varrefp()->name()) return false; - // But might be same name with different scopes - if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) { - return true; - } - if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) { - return false; - } - // Or rarely, different data types - if (litemp->varrefp()->dtypep() < ritemp->varrefp()->dtypep()) return true; - if (litemp->varrefp()->dtypep() > ritemp->varrefp()->dtypep()) return false; - } - // Sort by edge, AFTER variable, as we want multiple edges for same var adjacent. - // note the SenTree optimizer requires this order (more - // general first, less general last) - if (litemp->edgeType() < ritemp->edgeType()) return true; - if (litemp->edgeType() > ritemp->edgeType()) return false; + // Looks visually better if we keep sorted by name + if (!lhsp->varrefp() && rhsp->varrefp()) return true; + if (lhsp->varrefp() && !rhsp->varrefp()) return false; + if (lhsp->varrefp() && rhsp->varrefp()) { + 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; } + // Or rarely, different data types + if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true; + if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false; } + // Sort by edge, AFTER variable, as we want multiple edges for same var adjacent. + // note the SenTree optimizer requires this order (more + // general first, less general last) + if (lhsp->edgeType() < rhsp->edgeType()) return true; + if (lhsp->edgeType() > rhsp->edgeType()) return false; return false; } }; @@ -1792,30 +1766,10 @@ private: { AstUser4InUse m_inuse4; // Mark x in SENITEM(x) - for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; - senp = VN_CAST(senp->nextp(), NodeSenItem)) { - if (AstSenItem* itemp = VN_CAST(senp, SenItem)) { - if (itemp->varrefp() && itemp->varrefp()->varScopep()) { - itemp->varrefp()->varScopep()->user4(1); - } - } - } - // Find x in SENTREE(SENITEM(x)) - for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; - senp = nextp) { - nextp = VN_CAST(senp->nextp(), NodeSenItem); - if (AstSenGate* gatep = VN_CAST(senp, SenGate)) { - if (AstSenItem* itemp = VN_CAST(gatep->sensesp(), SenItem)) { - if (itemp->varrefp() && itemp->varrefp()->varScopep()) { - if (itemp->varrefp()->varScopep()->user4()) { - // Found, push this item up to the top - itemp->unlinkFrBack(); - nodep->addSensesp(itemp); - VL_DO_DANGLING(gatep->unlinkFrBack()->deleteTree(), gatep); - VL_DANGLING(senp); - } - } - } + for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp; + senp = VN_CAST(senp->nextp(), SenItem)) { + if (senp->varrefp() && senp->varrefp()->varScopep()) { + senp->varrefp()->varScopep()->user4(1); } } } @@ -1823,25 +1777,25 @@ private: // Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together. // Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs // Make things a little faster; check first if we need a sort - for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp; senp = nextp) { - nextp = VN_CAST(senp->nextp(), NodeSenItem); + nextp = VN_CAST(senp->nextp(), SenItem); // cppcheck-suppress unassignedVariable // cppcheck bug SenItemCmp cmp; if (nextp && !cmp(senp, nextp)) { // Something's out of order, sort it senp = NULL; - std::vector vec; - for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; - senp = VN_CAST(senp->nextp(), NodeSenItem)) { + std::vector vec; + for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp; + senp = VN_CAST(senp->nextp(), SenItem)) { vec.push_back(senp); } stable_sort(vec.begin(), vec.end(), SenItemCmp()); - for (std::vector::iterator it = vec.begin(); it != vec.end(); + for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) { (*it)->unlinkFrBack(); } - for (std::vector::iterator it = vec.begin(); it != vec.end(); + for (std::vector::iterator it = vec.begin(); it != vec.end(); ++it) { nodep->addSensesp(*it); } @@ -1850,13 +1804,12 @@ private: } // Pass2, remove dup edges - for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp; + for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp; senp = nextp) { - nextp = VN_CAST(senp->nextp(), NodeSenItem); - AstNodeSenItem* cmpp = nextp; - AstSenItem* litemp = VN_CAST(senp, SenItem); - AstSenItem* ritemp = VN_CAST(cmpp, SenItem); - if (litemp && ritemp) { + nextp = VN_CAST(senp->nextp(), SenItem); + AstSenItem* const litemp = senp; + AstSenItem* const ritemp = nextp; + if (ritemp) { if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameGateTree(ritemp->varrefp())) || (!litemp->varrefp() && !ritemp->varrefp())) { @@ -1876,7 +1829,7 @@ private: litemp->edgeType(VEdgeType::ET_BOTHEDGE); // Remove redundant node VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp); - VL_DANGLING(cmpp); + VL_DANGLING(ritemp); // Try to collapse again nextp = litemp; } @@ -1934,9 +1887,12 @@ private: if (constp->isZero()) { UINFO(4, "IF(0,{any},{x}) => {x}: " << nodep << endl); keepp = nodep->elsesp(); - } else { + } else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl); keepp = nodep->ifsp(); + } else { + UINFO(4, "IF condition is X, retaining: " << nodep << endl); + return; } if (keepp) { keepp->unlinkFrBackWithNext(); @@ -2322,7 +2278,7 @@ private: TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)"); TREEOP ("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)"); - TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a< a< a>>n TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1) TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<isSigPublic() // Can't elim publics! - && !nodep->isIO() && !nodep->isClassMember() - && ((nodep->isTemp() && !nodep->isTrace()) - || (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly()) - || m_elimUserVars)); // Post-Trace can kill most anything + if (nodep->isSigPublic()) return false; // Can't elim publics! + if (nodep->isIO() || nodep->isClassMember()) return false; + if (nodep->isTemp() && !nodep->isTrace()) return true; + if (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly()) return true; + return m_elimUserVars; // Post-Trace can kill most anything } void deadCheckScope() { diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index e0f67f03e..87faab264 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -171,8 +171,8 @@ private: UINFO(4, " Act: " << m_activep << endl); UINFO(4, " Act: " << oldactivep << endl); // Make a new sensitivity list, which is the combination of both blocks - AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true); - AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true); + AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true); + AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true); AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena); if (senb) treep->addSensesp(senb); if (AstSenTree* storep = oldactivep->sensesStorep()) { @@ -373,7 +373,8 @@ private: m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL. if (m_cfuncp) { - nodep->v3error("Unsupported: Delayed assignment inside public function/task"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Delayed assignment inside public function/task"); } if (VN_IS(nodep->lhsp(), ArraySel) || (VN_IS(nodep->lhsp(), Sel) @@ -385,7 +386,9 @@ private: "loops (non-delayed is ok - see docs)"); } AstBasicDType* basicp = lhsp->dtypep()->basicp(); - if (basicp && basicp->isEventValue()) nodep->v3error("Unsupported: event arrays"); + if (basicp && basicp->isEventValue()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays"); + } if (newlhsp) { nodep->lhsp(newlhsp); } else { diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 19f8939a3..e8e9a1e8f 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -154,6 +154,58 @@ public: } } + void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) { + for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { + if (const AstVar* varp = VN_CAST(nodep, Var)) { + if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) { + if (!init && sectionr != "") { + puts(sectionr); + sectionr = ""; + } + UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?"); + // These should be static const values, however microsloth VC++ doesn't + // support them. They also cause problems with GDB under GCC2.95. + if (varp->isWide()) { // Unsupported for output + if (!init) { + putsDecoration("// enum WData " + varp->nameProtect() + " //wide"); + } + } else if (varp->isString()) { + if (init) { + emitCtorSep(firstp); + puts(protect("var_" + varp->name()) + " ("); + iterateAndNextNull(varp->valuep()); + puts(")"); + } else { + puts("const std::string " + protect("var_" + varp->name()) + ";\n"); + } + } else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output + // putsDecoration("// enum ..... "+varp->nameProtect() + // +"not simple value, see variable above instead"); + } else if (VN_IS(varp->dtypep(), BasicDType) + && VN_CAST(varp->dtypep(), BasicDType) + ->isOpaque()) { // Can't put out e.g. doubles + } else { + if (init) { + emitCtorSep(firstp); + puts(protect("var_" + varp->name()) + " ("); + iterateAndNextNull(varp->valuep()); + puts(")"); + } else { + // enum + puts(varp->isQuad() ? "enum _QData" : "enum _IData"); + puts("" + varp->nameProtect() + " { " + varp->nameProtect() + " = "); + iterateAndNextNull(varp->valuep()); + puts("};\n"); + // var + puts(varp->isQuad() ? "const QData " : "const IData "); + puts(protect("var_" + varp->name()) + ";\n"); + } + } + } + } + } + } + struct CmpName { inline bool operator()(const AstNode* lhsp, const AstNode* rhsp) const { return lhsp->name() < rhsp->name(); @@ -598,7 +650,7 @@ public: } virtual void visit(AstFFlush* nodep) VL_OVERRIDE { if (!nodep->filep()) { - puts("Verilated::flushCall();\n"); + puts("Verilated::runFlushCallbacks();\n"); } else { puts("if ("); iterateAndNextNull(nodep->filep()); @@ -865,41 +917,51 @@ public: } virtual void visit(AstMulS* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Signed multiply of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Signed multiply of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPow* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPowSS* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPowSU* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } virtual void visit(AstPowUS* nodep) VL_OVERRIDE { if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3error("Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Power of " + << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); } visit(VN_CAST(nodep, NodeBiop)); } @@ -1057,7 +1119,7 @@ public: void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) { // Put out constant set to the specified variable, or given variable in a string if (nodep->num().isFourState()) { - nodep->v3error("Unsupported: 4-state numbers in this context"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context"); } else if (nodep->num().isString()) { putbs("std::string("); putsQuoted(nodep->num().toString()); @@ -2301,6 +2363,8 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { } emitVarCtors(&first); if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first); + string section(""); + emitParams(modp, true, &first, section /*ref*/); puts(" {\n"); emitCellCtors(modp); emitSensitives(); @@ -3031,35 +3095,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) { ofp()->putsPrivate(false); // public: emitVarList(modp->stmtsp(), EVL_CLASS_PAR, "", section /*ref*/); // Only those that are non-CONST - for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (const AstVar* varp = VN_CAST(nodep, Var)) { - if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) { - if (section != "") { - puts(section); - section = ""; - } - UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?"); - // These should be static const values, however microsloth VC++ doesn't - // support them. They also cause problems with GDB under GCC2.95. - if (varp->isWide()) { // Unsupported for output - putsDecoration("// enum WData " + varp->nameProtect() + " //wide"); - } else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output - // putsDecoration("// enum ..... "+varp->nameProtect() - // +"not simple value, see variable above instead"); - } else if (VN_IS(varp->dtypep(), BasicDType) - && VN_CAST(varp->dtypep(), BasicDType) - ->isOpaque()) { // Can't put out e.g. doubles - } else { - puts("enum "); - puts(varp->isQuad() ? "_QData" : "_IData"); - puts("" + varp->nameProtect() + " { " + varp->nameProtect() + " = "); - iterateAndNextNull(varp->valuep()); - puts("};"); - } - puts("\n"); - } - } - } + bool first = true; + emitParams(modp, false, &first, section /*ref*/); if (!VN_IS(modp, Class)) { puts("\n// CONSTRUCTORS\n"); diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 39a2f4fd6..b2b526f29 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -42,7 +42,8 @@ class EmitCInlines : EmitCBaseVisitor { } virtual void visit(AstCNew* nodep) VL_OVERRIDE { checkHeavy(nodep); - if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new"); + if (v3Global.opt.savable()) + v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new"); iterateChildren(nodep); } virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE { diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 793ce9bbc..5e741264f 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -163,8 +163,9 @@ class CMakeEmitter { + "_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { - v3error("Unsupported: This trace format is not supported in SystemC, " - "use VCD format."); + v3warn(E_UNSUPPORTED, + "Unsupported: This trace format is not supported in SystemC, " + "use VCD format."); } global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang() + ".cpp"); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index bc5ce4587..978c56e2e 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -332,12 +332,7 @@ class EmitCSyms : EmitCBaseVisitor { virtual void visit(AstVar* nodep) VL_OVERRIDE { nameCheck(nodep); iterateChildren(nodep); - if (nodep->isSigUserRdPublic() - // The VPI functions require a pointer to allow modification, - // but parameters are constants - && !nodep->isParam()) { - m_modVars.push_back(make_pair(m_modp, nodep)); - } + if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); } } virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE { // Assign numbers to all bins, so we know how big of an array to use @@ -794,16 +789,38 @@ void EmitCSyms::emitSymImp() { } puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,"); putsQuoted(protect(it->second.m_varBasePretty)); - puts(", &("); + + std::string varName; if (modp->isTop()) { - puts(protectIf(scopep->nameDotless() + "p", scopep->protect())); - puts("->"); + varName += (protectIf(scopep->nameDotless() + "p", scopep->protect()) + "->"); } else { - puts(protectIf(scopep->nameDotless(), scopep->protect())); - puts("."); + varName += (protectIf(scopep->nameDotless(), scopep->protect()) + "."); } - puts(varp->nameProtect()); - puts("), "); + + if (varp->isParam()) { + varName += protect("var_" + varp->name()); + } else { + varName += protect(varp->name()); + } + + if (varp->isParam()) { + if (varp->vlEnumType() == "VLVT_STRING") { + puts(", const_cast(static_cast("); + puts(varName.c_str()); + puts(".c_str())), "); + } else { + puts(", const_cast(static_cast(&("); + puts(varName.c_str()); + puts("))), "); + } + } else { + puts(", &("); + puts(varName.c_str()); + puts("), "); + } + + puts(varp->isParam() ? "true" : "false"); + puts(", "); puts(varp->vlEnumType()); // VLVT_UINT32 etc puts(","); puts(varp->vlEnumDir()); // VLVD_IN etc diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index e148bb1a0..6fe9cf8c0 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -104,8 +104,9 @@ public: putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp"); if (v3Global.opt.systemC()) { if (v3Global.opt.traceFormat() != TraceFormat::VCD) { - v3error("Unsupported: This trace format is not supported " - "in SystemC, use VCD format."); + v3warn(E_UNSUPPORTED, + "Unsupported: This trace format is not supported " + "in SystemC, use VCD format."); } else { putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp"); } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 19b6c7ec8..07c9395d5 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -160,9 +160,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } puts(")"); } - virtual void visit(AstSenGate* nodep) VL_OVERRIDE { - emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp()); - } virtual void visit(AstSenItem* nodep) VL_OVERRIDE { putfs(nodep, ""); puts(nodep->edgeType().verilogKwd()); diff --git a/src/V3Error.h b/src/V3Error.h index f86d5888f..88f96d0e1 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -44,6 +44,7 @@ public: EC_FATALSRC, // Kill the program, for internal source errors EC_ERROR, // General error out, can't suppress // Boolean information we track per-line, but aren't errors + I_CELLDEFINE, // Inside cell define from `celldefine/`endcelldefine I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/ I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/ I_LINT, // All lint messages @@ -51,6 +52,7 @@ public: // Error codes: E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable E_PORTSHORT, // Error: Output port is connected to a constant, electrical short + E_UNSUPPORTED, // Error: Unsupported (generally) E_TASKNSVAR, // Error: Task I/O not simple // // Warning codes: @@ -140,9 +142,9 @@ public: // Leading spaces indicate it can't be disabled. " MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR", // Boolean - " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE", + " I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE", // Errors - "DETECTARRAY", "PORTSHORT", "TASKNSVAR", + "DETECTARRAY", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", // Warnings " EC_FIRST_WARN", "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", @@ -170,7 +172,9 @@ public: return names[m_e]; } // Warnings that default to off - bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); } + bool defaultsOff() const { + return (m_e == IMPERFECTSCH || m_e == I_CELLDEFINE || styleError()); + } // Warnings that warn about nasty side effects bool dangerous() const { return (m_e == COMBDLY); } // Warnings we'll present to the user as errors diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index f3e47f857..623f98c1f 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -206,8 +206,8 @@ private: UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl); // -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}} if (rhsp->num().isFourState()) { - rhsp->v3error( // LCOV_EXCL_LINE // impossible? - "Unsupported: 4-state numbers in this context"); + rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible? + "Unsupported: 4-state numbers in this context"); } for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign( diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 579e3cb75..4cc568886 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -218,6 +218,8 @@ public: bool lastWarnWaived() { return m_waive; } // Specific flag ACCESSORS/METHODS + bool celldefineOn() const { return m_warnOn.test(V3ErrorCode::I_CELLDEFINE); } + void celldefineOn(bool flag) { warnOn(V3ErrorCode::I_CELLDEFINE, flag); } bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); } void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); } bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); } @@ -265,6 +267,21 @@ public: && m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn && m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn); } + // Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for + // equivalent. + int operatorCompare(const FileLine& rhs) const { + if (m_filenameno != rhs.m_filenameno) return (m_filenameno < rhs.m_filenameno) ? -1 : 1; + if (m_firstLineno != rhs.m_firstLineno) + return (m_firstLineno < rhs.m_firstLineno) ? -1 : 1; + if (m_firstColumn != rhs.m_firstColumn) + return (m_firstColumn < rhs.m_firstColumn) ? -1 : 1; + if (m_lastLineno != rhs.m_lastLineno) return (m_lastLineno < rhs.m_lastLineno) ? -1 : 1; + if (m_lastColumn != rhs.m_lastColumn) return (m_lastColumn < rhs.m_lastColumn) ? -1 : 1; + for (size_t i = 0; i < m_warnOn.size(); ++i) { + if (m_warnOn[i] != rhs.m_warnOn[i]) return (m_warnOn[i] < rhs.m_warnOn[i]) ? -1 : 1; + } + return 0; // (*this) and rhs are equivalent + } private: string warnContext(bool secondary) const; diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index cf3676f2b..8c3a785ad 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -483,8 +483,6 @@ private: iterateNewStmt(nodep, "User C Function", "User C Function"); } virtual void visit(AstSenItem* nodep) VL_OVERRIDE { - // Note we look at only AstSenItems, not AstSenGate's - // The gating term of a AstSenGate is normal logic m_inSenItem = true; if (m_logicVertexp) { // Already under logic; presumably a SenGate iterateChildren(nodep); @@ -493,11 +491,6 @@ private: } m_inSenItem = false; } - virtual void visit(AstSenGate* nodep) VL_OVERRIDE { - // First handle the clock part will be handled in a minute by visit AstSenItem - // The logic gating term is dealt with as logic - iterateNewStmt(nodep, "Clock gater", "Clock gater"); - } virtual void visit(AstInitial* nodep) VL_OVERRIDE { bool lastslow = m_inSlow; m_inSlow = true; diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 17343944d..1fb8467cb 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -116,8 +116,8 @@ private: virtual void visit(AstUdpTable* nodep) VL_OVERRIDE { if (!v3Global.opt.bboxUnsup()) { // If we support primitives, update V3Undriven to remove special case - nodep->v3error("Unsupported: Verilog 1995 UDP Tables. " - "Use --bbox-unsup to ignore tables."); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 1995 UDP Tables. " + "Use --bbox-unsup to ignore tables."); } } @@ -358,8 +358,8 @@ private: && !VN_IS(exprp, VarRef) // V3Const will collapse the SEL with the one we're about to make && !VN_IS(exprp, Concat) && !VN_IS(exprp, Sel)) { - nodep->v3error("Unsupported: Per-bit array instantiations with output " - "connections to non-wires."); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Per-bit array instantiations " + "with output connections to non-wires."); // Note spec allows more complicated matches such as slices and such } exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth); @@ -375,7 +375,8 @@ private: V3Const::constifyParamsEdit(arrselp->rhsp()); const AstConst* constp = VN_CAST(arrselp->rhsp(), Const); if (!constp) { - nodep->v3error( + nodep->v3warn( + E_UNSUPPORTED, "Unsupported: Non-constant index when passing interface to module"); return; } @@ -442,7 +443,6 @@ private: string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__"; AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true); newVarXRefp->varp(newp->modVarp()); - newVarXRefp->dtypep(newp->modVarp()->dtypep()); newp->exprp()->unlinkFrBack()->deleteTree(); newp->exprp(newVarXRefp); if (!prevPinp) { diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index e55660d70..bb6f1110c 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -75,12 +75,13 @@ public: void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { if (LinkCellsVertex* vvertexp = dynamic_cast(vertexp)) { - vvertexp->modp()->v3error( - "Unsupported: Recursive multiple modules (module instantiates " - "something leading back to itself): " - << vvertexp->modp()->prettyNameQ() << endl - << V3Error::warnMore() - << "... note: self-recursion (module instantiating itself directly) is supported."); + vvertexp->modp()->v3warn(E_UNSUPPORTED, + "Unsupported: Recursive multiple modules (module instantiates " + "something leading back to itself): " + << vvertexp->modp()->prettyNameQ() << endl + << V3Error::warnMore() + << "... note: self-recursion (module instantiating itself " + "directly) is supported."); V3Error::abortIfErrors(); } else { // Everything should match above, but... v3fatalSrc("Recursive instantiations"); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index df2da2803..99bd1fcb2 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -67,7 +67,6 @@ #include "V3SymTable.h" #include "V3Graph.h" #include "V3Ast.h" -#include "V3ParseImp.h" #include "V3String.h" #include @@ -540,8 +539,8 @@ private: } public: - VSymEnt* findDotted(VSymEnt* lookupSymp, const string& dotname, string& baddot, - VSymEnt*& okSymp) { + VSymEnt* findDotted(FileLine* /*refLocationp*/, VSymEnt* lookupSymp, const string& dotname, + string& baddot, VSymEnt*& okSymp) { // Given a dotted hierarchy name, return where in scope it is // Note when dotname=="" we just fall through and return lookupSymp UINFO(8, " dottedFind se" << cvtToHex(lookupSymp) << " '" << dotname << "'" << endl); @@ -711,35 +710,6 @@ class LinkDotFindVisitor : public AstNVisitor { // METHODS int debug() { return LinkDotState::debug(); } - AstConst* parseParamLiteral(FileLine* fl, const string& literal) const { - bool success = false; - if (literal[0] == '"') { - // This is a string - string v = literal.substr(1, literal.find('"', 1) - 1); - return new AstConst(fl, AstConst::VerilogStringLiteral(), v); - } else if (literal.find_first_of(".eEpP") != string::npos) { - // This may be a real - double v = V3ParseImp::parseDouble(literal.c_str(), literal.length(), &success); - if (success) return new AstConst(fl, AstConst::RealDouble(), v); - } - if (!success) { - // This is either an integer or an error - // We first try to convert it as C literal. If strtol returns - // 0 this is either an error or 0 was parsed. But in any case - // we will try to parse it as a verilog literal, hence having - // the false negative for 0 is okay. If anything remains in - // the string after the number, this is invalid C and we try - // the Verilog literal parser. - char* endp; - int v = strtol(literal.c_str(), &endp, 0); - if ((v != 0) && (endp[0] == 0)) { // C literal - return new AstConst(fl, AstConst::WidthedValue(), 32, v); - } else { // Try a Verilog literal (fatals if not) - return new AstConst(fl, AstConst::StringToParse(), literal.c_str()); - } - } - return NULL; - } void makeImplicitNew(AstClass* nodep) { AstFunc* newp = new AstFunc(nodep->fileline(), "new", NULL, NULL); newp->isConstructor(true); @@ -794,9 +764,10 @@ class LinkDotFindVisitor : public AstNVisitor { int oldBlockNum = m_blockNum; int oldModBlockNum = m_modBlockNum; if (doit && nodep->user2()) { - nodep->v3error("Unsupported: Identically recursive module (module instantiates " - "itself, without changing parameters): " - << AstNode::prettyNameQ(nodep->origName())); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Identically recursive module (module instantiates " + "itself, without changing parameters): " + << AstNode::prettyNameQ(nodep->origName())); } else if (doit) { UINFO(4, " Link Module: " << nodep << endl); UASSERT_OBJ(!nodep->dead(), nodep, "Module in cell tree mislabeled as dead?"); @@ -904,7 +875,7 @@ class LinkDotFindVisitor : public AstNVisitor { string scope = origname.substr(0, pos); string baddot; VSymEnt* okSymp; - aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp); + aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, scope, baddot, okSymp); UASSERT_OBJ(aboveSymp, nodep, "Can't find cell insertion point at " << AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ()); @@ -935,7 +906,7 @@ class LinkDotFindVisitor : public AstNVisitor { string ident = dottedname.substr(pos + strlen("__DOT__")); string baddot; VSymEnt* okSymp; - aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp); + aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp); UASSERT_OBJ(aboveSymp, nodep, "Can't find cellinline insertion point at " << AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ()); @@ -1036,10 +1007,16 @@ class LinkDotFindVisitor : public AstNVisitor { UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?"); iterateChildren(nodep); if (m_ftaskp && nodep->isParam()) { - nodep->v3error("Unsupported: Parameters in functions."); // Big3 unsupported too + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Parameters in functions"); // Big3 unsupported too VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } + if (nodep->isFuncLocal() && nodep->lifetime().isStatic()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' function/task variables"); + } else if (nodep->isClassMember() && nodep->lifetime().isStatic()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class members"); + } if (!m_statep->forScopeCreation()) { // Find under either a task or the module's vars VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name()); @@ -1129,7 +1106,8 @@ class LinkDotFindVisitor : public AstNVisitor { = new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM), nodep->name(), nodep); string svalue = v3Global.opt.parameter(nodep->name()); - if (AstNode* valuep = parseParamLiteral(nodep->fileline(), svalue)) { + if (AstNode* valuep + = AstConst::parseParamLiteral(nodep->fileline(), svalue)) { newp->valuep(valuep); UINFO(9, " replace parameter " << nodep << endl); UINFO(9, " with " << newp << endl); @@ -1482,13 +1460,15 @@ class LinkDotScopeVisitor : public AstNVisitor { string ifcellname = dtypep->cellName(); string baddot; VSymEnt* okSymp; - VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp); + VSymEnt* cellSymp = m_statep->findDotted(nodep->fileline(), m_modSymp, ifcellname, + baddot, okSymp); UASSERT_OBJ(cellSymp, nodep, "No symbol for interface cell: " << nodep->prettyNameQ(ifcellname)); UINFO(5, " Found interface cell: se" << cvtToHex(cellSymp) << " " << cellSymp->nodep() << endl); if (dtypep->modportName() != "") { - VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp); + VSymEnt* mpSymp = m_statep->findDotted(nodep->fileline(), m_modSymp, + ifcellname, baddot, okSymp); UASSERT_OBJ(mpSymp, nodep, "No symbol for interface modport: " << nodep->prettyNameQ(dtypep->modportName())); @@ -1537,7 +1517,8 @@ class LinkDotScopeVisitor : public AstNVisitor { = refp ? refp->name() : (inl.size() ? (inl + xrefp->name()) : xrefp->name()); string baddot; VSymEnt* okSymp; - symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp); + symp = m_statep->findDotted(nodep->rhsp()->fileline(), m_modSymp, scopename, + baddot, okSymp); if (inl == "") break; inl = LinkDotState::removeLastInlineScope(inl); } @@ -1560,7 +1541,8 @@ class LinkDotScopeVisitor : public AstNVisitor { string scopename = refp ? refp->varp()->name() : xrefp->dotted() + "." + xrefp->name(); string baddot; VSymEnt* okSymp; - VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp); + VSymEnt* symp = m_statep->findDotted(nodep->lhsp()->fileline(), m_modSymp, scopename, + baddot, okSymp); UASSERT_OBJ(symp, nodep, "No symbol for interface alias lhs"); UINFO(5, " Found a linked scope LHS: " << scopename << " se" << cvtToHex(symp) << " " << symp->nodep() << endl); @@ -1619,7 +1601,7 @@ class LinkDotIfaceVisitor : public AstNVisitor { virtual void visit(AstModportFTaskRef* nodep) VL_OVERRIDE { UINFO(5, " fif: " << nodep << endl); iterateChildren(nodep); - if (nodep->isExport()) nodep->v3error("Unsupported: modport export"); + if (nodep->isExport()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: modport export"); VSymEnt* symp = m_curSymp->findIdFallback(nodep->name()); if (!symp) { nodep->v3error("Modport item not found: " << nodep->prettyNameQ()); @@ -2026,12 +2008,24 @@ 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() == "this") { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: this"); + } else 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) { m_ds.init(m_curSymp); // Note m_ds.m_dot remains NULL; this is a reference not under a dot } + if (nodep->name() == "this") { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: this"); + m_ds.m_dotErr = true; + } else if (nodep->name() == "super") { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); + m_ds.m_dotErr = true; + } if (m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is membership. {scope}.{var}.HERE {member} AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack(); @@ -2077,8 +2071,8 @@ private: string baddot; VSymEnt* okSymp = NULL; if (allowScope) { - foundp = m_statep->findDotted(m_ds.m_dotSymp, nodep->name(), baddot, - okSymp); // Maybe NULL + foundp = m_statep->findDotted(nodep->fileline(), m_ds.m_dotSymp, nodep->name(), + baddot, okSymp); // Maybe NULL } else { foundp = m_ds.m_dotSymp->findIdFallback(nodep->name()); } @@ -2311,13 +2305,13 @@ private: // ignore (t_math_divw) dotSymp = m_modSymp; string inl = AstNode::dedotName(nodep->inlinedDots()); - dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp); + dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp); UASSERT_OBJ(dotSymp, nodep, "Couldn't resolve inlined scope " << AstNode::prettyNameQ(baddot) << " in: " << nodep->inlinedDots()); } - dotSymp - = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL + dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot, + okSymp); // Maybe NULL if (!m_statep->forScopeCreation()) { VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot); AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : NULL; @@ -2388,6 +2382,11 @@ private: } m_ds = lastStates; } + virtual void visit(AstWith* nodep) VL_OVERRIDE { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements"); + nodep->replaceWith(nodep->funcrefp()->unlinkFrBack()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstVar* nodep) VL_OVERRIDE { checkNoDot(nodep); iterateChildren(nodep); @@ -2460,7 +2459,8 @@ private: dotSymp = m_modSymp; string inl = AstNode::dedotName(nodep->inlinedDots()); UINFO(8, " Inlined " << inl << endl); - dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp); + dotSymp + = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp); if (!dotSymp) { okSymp->cellErrorScopes(nodep); nodep->v3fatalSrc("Couldn't resolve inlined scope " @@ -2468,7 +2468,7 @@ private: << " in: " << nodep->inlinedDots()); } } - dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot, + dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL } VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot); @@ -2611,6 +2611,12 @@ private: virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { UINFO(5, " " << nodep << endl); checkNoDot(nodep); + if (nodep->classMethod() && nodep->lifetime().isStatic()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method"); + } + if (nodep->isExtern()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: extern class methods"); + } VSymEnt* oldCurSymp = m_curSymp; { m_ftaskp = nodep; @@ -2627,7 +2633,7 @@ private: if (AstClassExtends* eitemp = VN_CAST(itemp, ClassExtends)) { // Replace abstract reference with hard pointer // Will need later resolution when deal with parameters - eitemp->v3error("Unsupported: class extends"); + eitemp->v3warn(E_UNSUPPORTED, "Unsupported: class extends"); } } VSymEnt* oldCurSymp = m_curSymp; diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 73fbe604c..55c7b24cf 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -178,7 +178,7 @@ private: AstNodeVarRef* varrefp; if (m_unsupportedHere || !(varrefp = VN_CAST(nodep->rhsp(), VarRef))) { - nodep->v3error("Unsupported: Incrementation in this context."); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Incrementation in this context."); return; } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 3c9185b33..56ff84b93 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -173,6 +173,17 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } + virtual void visit(AstWait* nodep) VL_OVERRIDE { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait statements"); + // Statements we'll just execute immediately; equivalent to if they followed this + if (AstNode* bodysp = nodep->bodysp()) { + bodysp->unlinkFrBackWithNext(); + nodep->replaceWith(bodysp); + } else { + nodep->unlinkFrBack(); + } + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstWhile* nodep) VL_OVERRIDE { // Don't need to track AstRepeat/AstFor as they have already been converted AstWhile* lastLoopp = m_loopp; @@ -260,7 +271,7 @@ private: AstJumpLabel* labelp = findAddLabel(beginp, false); nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp)); } else { - nodep->v3error("Unsupported: disable fork"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork"); } nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep); diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 8c0fe88ec..70c997d6d 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -228,8 +228,9 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { varp->primaryIO(true); } if (varp->direction().isRefOrConstRef()) { - varp->v3error("Unsupported: ref/const ref as primary input/output: " - << varp->prettyNameQ()); + varp->v3warn(E_UNSUPPORTED, + "Unsupported: ref/const ref as primary input/output: " + << varp->prettyNameQ()); } if (varp->isIO() && v3Global.opt.systemC()) { varp->sc(true); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 8fb47dc64..6d79174fa 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -196,8 +196,8 @@ private: if (v3Global.opt.publicFlatRW()) { switch (nodep->varType()) { - case AstVarType::VAR: - case AstVarType::PORT: + case AstVarType::VAR: // FALLTHRU + case AstVarType::PORT: // FALLTHRU case AstVarType::WIRE: nodep->sigUserRWPublic(true); break; default: break; } @@ -228,8 +228,8 @@ private: new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), nodep->valuep()->unlinkFrBack()))); } else if (!m_ftaskp && nodep->isNonOutput()) { - nodep->v3error( - "Unsupported: Default value on module input: " << nodep->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: " + << nodep->prettyNameQ()); nodep->valuep()->unlinkFrBack()->deleteTree(); } // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial else if (m_valueModp) { @@ -251,7 +251,7 @@ private: // What breaks later is we don't have a Scope/Cell representing // the interface to attach to if (m_modp->level() <= 2) { - nodep->v3error("Unsupported: Interfaced port on top level module"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Interfaced port on top level module"); } } } @@ -385,11 +385,50 @@ private: // FOREACH(array,loopvars,body) // -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body)) // nodep->dumpTree(cout, "-foreach-old:"); - AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext(); - AstNode* arrayp = nodep->arrayp(); - int dimension = 1; + UINFO(9, "FOREACH " << nodep << endl); + // nodep->dumpTree(cout, "-foreach-in:"); + AstNode* newp = nodep->bodysp(); + if (newp) newp->unlinkFrBackWithNext(); + // Separate iteration vars from base from variable + // Input: + // v--- arrayp + // 1. DOT(DOT(first, second), ASTSELLOOPVARS(third, var0..var1)) + // Separated: + // bracketp = ASTSELLOOPVARS(...) + // arrayp = DOT(DOT(first, second), third) + // firstVarp = var0..var1 + // Other examples + // 2. ASTSELBIT(first, var0)) + // 3. ASTSELLOOPVARS(first, var0..var1)) + // 4. DOT(DOT(first, second), ASTSELBIT(third, var0)) + AstNode* bracketp = nodep->arrayp(); + AstNode* firstVarsp = NULL; + while (AstDot* dotp = VN_CAST(bracketp, Dot)) { bracketp = dotp->rhsp(); } + if (AstSelBit* selp = VN_CAST(bracketp, SelBit)) { + firstVarsp = selp->rhsp()->unlinkFrBackWithNext(); + selp->replaceWith(selp->fromp()->unlinkFrBack()); + VL_DO_DANGLING(selp->deleteTree(), selp); + } else if (AstSelLoopVars* selp = VN_CAST(bracketp, SelLoopVars)) { + firstVarsp = selp->elementsp()->unlinkFrBackWithNext(); + selp->replaceWith(selp->fromp()->unlinkFrBack()); + VL_DO_DANGLING(selp->deleteTree(), selp); + } else { + nodep->v3error( + "Syntax error; foreach missing bracketed index variable (IEEE 1800-2017 12.7.3)"); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + AstNode* arrayp = nodep->arrayp(); // Maybe different node since bracketp looked + if (!VN_IS(arrayp, ParseRef)) { + // Code below needs to use other then attributes to figure out the bounds + // Also need to deal with queues, etc + arrayp->v3warn(E_UNSUPPORTED, "Unsupported: foreach on non-simple variable reference"); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + // Split into for loop // Must do innermost (last) variable first - AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext(); + int dimension = 1; AstNode* lastVarsp = firstVarsp; while (lastVarsp->nextp()) { lastVarsp = lastVarsp->nextp(); @@ -498,26 +537,55 @@ private: } virtual void visit(AstPrintTimeScale* nodep) VL_OVERRIDE { // Inlining may change hierarchy, so just save timescale where needed + cleanFileline(nodep); iterateChildren(nodep); nodep->name(m_modp->name()); nodep->timeunit(m_modp->timeunit()); } virtual void visit(AstSFormatF* nodep) VL_OVERRIDE { + cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } virtual void visit(AstTime* nodep) VL_OVERRIDE { + cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } virtual void visit(AstTimeD* nodep) VL_OVERRIDE { + cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } virtual void visit(AstTimeImport* nodep) VL_OVERRIDE { + cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } + virtual void visit(AstTimingControl* nodep) VL_OVERRIDE { + cleanFileline(nodep); + iterateChildren(nodep); + AstAlways* alwaysp = VN_CAST(nodep->backp(), Always); + if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) { + alwaysp->v3error("Timing control statements not legal under always_comb\n" + << nodep->warnMore() << "... Suggest use a normal 'always'"); + } else if (alwaysp && !alwaysp->sensesp()) { + // Verilator is still ony supporting SenTrees under an always, + // so allow the parser to handle everything and shim to + // historical AST here + if (AstSenTree* sensesp = nodep->sensesp()) { + sensesp->unlinkFrBackWithNext(); + alwaysp->sensesp(sensesp); + } + if (nodep->stmtsp()) alwaysp->addStmtp(nodep->stmtsp()->unlinkFrBackWithNext()); + } else { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: timing control statement in this location\n" + << nodep->warnMore() + << "... Suggest have one timing control statement " + << "per procedure, at the top of the procedure"); + } + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } virtual void visit(AstNode* nodep) VL_OVERRIDE { // Default: Just iterate diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index a6074a554..962a615fa 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -108,9 +108,16 @@ private: virtual void visit(AstVar* nodep) VL_OVERRIDE { iterateChildren(nodep); if (m_classp && !nodep->isParam()) nodep->varType(AstVarType::MEMBER); - if (m_classp && nodep->isParam()) nodep->v3error("Unsupported: class parameter"); + if (m_classp && nodep->isParam()) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: class parameter"); if (m_ftaskp) nodep->funcLocal(true); - if (nodep->lifetime().isNone()) nodep->lifetime(m_lifetime); + if (nodep->lifetime().isNone()) { + if (nodep->isFuncLocal() && nodep->isIO()) { + nodep->lifetime(VLifetime::AUTOMATIC); + } else { + nodep->lifetime(m_lifetime); + } + } if (nodep->isSigModPublic()) { nodep->sigModPublic(false); // We're done with this attribute m_modp->modPublic(true); // Avoid flattening if signals are exposed @@ -129,7 +136,7 @@ private: if (m_classp) nodep->classMethod(true); VLifetime origLifetime = m_lifetime; { - if (!nodep->lifetime().isNone()) m_lifetime = nodep->lifetime(); + m_lifetime = nodep->lifetime(); if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC; m_ftaskp = nodep; iterateChildren(nodep); @@ -167,8 +174,9 @@ private: addwherep = addwherep->backp(); } if (!VN_IS(addwherep, Always)) { // Assertion perhaps? - sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under " - "some complicated block"); + sensp->v3warn(E_UNSUPPORTED, + "Unsupported: Non-single-bit pos/negedge clock statement under " + "some complicated block"); addwherep = m_modp; } addwherep->addNext(newvarp); @@ -207,12 +215,9 @@ private: && !VN_IS(nodep->sensp(), EnumItemRef) // V3Const will cleanup && !nodep->isIllegal()) { if (debug()) nodep->dumpTree(cout, "-tree: "); - nodep->v3error("Unsupported: Complex statement in sensitivity list"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Complex statement in sensitivity list"); } } - virtual void visit(AstSenGate* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE - nodep->v3fatalSrc("SenGates shouldn't be in tree yet"); - } virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE { if (!nodep->attrp()) { @@ -239,7 +244,7 @@ private: } else if (VN_IS(basefromp, Replicate)) { // From {...}[...] syntax in IEEE 2017 if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); } - nodep->v3error("Unsupported: Select of concatenation"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Select of concatenation"); nodep = NULL; } else { if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); } @@ -309,13 +314,13 @@ private: break; case 'm': // %m - auto insert "name" if (isScan) { - nodep->v3error("Unsupported: %m in $fscanf"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: %m in $fscanf"); fmt = ""; } break; case 'l': // %l - auto insert "library" if (isScan) { - nodep->v3error("Unsupported: %l in $fscanf"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf"); fmt = ""; } if (m_modp) fmt = VString::quotePercent(m_modp->prettyName()); @@ -395,7 +400,8 @@ private: void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) { if (!filep) { - nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable"); } if (filep && filep->varp()) filep->varp()->attrFileDescr(true); } diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 483d32c15..2d8d39f36 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -108,11 +108,11 @@ private: virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildrenConst(nodep); } public: - // Set user1 on all referenced AstVar - void operator()(AstNode* node) { - AstNode::user1ClearTree(); - iterate(node); - } + // Remove marks from AstVars (clear user1) + void clear() { AstNode::user1ClearTree(); } + + // Mark all AstVars referenced by setting user1 + void mark(AstNode* node) { iterate(node); } }; class MergeCondVisitor : public AstNVisitor { @@ -239,6 +239,7 @@ private: m_mgCondp = NULL; m_mgLastp = NULL; m_mgNextp = NULL; + m_markVars.clear(); } void addToList(AstNode* nodep, AstNode* condp) { @@ -248,7 +249,7 @@ private: m_mgFirstp = nodep; m_mgCondp = condp; m_listLenght = 0; - m_markVars(condp); + m_markVars.mark(condp); } // Add node ++m_listLenght; @@ -268,9 +269,14 @@ private: if (AstNodeCond* const condp = extractCond(rhsp)) { if (!m_checkMergeable(nodep)) { // Node not mergeable. - // Finish current list if any, do not start a new one. - if (m_mgFirstp) mergeEnd(); - return; + // If no current list, then this node is just special, move on. + if (!m_mgFirstp) return; + // Otherwise finish current list + mergeEnd(); + // Finishing the list might make the node mergeable again, e.g. + // if the reason we could not merge was due to the condition + // being assigned, so check again and stop only if still no. + if (!m_checkMergeable(nodep)) return; } if (m_mgFirstp && (m_mgNextp != nodep || !condp->condp()->sameTree(m_mgCondp))) { // Node in different list, or has different condition. @@ -282,7 +288,7 @@ private: } else if (m_mgFirstp) { // RHS is not a conditional, but we already started a list. // If it's a 1-bit signal, and a mergeable assignment, try reduced forms - if (rhsp->widthMin() == 1 && m_checkMergeable(nodep)) { + if (m_mgNextp == nodep && rhsp->widthMin() == 1 && m_checkMergeable(nodep)) { // Is it a 'lhs = cond & value' or 'lhs = value & cond'? if (AstAnd* const andp = VN_CAST(rhsp, And)) { if (andp->lhsp()->sameTree(m_mgCondp) || andp->rhsp()->sameTree(m_mgCondp)) { @@ -320,6 +326,7 @@ public: m_mgLastp = NULL; m_mgNextp = NULL; m_listLenght = 0; + m_markVars.clear(); iterate(nodep); } virtual ~MergeCondVisitor() { diff --git a/src/V3Options.cpp b/src/V3Options.cpp index ba8827c96..f87ba3560 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -294,7 +294,7 @@ void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(file void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); } -string V3Options::allArgsString() { +string V3Options::allArgsString() const { string out; for (std::list::const_iterator it = m_impp->m_allArgs.begin(); it != m_impp->m_allArgs.end(); ++it) { @@ -568,7 +568,7 @@ string V3Options::getenvVERILATOR_ROOT() { } bool V3Options::systemCSystemWide() { -#ifdef HAVE_SYSTEMC_H +#ifdef HAVE_SYSTEMC return true; #else return false; @@ -603,8 +603,9 @@ void V3Options::notify() { if (allPublic()) { // We always call protect() on names, we don't check if public or not // Hence any external references wouldn't be able to find the refed public object. - cmdfl->v3error("Unsupported: Using --protect-ids with --public\n" // - + V3Error::warnMore() + "... Suggest remove --public."); + cmdfl->v3warn(E_UNSUPPORTED, "Unsupported: Using --protect-ids with --public\n" // + + V3Error::warnMore() + + "... Suggest remove --public."); } if (trace()) { cmdfl->v3warn(INSECURE, @@ -644,7 +645,8 @@ void V3Options::notify() { if (m_outputSplitCTrace < 0) m_outputSplitCTrace = m_outputSplit; if (v3Global.opt.main() && v3Global.opt.systemC()) { - cmdfl->v3error("--main not usable with SystemC. Suggest see examples for sc_main()."); + cmdfl->v3warn(E_UNSUPPORTED, + "--main not usable with SystemC. Suggest see examples for sc_main()."); } } @@ -824,85 +826,168 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char if (sw[0] == '-' && sw[1] == '-') ++sw; bool hadSwitchPart1 = true; // Single switches - // clang-format off - if (!strcmp(sw, "-E")) { m_preprocOnly = true; } - else if ( onoffb(sw, "-MMD", bflag/*ref*/)) { m_makeDepend = bflag; } - else if ( onoff (sw, "-MP", flag/*ref*/)) { m_makePhony = flag; } - else if (!strcmp(sw, "-P")) { m_preprocNoLine = true; } - else if ( onoff (sw, "-assert", flag/*ref*/)) { m_assert = flag; } - else if ( onoff (sw, "-autoflush", flag/*ref*/)) { m_autoflush = flag; } - else if ( onoff (sw, "-bbox-sys", flag/*ref*/)) { m_bboxSys = flag; } - else if ( onoff (sw, "-bbox-unsup", flag/*ref*/)) { m_bboxUnsup = flag; } - else if (!strcmp(sw, "-build")) { m_build = true; } - else if (!strcmp(sw, "-cc")) { m_outFormatOk = true; m_systemC = false; } - else if ( onoff (sw, "-cdc", flag/*ref*/)) { m_cdc = flag; } - else if ( onoff (sw, "-coverage", flag/*ref*/)) { coverage(flag); } - else if ( onoff (sw, "-coverage-line", flag/*ref*/)){ m_coverageLine = flag; } - else if ( onoff (sw, "-coverage-toggle", flag/*ref*/)){ m_coverageToggle = flag; } - else if ( onoff (sw, "-coverage-underscore", flag/*ref*/)){ m_coverageUnderscore = flag; } - else if ( onoff (sw, "-coverage-user", flag/*ref*/)){ m_coverageUser = flag; } - else if ( onoff (sw, "-covsp", flag/*ref*/)) { } // TBD - else if (!strcmp(sw, "-debug-abort")) { V3Error::vlAbort(); } // Undocumented, see also --debug-sigsegv - else if ( onoff (sw, "-debug-check", flag/*ref*/)) { m_debugCheck = flag; } - else if ( onoff (sw, "-debug-collision", flag/*ref*/)) { m_debugCollision = flag; } // Undocumented - else if ( onoff (sw, "-debug-leak", flag/*ref*/)) { m_debugLeak = flag; } - else if ( onoff (sw, "-debug-nondeterminism", flag/*ref*/)){ m_debugNondeterminism = flag; } - else if ( onoff (sw, "-debug-partition", flag/*ref*/)){ m_debugPartition = flag; } // Undocumented - else if ( onoff (sw, "-debug-protect", flag/*ref*/)){ m_debugProtect = flag; } // Undocumented - else if ( onoff (sw, "-debug-self-test", flag/*ref*/)){ m_debugSelfTest = flag; } // Undocumented - else if (!strcmp(sw, "-debug-sigsegv")) { throwSigsegv(); } // Undocumented, see also --debug-abort - else if (!strcmp(sw, "-debug-fatalsrc")) { v3fatalSrc("--debug-fatal-src"); } // Undocumented, see also --debug-abort - else if ( onoff (sw, "-decoration", flag/*ref*/)) { m_decoration = flag; } - else if ( onoff (sw, "-dpi-hdr-only", flag/*ref*/)) { m_dpiHdrOnly = flag; } - else if ( onoff (sw, "-dump-defines", flag/*ref*/)) { m_dumpDefines = flag; } - else if ( onoff (sw, "-dump-tree", flag/*ref*/)) { m_dumpTree = flag ? 3 : 0; } // Also see --dump-treei - else if ( onoff (sw, "-dump-tree-addrids", flag/*ref*/)){ m_dumpTreeAddrids = flag; } - else if ( onoff (sw, "-exe", flag/*ref*/)) { m_exe = flag; } - else if ( onoff (sw, "-flatten", flag/*ref*/)) { m_flatten = flag; } - else if ( onoff (sw, "-ignc", flag/*ref*/)) { m_ignc = flag; } - else if ( onoff (sw, "-inhibit-sim", flag/*ref*/)) { m_inhibitSim = flag; } - else if ( onoff (sw, "-lint-only", flag/*ref*/)) { m_lintOnly = flag; } - else if ( onoff (sw, "-main", flag/*ref*/)) { m_main = flag; } // Undocumented future - else if (!strcmp(sw, "-no-pins64")) { m_pinsBv = 33; } - else if ( onoff (sw, "-order-clock-delay", flag/*ref*/)) { m_orderClockDly = flag; } - else if (!strcmp(sw, "-pins64")) { m_pinsBv = 65; } - else if ( onoff (sw, "-pins-sc-uint", flag/*ref*/)) { m_pinsScUint = flag; if (!m_pinsScBigUint) m_pinsBv = 65; } - else if ( onoff (sw, "-pins-sc-biguint", flag/*ref*/)){ m_pinsScBigUint = flag; m_pinsBv = 513; } - else if ( onoff (sw, "-pins-uint8", flag/*ref*/)) { m_pinsUint8 = flag; } - else if ( onoff (sw, "-pp-comments", flag/*ref*/)) { m_ppComments = flag; } - else if (!strcmp(sw, "-private")) { m_public = false; } - else if ( onoff (sw, "-prof-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; } - else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; } // Undocumented, for backward compat - else if ( onoff (sw, "-prof-threads", flag/*ref*/)) { m_profThreads = flag; } - else if ( onoff (sw, "-protect-ids", flag/*ref*/)) { m_protectIds = flag; } - else if ( onoff (sw, "-public", flag/*ref*/)) { m_public = flag; } - else if ( onoff (sw, "-public-flat-rw", flag/*ref*/) ) { m_publicFlatRW = flag; v3Global.dpi(true); } - else if (!strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); } - else if ( onoff (sw, "-quiet-exit", flag/*ref*/)) { m_quietExit = flag; } - else if ( onoff (sw, "-relative-cfuncs", flag/*ref*/)) { m_relativeCFuncs = flag; } - else if ( onoff (sw, "-relative-includes", flag/*ref*/)) { m_relativeIncludes = flag; } - else if ( onoff (sw, "-report-unoptflat", flag/*ref*/)) { m_reportUnoptflat = flag; } - else if ( onoff (sw, "-savable", flag/*ref*/)) { m_savable = flag; } - else if (!strcmp(sw, "-sc")) { m_outFormatOk = true; m_systemC = true; } - else if ( onoffb(sw, "-skip-identical", bflag/*ref*/)) { m_skipIdentical = bflag; } - else if ( onoff (sw, "-stats", flag/*ref*/)) { m_stats = flag; } - else if ( onoff (sw, "-stats-vars", flag/*ref*/)) { m_statsVars = flag; m_stats |= flag; } - else if ( onoff (sw, "-structs-unpacked", flag/*ref*/)) { m_structsPacked = flag; } - else if (!strcmp(sw, "-sv")) { m_defaultLanguage = V3LangCode::L1800_2005; } - else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug - else if ( onoff (sw, "-trace", flag/*ref*/)) { m_trace = flag; } - else if ( onoff (sw, "-trace-coverage", flag/*ref*/)) { m_traceCoverage = flag; } - else if ( onoff (sw, "-trace-params", flag/*ref*/)) { m_traceParams = flag; } - else if ( onoff (sw, "-trace-structs", flag/*ref*/)) { m_traceStructs = flag; } - else if ( onoff (sw, "-trace-underscore", flag/*ref*/)) { m_traceUnderscore = flag; } - else if ( onoff (sw, "-underline-zero", flag/*ref*/)) { m_underlineZero = flag; } // Undocumented, old Verilator-2 - else if ( onoff (sw, "-verilate", flag/*ref*/)) { m_verilate = flag; } - else if ( onoff (sw, "-vpi", flag/*ref*/)) { m_vpi = flag; } - else if ( onoff (sw, "-Wpedantic", flag/*ref*/)) { m_pedantic = flag; } - else if ( onoff (sw, "-x-initial-edge", flag/*ref*/)) { m_xInitialEdge = flag; } - else if ( onoff (sw, "-xml-only", flag/*ref*/)) { m_xmlOnly = flag; } - else { hadSwitchPart1 = false; } - // clang-format on + if (!strcmp(sw, "-E")) { + m_preprocOnly = true; + } else if (onoffb(sw, "-MMD", bflag /*ref*/)) { + m_makeDepend = bflag; + } else if (onoff(sw, "-MP", flag /*ref*/)) { + m_makePhony = flag; + } else if (!strcmp(sw, "-P")) { + m_preprocNoLine = true; + } else if (onoff(sw, "-assert", flag /*ref*/)) { + m_assert = flag; + } else if (onoff(sw, "-autoflush", flag /*ref*/)) { + m_autoflush = flag; + } else if (onoff(sw, "-bbox-sys", flag /*ref*/)) { + m_bboxSys = flag; + } else if (onoff(sw, "-bbox-unsup", flag /*ref*/)) { + FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, true); + m_bboxUnsup = flag; + } else if (!strcmp(sw, "-build")) { + m_build = true; + } else if (!strcmp(sw, "-cc")) { + m_outFormatOk = true; + m_systemC = false; + } else if (onoff(sw, "-cdc", flag /*ref*/)) { + m_cdc = flag; + } else if (onoff(sw, "-coverage", flag /*ref*/)) { + coverage(flag); + } else if (onoff(sw, "-coverage-line", flag /*ref*/)) { + m_coverageLine = flag; + } else if (onoff(sw, "-coverage-toggle", flag /*ref*/)) { + m_coverageToggle = flag; + } else if (onoff(sw, "-coverage-underscore", flag /*ref*/)) { + m_coverageUnderscore = flag; + } else if (onoff(sw, "-coverage-user", flag /*ref*/)) { + m_coverageUser = flag; + } else if (!strcmp(sw, "-debug-abort")) { // Undocumented, see also --debug-sigsegv + V3Error::vlAbort(); + } else if (onoff(sw, "-debug-check", flag /*ref*/)) { + m_debugCheck = flag; + } else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented + m_debugCollision = flag; + } else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented + m_debugExitParse = flag; + } else if (onoff(sw, "-debug-leak", flag /*ref*/)) { + m_debugLeak = flag; + } else if (onoff(sw, "-debug-nondeterminism", flag /*ref*/)) { + m_debugNondeterminism = flag; + } else if (onoff(sw, "-debug-partition", flag /*ref*/)) { // Undocumented + m_debugPartition = flag; + } else if (onoff(sw, "-debug-protect", flag /*ref*/)) { // Undocumented + m_debugProtect = flag; + } else if (onoff(sw, "-debug-self-test", flag /*ref*/)) { // Undocumented + m_debugSelfTest = flag; + } else if (!strcmp(sw, "-debug-sigsegv")) { // Undocumented, see also --debug-abort + throwSigsegv(); + } else if (!strcmp(sw, "-debug-fatalsrc")) { // Undocumented, see also --debug-abort + v3fatalSrc("--debug-fatal-src"); + } else if (onoff(sw, "-decoration", flag /*ref*/)) { + m_decoration = flag; + } else if (onoff(sw, "-dpi-hdr-only", flag /*ref*/)) { + m_dpiHdrOnly = flag; + } else if (onoff(sw, "-dump-defines", flag /*ref*/)) { + m_dumpDefines = flag; + } else if (onoff(sw, "-dump-tree", flag /*ref*/)) { // Also see --dump-treei + m_dumpTree = flag ? 3 : 0; + } else if (onoff(sw, "-dump-tree-addrids", flag /*ref*/)) { + m_dumpTreeAddrids = flag; + } else if (onoff(sw, "-exe", flag /*ref*/)) { + m_exe = flag; + } else if (onoff(sw, "-flatten", flag /*ref*/)) { + m_flatten = flag; + } else if (onoff(sw, "-ignc", flag /*ref*/)) { + m_ignc = flag; + } else if (onoff(sw, "-inhibit-sim", flag /*ref*/)) { + m_inhibitSim = flag; + } else if (onoff(sw, "-lint-only", flag /*ref*/)) { + m_lintOnly = flag; + } else if (onoff(sw, "-main", flag /*ref*/)) { // Undocumented future + m_main = flag; + } else if (!strcmp(sw, "-no-pins64")) { + m_pinsBv = 33; + } else if (onoff(sw, "-order-clock-delay", flag /*ref*/)) { + m_orderClockDly = flag; + } else if (!strcmp(sw, "-pins64")) { + m_pinsBv = 65; + } else if (onoff(sw, "-pins-sc-uint", flag /*ref*/)) { + m_pinsScUint = flag; + if (!m_pinsScBigUint) m_pinsBv = 65; + } else if (onoff(sw, "-pins-sc-biguint", flag /*ref*/)) { + m_pinsScBigUint = flag; + m_pinsBv = 513; + } else if (onoff(sw, "-pins-uint8", flag /*ref*/)) { + m_pinsUint8 = flag; + } else if (onoff(sw, "-pp-comments", flag /*ref*/)) { + m_ppComments = flag; + } else if (!strcmp(sw, "-private")) { + m_public = false; + } else if (onoff(sw, "-prof-cfuncs", flag /*ref*/)) { + m_profCFuncs = flag; + } else if (onoff(sw, "-profile-cfuncs", flag /*ref*/)) { // Undocumented, renamed + m_profCFuncs = flag; + } else if (onoff(sw, "-prof-threads", flag /*ref*/)) { + m_profThreads = flag; + } else if (onoff(sw, "-protect-ids", flag /*ref*/)) { + m_protectIds = flag; + } else if (onoff(sw, "-public", flag /*ref*/)) { + m_public = flag; + } else if (onoff(sw, "-public-flat-rw", flag /*ref*/)) { + m_publicFlatRW = flag; + v3Global.dpi(true); + } else if (!strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { + addParameter(string(sw + strlen("-pvalue+")), false); + } else if (onoff(sw, "-quiet-exit", flag /*ref*/)) { + m_quietExit = flag; + } else if (onoff(sw, "-relative-cfuncs", flag /*ref*/)) { + m_relativeCFuncs = flag; + } else if (onoff(sw, "-relative-includes", flag /*ref*/)) { + m_relativeIncludes = flag; + } else if (onoff(sw, "-report-unoptflat", flag /*ref*/)) { + m_reportUnoptflat = flag; + } else if (onoff(sw, "-savable", flag /*ref*/)) { + m_savable = flag; + } else if (!strcmp(sw, "-sc")) { + m_outFormatOk = true; + m_systemC = true; + } else if (onoffb(sw, "-skip-identical", bflag /*ref*/)) { + m_skipIdentical = bflag; + } else if (onoff(sw, "-stats", flag /*ref*/)) { + m_stats = flag; + } else if (onoff(sw, "-stats-vars", flag /*ref*/)) { + m_statsVars = flag; + m_stats |= flag; + } else if (onoff(sw, "-structs-unpacked", flag /*ref*/)) { + m_structsPacked = flag; + } else if (!strcmp(sw, "-sv")) { + m_defaultLanguage = V3LangCode::L1800_2005; + } else if (onoff(sw, "-threads-coarsen", flag /*ref*/)) { // Undocumented, debug + m_threadsCoarsen = flag; + } else if (onoff(sw, "-trace", flag /*ref*/)) { + m_trace = flag; + } else if (onoff(sw, "-trace-coverage", flag /*ref*/)) { + m_traceCoverage = flag; + } else if (onoff(sw, "-trace-params", flag /*ref*/)) { + m_traceParams = flag; + } else if (onoff(sw, "-trace-structs", flag /*ref*/)) { + m_traceStructs = flag; + } else if (onoff(sw, "-trace-underscore", flag /*ref*/)) { + m_traceUnderscore = flag; + } else if (onoff(sw, "-underline-zero", flag /*ref*/)) { // Deprecated + m_underlineZero = flag; + } else if (onoff(sw, "-verilate", flag /*ref*/)) { + m_verilate = flag; + } else if (onoff(sw, "-vpi", flag /*ref*/)) { + m_vpi = flag; + } else if (onoff(sw, "-Wpedantic", flag /*ref*/)) { + m_pedantic = flag; + } else if (onoff(sw, "-x-initial-edge", flag /*ref*/)) { + m_xInitialEdge = flag; + } else if (onoff(sw, "-xml-only", flag /*ref*/)) { + m_xmlOnly = flag; + } else { + hadSwitchPart1 = false; + } if (hadSwitchPart1) { } else if (!strncmp(sw, "-O", 2)) { @@ -1552,6 +1637,7 @@ V3Options::V3Options() { m_coverageUser = false; m_debugCheck = false; m_debugCollision = false; + m_debugExitParse = false; m_debugLeak = true; m_debugNondeterminism = false; m_debugPartition = false; diff --git a/src/V3Options.h b/src/V3Options.h index 0a4d72f03..0c3830bcf 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -239,6 +239,7 @@ private: bool m_coverageUser; // main switch: --coverage-func bool m_debugCheck; // main switch: --debug-check bool m_debugCollision; // main switch: --debug-collision + bool m_debugExitParse; // main switch: --debug-exit-parse bool m_debugLeak; // main switch: --debug-leak bool m_debugNondeterminism; // main switch: --debug-nondeterminism bool m_debugPartition; // main switch: --debug-partition @@ -438,6 +439,7 @@ public: bool coverageUser() const { return m_coverageUser; } bool debugCheck() const { return m_debugCheck; } bool debugCollision() const { return m_debugCollision; } + bool debugExitParse() const { return m_debugExitParse; } bool debugLeak() const { return m_debugLeak; } bool debugNondeterminism() const { return m_debugNondeterminism; } bool debugPartition() const { return m_debugPartition; } @@ -596,7 +598,7 @@ public: // METHODS (from main) static string version(); static string argString(int argc, char** argv); ///< Return list of arguments as simple string - string allArgsString(); ///< Return all passed arguments as simple string + string allArgsString() const; ///< Return all passed arguments as simple string void bin(const string& flag) { m_bin = flag; } void parseOpts(FileLine* fl, int argc, char** argv); void parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index eb8b9a593..62f273d42 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -965,8 +965,8 @@ private: m_activep = NULL; m_topScopep = nodep; m_scopetopp = nodep->scopep(); - // Find sentree's - m_finder.main(m_topScopep); + // Find global SenTrees + m_finder.init(m_topScopep); // ProcessDomainsIterate will use these when it needs to move // something to a combodomain. This saves a ton of find() operations. AstSenTree* combp @@ -1282,8 +1282,7 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top) { const AstSenItem* fromSenListp = VN_CAST(fromp->sensesp(), SenItem); const AstSenItem* toSenListp = VN_CAST(top->sensesp(), SenItem); - // If clk gating is ever reenabled, we may need to update this to handle - // AstSenGate also. + UASSERT_OBJ(fromSenListp, fromp, "sensitivity list item is not an AstSenItem"); UASSERT_OBJ(toSenListp, top, "sensitivity list item is not an AstSenItem"); @@ -1531,7 +1530,7 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) { fromVertexp->domainp()->dumpTree(cout); } // LCOV_EXCL_STOP AstSenTree* newtreep = domainp->cloneTree(false); - AstNodeSenItem* newtree2p = fromVertexp->domainp()->sensesp()->cloneTree(true); + AstSenItem* newtree2p = fromVertexp->domainp()->sensesp()->cloneTree(true); UASSERT_OBJ(newtree2p, fromVertexp->domainp(), "No senitem found under clocked domain"); newtreep->addSensesp(newtree2p); diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 8d0d07546..97b1ce552 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -33,6 +33,7 @@ #include "V3Os.h" #include +#include // PATH_MAX (especially on FreeBSD) #include #include #include diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 64e14916a..ad43808c2 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -176,6 +176,19 @@ private: } return string("z") + cvtToStr(num); } + AstNodeDType* arraySubDTypep(AstNodeDType* nodep) { + // If an unpacked array, return the subDTypep under it + if (AstUnpackArrayDType* adtypep = VN_CAST(nodep, UnpackArrayDType)) { + return adtypep->subDTypep(); + } + // We have not resolved parameter of the child yet, so still + // have BracketArrayDType's. We'll presume it'll end up as assignment + // compatible (or V3Width will complain). + if (AstBracketArrayDType* adtypep = VN_CAST(nodep, BracketArrayDType)) { + return adtypep->subDTypep(); + } + return NULL; + } void collectPins(CloneMap* clonemapp, AstNodeModule* modp) { // Grab all I/O so we can remap our pins later for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { @@ -585,7 +598,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { pinp->v3error("Attempted parameter setting of non-parameter: Param " << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); } else if (VN_IS(pinp->exprp(), InitArray) - && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) { + && arraySubDTypep(modvarp->subDTypep())) { // Array assigned to array AstNode* exprp = pinp->exprp(); longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); @@ -647,10 +660,8 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { AstVar* modvarp = pinp->modVarp(); if (modvarp->isIfaceRef()) { AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType); - if (!portIrefp && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) { - portIrefp - = VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(), - IfaceRefDType); + if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) { + portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType); } AstIfaceRefDType* pinIrefp = NULL; @@ -662,34 +673,20 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) && VN_CAST(exprp->op1p(), VarRef)->varp() && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() - && VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), - UnpackArrayDType) - && VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), - UnpackArrayDType) - ->subDTypep() - && VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), - UnpackArrayDType) - ->subDTypep(), - IfaceRefDType)) { - pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), - UnpackArrayDType) - ->subDTypep(), - IfaceRefDType); + && arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()) + && VN_CAST( + arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), + IfaceRefDType)) { + pinIrefp = VN_CAST( + arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), + IfaceRefDType); } else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp() && VN_CAST(exprp, VarRef)->varp()->subDTypep() - && VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), - UnpackArrayDType) - && VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), - UnpackArrayDType) - ->subDTypep() - && VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), - UnpackArrayDType) - ->subDTypep(), + && arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()) + && VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()), IfaceRefDType)) { - pinIrefp = VN_CAST( - VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType) - ->subDTypep(), - IfaceRefDType); + pinIrefp = VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()), + IfaceRefDType); } UINFO(9, " portIfaceRef " << portIrefp << endl); diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index bfe861e5a..00c3f4f23 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -100,7 +100,7 @@ AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { } if (nrangep && nrangep->nextp()) { // Not supported by at least 2 of big 3 - nrangep->nextp()->v3error("Unsupported: Multidimensional cells/interfaces."); + nrangep->nextp()->v3warn(E_UNSUPPORTED, "Unsupported: Multidimensional cells/interfaces."); nrangep->nextp()->unlinkFrBackWithNext()->deleteTree(); } return VN_CAST(nrangep, Range); @@ -120,8 +120,6 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra if (rangep && isPacked) { arrayp = new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep); - } else if (VN_IS(nrangep, QueueRange)) { - arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL); } else if (rangep && (VN_IS(rangep->leftp(), Unbounded) || VN_IS(rangep->rightp(), Unbounded))) { @@ -132,12 +130,11 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra rangep); } else if (VN_IS(nrangep, UnsizedRange)) { arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp); - } else if (VN_IS(nrangep, AssocRange)) { - AstAssocRange* arangep = VN_CAST(nrangep, AssocRange); - AstNodeDType* keyp = arangep->keyDTypep(); - keyp->unlinkFrBack(); - arrayp - = new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp); + } else if (VN_IS(nrangep, BracketRange)) { + AstBracketRange* arangep = VN_CAST(nrangep, BracketRange); + AstNode* keyp = arangep->elementsp()->unlinkFrBack(); + arrayp = new AstBracketArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, + keyp); } else { UASSERT_OBJ(0, nrangep, "Expected range or unsized range"); } @@ -154,7 +151,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, << GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "") << endl); if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == AstVarType::PORT) { // Just a port list with variable name (not v2k format); AstPort already created - if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists"); + if (dtypep) fileline->v3warn(E_UNSUPPORTED, "Unsupported: Ranges ignored in port-lists"); return NULL; } if (GRAMMARP->m_varDecl == AstVarType::WREAL) { @@ -173,7 +170,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, if (GRAMMARP->m_varIO.isAny()) { type = AstVarType::PORT; } else { - fileline->v3fatalSrc("Unknown signal type declared"); + fileline->v3fatalSrc("Unknown signal type declared: " << type.ascii()); } } if (type == AstVarType::GENVAR) { diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index d095e5234..55e9994c9 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -34,6 +34,8 @@ #include "V3PreShell.h" #include "V3LanguageWords.h" +#include "V3ParseBison.h" // Generated by bison + #include //====================================================================== @@ -43,9 +45,6 @@ V3ParseImp* V3ParseImp::s_parsep = NULL; int V3ParseSym::s_anonNum = 0; -extern void yyerror(const char*); -extern void yyerrorf(const char* format, ...); - //###################################################################### // Parser constructor @@ -70,27 +69,27 @@ V3ParseImp::~V3ParseImp() { //###################################################################### // Parser utility methods -void V3ParseImp::ppline(const char* textp) { - // Handle `line directive +void V3ParseImp::lexPpline(const char* textp) { + // Handle lexer `line directive FileLine* prevFl = copyOrSameFileLine(); int enterExit; - fileline()->lineDirective(textp, enterExit /*ref*/); + lexFileline()->lineDirective(textp, enterExit /*ref*/); if (enterExit == 1) { // Enter - fileline()->parent(prevFl); + lexFileline()->parent(prevFl); } else if (enterExit == 2) { // Exit - FileLine* upFl = fileline()->parent(); + FileLine* upFl = lexFileline()->parent(); if (upFl) upFl = upFl->parent(); - if (upFl) fileline()->parent(upFl); + if (upFl) lexFileline()->parent(upFl); } } -void V3ParseImp::timescalePreproc(FileLine* fl, const char* textp) { +void V3ParseImp::lexTimescaleParse(FileLine* fl, const char* textp) { // Parse `timescale of / VTimescale unit; VTimescale prec; VTimescale::parseSlashed(fl, textp, unit /*ref*/, prec /*ref*/); m_timeLastUnit = v3Global.opt.timeComputeUnit(unit); - v3Global.rootp()->timeprecisionMerge(fileline(), prec); + v3Global.rootp()->timeprecisionMerge(fl, prec); } void V3ParseImp::timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, bool precSet, double precVal) { @@ -119,37 +118,39 @@ void V3ParseImp::timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, d fl->v3error("timeunit/timeprecision not under a module"); } } - v3Global.rootp()->timeprecisionMerge(fileline(), prec); + v3Global.rootp()->timeprecisionMerge(fl, prec); } -void V3ParseImp::verilatorCmtLintSave() { m_lintState.push_back(*parsep()->fileline()); } +void V3ParseImp::lexVerilatorCmtLintSave(const FileLine* fl) { m_lexLintState.push_back(*fl); } -void V3ParseImp::verilatorCmtLintRestore() { - if (m_lintState.empty()) { - yyerrorf("/*verilator lint_restore*/ without matching save."); +void V3ParseImp::lexVerilatorCmtLintRestore(FileLine* fl) { + if (m_lexLintState.empty()) { + fl->v3error("/*verilator lint_restore*/ without matching save"); return; } - parsep()->fileline()->warnStateFrom(m_lintState.back()); - m_lintState.pop_back(); + fl->warnStateFrom(m_lexLintState.back()); + m_lexLintState.pop_back(); } -void V3ParseImp::verilatorCmtLint(const char* textp, bool warnOff) { +void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff) { const char* sp = textp; - while (*sp && !isspace(*sp)) sp++; - while (*sp && isspace(*sp)) sp++; - while (*sp && !isspace(*sp)) sp++; - while (*sp && isspace(*sp)) sp++; + while (*sp && !isspace(*sp)) ++sp; + while (*sp && isspace(*sp)) ++sp; + while (*sp && !isspace(*sp)) ++sp; + while (*sp && isspace(*sp)) ++sp; string msg = sp; string::size_type pos; if ((pos = msg.find('*')) != string::npos) msg.erase(pos); - if (!(parsep()->fileline()->warnOff(msg, warnOff))) { - if (!parsep()->optFuture(msg)) { - yyerrorf("Unknown verilator lint message code: %s, in %s", msg.c_str(), textp); + // Use parsep()->lexFileline() as want to affect later FileLine's warnings + if (!(parsep()->lexFileline()->warnOff(msg, warnOff))) { + if (!v3Global.opt.isFuture(msg)) { + fl->v3error("Unknown verilator lint message code: '" << msg << "', in '" << textp + << "'"); } } } -void V3ParseImp::verilatorCmtBad(const char* textp) { +void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) { string cmtparse = textp; if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") { cmtparse.replace(0, strlen("/*verilator"), ""); @@ -157,10 +158,12 @@ void V3ParseImp::verilatorCmtBad(const char* textp) { while (isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); string cmtname; for (int i = 0; isalnum(cmtparse[i]); i++) { cmtname += cmtparse[i]; } - if (!parsep()->optFuture(cmtname)) yyerrorf("Unknown verilator comment: %s", textp); + if (!v3Global.opt.isFuture(cmtname)) { + fl->v3error("Unknown verilator comment: '" << textp << "'"); + } } -void V3ParseImp::errorPreprocDirective(const char* textp) { +void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) { // Find all `preprocessor spelling candidates // Can't make this static as might get more defines later when read cells VSpellCheck speller; @@ -171,43 +174,19 @@ void V3ParseImp::errorPreprocDirective(const char* textp) { } V3PreShell::candidateDefines(&speller); string suggest = speller.bestCandidateMsg(textp); - fileline()->v3error("Define or directive not defined: '" - << textp << "'\n" - << (suggest.empty() ? "" : fileline()->warnMore() + suggest)); + fl->v3error("Define or directive not defined: '" + << textp << "'\n" + << (suggest.empty() ? "" : fl->warnMore() + suggest)); } -void V3ParseImp::tag(const char* text) { - if (m_tagNodep) { - string tmp = text + strlen("/*verilator tag "); - string::size_type pos; - if ((pos = tmp.rfind("*/")) != string::npos) { tmp.erase(pos); } - m_tagNodep->tag(tmp); - } +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); } + return tmp; } -double V3ParseImp::parseDouble(const char* textp, size_t length, bool* successp) { - char* strgp = new char[length + 1]; - char* dp = strgp; - if (successp) *successp = true; - for (const char* sp = textp; sp < (textp + length); ++sp) { - if (*sp != '_') *dp++ = *sp; - } - *dp++ = '\0'; - char* endp = strgp; - double d = strtod(strgp, &endp); - size_t parsed_len = endp - strgp; - if (parsed_len != strlen(strgp)) { - if (successp) { - *successp = false; - } else { - yyerrorf("Syntax error parsing real: %s", strgp); - } - } - VL_DO_DANGLING(delete[] strgp, strgp); - return d; -} - -double V3ParseImp::parseTimenum(const char* textp) { +double V3ParseImp::lexParseTimenum(const char* textp) { size_t length = strlen(textp); char* strgp = new char[length + 1]; char* dp = strgp; @@ -295,8 +274,9 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i string modname = V3Os::filenameNonExt(modfilename); UINFO(2, __FUNCTION__ << ": " << modname << (inLibrary ? " [LIB]" : "") << endl); - m_fileline = new FileLine(fileline); - m_fileline->newContent(); + m_lexFileline = new FileLine(fileline); + m_lexFileline->newContent(); + m_bisonLastFileline = m_lexFileline; m_inLibrary = inLibrary; // Preprocess into m_ppBuffer @@ -344,7 +324,7 @@ void V3ParseImp::lexFile(const string& modname) { // Prepare for lexing UINFO(3, "Lexing " << modname << endl); s_parsep = this; - fileline()->warnResetDefault(); // Reenable warnings on each file + lexFileline()->warnResetDefault(); // Reenable warnings on each file lexDestroy(); // Restart from clean slate. lexNew(); @@ -352,6 +332,246 @@ void V3ParseImp::lexFile(const string& modname) { if (bisonParse()) v3fatal("Cannot continue\n"); } +void V3ParseImp::tokenPull() { + // Pull token from lex into the pipeline + // This corrupts yylval, must save/restore if required + // Fetch next token from prefetch or real lexer + yylexReadTok(); // sets yylval + m_tokensAhead.push_back(yylval); +} + +const V3ParseBisonYYSType* V3ParseImp::tokenPeekp(size_t depth) { + // Look ahead "depth" number of tokens in the input stream + // Returns pointer to token, which is no longer valid after changing m_tokensAhead + while (m_tokensAhead.size() <= depth) tokenPull(); + return &m_tokensAhead.at(depth); +} + +size_t V3ParseImp::tokenPipeScanParam(size_t depth) { + // Search around IEEE parameter_value_assignment to see if :: follows + // Return location of following token, or input if not found + // yaID [ '#(' ... ')' ] + if (tokenPeekp(depth)->token != '#') return depth; + if (tokenPeekp(depth + 1)->token != '(') return depth; + depth += 2; // Past the ( + int parens = 1; // Count first ( + while (true) { + int tok = tokenPeekp(depth)->token; + if (tok == 0) { + UINFO(9, "tokenPipeScanParam hit EOF; probably syntax error to come"); + break; + } else if (tok == '(') { + ++parens; + } else if (tok == ')') { + --parens; + if (parens == 0) { + ++depth; + break; + } + } + ++depth; + } + return depth; +} + +void V3ParseImp::tokenPipeline() { + // called from bison's "yylex", has a "this" + if (m_tokensAhead.empty()) tokenPull(); // corrupts yylval + yylval = m_tokensAhead.front(); + m_tokensAhead.pop_front(); + int token = yylval.token; + // If a paren, read another + if (token == '(' // + || token == yCONST__LEX // + || token == yGLOBAL__LEX // + || token == yLOCAL__LEX // + || token == yNEW__LEX // + || token == ySTATIC__LEX // + || token == yVIRTUAL__LEX // + || token == yWITH__LEX // + || token == yaID__LEX // + ) { + if (debugFlex() >= 6) { + cout << " tokenPipeline: reading ahead to find possible strength" << endl; + } + V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead + const V3ParseBisonYYSType* nexttokp = tokenPeekp(0); + int nexttok = nexttokp->token; + yylval = curValue; + // Now potentially munge the current token + if (token == '(' + && (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) { + token = yP_PAR__STRENGTH; + } else if (token == yCONST__LEX) { + if (nexttok == yREF) { + token = yCONST__REF; + } else { + token = yCONST__ETC; + } + } else if (token == yGLOBAL__LEX) { + if (nexttok == yCLOCKING) { + token = yGLOBAL__CLOCKING; + } else if (v3Global.opt.pedantic()) { + token = yGLOBAL__ETC; + } + // Avoid 2009 "global" conflicting with old code when we can + else { + token = yaID__LEX; + yylval.strp = V3ParseImp::parsep()->newString("global"); + } + } else if (token == yLOCAL__LEX) { + if (nexttok == yP_COLONCOLON) { + token = yLOCAL__COLONCOLON; + } else { + token = yLOCAL__ETC; + } + } else if (token == yNEW__LEX) { + if (nexttok == '(') { + token = yNEW__PAREN; + } else { + token = yNEW__ETC; + } + } else if (token == ySTATIC__LEX) { + if (nexttok == yCONSTRAINT) { + token = ySTATIC__CONSTRAINT; + } else { + token = ySTATIC__ETC; + } + } else if (token == yVIRTUAL__LEX) { + if (nexttok == yCLASS) { + token = yVIRTUAL__CLASS; + } else if (nexttok == yINTERFACE) { + token = yVIRTUAL__INTERFACE; + } else if (nexttok == yaID__ETC // + || nexttok == yaID__LEX) { + // || nexttok == yaID__aINTERFACE // but we may not know interfaces yet. + token = yVIRTUAL__anyID; + } else { + token = yVIRTUAL__ETC; + } + } else if (token == yWITH__LEX) { + if (nexttok == '(') { + token = yWITH__PAREN; + } else if (nexttok == '[') { + token = yWITH__BRA; + } else if (nexttok == '{') { + token = yWITH__CUR; + } else { + token = yWITH__ETC; + } + } else if (token == yaID__LEX) { + if (nexttok == yP_COLONCOLON) { + token = yaID__CC; + } else if (nexttok == '#') { + V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead + { + size_t depth = tokenPipeScanParam(0); + if (tokenPeekp(depth)->token == yP_COLONCOLON) { token = yaID__CC; } + } + yylval = curValue; + } + } + // If add to above "else if", also add to "if (token" further above + } + yylval.token = token; + // effectively returns yylval +} + +void V3ParseImp::tokenPipelineSym() { + // If an id, change the type based on symbol table + // Note above sometimes converts yGLOBAL to a yaID__LEX + tokenPipeline(); // sets yylval + int token = yylval.token; + if (token == yaID__LEX || token == yaID__CC) { + VSymEnt* foundp; + if (VSymEnt* look_underp = V3ParseImp::parsep()->symp()->nextId()) { + UINFO(7, " tokenPipelineSym: next id lookup forced under " << look_underp << endl); + // if (debug() >= 7) V3ParseImp::parsep()->symp()->dump(cout, " -symtree: "); + foundp = look_underp->findIdFallback(*(yylval.strp)); + // "consume" it. Must set again if want another token under temp scope + V3ParseImp::parsep()->symp()->nextId(NULL); + } else { + UINFO(7, " tokenPipelineSym: find upward " + << V3ParseImp::parsep()->symp()->symCurrentp() << " for '" + << *(yylval.strp) << "'" << endl); + // if (debug()>=9) V3ParseImp::parsep()->symp()->symCurrentp()->dump(cout, + // " -findtree: ", true); + foundp = V3ParseImp::parsep()->symp()->symCurrentp()->findIdFallback(*(yylval.strp)); + } + if (foundp) { + AstNode* scp = foundp->nodep(); + yylval.scp = scp; + UINFO(7, " tokenPipelineSym: Found " << scp << endl); + if (token == yaID__LEX) { // i.e. not yaID__CC + if (VN_IS(scp, Typedef)) { + token = yaID__aTYPE; + } else if (VN_IS(scp, TypedefFwd)) { + token = yaID__aTYPE; + } else if (VN_IS(scp, Class)) { + token = yaID__aTYPE; + } else if (VN_IS(scp, Package)) { + token = yaID__ETC; + } else { + token = yaID__ETC; + } + } + } else if ((token == yaID__LEX || token == yaID__CC) + && (*(yylval.strp) == "mailbox" // IEEE-standard class + || *(yylval.strp) == "process" // IEEE-standard class + || *(yylval.strp) == "semaphore")) { // IEEE-standard class + yylval.scp = NULL; + if (token == yaID__LEX) token = yaID__aTYPE; + } else { // Not found + yylval.scp = NULL; + if (token == yaID__CC) { + // IEEE does require this, but we may relax this as UVM breaks it, so allow bbox + // for today + if (!v3Global.opt.bboxUnsup()) { + // We'll get a parser error eventually but might not be obvious + // is missing package, and this confuses people + static int warned = false; + if (!warned++) { + yylval.fl->v3error( + "Package/class '" + *yylval.strp + + "' not found, and needs to be predeclared (IEEE 1800-2017 26.3)"); + } + } + } else if (token == yaID__LEX) { + token = yaID__ETC; + } + } + } + yylval.token = token; + // effectively returns yylval +} + +int V3ParseImp::tokenToBison() { + // Called as global since bison doesn't have our pointer + tokenPipelineSym(); // sets yylval + m_bisonLastFileline = yylval.fl; + + // yylval.scp = NULL; // Symbol table not yet needed - no packages + if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison + cout << "tokenToBison " << yylval << endl; + } + return yylval.token; +} + +//====================================================================== +// V3ParseBisonYYSType functions + +std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs) { + os << "TOKEN {" << rhs.fl->filenameLetters() << rhs.fl->asciiLineCol() << "}"; + os << "=" << rhs.token << " " << V3ParseImp::tokenName(rhs.token); + if (rhs.token == yaID__ETC // + || rhs.token == yaID__CC // + || rhs.token == yaID__LEX // + || rhs.token == yaID__aTYPE) { + os << " strp='" << *(rhs.strp) << "'"; + } + return os; +} + //====================================================================== // V3Parse functions diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 3441cc1c4..4c904b2cb 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -26,6 +26,7 @@ #include "V3Parse.h" #include "V3ParseSym.h" +#include #include class V3Lexer; @@ -40,6 +41,62 @@ typedef enum { uniq_NONE, uniq_UNIQUE, uniq_UNIQUE0, uniq_PRIORITY } V3UniqState typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty; +//============================================================================ +// Member qualifiers + +struct VMemberQualifiers { + union { + uint32_t m_flags; + struct { + uint32_t m_local : 1; // Local class item (ignored until warning implemented) + uint32_t m_protected : 1; // Protected class item (ignored until warning implemented) + uint32_t m_rand : 1; // Rand property/member qualifier (ignored until supported) + uint32_t m_randc : 1; // Randc property/member qualifier (ignored until supported) + uint32_t m_virtual : 1; // Virtual property/method qualifier + uint32_t m_automatic : 1; // Automatic property/method qualifier + uint32_t m_const : 1; // Const property/method qualifier + uint32_t m_static : 1; // Static class method + }; + }; + static VMemberQualifiers none() { + VMemberQualifiers q; + q.m_flags = 0; + return q; + } + static VMemberQualifiers combine(const VMemberQualifiers& a, const VMemberQualifiers& b) { + VMemberQualifiers q; + q.m_flags = a.m_flags | b.m_flags; + return q; + } + void applyToNodes(AstNodeFTask* nodesp) const { + for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), NodeFTask)) { + // Ignored for now: m_local + // Ignored for now: m_protected + if (m_virtual) nodep->isVirtual(true); + if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); + if (m_static) nodep->lifetime(VLifetime::STATIC); + if (m_const || m_rand || m_randc) { + nodep->v3error("Syntax error: 'const'/'rand'/'randc' not allowed before " + "function/task declaration"); + } + } + } + void applyToNodes(AstVar* nodesp) const { + for (AstVar* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), Var)) { + // Ignored for now: m_local + // Ignored for now: m_protected + // Ignored for now: m_rand + // Ignored for now: m_randc + if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); + if (m_static) nodep->lifetime(VLifetime::STATIC); + if (m_const) nodep->isConst(true); + if (m_virtual) { + nodep->v3error("Syntax error: 'virtual' not allowed before var declaration"); + } + } + } +}; + //============================================================================ // Parser YYSType, e.g. for parser's yylval // We can't use bison's %union as we want to pass the fileline with all tokens @@ -54,6 +111,7 @@ struct V3ParseBisonYYSType { int cint; double cdouble; bool cbool; + VMemberQualifiers qualifiers; V3UniqState uniqstate; V3ImportProperty iprop; VSigning::en signstate; @@ -78,7 +136,7 @@ struct V3ParseBisonYYSType { AstNodeFTask* ftaskp; AstNodeFTaskRef* ftaskrefp; AstNodeRange* rangep; - AstNodeSenItem* senitemp; + AstSenItem* senitemp; AstNodeVarRef* varnodep; AstPackage* packagep; AstPackageRef* packagerefp; @@ -92,6 +150,7 @@ struct V3ParseBisonYYSType { AstVarRef* varrefp; }; }; +std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs); #define YYSTYPE V3ParseBisonYYSType @@ -105,26 +164,23 @@ class V3ParseImp { V3Lexer* m_lexerp; // Current FlexLexer static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based - FileLine* m_fileline; // Filename/linenumber currently active + FileLine* m_lexFileline; // Filename/linenumber currently active for lexing + + FileLine* m_bisonLastFileline; // Filename/linenumber of last token - bool m_inCellDefine; // Inside a `celldefine bool m_inLibrary; // Currently reading a library vs. regular file - int m_inBeginKwd; // Inside a `begin_keywords - int m_lastVerilogState; // Last LEX state in `begin_keywords + int m_lexKwdDepth; // Inside a `begin_keywords + int m_lexKwdLast; // Last LEX state in `begin_keywords VOptionBool m_unconnectedDrive; // Last unconnected drive - int m_prevLexToken; // previous parsed token (for lexer) - bool m_ahead; // aheadval is valid - V3ParseBisonYYSType m_aheadVal; // ahead token value - V3ParseBisonYYSType m_curBisonVal; // current token for error reporting - V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting + int m_lexPrevToken; // previous parsed token (for lexer) + std::deque m_tokensAhead; // Tokens we parsed ahead of parser std::deque m_stringps; // Created strings for later cleanup std::deque m_numberps; // Created numbers for later cleanup - std::deque m_lintState; // Current lint state for save/restore + std::deque m_lexLintState; // Current lint state for save/restore std::deque m_ppBuffers; // Preprocessor->lex buffer of characters to process - string m_tag; // Contents (if any) of current verilator tag AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set. VTimescale m_timeLastUnit; // Last `timescale's unit @@ -140,47 +196,54 @@ public: if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("flex"); return level; } - static int debug() { return debugBison() ? debugFlex() : 0; } + static int debug() { + static int level = -1; + if (VL_UNLIKELY(level < 0)) + level = std::max(std::max(debugBison(), debugFlex()), + v3Global.opt.debugSrcLevel("V3ParseImp")); + return level; + } // Functions called by lex rules: int yylexThis(); static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); } - void ppline(const char* textp); - void linenoInc() { fileline()->linenoInc(); } - void verilatorCmtLint(const char* textp, bool warnOff); - void verilatorCmtLintSave(); - void verilatorCmtLintRestore(); - void verilatorCmtBad(const char* textp); - void errorPreprocDirective(const char* textp); - void tag(const char* text); void tagNodep(AstNode* nodep) { m_tagNodep = nodep; } AstNode* tagNodep() const { return m_tagNodep; } - void timescalePreproc(FileLine* fl, const char* textp); + void lexTimescaleParse(FileLine* fl, const char* textp); void timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal, bool precSet, double precVal); VTimescale timeLastUnit() const { return m_timeLastUnit; } - static double parseTimenum(const char* text); - static double parseDouble(const char* text, size_t length, bool* successp = NULL); - void pushBeginKeywords(int state) { - m_inBeginKwd++; - m_lastVerilogState = state; + FileLine* lexFileline() const { return m_lexFileline; } + FileLine* lexCopyOrSameFileLine() { return lexFileline()->copyOrSameFileLine(); } + static void lexErrorPreprocDirective(FileLine* fl, const char* textp); + static string lexParseTag(const char* textp); + static double lexParseTimenum(const char* text); + void lexPpline(const char* textp); + void lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff); + void lexVerilatorCmtLintSave(const FileLine* fl); + void lexVerilatorCmtLintRestore(FileLine* fl); + static void lexVerilatorCmtBad(FileLine* fl, const char* textp); + + void lexPushKeywords(int state) { + ++m_lexKwdDepth; + m_lexKwdLast = state; } - bool popBeginKeywords() { - if (m_inBeginKwd) { - m_inBeginKwd--; + bool lexPopKeywords() { + if (m_lexKwdDepth) { + --m_lexKwdDepth; return true; } else { return false; } } - int lastVerilogState() const { return m_lastVerilogState; } + int lexKwdLastState() const { return m_lexKwdLast; } static const char* tokenName(int tok); void ppPushText(const string& text) { m_ppBuffers.push_back(text); - if (fileline()->contentp()) fileline()->contentp()->pushText(text); + if (lexFileline()->contentp()) lexFileline()->contentp()->pushText(text); } size_t ppInputToLex(char* buf, size_t max_size); @@ -188,6 +251,7 @@ public: // TODO: Many of these functions are the old interface; they'd be better as non-static // and called as READP->newString(...) etc. + // These can be called by either parser or lexer, as not lex/parser-position aware string* newString(const string& text) { // Allocate a string, remembering it so we can reclaim storage at lex end string* strp = new string(text); @@ -211,12 +275,13 @@ public: return nump; } + // Bison sometimes needs error context without a token, so remember last token's line + // Only use this if do not have and cannot get a token-relevent fileline + FileLine* bisonLastFileline() const { return m_bisonLastFileline; } + // Return next token, for bison, since bison isn't class based, use a global THIS - FileLine* fileline() const { return m_fileline; } AstNetlist* rootp() const { return m_rootp; } - FileLine* copyOrSameFileLine() { return fileline()->copyOrSameFileLine(); } - bool inCellDefine() const { return m_inCellDefine; } - void inCellDefine(bool flag) { m_inCellDefine = flag; } + FileLine* copyOrSameFileLine() { return bisonLastFileline()->copyOrSameFileLine(); } bool inLibrary() const { return m_inLibrary; } VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; } @@ -228,10 +293,8 @@ public: void lexNew(); void lexDestroy(); static int stateVerilogRecent(); // Parser -> lexer communication - int prevLexToken() const { return m_prevLexToken; } // Parser -> lexer communication + int lexPrevToken() const { return m_lexPrevToken; } // Parser -> lexer communication size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf, max_size); } - V3ParseBisonYYSType curBisonVal() const { return m_curBisonVal; } - V3ParseBisonYYSType prevBisonVal() const { return m_prevBisonVal; } //==== Symbol tables V3ParseSym* symp() { return m_symp; } @@ -242,35 +305,34 @@ public: : m_rootp(rootp) , m_filterp(filterp) , m_symp(parserSymp) { - m_fileline = NULL; + m_lexFileline = NULL; m_lexerp = NULL; - m_inCellDefine = false; m_inLibrary = false; - m_inBeginKwd = 0; - m_lastVerilogState = stateVerilogRecent(); - m_prevLexToken = 0; - m_ahead = false; - m_curBisonVal.token = 0; - m_prevBisonVal.token = 0; - // m_aheadVal not used as m_ahead = false, and not all compilers support initing it + m_lexKwdDepth = 0; + m_lexKwdLast = stateVerilogRecent(); + m_lexPrevToken = 0; m_tagNodep = NULL; m_timeLastUnit = v3Global.opt.timeDefaultUnit(); } ~V3ParseImp(); void parserClear(); - void unputString(const char* textp, size_t length); + void lexUnputString(const char* textp, size_t length); // METHODS // Preprocess and read the Verilog file specified into the netlist database - int lexToBison(); // Pass token to bison + int tokenToBison(); // Pass token to bison void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, const string& errmsg); private: void lexFile(const string& modname); - int yylexReadTok(); - void lexToken(); // Internal; called from lexToBison + void yylexReadTok(); + void tokenPull(); + void tokenPipeline(); // Internal; called from tokenToBison + void tokenPipelineSym(); + size_t tokenPipeScanParam(size_t depth); + const V3ParseBisonYYSType* tokenPeekp(size_t depth); void preprocDumps(std::ostream& os); }; diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index 14100969a..06b2a4024 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -46,16 +46,16 @@ public: } }; -void V3ParseImp::unputString(const char* textp, size_t length) { +void V3ParseImp::lexUnputString(const char* textp, size_t length) { parsep()->m_lexerp->unputString(textp, length); } -int V3ParseImp::yylexReadTok() { +void V3ParseImp::yylexReadTok() { // Call yylex() remembering last non-whitespace token - parsep()->fileline()->startToken(); + parsep()->lexFileline()->startToken(); int token = parsep()->m_lexerp->yylex(); - m_prevLexToken = token; // Save so can find '#' to parse following number - return token; + m_lexPrevToken = token; // Save so can find '#' to parse following number + yylval.token = token; } //###################################################################### diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index dbe9bebc5..2befc7669 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -100,6 +100,13 @@ public: reinsert(nodep, parentp); pushScope(symp); } + void pushNewUnderNodeOrCurrent(AstNode* nodep, AstNode* parentp) { + if (parentp) { + pushNewUnder(nodep, findNewTable(parentp)); + } else { + pushNewUnder(nodep, NULL); + } + } void pushScope(VSymEnt* symp) { m_sympStack.push_back(symp); m_symCurrentp = symp; @@ -138,11 +145,19 @@ public: return NULL; } } + void importExtends(AstNode* classp) { + // Import from package::id_or_star to this + VSymEnt* symp = getTable(classp); + UASSERT_OBJ(symp, classp, // Internal problem, because we earlier found it + "Extends class package not found"); + // Walk old sym table and reinsert into current table + // We let V3LinkDot report the error instead of us + symCurrentp()->importFromClass(&m_syms, symp); + } void importItem(AstNode* packagep, const string& id_or_star) { // Import from package::id_or_star to this VSymEnt* symp = getTable(packagep); - UASSERT_OBJ(symp, packagep, - // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE + UASSERT_OBJ(symp, packagep, // Internal problem, because we earlier found it "Import package not found"); // Walk old sym table and reinsert into current table // We let V3LinkDot report the error instead of us @@ -151,8 +166,7 @@ public: void exportItem(AstNode* packagep, const string& id_or_star) { // Export from this the remote package::id_or_star VSymEnt* symp = getTable(packagep); - UASSERT_OBJ(symp, packagep, - // Internal problem, because we earlier found pkg to label it an ID__aPACKAGE + UASSERT_OBJ(symp, packagep, // Internal problem, because we earlier found it "Export package not found"); symCurrentp()->exportFromPackage(&m_syms, symp, id_or_star); } diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 4647f81e4..42765edb7 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -1,8 +1,3 @@ -%option noyywrap align interactive -%option stack -%option noc++ -%option prefix="V3PreLex" -%{ /************************************************************************** * DESCRIPTION: Verilator: Flex verilog preprocessor * @@ -20,6 +15,16 @@ * Do not use Flex in C++ mode. It has bugs with yyunput() which result in * lost characters. **************************************************************************/ +/* clang-format off */ + +%option noyywrap align interactive +%option stack +%option noc++ +%option prefix="V3PreLex" +%{ +#ifdef NEVER_JUST_FOR_CLANG_FORMAT + } +#endif #include "V3PreProc.h" #include "V3PreLex.h" @@ -27,17 +32,22 @@ # include // for isatty #endif -V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point +/* clang-format on */ + +V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point #define LEXP V3PreLex::s_currentLexp -#define YY_INPUT(buf,result,max_size) \ +#define YY_INPUT(buf, result, max_size) \ do { result = LEXP->inputToLex(buf, max_size); } while (false) // Accessors, because flex keeps changing the type of yyleng char* yyourtext() { return yytext; } size_t yyourleng() { return yyleng; } -void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=size; } +void yyourtext(const char* textp, size_t size) { + yytext = (char*)textp; + yyleng = size; +} // FL_FWD only tracks columns; preproc uses linenoInc() to track lines, so // insertion of a \n does not mess up line count @@ -46,12 +56,13 @@ void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=siz #define FL_BRK (LEXP->curFilelinep()->startToken()) // Prevent conflicts from perl version -static void linenoInc() {LEXP->linenoInc();} +static void linenoInc() { LEXP->linenoInc(); } static bool pedantic() { return LEXP->m_pedantic; } static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); } static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); } static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l); } +/* clang-format off */ /**********************************************************************/ %} @@ -308,6 +319,7 @@ bom [\357\273\277] [\r] { FL_FWDC; FL_BRK; } . { FL_FWDC; return VP_TEXT; } %% +// clang-format on void V3PreLex::pushStateDefArg(int level) { // Enter define substitution argument state @@ -336,12 +348,15 @@ void V3PreLex::pushStateIncFilename() { yymore(); } -void V3PreLex::debug(int level) { yy_flex_debug = level; } -int V3PreLex::debug() { return yy_flex_debug; } +void V3PreLex::debug(int level) { + yy_flex_debug = level; } +int V3PreLex::debug() { + return yy_flex_debug; } int V3PreLex::lex() { V3PreLex::s_currentLexp = this; // Tell parser where to get/put data - m_tokFilelinep = curFilelinep(); // Remember token start location, may be updated by the lexer later + // Remember token start location, may be updated by the lexer later + m_tokFilelinep = curFilelinep(); return yylex(); } @@ -354,30 +369,32 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) { // VPreStream* streamp = curStreamp(); if (debug() >= 10) { - cout<<"- pp:inputToLex ITL s="< max_size) { @@ -388,13 +405,15 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) { } } else { if (streamp->m_eof) { - if (yy_flex_debug) cout<<"- EOF\n"; + if (yy_flex_debug) cout << "- EOF\n"; } got = 0; // 0=EOF/EOS - although got was already 0. if (again) goto again; } } - if (debug() >= 10) { cout<<"- pp::inputToLex got="<= 10) { + cout << "- pp::inputToLex got=" << got << " '" << string(buf, got) << "'" << endl; + } return got; } @@ -402,7 +421,7 @@ string V3PreLex::endOfStream(bool& againr) { // Switch to file or next unputString againr = false; if (yy_flex_debug) { - cout<<"-EOS state="<m_termState<<" at "<m_eof) return ""; // Don't delete the final "EOF" stream bool exited_file = curStreamp()->m_file; @@ -424,18 +443,15 @@ string V3PreLex::endOfStream(bool& againr) { // immediately. curStreamp()->m_termState = 1; return "\n"; // Exit old file - } - else if (curStreamp()->m_termState == 1) { + } else if (curStreamp()->m_termState == 1) { // Now the EOF - can't be sent with other characters curStreamp()->m_termState = 2; return ""; // End of file - } - else if (curStreamp()->m_termState == 2) { + } else if (curStreamp()->m_termState == 2) { // Now ending `line curStreamp()->m_termState = 3; return curFilelinep()->lineDirectiveStrg(2); // Exit old file - } - else { + } else { // Final shutdown phase for a stream, we can finally change the // current fileline to the new stream curStreamp()->m_termState = 0; @@ -518,7 +534,7 @@ void V3PreLex::scanBytesBack(const string& str) { string V3PreLex::currentUnreadChars() { // WARNING - Peeking at internals - ssize_t left = (yy_n_chars - (yy_c_buf_p -currentBuffer()->yy_ch_buf)); + ssize_t left = (yy_n_chars - (yy_c_buf_p - currentBuffer()->yy_ch_buf)); if (left > 0) { // left may be -1 at EOS *(yy_c_buf_p) = (yy_hold_char); return string(yy_c_buf_p, left); @@ -536,25 +552,24 @@ int V3PreLex::currentStartState() const { } void V3PreLex::lineDirective(const char* textp) { - curFilelinep()->lineDirective(textp, m_enterExit/*ref*/); + curFilelinep()->lineDirective(textp, m_enterExit /*ref*/); // Make sure we have a dependency on whatever file was specified V3File::addSrcDepend(curFilelinep()->filename()); } void V3PreLex::warnBackslashSpace() { // Make fileline highlight the specific backslash and space - curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); + curFilelinep()->v3warn( + BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); } void V3PreLex::dumpSummary() { - cout<<"- pp::dumpSummary curBuf="<m_file?" [FILE]":""); - cout<m_file ? " [FILE]" : "") << endl; tmpstack.pop(); } } diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index c04726c8b..06fd9d726 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -364,8 +364,8 @@ private: virtual void visit(AstVar* nodep) VL_OVERRIDE { if (!nodep->isIO()) return; if (VN_IS(nodep->dtypep(), UnpackArrayDType)) { - nodep->v3error("Unsupported: unpacked arrays with protect-lib on " - << nodep->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: unpacked arrays with protect-lib on " + << nodep->prettyNameQ()); } if (nodep->direction() == VDirection::INPUT) { if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) { @@ -376,8 +376,8 @@ private: } else if (nodep->direction() == VDirection::OUTPUT) { handleOutput(nodep); } else { - nodep->v3error( - "Unsupported: protect-lib port direction: " << nodep->direction().ascii()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: protect-lib port direction: " + << nodep->direction().ascii()); } } diff --git a/src/V3SenTree.h b/src/V3SenTree.h index deca31018..d4f5c3ecc 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -13,17 +13,7 @@ // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //************************************************************************* -// V3Block's Transformations: -// -// Note this can be called multiple times. -// Create a IBLOCK(initial), SBLOCK(combo) -// ALWAYS: Remove any-edges from sense list -// If no POS/NEG in senselist, Fold into SBLOCK(combo) -// Else fold into SBLOCK(sequent). -// OPTIMIZE: When support async clocks, fold into that block if possible -// INITIAL: Move into IBLOCK -// WIRE: Move into SBLOCK(combo) -// +// AstSenTree related utilities. //************************************************************************* #ifndef _V3SENTREE_H_ @@ -32,14 +22,9 @@ #include "config_build.h" #include "verilatedos.h" -#include "V3Global.h" #include "V3Ast.h" #include "V3Hashed.h" -#include -#include -#include -#include #include VL_INCLUDE_UNORDERED_SET //###################################################################### @@ -50,22 +35,16 @@ class SenTreeSet { // Hash table of sensitive blocks. private: // TYPES - class HashSenTree { - public: - HashSenTree() {} + struct HashSenTree { size_t operator()(const AstSenTree* kp) const { return V3Hashed::uncachedHash(kp).fullValue(); } - // Copying required for OSX's libc++ }; - class EqSenTree { - public: - EqSenTree() {} + struct EqSenTree { bool operator()(const AstSenTree* ap, const AstSenTree* bp) const { return ap->sameTree(bp); } - // Copying required for OSX's libc++ }; // MEMBERS @@ -78,76 +57,57 @@ public: // METHODS void add(AstSenTree* nodep) { m_trees.insert(nodep); } + AstSenTree* find(AstSenTree* likep) { AstSenTree* resultp = NULL; Set::iterator it = m_trees.find(likep); if (it != m_trees.end()) resultp = *it; return resultp; } + void clear() { m_trees.clear(); } private: VL_UNCOPYABLE(SenTreeSet); }; -class SenTreeFinder : public AstNVisitor { +class SenTreeFinder { private: // STATE - AstTopScope* m_topscopep; // Top scope to add statement to - SenTreeSet m_trees; // Set of sensitive blocks, for folding + AstTopScope* m_topScopep; // Top scope to add global SenTrees to + SenTreeSet m_trees; // Set of global SenTrees - // VISITORS - VL_DEBUG_FUNC; // Declare debug() + VL_UNCOPYABLE(SenTreeFinder); - virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - // Only do the top - if (nodep->isTop()) iterateChildren(nodep); - } - virtual void visit(AstTopScope* nodep) VL_OVERRIDE { - m_topscopep = nodep; - iterateChildren(nodep); - // Don't clear topscopep, the namer persists beyond this visit - } - virtual void visit(AstScope* nodep) VL_OVERRIDE { - // But no SenTrees under TopScope's scope - } - // Memorize existing block names - virtual void visit(AstActive* nodep) VL_OVERRIDE { - // Don't grab SenTrees under Actives, only those that are global (under Scope directly) - iterateChildren(nodep); - } - virtual void visit(AstSenTree* nodep) VL_OVERRIDE { // - m_trees.add(nodep); - } - virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate - virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); } +public: + // CONSTRUCTORS + SenTreeFinder() + : m_topScopep(NULL) {} // METHODS -public: - void clear() { - m_topscopep = NULL; - m_trees.clear(); - } - AstSenTree* getSenTree(AstSenTree* sensesp) { - // Return a global sentree that matches given sense list. - AstSenTree* treep = m_trees.find(sensesp); + AstSenTree* getSenTree(AstSenTree* senTreep) { + // Return a global SenTree that matches given SenTree. If no such global + // SenTree exists, create one and add it to the stored TopScope. + AstSenTree* treep = m_trees.find(senTreep); // Not found, form a new one if (!treep) { - UASSERT(m_topscopep, "Never called main()"); - treep = sensesp->cloneTree(false); - m_topscopep->addStmtsp(treep); + UASSERT(m_topScopep, "Never called init()"); + treep = senTreep->cloneTree(false); + m_topScopep->addStmtsp(treep); UINFO(8, " New SENTREE " << treep << endl); m_trees.add(treep); - // Note blocks may have also been added above in the Active visitor } return treep; } -public: - // CONSTRUCTORS - SenTreeFinder() { clear(); } - virtual ~SenTreeFinder() {} - void main(AstTopScope* nodep) { iterate(nodep); } + void init(AstTopScope* topScopep) { + // Keep hold of top scope so we can add global SenTrees later + m_topScopep = topScopep; + // Gather existing global SenTrees + for (AstNode* nodep = topScopep->stmtsp(); nodep; nodep = nodep->nextp()) { + if (AstSenTree* senTreep = VN_CAST(nodep, SenTree)) m_trees.add(senTreep); + } + } }; #endif // Guard diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 5cc78823a..3cda051f0 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -122,8 +122,6 @@ #include #include #include -#include VL_INCLUDE_UNORDERED_MAP -#include VL_INCLUDE_UNORDERED_SET struct SplitVarImpl { static AstNodeAssign* newAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp, @@ -175,10 +173,7 @@ struct SplitVarImpl { if (const char* reason = cannotSplitVarTypeReason(varp->varType())) return reason; if (const char* reason = cannotSplitVarDirectionReason(varp->direction())) return reason; if (varp->isSigPublic()) return "it is public"; - if (varp->isInoutish()) return "it is bidirectional"; if (varp->isUsedLoopIdx()) return "it is used as a loop variable"; - if (varp->isGenVar()) return "it is genvar"; - if (varp->isParam()) return "it is parameter"; return NULL; } @@ -228,6 +223,15 @@ const char* const SplitVarImpl::notSplitMsg // AstVarRef -> Create a temporary variable and refer the variable // AstSliceSel -> Create a temporary variable and refer the variable +// Compare AstNode* to get deterministic ordering when showing messages. +struct AstNodeComparator { + bool operator()(const AstNode* ap, const AstNode* bp) const { + const int lineComp = ap->fileline()->operatorCompare(*bp->fileline()); + if (lineComp != 0) return lineComp < 0; + return ap < bp; + } +}; + class UnpackRef { // m_nodep is called in this context (AstNodeStmt, AstCell, AstNodeFTask, or AstAlways) AstNode* m_contextp; @@ -277,19 +281,14 @@ public: } bool lvalue() const { return m_lvalue; } bool ftask() const { return m_ftask; } + bool operator<(const UnpackRef& other) const { + return AstNodeComparator()(m_nodep, other.m_nodep); + } }; class UnpackRefMap { public: - struct Hash { - size_t operator()(const UnpackRef& r) const { return reinterpret_cast(r.nodep()); } - }; - struct Compare { - bool operator()(const UnpackRef& a, const UnpackRef& b) const { - return a.nodep() == b.nodep(); - } - }; - typedef std::map > MapType; + typedef std::map, AstNodeComparator> MapType; typedef MapType::iterator MapIt; typedef MapType::value_type::second_type::iterator SetIt; @@ -336,30 +335,14 @@ public: MapIt end() { return m_map.end(); } }; -// Compare AstNode* to get deterministic ordering when showing messages. -struct AstNodeComparator { - bool operator()(const AstNode* ap, const AstNode* bp) const { - const FileLine* afp = ap->fileline(); - const FileLine* bfp = bp->fileline(); - if (afp->firstLineno() != bfp->firstLineno()) - return afp->firstLineno() < bfp->firstLineno(); - if (afp->firstColumn() != bfp->firstColumn()) - return afp->firstColumn() < bfp->firstColumn(); - // Don't comapre its filename because it is expensive. - // Line number and column is practically enough. - // The comparison of raw pointer here is just in case. - // The comparison of this pointer may differ on different run, - // but this is just warning message order. (mostly for CI) - // Verilated result is same anyway. - return ap < bp; - } -}; - // Found nodes for SplitPackedVarVisitor struct RefsInModule { - std::set m_vars; - std::set m_refs; - std::set m_sels; + typedef std::set VarSet; + typedef std::set VarRefSet; + typedef std::set SelSet; + VarSet m_vars; + VarRefSet m_refs; + SelSet m_sels; public: void add(AstVar* nodep) { m_vars.insert(nodep); } @@ -381,12 +364,10 @@ public: v.iterate(nodep); } void visit(AstNVisitor* visitor) { - for (std::set::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end; - ++it) { + for (VarSet::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end; ++it) { visitor->iterate(*it); } - for (std::set::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end; - ++it) { + for (SelSet::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end; ++it) { // If m_refs includes VarRef from ArraySel, remove it // because the VarRef would not be visited in SplitPackedVarVisitor::visit(AstSel*). if (AstVarRef* refp = VN_CAST((*it)->fromp(), VarRef)) { @@ -399,8 +380,7 @@ public: UASSERT_OBJ(reinterpret_cast((*it)->op1p()) != 1, *it, "stale"); visitor->iterate(*it); } - for (std::set::iterator it = m_refs.begin(), it_end = m_refs.end(); - it != it_end; ++it) { + for (VarRefSet::iterator it = m_refs.begin(), it_end = m_refs.end(); it != it_end; ++it) { UASSERT_OBJ(reinterpret_cast((*it)->op1p()) != 1, *it, "stale"); visitor->iterate(*it); } @@ -894,15 +874,16 @@ class PackedVarRef { AstBasicDType* m_basicp; // Cache the ptr since varp->dtypep()->basicp() is expensive bool m_dedupDone; static void dedupRefs(std::vector& refs) { - vl_unordered_map nodes; + // Use raw pointer to dedup + typedef std::map NodeIndices; + NodeIndices nodes; for (size_t i = 0; i < refs.size(); ++i) { nodes.insert(std::make_pair(refs[i].nodep(), i)); } std::vector vect; vect.reserve(nodes.size()); - for (vl_unordered_map::const_iterator it = nodes.begin(), - it_end = nodes.end(); - it != it_end; ++it) { + for (NodeIndices::const_iterator it = nodes.begin(), it_end = nodes.end(); it != it_end; + ++it) { vect.push_back(refs[it->second]); } refs.swap(vect); @@ -983,24 +964,12 @@ public: }; class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { + typedef std::map PackedVarRefMap; AstNetlist* m_netp; AstNodeModule* m_modp; // Current module (just for log) int m_numSplit; // Total number of split variables // key:variable to be split. value:location where the variable is referenced. - vl_unordered_map m_refs; - virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { - UASSERT_OBJ(m_modp == NULL, m_modp, "Nested module declaration"); - if (!VN_IS(nodep, Module)) { - UINFO(5, "Skip " << nodep->prettyNameQ() << "\n"); - return; - } - UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()"); - m_modp = nodep; - UINFO(3, "Start analyzing module " << nodep->prettyName() << '\n'); - iterateChildren(nodep); - split(); - m_modp = NULL; - } + PackedVarRefMap m_refs; virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { if (!cannotSplitTaskReason(nodep)) iterateChildren(nodep); } @@ -1017,7 +986,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { virtual void visit(AstVarRef* nodep) VL_OVERRIDE { AstVar* varp = nodep->varp(); visit(varp); - vl_unordered_map::iterator refit = m_refs.find(varp); + PackedVarRefMap::iterator refit = m_refs.find(varp); if (refit == m_refs.end()) return; // variable without split_var metacomment UASSERT_OBJ(varp->attrSplitVar(), varp, "split_var attribute must be attached"); UASSERT_OBJ(!nodep->packagep(), nodep, @@ -1036,7 +1005,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { } AstVar* varp = vrefp->varp(); - vl_unordered_map::iterator refit = m_refs.find(varp); + PackedVarRefMap::iterator refit = m_refs.find(varp); if (refit == m_refs.end()) { iterateChildren(nodep); return; // Variable without split_var metacomment @@ -1198,9 +1167,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { } // Do the actual splitting operation void split() { - for (vl_unordered_map::iterator it = m_refs.begin(), - it_end = m_refs.end(); - it != it_end; ++it) { + for (PackedVarRefMap::iterator it = m_refs.begin(), it_end = m_refs.end(); it != it_end; + ++it) { it->second.dedup(); AstVar* varp = it->first; UINFO(3, "In module " << m_modp->name() << " var " << varp->prettyNameQ() @@ -1246,7 +1214,7 @@ public: , m_modp(NULL) , m_numSplit(0) { // If you want ignore refs and walk the tne entire AST, - // just call iterate(nodep) and disable the following for-loop. + // just call iterateChildren(m_modp) and split() for each module for (SplitVarRefsMap::iterator it = refs.begin(), it_end = refs.end(); it != it_end; ++it) { m_modp = it->first; diff --git a/src/V3String.cpp b/src/V3String.cpp index 3433306a6..d93b388dc 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -121,6 +121,24 @@ bool VString::isWhitespace(const string& str) { return true; } +double VString::parseDouble(const string& str, bool* successp) { + char* strgp = new char[str.size() + 1]; + char* dp = strgp; + if (successp) *successp = true; + for (const char* sp = str.c_str(); *sp; ++sp) { + if (*sp != '_') *dp++ = *sp; + } + *dp++ = '\0'; + char* endp = strgp; + double d = strtod(strgp, &endp); + size_t parsed_len = endp - strgp; + if (parsed_len != strlen(strgp)) { + if (successp) *successp = false; + } + VL_DO_DANGLING(delete[] strgp, strgp); + return d; +} + //###################################################################### // VHashSha256 diff --git a/src/V3String.h b/src/V3String.h index 50a725dbd..a3472c3f7 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -89,6 +89,8 @@ public: static string removeWhitespace(const string& str); // Return true if only whitespace or "" static bool isWhitespace(const string& str); + // Return double by parsing string + static double parseDouble(const string& str, bool* successp); }; //###################################################################### diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 10dd2f439..a6d66421e 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -181,8 +181,10 @@ public: } private: - void importOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp) { - if (srcp->exported() && !findIdFlat(name)) { // Don't insert over existing entry + void importOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp, + bool honorExport) { + if ((!honorExport || srcp->exported()) + && !findIdFlat(name)) { // Don't insert over existing entry VSymEnt* symp = new VSymEnt(graphp, srcp); symp->exported(false); // Can't reimport an import without an export symp->imported(true); @@ -198,15 +200,25 @@ private: } public: + void importFromClass(VSymGraph* graphp, const VSymEnt* srcp) { + // Import tokens from source symbol table into this symbol table + // Used for classes in early parsing only to handle "extends" + for (IdNameMap::const_iterator it = srcp->m_idNameMap.begin(); + it != srcp->m_idNameMap.end(); ++it) { + importOneSymbol(graphp, it->first, it->second, false); + } + } void importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) { // Import tokens from source symbol table into this symbol table if (id_or_star != "*") { IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star); - if (it != srcp->m_idNameMap.end()) importOneSymbol(graphp, it->first, it->second); + if (it != srcp->m_idNameMap.end()) { + importOneSymbol(graphp, it->first, it->second, true); + } } else { for (IdNameMap::const_iterator it = srcp->m_idNameMap.begin(); it != srcp->m_idNameMap.end(); ++it) { - importOneSymbol(graphp, it->first, it->second); + importOneSymbol(graphp, it->first, it->second, true); } } } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 30ef04ec9..b9f8f2445 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -846,11 +846,12 @@ private: newPortp->funcLocal(true); dpip->addArgsp(newPortp); if (!portp->basicp()) { - portp->v3error( + portp->v3warn( + E_UNSUPPORTED, "Unsupported: DPI argument of type " - << portp->basicp()->prettyTypeName() << endl - << portp->warnMore() - << "... For best portability, use bit, byte, int, or longint"); + << portp->basicp()->prettyTypeName() << endl + << portp->warnMore() + << "... For best portability, use bit, byte, int, or longint"); // We don't warn on logic either, although the 4-stateness is lost. // That's what other simulators do. } @@ -971,9 +972,10 @@ private: } } else { if (portp->isWide()) { - nodep->v3error("Unsupported: Public functions with return > 64 bits wide.\n" - + V3Error::warnMore() - + "... Suggest make it an output argument instead?"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Public functions with return > 64 bits wide.\n" + + V3Error::warnMore() + + "... Suggest make it an output argument instead?"); } } @@ -1265,7 +1267,8 @@ private: if (v3Global.opt.protectIds() && nodep->taskPublic()) { // We always call protect() on names, we don't check if public or not // Hence any external references wouldn't be able to find the refed public object. - nodep->v3error("Unsupported: Using --protect-ids with public function"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Using --protect-ids with public function"); } if (modes > 1) { nodep->v3error("Cannot mix DPI import, DPI export, class methods, and/or public " @@ -1463,9 +1466,10 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // Problem otherwise is we might have a varref, task // call, or something else that only makes sense in the // domain of the function, not the callee. - nodep->v3error("Unsupported: Non-constant default value in missing argument " - << portp->prettyNameQ() << " in function call to " - << nodep->taskp()->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Non-constant default value in missing argument " + << portp->prettyNameQ() << " in function call to " + << nodep->taskp()->prettyTypeName()); newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0); } else { newvaluep = newvaluep->cloneTree(true); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 184f92571..feab69955 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -380,8 +380,9 @@ class TristateVisitor : public TristateBaseVisitor { invarp->name() + "__en", invarp); UINFO(9, " newenv " << newp << endl); if (!m_modp) { - invarp->v3error("Unsupported: Creating tristate signal not underneath a module: " - << invarp->prettyNameQ()); + invarp->v3warn(E_UNSUPPORTED, + "Unsupported: Creating tristate signal not underneath a module: " + << invarp->prettyNameQ()); } else { m_modp->addStmtp(newp); } @@ -397,8 +398,9 @@ class TristateVisitor : public TristateBaseVisitor { invarp->name() + "__out", invarp); UINFO(9, " newout " << newp << endl); if (!m_modp) { - invarp->v3error("Unsupported: Creating tristate signal not underneath a module: " - << invarp->prettyNameQ()); + invarp->v3warn(E_UNSUPPORTED, + "Unsupported: Creating tristate signal not underneath a module: " + << invarp->prettyNameQ()); } else { m_modp->addStmtp(newp); } @@ -412,7 +414,8 @@ class TristateVisitor : public TristateBaseVisitor { "__Vtriunconn" + cvtToStr(m_unique++), dtypep); UINFO(9, " newunc " << newp << endl); if (!m_modp) { - newp->v3error("Unsupported: Creating tristate signal not underneath a module"); + newp->v3warn(E_UNSUPPORTED, + "Unsupported: Creating tristate signal not underneath a module"); } else { m_modp->addStmtp(newp); } @@ -447,10 +450,11 @@ class TristateVisitor : public TristateBaseVisitor { varp->user3p(pullp); // save off to indicate the pull direction } else { if (oldpullp->direction() != pullp->direction()) { - pullp->v3error("Unsupported: Conflicting pull directions.\n" - << pullp->warnContextPrimary() << endl - << oldpullp->warnOther() << "... Location of conflicting pull.\n" - << oldpullp->warnContextSecondary()); + pullp->v3warn(E_UNSUPPORTED, "Unsupported: Conflicting pull directions.\n" + << pullp->warnContextPrimary() << endl + << oldpullp->warnOther() + << "... Location of conflicting pull.\n" + << oldpullp->warnContextSecondary()); } } } @@ -460,14 +464,16 @@ class TristateVisitor : public TristateBaseVisitor { // The best way would be to visit the tree again and find any user1p() // pointers that did not get picked up and expanded. if (m_alhs && nodep->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported LHS tristate construct: " << nodep->prettyTypeName()); } // Ignore Var's because they end up adjacent to statements if ((nodep->op1p() && nodep->op1p()->user1p() && !VN_IS(nodep->op1p(), Var)) || (nodep->op2p() && nodep->op2p()->user1p() && !VN_IS(nodep->op1p(), Var)) || (nodep->op3p() && nodep->op3p()->user1p() && !VN_IS(nodep->op1p(), Var)) || (nodep->op4p() && nodep->op4p()->user1p() && !VN_IS(nodep->op1p(), Var))) { - nodep->v3error("Unsupported tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported tristate construct: " << nodep->prettyTypeName()); } } @@ -678,7 +684,8 @@ class TristateVisitor : public TristateBaseVisitor { } } else { if (m_alhs && nodep->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } iterateChildren(nodep); @@ -689,8 +696,8 @@ class TristateVisitor : public TristateBaseVisitor { // error. AstNode* condp = nodep->condp(); if (condp->user1p()) { - condp->v3error("Unsupported: don't know how to deal with " - "tristate logic in the conditional expression"); + condp->v3warn(E_UNSUPPORTED, "Unsupported: don't know how to deal with " + "tristate logic in the conditional expression"); } AstNode* expr1p = nodep->expr1p(); AstNode* expr2p = nodep->expr2p(); @@ -732,8 +739,8 @@ class TristateVisitor : public TristateBaseVisitor { iterateChildren(nodep); UINFO(9, dbgState() << nodep << endl); if (nodep->lsbp()->user1p()) { - nodep->v3error( - "Unsupported RHS tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported RHS tristate construct: " + << nodep->prettyTypeName()); } if (nodep->fromp()->user1p()) { // SEL(VARREF, lsb) AstNode* en1p = getEnp(nodep->fromp()); @@ -804,7 +811,8 @@ class TristateVisitor : public TristateBaseVisitor { } else { if (debug() >= 9) nodep->backp()->dumpTree(cout, "-bufif: "); if (m_alhs) { - nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } m_tgraph.didProcess(nodep); @@ -834,7 +842,8 @@ class TristateVisitor : public TristateBaseVisitor { associateLogic(nodep->rhsp(), nodep); } else { if (m_alhs && nodep->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } // ANDs and Z's have issues. Earlier optimizations convert @@ -956,13 +965,14 @@ class TristateVisitor : public TristateBaseVisitor { } void visitEqNeqWild(AstNodeBiop* nodep) { if (!VN_IS(nodep->rhsp(), Const)) { - nodep->v3error( // Says spac. - "Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); + nodep->v3warn(E_UNSUPPORTED, // Says spac. + "Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // rhs we want to keep X/Z intact, so otherwise ignore } iterateAndNextNull(nodep->lhsp()); if (nodep->lhsp()->user1p()) { - nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported LHS tristate construct: " << nodep->prettyTypeName()); return; } } @@ -982,7 +992,7 @@ class TristateVisitor : public TristateBaseVisitor { } if (!varrefp) { if (debug() >= 4) nodep->dumpTree(cout, "- "); - nodep->v3error("Unsupported pullup/down (weak driver) construct."); + nodep->v3warn(E_UNSUPPORTED, "Unsupported pullup/down (weak driver) construct."); } else { if (m_graphing) { varrefp->lvalue(true); @@ -1115,8 +1125,8 @@ class TristateVisitor : public TristateBaseVisitor { if (!outModVarp) { // At top, no need for __out as might be input only. Otherwise resolvable. if (!m_modp->isTop()) { - nodep->v3error( - "Unsupported: tristate in top-level IO: " << nodep->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: tristate in top-level IO: " + << nodep->prettyNameQ()); } } else { AstNode* outexprp = nodep->exprp()->cloneTree(false); // Note has lvalue() set @@ -1160,8 +1170,8 @@ class TristateVisitor : public TristateBaseVisitor { // pinReconnect should have converted this exprrefp = VN_CAST(outpinp->exprp(), VarRef); if (!exprrefp) { - nodep->v3error("Unsupported tristate port expression: " - << nodep->exprp()->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported tristate port expression: " + << nodep->exprp()->prettyTypeName()); } } } else { @@ -1169,8 +1179,8 @@ class TristateVisitor : public TristateBaseVisitor { exprrefp = VN_CAST(outAssignp->rhsp(), VarRef); // This should be the same var as the output pin if (!exprrefp) { - nodep->v3error("Unsupported tristate port expression: " - << nodep->exprp()->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported tristate port expression: " + << nodep->exprp()->prettyTypeName()); } } if (exprrefp) { diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index d0769702d..3ebaa05ec 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -210,8 +210,8 @@ private: AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* newp; if (!VN_IS(rhsp, Const)) { - nodep->v3error("Unsupported: RHS of ==? or !=? must be " - "constant to be synthesizable"); // Says spec. + nodep->v3warn(E_UNSUPPORTED, "Unsupported: RHS of ==? or !=? must be " + "constant to be synthesizable"); // Says spec. // Replace with anything that won't cause more errors newp = new AstEq(nodep->fileline(), lhsp, rhsp); } else { diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 6d1eb0cb7..795d5ec04 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -59,7 +59,8 @@ private: // VISITORS bool cantUnroll(AstNode* nodep, const char* reason) { - if (m_generate) nodep->v3error("Unsupported: Can't unroll generate for; " << reason); + if (m_generate) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Can't unroll generate for; " << reason); UINFO(3, " Can't Unroll: " << reason << " :" << nodep << endl); // if (debug() >= 9) nodep->dumpTree(cout, "-cant-"); V3Stats::addStatSum(string("Unrolling gave up, ") + reason, 1); @@ -112,7 +113,7 @@ private: // Assignment of next value check AstAssign* incAssp = VN_CAST(incp, Assign); if (!incAssp) return cantUnroll(nodep, "no increment assignment"); - UASSERT_OBJ(!incAssp->nextp(), nodep, "increment shouldn't be a list"); + if (incAssp->nextp()) return cantUnroll(nodep, "multiple increments"); m_forVarp = VN_CAST(initAssp->lhsp(), VarRef)->varp(); m_forVscp = VN_CAST(initAssp->lhsp(), VarRef)->varScopep(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 940d50ea8..de04c0a82 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -479,8 +479,8 @@ private: && (VN_IS(vdtypep, AssocArrayDType) // || VN_IS(vdtypep, DynArrayDType) // || VN_IS(vdtypep, QueueDType))) { - nodep->v3error("Unsupported: Concatenation to form " << vdtypep->prettyDTypeNameQ() - << "data type"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form " + << vdtypep->prettyDTypeNameQ() << "data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); @@ -564,10 +564,18 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { - nodep->v3error("Unsupported: fork statements"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: fork statements"); // TBD might support only normal join, if so complain about other join flavors } } + virtual void visit(AstDisableFork* nodep) VL_OVERRIDE { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork statements"); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } + virtual void visit(AstWaitFork* nodep) VL_OVERRIDE { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements"); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } virtual void visit(AstToLowerN* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); @@ -589,8 +597,8 @@ private: if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) || VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) { - nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ() - << " data type"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " + << vdtypep->prettyDTypeNameQ() << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); @@ -746,8 +754,8 @@ private: int width = nodep->widthConst(); UASSERT_OBJ(nodep->dtypep(), nodep, "dtype wasn't set"); // by V3WidthSel if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() < nodep->lsbConst()) { - nodep->v3error("Unsupported: MSB < LSB of bit extract: " - << nodep->msbConst() << "<" << nodep->lsbConst()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: MSB < LSB of bit extract: " + << nodep->msbConst() << "<" << nodep->lsbConst()); width = (nodep->lsbConst() - nodep->msbConst() + 1); nodep->dtypeSetLogicSized(width, VSigning::UNSIGNED); nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width)); @@ -1061,9 +1069,9 @@ private: } virtual void visit(AstUnbounded* nodep) VL_OVERRIDE { nodep->dtypeSetSigned32(); // Used in int context - if (!VN_IS(nodep->backp(), IsUnbounded) + if (!VN_IS(nodep->backp(), IsUnbounded) && !VN_IS(nodep->backp(), BracketArrayDType) && !(VN_IS(nodep->backp(), Var) && VN_CAST(nodep->backp(), Var)->isParam())) { - nodep->v3error("Unsupported/illegal unbounded ('$') in this context."); + nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context."); } } virtual void visit(AstIsUnbounded* nodep) VL_OVERRIDE { @@ -1083,7 +1091,7 @@ private: AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); nodep->dtypeFrom(expDTypep); // Assume user knows the rules; go with the flow if (nodep->width() > 64) { - nodep->v3error("Unsupported: $c can't generate wider than 64 bits"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits"); } } } @@ -1267,7 +1275,7 @@ private: break; } case AstAttrType::DIM_BITS: { - nodep->v3error("Unsupported: $bits for queue"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for queue"); break; } default: nodep->v3error("Unhandled attribute type"); @@ -1332,9 +1340,8 @@ private: // DTYPES virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); // Cleanup array size userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p()); nodep->dtypep(nodep); // The array itself, not subDtype @@ -1349,29 +1356,52 @@ private: } virtual void visit(AstAssocArrayDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); - if (nodep->keyChildDTypep()) { - nodep->keyDTypep(moveDTypeEdit(nodep, nodep->keyChildDTypep())); - } // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); - nodep->keyDTypep(iterateEditDTypep(nodep, nodep->keyDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); + nodep->keyDTypep(iterateEditMoveDTypep(nodep, nodep->keyDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); } + virtual void visit(AstBracketArrayDType* nodep) VL_OVERRIDE { + // Type inserted only because parser didn't know elementsp() type + // Resolve elementsp's type + userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); + // We must edit when dtype still under normal nodes and before type table + // See notes in iterateEditMoveDTypep + AstNodeDType* childp = nodep->childDTypep(); + childp->unlinkFrBack(); + AstNode* elementsp = nodep->elementsp()->unlinkFrBack(); + AstNode* newp; + if (VN_IS(elementsp, Unbounded)) { + newp = new AstQueueDType(nodep->fileline(), VFlagChildDType(), childp, NULL); + VL_DO_DANGLING(elementsp->deleteTree(), elementsp); + } else if (AstNodeDType* keyp = VN_CAST(elementsp, NodeDType)) { + newp = new AstAssocArrayDType(nodep->fileline(), VFlagChildDType(), childp, keyp); + } else { + // Must be expression that is constant, but we'll determine that later + newp = new AstUnpackArrayDType( + nodep->fileline(), VFlagChildDType(), childp, + new AstRange(nodep->fileline(), new AstConst(elementsp->fileline(), 0), + new AstSub(elementsp->fileline(), elementsp, + new AstConst(elementsp->fileline(), 1)))); + } + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + // Normally parent's iteration would cover this, but we might have entered by a specific + // visit + VL_DO_DANGLING(userIterate(newp, NULL), newp); + } virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); } virtual void visit(AstQueueDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype if (VN_IS(nodep->boundp(), Unbounded)) { nodep->boundp()->unlinkFrBack()->deleteTree(); // NULL will represent unbounded @@ -1380,9 +1410,8 @@ private: } virtual void visit(AstUnsizedArrayDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); // Cleanup array size nodep->dtypep(nodep); // The array itself, not subDtype UINFO(4, "dtWidthed " << nodep << endl); @@ -1412,12 +1441,8 @@ private: } virtual void visit(AstConstDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - // Move any childDTypep to instead be in global AstTypeTable. - // This way if this node gets deleted and some other dtype points to it - // it won't become a dead pointer. This doesn't change the object pointed to. - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); userIterateChildren(nodep, NULL); nodep->dtypep(nodep); // Should already be set, but be clear it's not the subDType nodep->widthFromSub(nodep->subDTypep()); @@ -1444,8 +1469,14 @@ private: } userIterateChildren(nodep, NULL); if (nodep->subDTypep()) { - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + // Normally iterateEditMoveDTypep iterate would work, but the refs are under + // the TypeDef which will upset iterateEditMoveDTypep as it can't find it under + // this node's childDTypep + userIterate(nodep->subDTypep(), NULL); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->typedefp(NULL); // Note until line above subDTypep() may have followed this + // Widths are resolved, but special iterate to check for recurstion + userIterate(nodep->subDTypep(), NULL); } // Effectively nodep->dtypeFrom(nodep->dtypeSkipRefp()); // But might be recursive, so instead manually recurse into the referenced type @@ -1457,17 +1488,22 @@ private: } virtual void visit(AstTypedef* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); + nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); userIterateChildren(nodep, NULL); - nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep())); } virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); + nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); userIterateChildren(nodep, NULL); - nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep())); nodep->widthFromSub(nodep->subDTypep()); } + virtual void visit(AstCastDynamic* nodep) VL_OVERRIDE { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: $cast. Suggest try static cast."); + AstNode* newp = new AstConst(nodep->fileline(), 1); + newp->dtypeSetSigned32(); // Spec says integer return + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } virtual void visit(AstCastParse* nodep) VL_OVERRIDE { // nodep->dtp could be data type, or a primary_constant // Don't iterate lhsp, will deal with that once convert the type @@ -1480,13 +1516,13 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); userIterate(newp, m_vup); } else { - nodep->v3error("Unsupported: Cast to " << nodep->dtp()->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Cast to " << nodep->dtp()->prettyTypeName()); nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); } } virtual void visit(AstCast* nodep) VL_OVERRIDE { - if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); - nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep())); + nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); // if (debug()) nodep->dumpTree(cout, " CastPre: "); userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); // When more general casts are supported, the cast elimination will be done later. @@ -1538,7 +1574,8 @@ private: AstBasicDType* underDtp = VN_CAST(nodep->lhsp()->dtypep(), BasicDType); if (!underDtp) underDtp = nodep->lhsp()->dtypep()->basicp(); if (!underDtp) { - nodep->v3error("Unsupported: Size-changing cast on non-basic data type"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Size-changing cast on non-basic data type"); underDtp = VN_CAST(nodep->findLogicBoolDType(), BasicDType); } // A cast propagates its size to the lower expression and is included in the maximum @@ -1593,8 +1630,7 @@ private: } nodep->doingWidth(true); // Make sure dtype is sized - if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); - nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep())); + nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var"); if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) { if (!(m_ftaskp && m_ftaskp->dpiImport())) { @@ -1608,7 +1644,8 @@ private: && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType) || VN_IS(nodep->dtypeSkipRefp(), NodeArrayDType) || VN_IS(nodep->dtypeSkipRefp(), NodeUOrStructDType))) { - nodep->v3error("Unsupported: Inputs and outputs must be simple data types"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Inputs and outputs must be simple data types"); } if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) nodep->isConst(true); // Parameters if implicit untyped inherit from what they are assigned to @@ -1724,8 +1761,7 @@ private: virtual void visit(AstEnumDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed UINFO(5, " ENUMDTYPE " << nodep << endl); - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); nodep->widthFromSub(nodep->subDTypep()); // Assign widths @@ -1926,22 +1962,26 @@ private: virtual void visit(AstClass* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; userIterateChildren(nodep, NULL); // First size all members + if (nodep->isVirtual()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: virtual class"); nodep->repairCache(); } + virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE { + if (nodep->didWidthAndSet()) return; + // TODO this maybe eventually required to properly resolve members, + // though causes problems with t_class_forward.v, so for now avoided + // userIterateChildren(nodep->classp(), NULL); + } virtual void visit(AstClassExtends* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; - nodep->v3error("Unsupported: class extends"); // Member/meth access breaks + nodep->v3warn(E_UNSUPPORTED, "Unsupported: class extends"); // Member/meth access breaks VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - // if (nodep->childDTypep()) { - // nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern } - // } + // nodep->dtypep(iterateEditMoveDTypep(nodep)); // data_type '{ pattern } // userIterateChildren(nodep, NULL); } virtual void visit(AstMemberDType* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep)); // Iterate into subDTypep() to resolve that type and update pointer. - nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep())); + nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The member itself, not subDtype nodep->widthFromSub(nodep->subDTypep()); } @@ -2084,9 +2124,10 @@ private: } else if (basicp && basicp->isString()) { methodCallString(nodep, basicp); } else { - nodep->v3error("Unsupported: Member call on object '" - << nodep->fromp()->prettyTypeName() << "' which is a '" - << nodep->fromp()->dtypep()->prettyTypeName() << "'"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Member call on object '" + << nodep->fromp()->prettyTypeName() + << "' which is a '" + << nodep->fromp()->dtypep()->prettyTypeName() << "'"); } } void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) { @@ -2200,7 +2241,8 @@ private: if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad(); } if (adtypep->itemsp()->width() > 64 || msbdim >= (1 << 16)) { - nodep->v3error("Unsupported: enum next/prev method on enum with > 10 bits"); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: enum next/prev method on enum with > 10 bits"); return; } } @@ -2285,8 +2327,8 @@ private: void methodCallLValue(AstMethodCall* nodep, AstNode* childp, bool lvalue) { AstNodeVarRef* varrefp = VN_CAST(childp, NodeVarRef); if (!varrefp) { - nodep->v3error("Unsupported: Non-variable on LHS of built-in method '" - << nodep->prettyName() << "'"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-variable on LHS of built-in method '" + << nodep->prettyName() << "'"); } else { if (lvalue) varrefp->lvalue(true); } @@ -2315,8 +2357,8 @@ private: NULL); newp->makeStatement(); } else { - nodep->v3error("Unsupported/unknown built-in dynamic array method " - << nodep->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method " + << nodep->prettyNameQ()); } if (newp) { newp->didWidth(true); @@ -2360,8 +2402,9 @@ private: newp->didWidth(true); newp->makeStatement(); } else { - nodep->v3error("Unsupported: Queue .delete(index) method, as is O(n) " - "complexity and slow."); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Queue .delete(index) method, as is O(n) " + "complexity and slow."); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "erase", index_exprp->unlinkFrBack()); newp->protect(false); @@ -2380,7 +2423,8 @@ private: newp->protect(false); newp->makeStatement(); } else { - nodep->v3error( + nodep->v3warn( + E_UNSUPPORTED, "Unsupported: Queue .insert method, as is O(n) complexity and slow."); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), index_exprp->unlinkFrBack()); @@ -2407,8 +2451,8 @@ private: newp->protect(false); newp->makeStatement(); } else { - nodep->v3error("Unsupported/unknown built-in associative array method " - << nodep->prettyNameQ()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in associative array method " + << nodep->prettyNameQ()); } if (newp) { newp->didWidth(true); @@ -2671,16 +2715,17 @@ private: virtual void visit(AstPattern* nodep) VL_OVERRIDE { if (nodep->didWidthAndSet()) return; UINFO(9, "PATTERN " << nodep << endl); - if (nodep->childDTypep()) - nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern } + if (nodep->childDTypep()) { // data_type '{ pattern } + nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); + } if (!nodep->dtypep() && m_vup->dtypeNullp()) { // Get it from parent assignment/pin/etc nodep->dtypep(m_vup->dtypep()); } AstNodeDType* dtypep = nodep->dtypep(); if (!dtypep) { - nodep->v3error("Unsupported/Illegal: Assignment pattern" - " member not underneath a supported construct: " - << nodep->backp()->prettyTypeName()); + nodep->v3warn(E_UNSUPPORTED, "Unsupported/Illegal: Assignment pattern" + " member not underneath a supported construct: " + << nodep->backp()->prettyTypeName()); return; } { @@ -2737,9 +2782,10 @@ private: } else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) { VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep); } else { - nodep->v3error( + nodep->v3warn( + E_UNSUPPORTED, "Unsupported: Assignment pattern applies against non struct/union data type: " - << dtypep->prettyDTypeNameQ()); + << dtypep->prettyDTypeNameQ()); } } } @@ -3113,7 +3159,7 @@ private: if (AstBasicDType* basicp = nodep->rhsp()->dtypep()->basicp()) { if (basicp->isEventValue()) { // see t_event_copy.v for commentary on the mess involved - nodep->v3error("Unsupported: assignment of event data type"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type"); } } if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) { @@ -3442,15 +3488,17 @@ private: = VN_CAST(nodep->memp()->dtypep()->skipRefp(), UnpackArrayDType)) { subp = adtypep->subDTypep(); } else { - nodep->memp()->v3error("Unsupported: " - << nodep->verilogKwd() - << " into other than unpacked or associative array"); + nodep->memp()->v3warn(E_UNSUPPORTED, + "Unsupported: " + << nodep->verilogKwd() + << " into other than unpacked or associative array"); } if (subp && (!subp->skipRefp()->basicp() || !subp->skipRefp()->basicp()->keyword().isIntNumeric())) { - nodep->memp()->v3error("Unsupported: " << nodep->verilogKwd() - << " array values must be integral"); + nodep->memp()->v3warn(E_UNSUPPORTED, + "Unsupported: " << nodep->verilogKwd() + << " array values must be integral"); } userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p()); @@ -3546,11 +3594,12 @@ private: << conDTypep->prettyDTypeNameQ() << " data type." << endl); } else if (nodep->modVarp()->isTristate()) { if (pinwidth != conwidth) { - nodep->v3error("Unsupported: " << ucfirst(nodep->prettyOperatorName()) - << " to inout signal requires " << pinwidth - << " bits, but connection's " - << nodep->exprp()->prettyTypeName() - << " generates " << conwidth << " bits."); + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: " << ucfirst(nodep->prettyOperatorName()) + << " to inout signal requires " << pinwidth + << " bits, but connection's " + << nodep->exprp()->prettyTypeName() + << " generates " << conwidth << " bits."); // otherwise would need some mess to force both sides to proper size } } @@ -3646,11 +3695,14 @@ private: // Grab width from the output variable (if it's a function) if (nodep->didWidth()) return; if (nodep->doingWidth()) { - nodep->v3error("Unsupported: Recursive function or task call"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call"); nodep->dtypeSetLogicBool(); nodep->didWidth(true); return; } + if (nodep->isVirtual() || nodep->pureVirtual()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'virtual' class method"); + } // Function hasn't been widthed, so make it so. // Would use user1 etc, but V3Width called from too many places to spend a user nodep->doingWidth(true); @@ -3802,10 +3854,11 @@ private: << portp->prettyTypeName() << " but connection is " << pinp->prettyTypeName() << "."); } else if (portp->isWritable() && pinp->width() != portp->width()) { - pinp->v3error("Unsupported: Function output argument " - << portp->prettyNameQ() << " requires " << portp->width() - << " bits, but connection's " << pinp->prettyTypeName() - << " generates " << pinp->width() << " bits."); + pinp->v3warn(E_UNSUPPORTED, "Unsupported: Function output argument " + << portp->prettyNameQ() << " requires " + << portp->width() << " bits, but connection's " + << pinp->prettyTypeName() << " generates " + << pinp->width() << " bits."); // otherwise would need some mess to force both sides to proper size // (get an ASSIGN with EXTEND on the lhs instead of rhs) } @@ -4948,32 +5001,48 @@ private: //---------------------------------------------------------------------- // METHODS - data types - AstNodeDType* moveDTypeEdit(AstNode* nodep, AstNodeDType* dtnodep) { - // DTypes at parse time get added as a e.g. childDType to some node types such as AstVars. - // Move type to global scope, so removing/changing a variable won't lose the dtype. - UASSERT_OBJ(dtnodep, nodep, "Caller should check for NULL before calling moveDTypeEdit"); - UINFO(9, "moveDTypeEdit " << dtnodep << endl); - dtnodep->unlinkFrBack(); // Make non-child - v3Global.rootp()->typeTablep()->addTypesp(dtnodep); + AstNodeDType* iterateEditMoveDTypep(AstNode* parentp, AstNodeDType* dtnodep) { + UASSERT_OBJ(dtnodep, parentp, "Caller should check for NULL before computing dtype"); + // Iterate into a data type to resolve that type. + // The data type may either: + // 1. Be a child (typically getChildDTypep() returns it) + // DTypes at parse time get added as these to some node types + // such as AstVars. + // This function will move it to global scope (that is #2 + // will now apply). + // 2. Be under the Netlist and pointed to by an Ast member variable + // (typically refDTypep() or dtypep() returns it) + // so removing/changing a variable won't lose the dtype + + // Case #1 above applies? + bool child1 = (parentp->getChildDTypep() == dtnodep); + bool child2 = (parentp->getChild2DTypep() == dtnodep); + if (child1 || child2) { + UINFO(9, "iterateEditMoveDTypep child iterating " << dtnodep << endl); + // Iterate, this might edit the dtypes which means dtnodep now lost + VL_DO_DANGLING(userIterate(dtnodep, NULL), dtnodep); + // Figure out the new dtnodep, remained a child of parent so find it there + dtnodep = child1 ? parentp->getChildDTypep() : parentp->getChild2DTypep(); + UASSERT_OBJ(dtnodep, parentp, "iterateEditMoveDTypep lost pointer to child"); + UASSERT_OBJ(dtnodep->didWidth(), parentp, + "iterateEditMoveDTypep didn't get width resolution of " + << dtnodep->prettyTypeName()); + // Move to under netlist + UINFO(9, "iterateEditMoveDTypep child moving " << dtnodep << endl); + dtnodep->unlinkFrBack(); + v3Global.rootp()->typeTablep()->addTypesp(dtnodep); + } + if (!dtnodep->didWidth()) { + UINFO(9, "iterateEditMoveDTypep pointer iterating " << dtnodep << endl); + // See notes in visit(AstBracketArrayDType*) + UASSERT_OBJ(!VN_IS(dtnodep, BracketArrayDType), parentp, + "Brackets should have been iterated as children"); + userIterate(dtnodep, NULL); + UASSERT_OBJ(dtnodep->didWidth(), parentp, + "iterateEditMoveDTypep didn't get width resolution"); + } return dtnodep; } - AstNodeDType* moveChildDTypeEdit(AstNode* nodep) { - return moveDTypeEdit(nodep, nodep->getChildDTypep()); - } - AstNodeDType* iterateEditDTypep(AstNode* parentp, AstNodeDType* nodep) { - // Iterate into a data type to resolve that type. This process - // may eventually create a new data type, but not today - // it may make a new datatype, need subChildDType() to point to it; - // maybe we have user5p indicate a "replace me with" pointer. - // Need to be careful with "implicit" types though. - // - // Alternative is to have WidthVP return information. - // or have a call outside of normal visitor land. - // or have a m_return type (but need to return if width called multiple times) - UASSERT_OBJ(nodep, parentp, "Null dtype when widthing dtype"); - userIterate(nodep, NULL); - return nodep; - } AstConst* dimensionValue(FileLine* fileline, AstNodeDType* nodep, AstAttrType attrType, int dim) { diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 65eff9830..880b3bf80 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -276,7 +276,9 @@ private: } else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) { // SELBIT(string, index) -> GETC(string, index) AstNodeVarRef* varrefp = VN_CAST(fromp, NodeVarRef); - if (!varrefp) nodep->v3error("Unsupported: String array operation on non-variable"); + if (!varrefp) + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: String array operation on non-variable"); AstNode* newp; if (varrefp && varrefp->lvalue()) { newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp); @@ -499,7 +501,7 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { - nodep->v3error("Unsupported: Slice of non-constant bounds"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Slice of non-constant bounds"); } } else if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType) || (VN_IS(ddtypep, NodeUOrStructDType) diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 1ef486096..66800410b 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -104,6 +104,10 @@ static void process() { // Sort modules by level so later algorithms don't need to care V3LinkLevel::modSortByLevel(); V3Error::abortIfErrors(); + if (v3Global.opt.debugExitParse()) { + cout << "--debug-exit-parse: Exiting after parse\n"; + exit(0); + } // Convert parseref's to varrefs, and other directly post parsing fixups V3LinkParse::linkParse(v3Global.rootp()); @@ -580,20 +584,15 @@ static void verilate(const string& argString) { FileLine::deleteAllRemaining(); } -static void execBuildJob() { - UASSERT(v3Global.opt.build(), "--build is not specified."); - UASSERT(v3Global.opt.gmake(), "--build requires GNU Make."); - UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake."); - UINFO(1, "Start Build\n"); - +static string buildMakeCmd(const string& makefile, const string& target) { const V3StringList& makeFlags = v3Global.opt.makeFlags(); const int jobs = v3Global.opt.buildJobs(); UASSERT(jobs >= 0, "-j option parser in V3Options.cpp filters out negative value"); - std::stringstream cmd; + std::ostringstream cmd; cmd << v3Global.opt.getenvMAKE(); cmd << " -C " << v3Global.opt.makeDir(); - cmd << " -f " << v3Global.opt.prefix() << ".mk"; + cmd << " -f " << makefile; if (jobs == 0) { cmd << " -j"; } else if (jobs > 1) { @@ -602,8 +601,18 @@ static void execBuildJob() { for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) { cmd << ' ' << *it; } + if (!target.empty()) { cmd << ' ' << target; } - const std::string cmdStr = cmd.str(); + return cmd.str(); +} + +static void execBuildJob() { + UASSERT(v3Global.opt.build(), "--build is not specified."); + UASSERT(v3Global.opt.gmake(), "--build requires GNU Make."); + UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake."); + UINFO(1, "Start Build\n"); + + const string cmdStr = buildMakeCmd(v3Global.opt.prefix() + ".mk", ""); const int exit_code = V3Os::system(cmdStr); if (exit_code != 0) { v3error(cmdStr << " exitted with " << exit_code << std::endl); diff --git a/src/config_build.h.in b/src/config_build.h.in index 250ac1f96..f31046e03 100644 --- a/src/config_build.h.in +++ b/src/config_build.h.in @@ -80,7 +80,7 @@ using std::make_pair; // Define if SystemC found // - If defined, the default search path has it, so support is always enabled. // - If undef, not system-wide, user can set SYSTEMC_INCLUDE. -#undef HAVE_SYSTEMC_H +#undef HAVE_SYSTEMC //********************************************************************** //**** OS and compiler specifics diff --git a/src/verilog.l b/src/verilog.l index 6635286ac..c309be3fd 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -13,73 +13,61 @@ * SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 * *************************************************************************/ +/* clang-format off */ %option interactive c++ stack noyywrap %{ /* %option nodefault */ +#ifdef NEVER_JUST_FOR_CLANG_FORMAT + } +#endif +// clang-format on #include "V3Number.h" #include "V3ParseImp.h" // Defines YYTYPE; before including bison header #include "V3ParseBison.h" // Generated by bison -extern void yyerror(const char*); -extern void yyerrorf(const char* format, ...); - #define STATE_VERILOG_RECENT S17 // State name for most recent Verilog Version #define PARSEP V3ParseImp::parsep() -#define SYMP PARSEP->symp() #define YY_INPUT(buf, result, max_size) \ - do { result = PARSEP->flexPpInputToLex(buf, max_size); } while (false) + do { result = PARSEP->flexPpInputToLex(buf, max_size); } while (false) //====================================================================== -#define FL_FWD (PARSEP->fileline()->forwardToken(yytext, yyleng, true)) +#define FL_FWD (PARSEP->lexFileline()->forwardToken(yytext, yyleng, true)) // Use this to break between tokens whereever not return'ing a token (e.g. skipping inside lexer) -#define FL_BRK (PARSEP->fileline()->startToken()) +#define FL_BRK (PARSEP->lexFileline()->startToken()) -#define CRELINE() (PARSEP->copyOrSameFileLine()) +#define CRELINE() (PARSEP->lexCopyOrSameFileLine()) -#define FL do { FL_FWD; yylval.fl = CRELINE(); } while (false) +#define FL \ + do { \ + FL_FWD; \ + yylval.fl = CRELINE(); \ + } while (false) #define ERROR_RSVD_WORD(language) \ - do { FL_FWD; \ - yyerrorf("Unsupported: " language " reserved word not implemented: '%s'", yytext); \ - FL_BRK; } while(0) + do { \ + FL; \ + yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: " << language \ + << " reserved word not implemented: '" \ + << yytext << "'"); \ + FL_BRK; \ + } while (0) //====================================================================== -void yyerror(const char* errmsg) { - PARSEP->fileline()->v3error(errmsg); - static const char* const colonmsg = "syntax error, unexpected ::, "; - // tokens; - if (0 == strncmp(errmsg, colonmsg, strlen(colonmsg)) - && PARSEP->prevBisonVal().token == yaID__ETC - && PARSEP->curBisonVal().token == yP_COLONCOLON) { - static int warned = false; - if (!warned++) { - std::cerr << PARSEP->fileline()->warnMore() - << ("... Perhaps '" + *PARSEP->prevBisonVal().strp - + "' is a package which needs to be predeclared? (IEEE 1800-2017 26.3)") - << std::endl; - } - } -} - -void yyerrorf(const char* format, ...) { - const int maxlen = 2000; - char msg[maxlen]; - - va_list ap; - va_start(ap, format); - VL_VSNPRINTF(msg, maxlen, format, ap); - msg[maxlen - 1] = '\0'; - va_end(ap); - - yyerror(msg); +static double lexParseDouble(FileLine* fl, const char* textp, size_t length) { + string text = std::string(textp, length); + bool success = false; + double d = VString::parseDouble(text, &success); + if (!success) fl->v3error("Syntax error parsing real: '" << textp << "'"); + return d; } +// clang-format off /**********************************************************************/ %} @@ -181,6 +169,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$atanh" { FL; return yD_ATANH; } "$bitstoreal" { FL; return yD_BITSTOREAL; } "$bitstoshortreal" { FL; return yD_BITSTOSHORTREAL; } + "$cast" { FL; return yD_CAST; } "$ceil" { FL; return yD_CEIL; } "$cos" { FL; return yD_COS; } "$cosh" { FL; return yD_COSH; } @@ -276,6 +265,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$writeb" { FL; return yD_WRITEB; } "$writeh" { FL; return yD_WRITEH; } "$writeo" { FL; return yD_WRITEO; } + "$writememb" { FL; return yD_WRITEMEMB; } "$writememh" { FL; return yD_WRITEMEMH; } /* Keywords */ "always" { FL; return yALWAYS; } @@ -301,7 +291,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "endmodule" { FL; return yENDMODULE; } "endprimitive" { FL; return yENDPRIMITIVE; } "endspecify" { FL; return yENDSPECIFY; } - "endtable" { FL_FWD; yyerrorf("Syntax error: ENDTABLE outside of TABLE"); FL_BRK; } + "endtable" { FL; yylval.fl->v3error("Syntax error: ENDTABLE outside of TABLE"); FL_BRK; } "endtask" { FL; return yENDTASK; } "event" { FL; return yEVENT; } "for" { FL; return yFOR; } @@ -406,7 +396,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "design" { ERROR_RSVD_WORD("Verilog 2001-config"); } "endconfig" { ERROR_RSVD_WORD("Verilog 2001-config"); } "incdir" { ERROR_RSVD_WORD("Verilog 2001-config"); } - "include" { FL_FWD; yyerrorf("Unsupported: Verilog 2001-config reserved word not implemented; suggest you want `include instead: %s", yytext); FL_BRK; } + "include" { FL; yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 2001-config reserved word not implemented;" + " suggest you want `include instead: '" << yytext << "'"); + FL_BRK; } "instance" { ERROR_RSVD_WORD("Verilog 2001-config"); } "liblist" { ERROR_RSVD_WORD("Verilog 2001-config"); } "library" { ERROR_RSVD_WORD("Verilog 2001-config"); } @@ -446,6 +438,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; } "$warning" { FL; return yD_WARNING; } /* SV2005 Keywords */ + /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */ "$unit" { FL; return yD_UNIT; } /* Yes, a keyword, not task */ "alias" { FL; return yALIAS; } "always_comb" { FL; return yALWAYS_COMB; } @@ -453,7 +446,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "always_latch" { FL; return yALWAYS_LATCH; } "assert" { FL; return yASSERT; } "assume" { FL; return yASSUME; } + "before" { FL; return yBEFORE; } "bind" { FL; return yBIND; } + "bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "binsof" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "bit" { FL; return yBIT; } "break" { FL; return yBREAK; } "byte" { FL; return yBYTE; } @@ -461,32 +457,45 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "class" { FL; return yCLASS; } "clocking" { FL; return yCLOCKING; } "const" { FL; return yCONST__LEX; } + "constraint" { FL; return yCONSTRAINT; } "context" { FL; return yCONTEXT; } "continue" { FL; return yCONTINUE; } "cover" { FL; return yCOVER; } + "covergroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "coverpoint" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "cross" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "dist" { FL; return yDIST; } "do" { FL; return yDO; } "endclass" { FL; return yENDCLASS; } "endclocking" { FL; return yENDCLOCKING; } + "endgroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "endinterface" { FL; return yENDINTERFACE; } "endpackage" { FL; return yENDPACKAGE; } "endprogram" { FL; return yENDPROGRAM; } "endproperty" { FL; return yENDPROPERTY; } + "endsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "enum" { FL; return yENUM; } + "expect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "export" { FL; return yEXPORT; } "extends" { FL; return yEXTENDS; } "extern" { FL; return yEXTERN; } "final" { FL; return yFINAL; } + "first_match" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "forkjoin" { FL; return yFORKJOIN; } "iff" { FL; return yIFF; } + "ignore_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "illegal_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "import" { FL; return yIMPORT; } "inside" { FL; return yINSIDE; } "int" { FL; return yINT; } "interface" { FL; return yINTERFACE; } + "intersect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "join_any" { FL; return yJOIN_ANY; } "join_none" { FL; return yJOIN_NONE; } "local" { FL; return yLOCAL__LEX; } "logic" { FL; return yLOGIC; } "longint" { FL; return yLONGINT; } + "matches" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "modport" { FL; return yMODPORT; } "new" { FL; return yNEW__LEX; } "null" { FL; return yNULL; } @@ -500,16 +509,22 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "rand" { FL; return yRAND; } "randc" { FL; return yRANDC; } "randcase" { FL; return yRANDCASE; } + "randomize" { FL; return yRANDOMIZE; } + "randsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "ref" { FL; return yREF; } "restrict" { FL; return yRESTRICT; } "return" { FL; return yRETURN; } + "sequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "shortint" { FL; return ySHORTINT; } "shortreal" { FL; return ySHORTREAL; } - "static" { FL; return ySTATIC__ETC; } + "solve" { FL; return ySOLVE; } + "static" { FL; return ySTATIC__LEX; } "string" { FL; return ySTRING; } "struct" { FL; return ySTRUCT; } "super" { FL; return ySUPER; } + "tagged" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "this" { FL; return yTHIS; } + "throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "timeprecision" { FL; return yTIMEPRECISION; } "timeunit" { FL; return yTIMEUNIT; } "type" { FL; return yTYPE; } @@ -519,46 +534,20 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "var" { FL; return yVAR; } "virtual" { FL; return yVIRTUAL__LEX; } "void" { FL; return yVOID; } - /* Generic unsupported warnings */ - /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */ - "before" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "binsof" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "constraint" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "covergroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "coverpoint" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "cross" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "dist" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "endgroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "endsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "expect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "first_match" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "ignore_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "illegal_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "intersect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "matches" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "randomize" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "randsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "sequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "solve" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "tagged" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "wait_order" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "wildcard" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "with" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "with" { FL; return yWITH__LEX; } "within" { ERROR_RSVD_WORD("SystemVerilog 2005"); } } /* SystemVerilog 2009 */ { /* Keywords */ - "global" { FL; return yGLOBAL__LEX; } - "unique0" { FL; return yUNIQUE0; } - /* Generic unsupported warnings */ "accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "checker" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "endchecker" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "eventually" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "global" { FL; return yGLOBAL__LEX; } "implies" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "let" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "nexttime" { ERROR_RSVD_WORD("SystemVerilog 2009"); } @@ -571,6 +560,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "strong" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "sync_accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "sync_reject_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "unique0" { FL; return yUNIQUE0; } "until" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "until_with" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "untyped" { ERROR_RSVD_WORD("SystemVerilog 2009"); } @@ -583,7 +573,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "implements" { FL; return yIMPLEMENTS; } "interconnect" { ERROR_RSVD_WORD("SystemVerilog 2012"); } "nettype" { ERROR_RSVD_WORD("SystemVerilog 2012"); } - "soft" { ERROR_RSVD_WORD("SystemVerilog 2012"); } + "soft" { FL; return ySOFT; } } /* System Verilog 2017 */ @@ -697,10 +687,18 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { "/*verilator"{ws}*"*/" { FL_FWD; FL_BRK; } /* Ignore empty comments, may be `endif // verilator */ "/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; } + "/*verilator clocker*/" { FL; return yVL_CLOCKER; } "/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; } + "/*verilator coverage_off*/" { FL_FWD; PARSEP->lexFileline()->coverageOn(false); FL_BRK; } + "/*verilator coverage_on*/" { FL_FWD; PARSEP->lexFileline()->coverageOn(true); FL_BRK; } "/*verilator full_case*/" { FL; return yVL_FULL_CASE; } "/*verilator inline_module*/" { FL; return yVL_INLINE_MODULE; } "/*verilator isolate_assignments*/" { FL; return yVL_ISOLATE_ASSIGNMENTS; } + "/*verilator lint_off"[^*]*"*/" { FL; PARSEP->lexVerilatorCmtLint(yylval.fl, yytext, true); FL_BRK; } + "/*verilator lint_on"[^*]*"*/" { FL; PARSEP->lexVerilatorCmtLint(yylval.fl, yytext, false); FL_BRK; } + "/*verilator lint_restore*/" { FL; PARSEP->lexVerilatorCmtLintRestore(PARSEP->lexFileline()); FL_BRK; } + "/*verilator lint_save*/" { FL; PARSEP->lexVerilatorCmtLintSave(PARSEP->lexFileline()); FL_BRK; } + "/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; } "/*verilator no_inline_module*/" { FL; return yVL_NO_INLINE_MODULE; } "/*verilator no_inline_task*/" { FL; return yVL_NO_INLINE_TASK; } "/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; } @@ -709,25 +707,18 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; } "/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc "/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; } - "/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; } - "/*verilator sc_clock*/" { FL; return yVL_CLOCK; } - "/*verilator clocker*/" { FL; return yVL_CLOCKER; } - "/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; } "/*verilator sc_bv*/" { FL; return yVL_SC_BV; } + "/*verilator sc_clock*/" { FL; return yVL_CLOCK; } "/*verilator sformat*/" { FL; return yVL_SFORMAT; } + "/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; } "/*verilator systemc_clock*/" { FL; return yVL_CLOCK; } - "/*verilator tracing_off*/" { FL_FWD; PARSEP->fileline()->tracingOn(false); FL_BRK; } - "/*verilator tracing_on*/" { FL_FWD; PARSEP->fileline()->tracingOn(true); FL_BRK; } - "/*verilator coverage_off*/" { FL_FWD; PARSEP->fileline()->coverageOn(false); FL_BRK; } - "/*verilator coverage_on*/" { FL_FWD; PARSEP->fileline()->coverageOn(true); FL_BRK; } - "/*verilator lint_off"[^*]*"*/" { FL_FWD; PARSEP->verilatorCmtLint(yytext, true); FL_BRK; } - "/*verilator lint_on"[^*]*"*/" { FL_FWD; PARSEP->verilatorCmtLint(yytext, false); FL_BRK; } - "/*verilator lint_restore*/" { FL_FWD; PARSEP->verilatorCmtLintRestore(); FL_BRK; } - "/*verilator lint_save*/" { FL_FWD; PARSEP->verilatorCmtLintSave(); FL_BRK; } - "/*verilator tag"[^*]*"*/" { FL_FWD; PARSEP->tag(yytext); FL_BRK; } + "/*verilator tag"[^*]*"*/" { FL; yylval.strp = PARSEP->newString(V3ParseImp::lexParseTag(yytext)); + return yVL_TAG; } + "/*verilator tracing_off*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(false); FL_BRK; } + "/*verilator tracing_on*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(true); FL_BRK; } "/**/" { FL_FWD; FL_BRK; } - "/*"[^*]+"*/" { FL_FWD; PARSEP->verilatorCmtBad(yytext); FL_BRK; } + "/*"[^*]+"*/" { FL; V3ParseImp::lexVerilatorCmtBad(yylval.fl, yytext); FL_BRK; } } /************************************************************************/ @@ -797,7 +788,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "-:" { FL; return yP_MINUSCOLON; } ".*" { FL; return yP_DOTSTAR; } ":+" { FL; yyless(1); - PARSEP->fileline()->v3warn(COLONPLUS, "Perhaps instead of ':+' the intent was '+:'?"); + yylval.fl->v3warn(COLONPLUS, "Perhaps instead of ':+' the intent was '+:'?"); return ':'; } } @@ -855,12 +846,12 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} \" { yy_push_state(STRING); yymore(); } {vnum} { /* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */ - if (PARSEP->prevLexToken()=='#') { + if (PARSEP->lexPrevToken()=='#') { int shortlen = 0; while (isdigit(yytext[shortlen])) shortlen++; if (shortlen) { // Push rest past numbers for later parse - PARSEP->unputString(yytext+shortlen, yyleng-shortlen); + PARSEP->lexUnputString(yytext+shortlen, yyleng-shortlen); // Return is stuff before the tick yyleng = shortlen; yytext[yyleng] = '\0'; @@ -876,15 +867,15 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} return yaINTNUM; } [0-9][_0-9]*(\.[_0-9]+)([eE][-+]?[_0-9]+)? { - FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng); + FL; yylval.cdouble = lexParseDouble(yylval.fl, yytext, yyleng); return yaFLOATNUM; } [0-9][_0-9]*(\.[_0-9]+)?([eE][-+]?[_0-9]+) { - FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng); + FL; yylval.cdouble = lexParseDouble(yylval.fl, yytext, yyleng); return yaFLOATNUM; } [0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s) { - FL; yylval.cdouble = PARSEP->parseTimenum(yytext); + FL; yylval.cdouble = V3ParseImp::lexParseTimenum(yytext); return yaTIMENUM; } 1step { @@ -895,9 +886,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /************************************************************************/ /* STRINGS */ -<> { FL_FWD; yyerrorf("EOF in unterminated string"); +<> { FL; yylval.fl->v3error("EOF in unterminated string"); yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } -{crnl} { FL_FWD; yyerrorf("Unterminated string"); FL_BRK; } +{crnl} { FL; yylval.fl->v3error("Unterminated string"); + FL_BRK; } \\{crnl} { yymore(); } \\. { yymore(); } \" { yy_pop_state(); @@ -912,7 +904,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "*)" { FL_FWD; yy_pop_state(); FL_BRK; } {word} { yymore(); } . { yymore(); } -<> { FL_FWD; yyerrorf("EOF in (*"); +<> { FL; yylval.fl->v3error("EOF in (*"); yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } /************************************************************************/ @@ -928,9 +920,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} {crnl} { yymore(); }
";" { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLELINE; }
"endtable" { yy_pop_state(); FL; return yENDTABLE; } -
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->ppline(yytext); FL_BRK; } +
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; }
. { yymore(); } -
<> { FL_FWD; yyerrorf("EOF in TABLE"); +
<> { FL; yylval.fl->v3error("EOF in TABLE"); yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); } /************************************************************************/ @@ -941,58 +933,62 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { "`accelerate" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`autoexpand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`celldefine" { FL_FWD; PARSEP->inCellDefine(true); FL_BRK; } + "`celldefine" { FL_FWD; PARSEP->lexFileline()->celldefineOn(true); FL_BRK; } "`default_decay_time"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog spec - delays only - "`default_nettype"{ws}+"wire" { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; } - "`default_nettype"{ws}+"none" { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; } - "`default_nettype"{ws}+[a-zA-Z0-9]* { FL_FWD; yyerrorf("Unsupported: `default_nettype of other than none or wire: %s", yytext); FL_BRK; } - "`default_trireg_strength"{ws}+[^\n\r]* { FL_FWD; yyerrorf("Unsupported: Verilog optional directive not implemented: %s", yytext); FL_BRK; } + "`default_nettype"{ws}+"wire" { FL_FWD; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; } + "`default_nettype"{ws}+"none" { FL_FWD; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; } + "`default_nettype"{ws}+[a-zA-Z0-9]* { FL; yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: `default_nettype of other than none or wire: '" + << yytext << "'"); + FL_BRK; } + "`default_trireg_strength"{ws}+[^\n\r]* { FL; yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: Verilog optional directive not implemented: '" + << yytext << "'"); + FL_BRK; } "`delay_mode_distributed" { FL_FWD; FL_BRK; } // Verilog spec - delays only "`delay_mode_path" { FL_FWD; FL_BRK; } // Verilog spec - delays only "`delay_mode_unit" { FL_FWD; FL_BRK; } // Verilog spec - delays only "`delay_mode_zero" { FL_FWD; FL_BRK; } // Verilog spec - delays only "`disable_portfaults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`enable_portfaults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`endcelldefine" { FL_FWD; PARSEP->inCellDefine(false); FL_BRK; } + "`endcelldefine" { FL_FWD; PARSEP->lexFileline()->celldefineOn(false); FL_BRK; } "`endprotect" { FL_FWD; FL_BRK; } "`expand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`inline" { FL_FWD; FL_BRK; } - "`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->ppline(yytext); FL_BRK; } + "`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; } "`noaccelerate" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`noexpand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`noremove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`noremove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`nosuppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`nounconnected_drive" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); FL_BRK; } + "`nounconnected_drive" { FL; return yaT_NOUNCONNECTED; } "`portcoerce" { FL_FWD; FL_BRK; } "`pragma"{ws}*[^\n\r]* { FL_FWD; FL_BRK; } // Verilog 2005 "`protect" { FL_FWD; FL_BRK; } "`remove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`remove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`resetall" { FL; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); + "`resetall" { FL; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility - "`timescale"{ws}+[^\n\r]* { FL_FWD; PARSEP->timescalePreproc(PARSEP->fileline(), - yytext + strlen("`timescale")); + "`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl, + yytext + strlen("`timescale")); FL_BRK; } - "`unconnected_drive"{ws}+"pull0" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); FL_BRK; } - "`unconnected_drive"{ws}+"pull1" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); FL_BRK; } - "`unconnected_drive" { FL_FWD; yyerrorf("Bad `unconnected_drive syntax"); FL_BRK; } + "`unconnected_drive"{ws}+"pull0" { FL; return yaT_UNCONNECTED_PULL0; } + "`unconnected_drive"{ws}+"pull1" { FL; return yaT_UNCONNECTED_PULL1; } + "`unconnected_drive" { FL; yylval.fl->v3error("Bad `unconnected_drive syntax"); FL_BRK; } "`uselib"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog-XL compatibility /* See also setLanguage below */ - "`begin_keywords"[ \t]*\"1364-1995\" { FL_FWD; yy_push_state(V95); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1364-2001\" { FL_FWD; yy_push_state(V01); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1364-2001-noconfig\" { FL_FWD; yy_push_state(V01); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1364-2005\" { FL_FWD; yy_push_state(V05); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"VAMS[-0-9.]*\" { FL_FWD; yy_push_state(VA5); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1800-2005\" { FL_FWD; yy_push_state(S05); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1800-2009\" { FL_FWD; yy_push_state(S09); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1800-2012\" { FL_FWD; yy_push_state(S12); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1800-2017\" { FL_FWD; yy_push_state(S17); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } - "`begin_keywords"[ \t]*\"1800[+]VAMS\" { FL_FWD; yy_push_state(SAX); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } /*Latest SV*/ - "`end_keywords" { FL_FWD; yy_pop_state(); - if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block"); + "`begin_keywords"[ \t]*\"1364-1995\" { FL_FWD; yy_push_state(V95); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1364-2001\" { FL_FWD; yy_push_state(V01); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1364-2001-noconfig\" { FL_FWD; yy_push_state(V01); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1364-2005\" { FL_FWD; yy_push_state(V05); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"VAMS[-0-9.]*\" { FL_FWD; yy_push_state(VA5); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1800-2005\" { FL_FWD; yy_push_state(S05); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1800-2009\" { FL_FWD; yy_push_state(S09); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1800-2012\" { FL_FWD; yy_push_state(S12); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1800-2017\" { FL_FWD; yy_push_state(S17); PARSEP->lexPushKeywords(YY_START); FL_BRK; } + "`begin_keywords"[ \t]*\"1800[+]VAMS\" { FL_FWD; yy_push_state(SAX); PARSEP->lexPushKeywords(YY_START); FL_BRK; } /*Latest SV*/ + "`end_keywords" { FL; yy_pop_state(); + if (!PARSEP->lexPopKeywords()) yylval.fl->v3error("`end_keywords when not inside `begin_keywords block"); FL_BRK; } /* Verilator */ @@ -1003,12 +999,12 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "`systemc_implementation" { FL_FWD; BEGIN SYSCIMP; FL_BRK; } "`systemc_interface" { FL_FWD; BEGIN SYSCINT; FL_BRK; } "`verilator_config" { FL_FWD; BEGIN VLT; FL_BRK; } - "`verilog" { FL_FWD; BEGIN PARSEP->lastVerilogState(); FL_BRK; } + "`verilog" { FL_FWD; BEGIN PARSEP->lexKwdLastState(); FL_BRK; } /* Errors */ - "<<<<<<<"[^\n\r]* { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; } - "======="[^\n\r]* { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; } - ">>>>>>>"[^\n\r]* { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; } + "<<<<<<<"[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; } + "======="[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; } + ">>>>>>>"[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; } /* If add to this list also add to V3LanguageWords.h */ } @@ -1031,157 +1027,17 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* Default rules - leave last */ { - "`"[a-zA-Z_0-9]+ { FL_FWD; PARSEP->errorPreprocDirective(yytext); FL_BRK; } + "`"[a-zA-Z_0-9]+ { FL; V3ParseImp::lexErrorPreprocDirective(yylval.fl, yytext); FL_BRK; } "//"[^\n]* { FL_FWD; FL_BRK; } /* throw away single line comments */ . { FL; return yytext[0]; } /* return single char ops. */ } /* Catch all - absolutely last */ -<*>.|\n { FL_FWD; yyerrorf("Missing verilog.l rule: Default rule invoked in state %d: %s", YY_START, yytext); FL_BRK; } +<*>.|\n { FL; yylval.fl->v3error("Missing verilog.l rule: Default rule invoked in state " + << YY_START << " '" << yytext << "'"); + FL_BRK; } %% +// Avoid code here as cl format misindents +// For implementation functions see V3ParseImp.cpp int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; } - -void V3ParseImp::lexToken() { - // called from lexToBison, has a "this" - // Fetch next token from prefetch or real lexer - int token; - if (m_ahead) { - // We prefetched an extra token, give it back - m_ahead = false; - token = m_aheadVal.token; - yylval = m_aheadVal; - } else { - // Parse new token - token = yylexReadTok(); - // yylval // Set by yylexReadTok() - } - // If a paren, read another - if (token == '(' // - || token == yCONST__LEX // - || token == yGLOBAL__LEX // - || token == yLOCAL__LEX // - || token == yNEW__LEX // - || token == yVIRTUAL__LEX - // Never put yID_* here; below symbol table resolution would break - ) { - if (debugFlex() >= 6) { - cout << " lexToken: reading ahead to find possible strength" << endl; - } - V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead - int nexttok = yylexReadTok(); - m_ahead = true; - m_aheadVal = yylval; - m_aheadVal.token = nexttok; - yylval = curValue; - // Now potentially munge the current token - if (token == '(' - && (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) { - token = yP_PAR__STRENGTH; - } else if (token == yCONST__LEX) { - if (nexttok == yREF) { - token = yCONST__REF; - } else { - token = yCONST__ETC; - } - } else if (token == yGLOBAL__LEX) { - if (nexttok == yCLOCKING) { - token = yGLOBAL__CLOCKING; - } else if (v3Global.opt.pedantic()) { - token = yGLOBAL__ETC; - } - // Avoid 2009 "global" conflicting with old code when we can - else { - token = yaID__LEX; - yylval.strp = PARSEP->newString("global"); - } - } else if (token == yLOCAL__LEX) { - if (nexttok == yP_COLONCOLON) { - token = yLOCAL__COLONCOLON; - } else { - token = yLOCAL__ETC; - } - } else if (token == yNEW__LEX) { - if (nexttok == '(') { - token = yNEW__PAREN; - } else { - token = yNEW__ETC; - } - } else if (token == yVIRTUAL__LEX) { - if (nexttok == yCLASS) { - token = yVIRTUAL__CLASS; - } else if (nexttok == yINTERFACE) { - token = yVIRTUAL__INTERFACE; - } else if (nexttok == yaID__ETC // - || nexttok == yaID__LEX) { - // || nexttok == yaID__aINTERFACE // but we may not know interfaces yet. - token = yVIRTUAL__anyID; - } else { - token = yVIRTUAL__ETC; - } - } - // If add to above "else if", also add to "if (token" further above - } - // If an id, change the type based on symbol table - // Note above sometimes converts yGLOBAL to a yaID__LEX - if (token == yaID__LEX) { - VSymEnt* foundp; - if (VSymEnt* look_underp = SYMP->nextId()) { - UINFO(7, " lexToken: next id lookup forced under " << look_underp << endl); - foundp = look_underp->findIdFallback(*(yylval.strp)); - // "consume" it. Must set again if want another token under temp scope - SYMP->nextId(NULL); - } else { - UINFO(7, " lexToken: find upward " << SYMP->symCurrentp() << " for '" - << *(yylval.strp) << "'" << endl); - // if (debug()>=9) SYMP->symCurrentp()->dump(cout," -findtree: ", true); - foundp = SYMP->symCurrentp()->findIdFallback(*(yylval.strp)); - } - if (foundp) { - AstNode* scp = foundp->nodep(); - yylval.scp = scp; - UINFO(7, " lexToken: Found " << scp << endl); - if (VN_IS(scp, Typedef)) { - token = yaID__aTYPE; - } else if (VN_IS(scp, TypedefFwd)) { - token = yaID__aTYPE; - } else if (VN_IS(scp, Class)) { - token = yaID__aTYPE; - } - // Packages (and class static references) we could - // alternatively determine by looking for an yaID__LEX followed - // by yP_COLONCOLON (but we can't lookahead after an yaID__LEX - // as described above.) - else if (VN_IS(scp, Package)) { - token = yaID__aPACKAGE; - } else { - token = yaID__ETC; - } - } else { // Not found - yylval.scp = NULL; - token = yaID__ETC; - } - } - yylval.token = token; - // effectively returns yylval -} - -int V3ParseImp::lexToBison() { - // Called as global since bison doesn't have our pointer - lexToken(); // sets yylval - m_prevBisonVal = m_curBisonVal; - m_curBisonVal = yylval; - - // yylval.scp = NULL; // Symbol table not yet needed - no packages - if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison - cout << " {" << yylval.fl->filenameLetters() << yylval.fl->asciiLineCol() - << "} lexToBison TOKEN=" << yylval.token << " " << tokenName(yylval.token); - if (yylval.token == yaID__ETC // - || yylval.token == yaID__LEX // - || yylval.token == yaID__aTYPE) { - cout << " strp='" << *(yylval.strp) << "'"; - } - cout << endl; - } - return yylval.token; -} diff --git a/src/verilog.y b/src/verilog.y index 96ce8a826..fa324cdfa 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -15,8 +15,13 @@ //************************************************************************* // Original code here by Paul Wasson and Duane Galbi //************************************************************************* +// clang-format off %{ +#ifdef NEVER_JUST_FOR_CLANG_FORMAT + } +#endif +// clang-format on #include "V3Ast.h" #include "V3Global.h" #include "V3Config.h" @@ -24,18 +29,17 @@ #include #include +#include -#define YYERROR_VERBOSE 1 -#define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH +#define YYERROR_VERBOSE 1 // For prior to Bison 3.6 +#define YYINITDEPTH 10000 // Older bisons ignore YYMAXDEPTH #define YYMAXDEPTH 10000 // Pick up new lexer -#define yylex PARSEP->lexToBison -#define BBUNSUP(fl,msg) { if (!v3Global.opt.bboxUnsup()) { (fl)->v3error(msg); } } -#define GATEUNSUP(fl,tok) { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: "<<(tok)); } - -extern void yyerror(const char* errmsg); -extern void yyerrorf(const char* format, ...); +#define yylex PARSEP->tokenToBison +#define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) +#define GATEUNSUP(fl, tok) \ + { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } //====================================================================== // Statics (for here only) @@ -46,72 +50,78 @@ extern void yyerrorf(const char* format, ...); class V3ParseGrammar { public: - bool m_impliedDecl; // Allow implied wire declarations - AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc) - bool m_varDeclTyped; // Var got reg/wire for dedup check - VDirection m_varIO; // Direction for next signal declaration (reg/wire/etc) - VLifetime m_varLifetime; // Static/Automatic for next signal - AstVar* m_varAttrp; // Current variable for attribute adding - AstRange* m_gateRangep; // Current range for gate declarations - AstCase* m_caseAttrp; // Current case statement for attribute adding - AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration - AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration - AstNodeModule* m_modp; // Last module for timeunits - bool m_pinAnsi; // In ANSI port list - int m_pinNum; // Pin number currently parsing - FileLine* m_instModuleFl; // Fileline of module referenced for instantiations - string m_instModule; // Name of module referenced for instantiations - AstPin* m_instParamp; // Parameters for instantiations - bool m_tracingParse; // Tracing disable for parser + bool m_impliedDecl; // Allow implied wire declarations + AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc) + bool m_varDeclTyped; // Var got reg/wire for dedup check + VDirection m_varIO; // Direction for next signal declaration (reg/wire/etc) + VLifetime m_varLifetime; // Static/Automatic for next signal + AstVar* m_varAttrp; // Current variable for attribute adding + AstRange* m_gateRangep; // Current range for gate declarations + AstCase* m_caseAttrp; // Current case statement for attribute adding + AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration + AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration + AstNodeModule* m_modp; // Last module for timeunits + bool m_pinAnsi; // In ANSI port list + FileLine* m_instModuleFl; // Fileline of module referenced for instantiations + string m_instModule; // Name of module referenced for instantiations + AstPin* m_instParamp; // Parameters for instantiations + bool m_tracingParse; // Tracing disable for parser - static int s_modTypeImpNum; // Implicit type number, incremented each module + int m_pinNum; // Pin number currently parsing + std::stack m_pinStack; // Queue of pin numbers being parsed + + static int s_modTypeImpNum; // Implicit type number, incremented each module // CONSTRUCTORS V3ParseGrammar() { - m_impliedDecl = false; - m_varDecl = AstVarType::UNKNOWN; + m_impliedDecl = false; + m_varDecl = AstVarType::UNKNOWN; m_varDeclTyped = false; - m_varIO = VDirection::NONE; - m_varDTypep = NULL; - m_gateRangep = NULL; - m_memDTypep = NULL; - m_modp = NULL; - m_pinAnsi = false; - m_pinNum = -1; - m_instModuleFl = NULL; - m_instModule = ""; - m_instParamp = NULL; - m_varAttrp = NULL; - m_caseAttrp = NULL; - m_tracingParse = true; + m_varIO = VDirection::NONE; + m_varDTypep = NULL; + m_gateRangep = NULL; + m_memDTypep = NULL; + m_modp = NULL; + m_pinAnsi = false; + m_pinNum = -1; + m_instModuleFl = NULL; + m_instModule = ""; + m_instParamp = NULL; + m_varAttrp = NULL; + m_caseAttrp = NULL; + m_tracingParse = true; } static V3ParseGrammar* singletonp() { - static V3ParseGrammar singleton; - return &singleton; + static V3ParseGrammar singleton; + return &singleton; } // METHODS AstNode* argWrapList(AstNode* nodep); bool allTracingOn(FileLine* fl) { - return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); + return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); } AstRange* scrubRange(AstNodeRange* rangep); AstNodeDType* createArray(AstNodeDType* basep, AstNodeRange* rangep, bool isPacked); - AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, AstNode* attrsp); + AstVar* createVariable(FileLine* fileline, const string& name, AstNodeRange* arrayp, + AstNode* attrsp); AstNode* createSupplyExpr(FileLine* fileline, const string& name, int value); AstText* createTextQuoted(FileLine* fileline, const string& text) { - string newtext = deQuote(fileline, text); - return new AstText(fileline, newtext); + string newtext = deQuote(fileline, text); + return new AstText(fileline, newtext); } AstDisplay* createDisplayError(FileLine* fileline) { - AstDisplay* nodep = new AstDisplay(fileline, AstDisplayType::DT_ERROR, "", NULL, NULL); - nodep->addNext(new AstStop(fileline, true)); - return nodep; + AstDisplay* nodep = new AstDisplay(fileline, AstDisplayType::DT_ERROR, "", NULL, NULL); + nodep->addNext(new AstStop(fileline, true)); + return nodep; } AstNode* createGatePin(AstNode* exprp) { - AstRange* rangep = m_gateRangep; - if (!rangep) return exprp; - else return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true)); + AstRange* rangep = m_gateRangep; + if (!rangep) { + return exprp; + } else { + return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true)); + } } void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { endLabel(fl, nodep->prettyName(), endnamep); @@ -119,34 +129,44 @@ public: void endLabel(FileLine* fl, const string& name, string* endnamep) { if (fl && endnamep && *endnamep != "" && name != *endnamep && name != AstNode::prettyName(*endnamep)) { - fl->v3warn(ENDLABEL,"End label '"<<*endnamep<<"' does not match begin label '"<v3warn(ENDLABEL, "End label '" << *endnamep << "' does not match begin label '" + << name << "'"); } } void setVarDecl(AstVarType type) { m_varDecl = type; } void setDType(AstNodeDType* dtypep) { - if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep=NULL); // It was cloned, so this is safe. - m_varDTypep = dtypep; + if (m_varDTypep) VL_DO_CLEAR(m_varDTypep->deleteTree(), m_varDTypep = NULL); + m_varDTypep = dtypep; + } + void pinPush() { + m_pinStack.push(m_pinNum); + m_pinNum = 1; + } + void pinPop(FileLine* fl) { + if (VL_UNCOVERABLE(m_pinStack.empty())) { fl->v3fatalSrc("Underflow of pin stack"); } + m_pinNum = m_pinStack.top(); + m_pinStack.pop(); } AstPackage* unitPackage(FileLine* fl) { - // Find one made earlier? - VSymEnt* symp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName()); - AstPackage* pkgp; - if (!symp) { - pkgp = PARSEP->rootp()->dollarUnitPkgAddp(); - SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global - } else { - pkgp = VN_CAST(symp->nodep(), Package); - } - return pkgp; + // Find one made earlier? + VSymEnt* symp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName()); + AstPackage* pkgp; + if (!symp) { + pkgp = PARSEP->rootp()->dollarUnitPkgAddp(); + SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global + } else { + pkgp = VN_CAST(symp->nodep(), Package); + } + return pkgp; } AstNodeDType* addRange(AstBasicDType* dtypep, AstNodeRange* rangesp, bool isPacked) { - // If dtypep isn't basic, don't use this, call createArray() instead - if (!rangesp) { - return dtypep; - } else { - // If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]" - // then [1:1] becomes the basicdtype range; everything else is arraying - // the final [5:5][4:4] will be passed in another call to createArray + // If dtypep isn't basic, don't use this, call createArray() instead + if (!rangesp) { + return dtypep; + } else { + // If rangesp is "wire [3:3][2:2][1:1] foo [5:5][4:4]" + // then [1:1] becomes the basicdtype range; everything else is arraying + // the final [5:5][4:4] will be passed in another call to createArray AstNodeRange* rangearraysp = NULL; if (dtypep->isRanged()) { rangearraysp = rangesp; // Already a range; everything is an array @@ -160,26 +180,27 @@ public: if (AstRange* finalRangep = VN_CAST(finalp, Range)) { // not an UnsizedRange if (dtypep->implicit()) { // It's no longer implicit but a wire logic type - AstBasicDType* newp = new AstBasicDType(dtypep->fileline(), AstBasicDTypeKwd::LOGIC, - dtypep->numeric(), dtypep->width(), dtypep->widthMin()); + AstBasicDType* newp = new AstBasicDType( + dtypep->fileline(), AstBasicDTypeKwd::LOGIC, dtypep->numeric(), + dtypep->width(), dtypep->widthMin()); VL_DO_DANGLING(dtypep->deleteTree(), dtypep); dtypep = newp; } dtypep->rangep(finalRangep); } - } - return createArray(dtypep, rangearraysp, isPacked); - } + } + return createArray(dtypep, rangearraysp, isPacked); + } } - string deQuote(FileLine* fileline, string text); + string deQuote(FileLine* fileline, string text); void checkDpiVer(FileLine* fileline, const string& str) { - if (str != "DPI-C" && !v3Global.opt.bboxSys()) { - fileline->v3error("Unsupported DPI type '"<v3error("Unsupported DPI type '" << str << "': Use 'DPI-C'"); + } } }; -const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" +const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT; int V3ParseGrammar::s_modTypeImpNum = 0; @@ -187,161 +208,232 @@ int V3ParseGrammar::s_modTypeImpNum = 0; //====================================================================== // Macro functions -#define CRELINE() (PARSEP->copyOrSameFileLine()) // Only use in empty rules, so lines point at beginnings +#define CRELINE() \ + (PARSEP->copyOrSameFileLine()) // Only use in empty rules, so lines point at beginnings #define FILELINE_OR_CRE(nodep) ((nodep) ? (nodep)->fileline() : CRELINE()) -#define VARRESET_LIST(decl) { GRAMMARP->m_pinNum=1; GRAMMARP->m_pinAnsi=false; \ - VARRESET(); VARDECL(decl); } // Start of pinlist -#define VARRESET_NONLIST(decl) { GRAMMARP->m_pinNum=0; GRAMMARP->m_pinAnsi=false; \ - VARRESET(); VARDECL(decl); } // Not in a pinlist -#define VARRESET() { VARDECL(UNKNOWN); VARIO(NONE); VARDTYPE_NDECL(NULL); \ - GRAMMARP->m_varLifetime = VLifetime::NONE; \ - GRAMMARP->m_varDeclTyped = false; } -#define VARDECL(type) { GRAMMARP->setVarDecl(AstVarType::type); } -#define VARIO(type) { GRAMMARP->m_varIO = VDirection::type; } -#define VARLIFE(flag) { GRAMMARP->m_varLifetime = flag; } -#define VARDTYPE(dtypep) { GRAMMARP->setDType(dtypep); GRAMMARP->m_varDeclTyped = true; } -#define VARDTYPE_NDECL(dtypep) { GRAMMARP->setDType(dtypep); } // Port that is range or signed only (not a decl) +#define VARRESET_LIST(decl) \ + { \ + GRAMMARP->m_pinNum = 1; \ + GRAMMARP->m_pinAnsi = false; \ + VARRESET(); \ + VARDECL(decl); \ + } // Start of pinlist +#define VARRESET_NONLIST(decl) \ + { \ + GRAMMARP->m_pinNum = 0; \ + GRAMMARP->m_pinAnsi = false; \ + VARRESET(); \ + VARDECL(decl); \ + } // Not in a pinlist +#define VARRESET() \ + { \ + VARDECL(UNKNOWN); \ + VARIO(NONE); \ + VARDTYPE_NDECL(NULL); \ + GRAMMARP->m_varLifetime = VLifetime::NONE; \ + GRAMMARP->m_varDeclTyped = false; \ + } +#define VARDECL(type) \ + { GRAMMARP->setVarDecl(AstVarType::type); } +#define VARIO(type) \ + { GRAMMARP->m_varIO = VDirection::type; } +#define VARLIFE(flag) \ + { GRAMMARP->m_varLifetime = flag; } +#define VARDTYPE(dtypep) \ + { \ + GRAMMARP->setDType(dtypep); \ + GRAMMARP->m_varDeclTyped = true; \ + } +#define VARDTYPE_NDECL(dtypep) \ + { GRAMMARP->setDType(dtypep); } // Port that is range or signed only (not a decl) -#define VARDONEA(fl,name,array,attrs) GRAMMARP->createVariable((fl),(name),(array),(attrs)) -#define VARDONEP(portp,array,attrs) GRAMMARP->createVariable((portp)->fileline(),(portp)->name(),(array),(attrs)) +#define VARDONEA(fl, name, array, attrs) GRAMMARP->createVariable((fl), (name), (array), (attrs)) +#define VARDONEP(portp, array, attrs) \ + GRAMMARP->createVariable((portp)->fileline(), (portp)->name(), (array), (attrs)) #define PINNUMINC() (GRAMMARP->m_pinNum++) -#define GATERANGE(rangep) { GRAMMARP->m_gateRangep = rangep; } +#define GATERANGE(rangep) \ + { GRAMMARP->m_gateRangep = rangep; } -#define INSTPREP(modfl,modname,paramsp) { \ - GRAMMARP->m_impliedDecl = true; \ - GRAMMARP->m_instModuleFl = modfl; GRAMMARP->m_instModule = modname; \ - GRAMMARP->m_instParamp = paramsp; } +#define INSTPREP(modfl, modname, paramsp) \ + { \ + GRAMMARP->m_impliedDecl = true; \ + GRAMMARP->m_instModuleFl = modfl; \ + GRAMMARP->m_instModule = modname; \ + GRAMMARP->m_instParamp = paramsp; \ + } -#define DEL(nodep) { if (nodep) nodep->deleteTree(); } +static AstPackage* CAST_PACKAGE_CLASS(AstNode* nodep) { + if (!nodep) { + return NULL; + } else if (AstPackage* pkgp = VN_CAST(nodep, Package)) { + return pkgp; + } else { + BBUNSUP(nodep->fileline(), "Unsupported class :: reference"); + return NULL; + } +} + +#define DEL(nodep) \ + { \ + if (nodep) nodep->deleteTree(); \ + } static void ERRSVKWD(FileLine* fileline, const string& tokname) { static int toldonce = 0; - fileline->v3error(string("Unexpected '")+tokname+"': '"+tokname - +"' is a SystemVerilog keyword misused as an identifier." - +(!toldonce++ - ? "\n"+V3Error::warnMore() - +"... Suggest modify the Verilog-2001 code to avoid SV keywords," - +" or use `begin_keywords or --language." - : "")); + fileline->v3error( + string("Unexpected '") + tokname + "': '" + tokname + + "' is a SystemVerilog keyword misused as an identifier." + + (!toldonce++ ? "\n" + V3Error::warnMore() + + "... Suggest modify the Verilog-2001 code to avoid SV keywords," + + " or use `begin_keywords or --language." + : "")); } static void UNSUPREAL(FileLine* fileline) { - fileline->v3warn(SHORTREAL, "Unsupported: shortreal being promoted to real (suggest use real instead)"); + fileline->v3warn(SHORTREAL, + "Unsupported: shortreal being promoted to real (suggest use real instead)"); +} + +//====================================================================== + +void yyerror(const char* errmsg) { + PARSEP->bisonLastFileline()->v3error(errmsg); + static const char* const colonmsg = "syntax error, unexpected"; +} + +void yyerrorf(const char* format, ...) { + const int maxlen = 2000; + char msg[maxlen]; + + va_list ap; + va_start(ap, format); + VL_VSNPRINTF(msg, maxlen, format, ap); + msg[maxlen - 1] = '\0'; + va_end(ap); + + yyerror(msg); } //====================================================================== class AstSenTree; +// clang-format off %} +// Bison 3.0 and newer +BISONPRE_VERSION(3.0,%define parse.error verbose) + // When writing Bison patterns we use yTOKEN instead of "token", // so Bison will error out on unknown "token"s. // Generic lexer tokens, for example a number // IEEE: real_number -%token yaFLOATNUM "FLOATING-POINT NUMBER" +%token yaFLOATNUM "FLOATING-POINT NUMBER" // IEEE: identifier, class_identifier, class_variable_identifier, // covergroup_variable_identifier, dynamic_array_variable_identifier, // enum_identifier, interface_identifier, interface_instance_identifier, // package_identifier, type_identifier, variable_identifier, -%token yaID__ETC "IDENTIFIER" -%token yaID__LEX "IDENTIFIER-in-lex" -%token yaID__aPACKAGE "PACKAGE-IDENTIFIER" -%token yaID__aTYPE "TYPE-IDENTIFIER" -// Can't predecode aFUNCTION, can declare after use -// Can't predecode aINTERFACE, can declare after use -// Can't predecode aTASK, can declare after use +%token yaID__ETC "IDENTIFIER" +%token yaID__CC "IDENTIFIER-::" +%token yaID__LEX "IDENTIFIER-in-lex" +%token yaID__aTYPE "TYPE-IDENTIFIER" +// Can't predecode aFUNCTION, can declare after use +// Can't predecode aINTERFACE, can declare after use +// Can't predecode aTASK, can declare after use // IEEE: integral_number -%token yaINTNUM "INTEGER NUMBER" +%token yaINTNUM "INTEGER NUMBER" // IEEE: time_literal + time_unit -%token yaTIMENUM "TIME NUMBER" +%token yaTIMENUM "TIME NUMBER" // IEEE: string_literal -%token yaSTRING "STRING" -%token yaSTRING__IGNORE "STRING-ignored" // Used when expr:string not allowed +%token yaSTRING "STRING" +%token yaSTRING__IGNORE "STRING-ignored" // Used when expr:string not allowed -%token yaTIMINGSPEC "TIMING SPEC ELEMENT" +%token yaTIMINGSPEC "TIMING SPEC ELEMENT" -%token ygenSTRENGTH "STRENGTH keyword (strong1/etc)" +%token ygenSTRENGTH "STRENGTH keyword (strong1/etc)" -%token yaTABLELINE "TABLE LINE" +%token yaTABLELINE "TABLE LINE" -%token yaSCHDR "`systemc_header BLOCK" -%token yaSCINT "`systemc_ctor BLOCK" -%token yaSCIMP "`systemc_dtor BLOCK" -%token yaSCIMPH "`systemc_interface BLOCK" -%token yaSCCTOR "`systemc_implementation BLOCK" -%token yaSCDTOR "`systemc_imp_header BLOCK" +%token yaSCHDR "`systemc_header BLOCK" +%token yaSCINT "`systemc_ctor BLOCK" +%token yaSCIMP "`systemc_dtor BLOCK" +%token yaSCIMPH "`systemc_interface BLOCK" +%token yaSCCTOR "`systemc_implementation BLOCK" +%token yaSCDTOR "`systemc_imp_header BLOCK" -%token yVLT_CLOCKER "clocker" -%token yVLT_CLOCK_ENABLE "clock_enable" -%token yVLT_COVERAGE_BLOCK_OFF "coverage_block_off" -%token yVLT_COVERAGE_OFF "coverage_off" -%token yVLT_COVERAGE_ON "coverage_on" -%token yVLT_FULL_CASE "full_case" -%token yVLT_INLINE "inline" -%token yVLT_ISOLATE_ASSIGNMENTS "isolate_assignments" -%token yVLT_LINT_OFF "lint_off" -%token yVLT_LINT_ON "lint_on" -%token yVLT_NO_CLOCKER "no_clocker" -%token yVLT_NO_INLINE "no_inline" -%token yVLT_PARALLEL_CASE "parallel_case" -%token yVLT_PUBLIC "public" -%token yVLT_PUBLIC_FLAT "public_flat" -%token yVLT_PUBLIC_FLAT_RD "public_flat_rd" -%token yVLT_PUBLIC_FLAT_RW "public_flat_rw" -%token yVLT_PUBLIC_MODULE "public_module" -%token yVLT_SC_BV "sc_bv" -%token yVLT_SFORMAT "sformat" -%token yVLT_SPLIT_VAR "split_var" -%token yVLT_TRACING_OFF "tracing_off" -%token yVLT_TRACING_ON "tracing_on" +%token yVLT_CLOCKER "clocker" +%token yVLT_CLOCK_ENABLE "clock_enable" +%token yVLT_COVERAGE_BLOCK_OFF "coverage_block_off" +%token yVLT_COVERAGE_OFF "coverage_off" +%token yVLT_COVERAGE_ON "coverage_on" +%token yVLT_FULL_CASE "full_case" +%token yVLT_INLINE "inline" +%token yVLT_ISOLATE_ASSIGNMENTS "isolate_assignments" +%token yVLT_LINT_OFF "lint_off" +%token yVLT_LINT_ON "lint_on" +%token yVLT_NO_CLOCKER "no_clocker" +%token yVLT_NO_INLINE "no_inline" +%token yVLT_PARALLEL_CASE "parallel_case" +%token yVLT_PUBLIC "public" +%token yVLT_PUBLIC_FLAT "public_flat" +%token yVLT_PUBLIC_FLAT_RD "public_flat_rd" +%token yVLT_PUBLIC_FLAT_RW "public_flat_rw" +%token yVLT_PUBLIC_MODULE "public_module" +%token yVLT_SC_BV "sc_bv" +%token yVLT_SFORMAT "sformat" +%token yVLT_SPLIT_VAR "split_var" +%token yVLT_TRACING_OFF "tracing_off" +%token yVLT_TRACING_ON "tracing_on" -%token yVLT_D_BLOCK "--block" -%token yVLT_D_FILE "--file" -%token yVLT_D_FUNCTION "--function" -%token yVLT_D_LINES "--lines" -%token yVLT_D_MODULE "--module" -%token yVLT_D_MATCH "--match" -%token yVLT_D_MSG "--msg" -%token yVLT_D_RULE "--rule" -%token yVLT_D_TASK "--task" -%token yVLT_D_VAR "--var" +%token yVLT_D_BLOCK "--block" +%token yVLT_D_FILE "--file" +%token yVLT_D_FUNCTION "--function" +%token yVLT_D_LINES "--lines" +%token yVLT_D_MODULE "--module" +%token yVLT_D_MATCH "--match" +%token yVLT_D_MSG "--msg" +%token yVLT_D_RULE "--rule" +%token yVLT_D_TASK "--task" +%token yVLT_D_VAR "--var" -%token yaD_PLI "${pli-system}" +%token yaD_PLI "${pli-system}" -%token yaT_RESETALL "`resetall" +%token yaT_NOUNCONNECTED "`nounconnecteddrive" +%token yaT_RESETALL "`resetall" +%token yaT_UNCONNECTED_PULL0 "`unconnected_drive pull0" +%token yaT_UNCONNECTED_PULL1 "`unconnected_drive pull1" // is the fileline, abbreviated to shorten "$1" references -%token '!' -%token '#' -%token '%' -%token '&' -%token '(' -%token ')' -%token '*' -%token '+' -%token ',' -%token '-' -%token '.' -%token '/' -%token ':' -%token ';' -%token '<' -%token '=' -%token '>' -%token '?' -%token '@' -%token '[' -%token ']' -%token '^' -%token '{' -%token '|' -%token '}' -%token '~' +%token '!' +%token '#' +%token '%' +%token '&' +%token '(' +%token ')' +%token '*' +%token '+' +%token ',' +%token '-' +%token '.' +%token '/' +%token ':' +%token ';' +%token '<' +%token '=' +%token '>' +%token '?' +%token '@' +%token '[' +%token ']' +%token '^' +%token '{' +%token '|' +%token '}' +%token '~' // Specific keywords // yKEYWORD means match "keyword" @@ -349,416 +441,518 @@ class AstSenTree; // for example yP_ for punctuation based operators. // Double underscores "yX__Y" means token X followed by Y, // and "yX__ETC" means X folled by everything but Y(s). -%token yALIAS "alias" -%token yALWAYS "always" -%token yALWAYS_COMB "always_comb" -%token yALWAYS_FF "always_ff" -%token yALWAYS_LATCH "always_latch" -%token yAND "and" -%token yASSERT "assert" -%token yASSIGN "assign" -%token yASSUME "assume" -%token yAUTOMATIC "automatic" -%token yBEGIN "begin" -%token yBIND "bind" -%token yBIT "bit" -%token yBREAK "break" -%token yBUF "buf" -%token yBUFIF0 "bufif0" -%token yBUFIF1 "bufif1" -%token yBYTE "byte" -%token yCASE "case" -%token yCASEX "casex" -%token yCASEZ "casez" -%token yCHANDLE "chandle" -%token yCLASS "class" -%token yCLOCKING "clocking" -%token yCMOS "cmos" -%token yCONST__ETC "const" -%token yCONST__LEX "const-in-lex" -%token yCONST__REF "const-then-ref" -%token yCONTEXT "context" -%token yCONTINUE "continue" -%token yCOVER "cover" -%token yDEASSIGN "deassign" -%token yDEFAULT "default" -%token yDEFPARAM "defparam" -%token yDISABLE "disable" -%token yDO "do" -%token yEDGE "edge" -%token yELSE "else" -%token yEND "end" -%token yENDCASE "endcase" -%token yENDCLASS "endclass" -%token yENDCLOCKING "endclocking" -%token yENDFUNCTION "endfunction" -%token yENDGENERATE "endgenerate" -%token yENDINTERFACE "endinterface" -%token yENDMODULE "endmodule" -%token yENDPACKAGE "endpackage" -%token yENDPRIMITIVE "endprimitive" -%token yENDPROGRAM "endprogram" -%token yENDPROPERTY "endproperty" -%token yENDSPECIFY "endspecify" -%token yENDTABLE "endtable" -%token yENDTASK "endtask" -%token yENUM "enum" -%token yEVENT "event" -%token yEXPORT "export" -%token yEXTENDS "extends" -%token yEXTERN "extern" -%token yFINAL "final" -%token yFOR "for" -%token yFORCE "force" -%token yFOREACH "foreach" -%token yFOREVER "forever" -%token yFORK "fork" -%token yFORKJOIN "forkjoin" -%token yFUNCTION "function" -%token yGENERATE "generate" -%token yGENVAR "genvar" -%token yGLOBAL__CLOCKING "global-then-clocking" -%token yGLOBAL__ETC "global" -%token yGLOBAL__LEX "global-in-lex" -%token yIF "if" -%token yIFF "iff" -%token yIMPLEMENTS "implements" -%token yIMPORT "import" -%token yINITIAL "initial" -%token yINOUT "inout" -%token yINPUT "input" -%token yINSIDE "inside" -%token yINT "int" -%token yINTEGER "integer" -%token yINTERFACE "interface" -%token yJOIN "join" -%token yJOIN_ANY "join_any" -%token yJOIN_NONE "join_none" -%token yLOCALPARAM "localparam" -%token yLOCAL__COLONCOLON "local-then-::" -%token yLOCAL__ETC "local" -%token yLOCAL__LEX "local-in-lex" -%token yLOGIC "logic" -%token yLONGINT "longint" -%token yMODPORT "modport" -%token yMODULE "module" -%token yNAND "nand" -%token yNEGEDGE "negedge" -%token yNEW__ETC "new" -%token yNEW__LEX "new-in-lex" -%token yNEW__PAREN "new-then-paren" -%token yNMOS "nmos" -%token yNOR "nor" -%token yNOT "not" -%token yNOTIF0 "notif0" -%token yNOTIF1 "notif1" -%token yNULL "null" -%token yOR "or" -%token yOUTPUT "output" -%token yPACKAGE "package" -%token yPACKED "packed" -%token yPARAMETER "parameter" -%token yPMOS "pmos" -%token yPOSEDGE "posedge" -%token yPRIMITIVE "primitive" -%token yPRIORITY "priority" -%token yPROGRAM "program" -%token yPROPERTY "property" -%token yPROTECTED "protected" -%token yPULLDOWN "pulldown" -%token yPULLUP "pullup" -%token yPURE "pure" -%token yRAND "rand" -%token yRANDC "randc" -%token yRANDCASE "randcase" -%token yRCMOS "rcmos" -%token yREAL "real" -%token yREALTIME "realtime" -%token yREF "ref" -%token yREG "reg" -%token yRELEASE "release" -%token yREPEAT "repeat" -%token yRESTRICT "restrict" -%token yRETURN "return" -%token yRNMOS "rnmos" -%token yRPMOS "rpmos" -%token yRTRAN "rtran" -%token yRTRANIF0 "rtranif0" -%token yRTRANIF1 "rtranif1" -%token ySCALARED "scalared" -%token ySHORTINT "shortint" -%token ySHORTREAL "shortreal" -%token ySIGNED "signed" -%token ySPECIFY "specify" -%token ySPECPARAM "specparam" -%token ySTATIC__ETC "static" -%token ySTRING "string" -%token ySTRUCT "struct" -%token ySUPER "super" -%token ySUPPLY0 "supply0" -%token ySUPPLY1 "supply1" -%token yTABLE "table" -%token yTASK "task" -%token yTHIS "this" -%token yTIME "time" -%token yTIMEPRECISION "timeprecision" -%token yTIMEUNIT "timeunit" -%token yTRAN "tran" -%token yTRANIF0 "tranif0" -%token yTRANIF1 "tranif1" -%token yTRI "tri" -%token yTRI0 "tri0" -%token yTRI1 "tri1" -%token yTRIAND "triand" -%token yTRIOR "trior" -%token yTRIREG "trireg" -%token yTRUE "true" -%token yTYPE "type" -%token yTYPEDEF "typedef" -%token yUNION "union" -%token yUNIQUE "unique" -%token yUNIQUE0 "unique0" -%token yUNSIGNED "unsigned" -%token yVAR "var" -%token yVECTORED "vectored" -%token yVIRTUAL__CLASS "virtual-then-class" -%token yVIRTUAL__ETC "virtual" -%token yVIRTUAL__INTERFACE "virtual-then-interface" -%token yVIRTUAL__LEX "virtual-in-lex" -%token yVIRTUAL__anyID "virtual-then-identifier" -%token yVOID "void" -%token yWAIT "wait" -%token yWAND "wand" -%token yWHILE "while" -%token yWIRE "wire" -%token yWOR "wor" -%token yWREAL "wreal" -%token yXNOR "xnor" -%token yXOR "xor" +//UNSUP %token yACCEPT_ON "accept_on" +%token yALIAS "alias" +%token yALWAYS "always" +%token yALWAYS_COMB "always_comb" +%token yALWAYS_FF "always_ff" +%token yALWAYS_LATCH "always_latch" +%token yAND "and" +%token yASSERT "assert" +%token yASSIGN "assign" +%token yASSUME "assume" +%token yAUTOMATIC "automatic" +%token yBEFORE "before" +%token yBEGIN "begin" +%token yBIND "bind" +//UNSUP %token yBINS "bins" +//UNSUP %token yBINSOF "binsof" +%token yBIT "bit" +%token yBREAK "break" +%token yBUF "buf" +%token yBUFIF0 "bufif0" +%token yBUFIF1 "bufif1" +%token yBYTE "byte" +%token yCASE "case" +%token yCASEX "casex" +%token yCASEZ "casez" +%token yCHANDLE "chandle" +//UNSUP %token yCHECKER "checker" +%token yCLASS "class" +//UNSUP %token yCLOCK "clock" +%token yCLOCKING "clocking" +%token yCMOS "cmos" +%token yCONSTRAINT "constraint" +%token yCONST__ETC "const" +%token yCONST__LEX "const-in-lex" +//UNSUP %token yCONST__LOCAL "const-then-local" +%token yCONST__REF "const-then-ref" +%token yCONTEXT "context" +%token yCONTINUE "continue" +%token yCOVER "cover" +//UNSUP %token yCOVERGROUP "covergroup" +//UNSUP %token yCOVERPOINT "coverpoint" +//UNSUP %token yCROSS "cross" +%token yDEASSIGN "deassign" +%token yDEFAULT "default" +%token yDEFPARAM "defparam" +%token yDISABLE "disable" +%token yDIST "dist" +%token yDO "do" +%token yEDGE "edge" +%token yELSE "else" +%token yEND "end" +%token yENDCASE "endcase" +//UNSUP %token yENDCHECKER "endchecker" +%token yENDCLASS "endclass" +%token yENDCLOCKING "endclocking" +%token yENDFUNCTION "endfunction" +%token yENDGENERATE "endgenerate" +//UNSUP %token yENDGROUP "endgroup" +%token yENDINTERFACE "endinterface" +%token yENDMODULE "endmodule" +%token yENDPACKAGE "endpackage" +%token yENDPRIMITIVE "endprimitive" +%token yENDPROGRAM "endprogram" +%token yENDPROPERTY "endproperty" +//UNSUP %token yENDSEQUENCE "endsequence" +%token yENDSPECIFY "endspecify" +%token yENDTABLE "endtable" +%token yENDTASK "endtask" +%token yENUM "enum" +%token yEVENT "event" +//UNSUP %token yEVENTUALLY "eventually" +//UNSUP %token yEXPECT "expect" +%token yEXPORT "export" +%token yEXTENDS "extends" +%token yEXTERN "extern" +%token yFINAL "final" +//UNSUP %token yFIRST_MATCH "first_match" +%token yFOR "for" +%token yFORCE "force" +%token yFOREACH "foreach" +%token yFOREVER "forever" +%token yFORK "fork" +%token yFORKJOIN "forkjoin" +%token yFUNCTION "function" +//UNSUP %token yFUNCTION__ETC "function" +//UNSUP %token yFUNCTION__LEX "function-in-lex" +//UNSUP %token yFUNCTION__aPUREV "function-is-pure-virtual" +%token yGENERATE "generate" +%token yGENVAR "genvar" +%token yGLOBAL__CLOCKING "global-then-clocking" +%token yGLOBAL__ETC "global" +%token yGLOBAL__LEX "global-in-lex" +%token yIF "if" +%token yIFF "iff" +//UNSUP %token yIGNORE_BINS "ignore_bins" +//UNSUP %token yILLEGAL_BINS "illegal_bins" +%token yIMPLEMENTS "implements" +//UNSUP %token yIMPLIES "implies" +%token yIMPORT "import" +%token yINITIAL "initial" +%token yINOUT "inout" +%token yINPUT "input" +%token yINSIDE "inside" +%token yINT "int" +%token yINTEGER "integer" +//UNSUP %token yINTERCONNECT "interconnect" +%token yINTERFACE "interface" +//UNSUP %token yINTERSECT "intersect" +%token yJOIN "join" +%token yJOIN_ANY "join_any" +%token yJOIN_NONE "join_none" +//UNSUP %token yLET "let" +%token yLOCALPARAM "localparam" +%token yLOCAL__COLONCOLON "local-then-::" +%token yLOCAL__ETC "local" +%token yLOCAL__LEX "local-in-lex" +%token yLOGIC "logic" +%token yLONGINT "longint" +//UNSUP %token yMATCHES "matches" +%token yMODPORT "modport" +%token yMODULE "module" +%token yNAND "nand" +%token yNEGEDGE "negedge" +//UNSUP %token yNETTYPE "nettype" +%token yNEW__ETC "new" +%token yNEW__LEX "new-in-lex" +%token yNEW__PAREN "new-then-paren" +//UNSUP %token yNEXTTIME "nexttime" +%token yNMOS "nmos" +%token yNOR "nor" +%token yNOT "not" +%token yNOTIF0 "notif0" +%token yNOTIF1 "notif1" +%token yNULL "null" +%token yOR "or" +%token yOUTPUT "output" +%token yPACKAGE "package" +%token yPACKED "packed" +%token yPARAMETER "parameter" +%token yPMOS "pmos" +%token yPOSEDGE "posedge" +%token yPRIMITIVE "primitive" +%token yPRIORITY "priority" +%token yPROGRAM "program" +%token yPROPERTY "property" +%token yPROTECTED "protected" +%token yPULLDOWN "pulldown" +%token yPULLUP "pullup" +%token yPURE "pure" +%token yRAND "rand" +%token yRANDC "randc" +%token yRANDCASE "randcase" +%token yRANDOMIZE "randomize" +//UNSUP %token yRANDSEQUENCE "randsequence" +%token yRCMOS "rcmos" +%token yREAL "real" +%token yREALTIME "realtime" +%token yREF "ref" +%token yREG "reg" +//UNSUP %token yREJECT_ON "reject_on" +%token yRELEASE "release" +%token yREPEAT "repeat" +%token yRESTRICT "restrict" +%token yRETURN "return" +%token yRNMOS "rnmos" +%token yRPMOS "rpmos" +%token yRTRAN "rtran" +%token yRTRANIF0 "rtranif0" +%token yRTRANIF1 "rtranif1" +%token ySCALARED "scalared" +//UNSUP %token ySEQUENCE "sequence" +%token ySHORTINT "shortint" +%token ySHORTREAL "shortreal" +%token ySIGNED "signed" +%token ySOFT "soft" +%token ySOLVE "solve" +%token ySPECIFY "specify" +%token ySPECPARAM "specparam" +%token ySTATIC__CONSTRAINT "static-then-constraint" +%token ySTATIC__ETC "static" +%token ySTATIC__LEX "static-in-lex" +%token ySTRING "string" +//UNSUP %token ySTRONG "strong" +%token ySTRUCT "struct" +%token ySUPER "super" +%token ySUPPLY0 "supply0" +%token ySUPPLY1 "supply1" +//UNSUP %token ySYNC_ACCEPT_ON "sync_accept_on" +//UNSUP %token ySYNC_REJECT_ON "sync_reject_on" +//UNSUP %token yS_ALWAYS "s_always" +//UNSUP %token yS_EVENTUALLY "s_eventually" +//UNSUP %token yS_NEXTTIME "s_nexttime" +//UNSUP %token yS_UNTIL "s_until" +//UNSUP %token yS_UNTIL_WITH "s_until_with" +%token yTABLE "table" +//UNSUP %token yTAGGED "tagged" +%token yTASK "task" +//UNSUP %token yTASK__ETC "task" +//UNSUP %token yTASK__LEX "task-in-lex" +//UNSUP %token yTASK__aPUREV "task-is-pure-virtual" +%token yTHIS "this" +//UNSUP %token yTHROUGHOUT "throughout" +%token yTIME "time" +%token yTIMEPRECISION "timeprecision" +%token yTIMEUNIT "timeunit" +%token yTRAN "tran" +%token yTRANIF0 "tranif0" +%token yTRANIF1 "tranif1" +%token yTRI "tri" +%token yTRI0 "tri0" +%token yTRI1 "tri1" +%token yTRIAND "triand" +%token yTRIOR "trior" +%token yTRIREG "trireg" +%token yTRUE "true" +%token yTYPE "type" +%token yTYPEDEF "typedef" +%token yUNION "union" +%token yUNIQUE "unique" +%token yUNIQUE0 "unique0" +%token yUNSIGNED "unsigned" +//UNSUP %token yUNTIL "until" +//UNSUP %token yUNTIL_WITH "until_with" +//UNSUP %token yUNTYPED "untyped" +%token yVAR "var" +%token yVECTORED "vectored" +%token yVIRTUAL__CLASS "virtual-then-class" +%token yVIRTUAL__ETC "virtual" +%token yVIRTUAL__INTERFACE "virtual-then-interface" +%token yVIRTUAL__LEX "virtual-in-lex" +%token yVIRTUAL__anyID "virtual-then-identifier" +%token yVOID "void" +%token yWAIT "wait" +//UNSUP %token yWAIT_ORDER "wait_order" +%token yWAND "wand" +//UNSUP %token yWEAK "weak" +%token yWHILE "while" +//UNSUP %token yWILDCARD "wildcard" +%token yWIRE "wire" +//UNSUP %token yWITHIN "within" +%token yWITH__BRA "with-then-[" +%token yWITH__CUR "with-then-{" +%token yWITH__ETC "with" +%token yWITH__LEX "with-in-lex" +%token yWITH__PAREN "with-then-(" +%token yWOR "wor" +%token yWREAL "wreal" +%token yXNOR "xnor" +%token yXOR "xor" -%token yD_ACOS "$acos" -%token yD_ACOSH "$acosh" -%token yD_ASIN "$asin" -%token yD_ASINH "$asinh" -%token yD_ATAN "$atan" -%token yD_ATAN2 "$atan2" -%token yD_ATANH "$atanh" -%token yD_BITS "$bits" -%token yD_BITSTOREAL "$bitstoreal" -%token yD_BITSTOSHORTREAL "$bitstoshortreal" -%token yD_C "$c" -%token yD_CEIL "$ceil" -%token yD_CLOG2 "$clog2" -%token yD_COS "$cos" -%token yD_COSH "$cosh" -%token yD_COUNTBITS "$countbits" -%token yD_COUNTONES "$countones" -%token yD_DIMENSIONS "$dimensions" -%token yD_DISPLAY "$display" -%token yD_DISPLAYB "$displayb" -%token yD_DISPLAYH "$displayh" -%token yD_DISPLAYO "$displayo" -%token yD_DUMPALL "$dumpall" -%token yD_DUMPFILE "$dumpfile" -%token yD_DUMPFLUSH "$dumpflush" -%token yD_DUMPLIMIT "$dumplimit" -%token yD_DUMPOFF "$dumpoff" -%token yD_DUMPON "$dumpon" -%token yD_DUMPPORTS "$dumpports" -%token yD_DUMPVARS "$dumpvars" -%token yD_ERROR "$error" -%token yD_EXP "$exp" -%token yD_FATAL "$fatal" -%token yD_FCLOSE "$fclose" -%token yD_FDISPLAY "$fdisplay" -%token yD_FDISPLAYB "$fdisplayb" -%token yD_FDISPLAYH "$fdisplayh" -%token yD_FDISPLAYO "$fdisplayo" -%token yD_FEOF "$feof" -%token yD_FERROR "$ferror" -%token yD_FFLUSH "$fflush" -%token yD_FGETC "$fgetc" -%token yD_FGETS "$fgets" -%token yD_FINISH "$finish" -%token yD_FLOOR "$floor" -%token yD_FOPEN "$fopen" -%token yD_FREAD "$fread" -%token yD_FREWIND "$frewind" -%token yD_FSCANF "$fscanf" -%token yD_FSEEK "$fseek" -%token yD_FTELL "$ftell" -%token yD_FWRITE "$fwrite" -%token yD_FWRITEB "$fwriteb" -%token yD_FWRITEH "$fwriteh" -%token yD_FWRITEO "$fwriteo" -%token yD_HIGH "$high" -%token yD_HYPOT "$hypot" -%token yD_INCREMENT "$increment" -%token yD_INFO "$info" -%token yD_ISUNBOUNDED "$isunbounded" -%token yD_ISUNKNOWN "$isunknown" -%token yD_ITOR "$itor" -%token yD_LEFT "$left" -%token yD_LN "$ln" -%token yD_LOG10 "$log10" -%token yD_LOW "$low" -%token yD_ONEHOT "$onehot" -%token yD_ONEHOT0 "$onehot0" -%token yD_PAST "$past" -%token yD_POW "$pow" -%token yD_PRINTTIMESCALE "$printtimescale" -%token yD_RANDOM "$random" -%token yD_READMEMB "$readmemb" -%token yD_READMEMH "$readmemh" -%token yD_REALTIME "$realtime" -%token yD_REALTOBITS "$realtobits" -%token yD_REWIND "$rewind" -%token yD_RIGHT "$right" -%token yD_ROOT "$root" -%token yD_RTOI "$rtoi" -%token yD_SAMPLED "$sampled" -%token yD_SFORMAT "$sformat" -%token yD_SFORMATF "$sformatf" -%token yD_SHORTREALTOBITS "$shortrealtobits" -%token yD_SIGNED "$signed" -%token yD_SIN "$sin" -%token yD_SINH "$sinh" -%token yD_SIZE "$size" -%token yD_SQRT "$sqrt" -%token yD_SSCANF "$sscanf" -%token yD_STIME "$stime" -%token yD_STOP "$stop" -%token yD_SWRITE "$swrite" -%token yD_SWRITEB "$swriteb" -%token yD_SWRITEH "$swriteh" -%token yD_SWRITEO "$swriteo" -%token yD_SYSTEM "$system" -%token yD_TAN "$tan" -%token yD_TANH "$tanh" -%token yD_TESTPLUSARGS "$test$plusargs" -%token yD_TIME "$time" -%token yD_TIMEFORMAT "$timeformat" -%token yD_TYPENAME "$typename" -%token yD_UNGETC "$ungetc" -%token yD_UNIT "$unit" -%token yD_UNPACKED_DIMENSIONS "$unpacked_dimensions" -%token yD_UNSIGNED "$unsigned" -%token yD_VALUEPLUSARGS "$value$plusargs" -%token yD_WARNING "$warning" -%token yD_WRITE "$write" -%token yD_WRITEB "$writeb" -%token yD_WRITEH "$writeh" -%token yD_WRITEMEMH "$writememh" -%token yD_WRITEO "$writeo" +%token yD_ACOS "$acos" +%token yD_ACOSH "$acosh" +%token yD_ASIN "$asin" +%token yD_ASINH "$asinh" +%token yD_ATAN "$atan" +%token yD_ATAN2 "$atan2" +%token yD_ATANH "$atanh" +%token yD_BITS "$bits" +%token yD_BITSTOREAL "$bitstoreal" +%token yD_BITSTOSHORTREAL "$bitstoshortreal" +%token yD_C "$c" +%token yD_CAST "$cast" +%token yD_CEIL "$ceil" +%token yD_CLOG2 "$clog2" +%token yD_COS "$cos" +%token yD_COSH "$cosh" +%token yD_COUNTBITS "$countbits" +%token yD_COUNTONES "$countones" +%token yD_DIMENSIONS "$dimensions" +%token yD_DISPLAY "$display" +%token yD_DISPLAYB "$displayb" +%token yD_DISPLAYH "$displayh" +%token yD_DISPLAYO "$displayo" +%token yD_DUMPALL "$dumpall" +%token yD_DUMPFILE "$dumpfile" +%token yD_DUMPFLUSH "$dumpflush" +%token yD_DUMPLIMIT "$dumplimit" +%token yD_DUMPOFF "$dumpoff" +%token yD_DUMPON "$dumpon" +%token yD_DUMPPORTS "$dumpports" +%token yD_DUMPVARS "$dumpvars" +%token yD_ERROR "$error" +%token yD_EXP "$exp" +%token yD_FATAL "$fatal" +%token yD_FCLOSE "$fclose" +%token yD_FDISPLAY "$fdisplay" +%token yD_FDISPLAYB "$fdisplayb" +%token yD_FDISPLAYH "$fdisplayh" +%token yD_FDISPLAYO "$fdisplayo" +%token yD_FEOF "$feof" +%token yD_FERROR "$ferror" +%token yD_FFLUSH "$fflush" +%token yD_FGETC "$fgetc" +%token yD_FGETS "$fgets" +%token yD_FINISH "$finish" +%token yD_FLOOR "$floor" +%token yD_FOPEN "$fopen" +%token yD_FREAD "$fread" +%token yD_FREWIND "$frewind" +%token yD_FSCANF "$fscanf" +%token yD_FSEEK "$fseek" +%token yD_FTELL "$ftell" +%token yD_FWRITE "$fwrite" +%token yD_FWRITEB "$fwriteb" +%token yD_FWRITEH "$fwriteh" +%token yD_FWRITEO "$fwriteo" +%token yD_HIGH "$high" +%token yD_HYPOT "$hypot" +%token yD_INCREMENT "$increment" +%token yD_INFO "$info" +%token yD_ISUNBOUNDED "$isunbounded" +%token yD_ISUNKNOWN "$isunknown" +%token yD_ITOR "$itor" +%token yD_LEFT "$left" +%token yD_LN "$ln" +%token yD_LOG10 "$log10" +%token yD_LOW "$low" +%token yD_ONEHOT "$onehot" +%token yD_ONEHOT0 "$onehot0" +%token yD_PAST "$past" +%token yD_POW "$pow" +%token yD_PRINTTIMESCALE "$printtimescale" +%token yD_RANDOM "$random" +%token yD_READMEMB "$readmemb" +%token yD_READMEMH "$readmemh" +%token yD_REALTIME "$realtime" +%token yD_REALTOBITS "$realtobits" +%token yD_REWIND "$rewind" +%token yD_RIGHT "$right" +%token yD_ROOT "$root" +%token yD_RTOI "$rtoi" +%token yD_SAMPLED "$sampled" +%token yD_SFORMAT "$sformat" +%token yD_SFORMATF "$sformatf" +%token yD_SHORTREALTOBITS "$shortrealtobits" +%token yD_SIGNED "$signed" +%token yD_SIN "$sin" +%token yD_SINH "$sinh" +%token yD_SIZE "$size" +%token yD_SQRT "$sqrt" +%token yD_SSCANF "$sscanf" +%token yD_STIME "$stime" +%token yD_STOP "$stop" +%token yD_SWRITE "$swrite" +%token yD_SWRITEB "$swriteb" +%token yD_SWRITEH "$swriteh" +%token yD_SWRITEO "$swriteo" +%token yD_SYSTEM "$system" +%token yD_TAN "$tan" +%token yD_TANH "$tanh" +%token yD_TESTPLUSARGS "$test$plusargs" +%token yD_TIME "$time" +%token yD_TIMEFORMAT "$timeformat" +%token yD_TYPENAME "$typename" +%token yD_UNGETC "$ungetc" +%token yD_UNIT "$unit" +%token yD_UNPACKED_DIMENSIONS "$unpacked_dimensions" +%token yD_UNSIGNED "$unsigned" +%token yD_VALUEPLUSARGS "$value$plusargs" +%token yD_WARNING "$warning" +%token yD_WRITE "$write" +%token yD_WRITEB "$writeb" +%token yD_WRITEH "$writeh" +%token yD_WRITEMEMB "$writememb" +%token yD_WRITEMEMH "$writememh" +%token yD_WRITEO "$writeo" -%token yVL_CLOCK "/*verilator sc_clock*/" -%token yVL_CLOCKER "/*verilator clocker*/" -%token yVL_NO_CLOCKER "/*verilator no_clocker*/" -%token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" -%token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" -%token yVL_FULL_CASE "/*verilator full_case*/" -%token yVL_INLINE_MODULE "/*verilator inline_module*/" -%token yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/" -%token yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/" -%token yVL_NO_INLINE_TASK "/*verilator no_inline_task*/" -%token yVL_SC_BV "/*verilator sc_bv*/" -%token yVL_SFORMAT "/*verilator sformat*/" -%token yVL_PARALLEL_CASE "/*verilator parallel_case*/" -%token yVL_PUBLIC "/*verilator public*/" -%token yVL_PUBLIC_FLAT "/*verilator public_flat*/" -%token yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/" -%token yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/" -%token yVL_PUBLIC_MODULE "/*verilator public_module*/" -%token yVL_SPLIT_VAR "/*verilator split_var*/" +%token yVL_CLOCK "/*verilator sc_clock*/" +%token yVL_CLOCKER "/*verilator clocker*/" +%token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" +%token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" +%token yVL_FULL_CASE "/*verilator full_case*/" +%token yVL_INLINE_MODULE "/*verilator inline_module*/" +%token yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/" +%token yVL_NO_CLOCKER "/*verilator no_clocker*/" +%token yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/" +%token yVL_NO_INLINE_TASK "/*verilator no_inline_task*/" +%token yVL_PARALLEL_CASE "/*verilator parallel_case*/" +%token yVL_PUBLIC "/*verilator public*/" +%token yVL_PUBLIC_FLAT "/*verilator public_flat*/" +%token yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/" +%token yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/" +%token yVL_PUBLIC_MODULE "/*verilator public_module*/" +%token yVL_SC_BV "/*verilator sc_bv*/" +%token yVL_SFORMAT "/*verilator sformat*/" +%token yVL_SPLIT_VAR "/*verilator split_var*/" +%token yVL_TAG "/*verilator tag*/" -%token yP_TICK "'" -%token yP_TICKBRA "'{" -%token yP_OROR "||" -%token yP_ANDAND "&&" -%token yP_NOR "~|" -%token yP_XNOR "^~" -%token yP_NAND "~&" -%token yP_EQUAL "==" -%token yP_NOTEQUAL "!=" -%token yP_CASEEQUAL "===" -%token yP_CASENOTEQUAL "!==" -%token yP_WILDEQUAL "==?" -%token yP_WILDNOTEQUAL "!=?" -%token yP_GTE ">=" -%token yP_LTE "<=" -%token yP_LTE__IGNORE "<=-ignored" // Used when expr:<= means assignment -%token yP_SLEFT "<<" -%token yP_SRIGHT ">>" -%token yP_SSRIGHT ">>>" -%token yP_POW "**" +%token yP_TICK "'" +%token yP_TICKBRA "'{" +%token yP_OROR "||" +%token yP_ANDAND "&&" +%token yP_NOR "~|" +%token yP_XNOR "^~" +%token yP_NAND "~&" +%token yP_EQUAL "==" +%token yP_NOTEQUAL "!=" +%token yP_CASEEQUAL "===" +%token yP_CASENOTEQUAL "!==" +%token yP_WILDEQUAL "==?" +%token yP_WILDNOTEQUAL "!=?" +%token yP_GTE ">=" +%token yP_LTE "<=" +%token yP_LTE__IGNORE "<=-ignored" // Used when expr:<= means assignment +%token yP_SLEFT "<<" +%token yP_SRIGHT ">>" +%token yP_SSRIGHT ">>>" +%token yP_POW "**" -%token yP_PAR__STRENGTH "(-for-strength" +//UNSUP %token yP_PAR__IGNORE "(-ignored" // Used when sequence_expr:expr:( is ignored +%token yP_PAR__STRENGTH "(-for-strength" -%token yP_LTMINUSGT "<->" -%token yP_PLUSCOLON "+:" -%token yP_MINUSCOLON "-:" -%token yP_MINUSGT "->" -%token yP_MINUSGTGT "->>" -%token yP_EQGT "=>" -%token yP_ASTGT "*>" -%token yP_ANDANDAND "&&&" -%token yP_POUNDPOUND "##" -%token yP_DOTSTAR ".*" +%token yP_LTMINUSGT "<->" +%token yP_PLUSCOLON "+:" +%token yP_MINUSCOLON "-:" +%token yP_MINUSGT "->" +%token yP_MINUSGTGT "->>" +%token yP_EQGT "=>" +%token yP_ASTGT "*>" +%token yP_ANDANDAND "&&&" +%token yP_POUNDPOUND "##" +//UNSUP %token yP_POUNDMINUSPD "#-#" +//UNSUP %token yP_POUNDEQPD "#=#" +%token yP_DOTSTAR ".*" -%token yP_ATAT "@@" -%token yP_COLONCOLON "::" -%token yP_COLONEQ ":=" -%token yP_COLONDIV ":/" -%token yP_ORMINUSGT "|->" -%token yP_OREQGT "|=>" -%token yP_BRASTAR "[*" -%token yP_BRAEQ "[=" -%token yP_BRAMINUSGT "[->" +%token yP_ATAT "@@" +%token yP_COLONCOLON "::" +%token yP_COLONEQ ":=" +%token yP_COLONDIV ":/" +%token yP_ORMINUSGT "|->" +%token yP_OREQGT "|=>" +%token yP_BRASTAR "[*" +%token yP_BRAEQ "[=" +%token yP_BRAMINUSGT "[->" +//UNSUP %token yP_BRAPLUSKET "[+]" -%token yP_PLUSPLUS "++" -%token yP_MINUSMINUS "--" -%token yP_PLUSEQ "+=" -%token yP_MINUSEQ "-=" -%token yP_TIMESEQ "*=" -%token yP_DIVEQ "/=" -%token yP_MODEQ "%=" -%token yP_ANDEQ "&=" -%token yP_OREQ "|=" -%token yP_XOREQ "^=" -%token yP_SLEFTEQ "<<=" -%token yP_SRIGHTEQ ">>=" -%token yP_SSRIGHTEQ ">>>=" +%token yP_PLUSPLUS "++" +%token yP_MINUSMINUS "--" +%token yP_PLUSEQ "+=" +%token yP_MINUSEQ "-=" +%token yP_TIMESEQ "*=" +%token yP_DIVEQ "/=" +%token yP_MODEQ "%=" +%token yP_ANDEQ "&=" +%token yP_OREQ "|=" +%token yP_XOREQ "^=" +%token yP_SLEFTEQ "<<=" +%token yP_SRIGHTEQ ">>=" +%token yP_SSRIGHTEQ ">>>=" // [* is not a operator, as "[ * ]" is legal // [= and [-> could be repitition operators, but to match [* we don't add them. // '( is not a operator, as "' (" is legal //******************** +// Verilog op precedence +//UNSUP %token prUNARYARITH +//UNSUP %token prREDUCTION +//UNSUP %token prNEGATION +//UNSUP %token prEVENTBEGIN +//UNSUP %token prTAGGED + // These prevent other conflicts -%left yP_ANDANDAND +%left yP_ANDANDAND +//UNSUP %left yMATCHES +//UNSUP %left prTAGGED +//UNSUP %left prSEQ_CLOCKING // PSL op precedence -%right yP_ORMINUSGT yP_OREQGT + +// Lowest precedence +// These are in IEEE 17.7.1 +//UNSUP %nonassoc yALWAYS yS_ALWAYS yEVENTUALLY yS_EVENTUALLY yACCEPT_ON yREJECT_ON ySYNC_ACCEPT_ON ySYNC_REJECT_ON + +%right yP_ORMINUSGT yP_OREQGT +//UNSUP %right yP_ORMINUSGT yP_OREQGT yP_POUNDMINUSPD yP_POUNDEQPD +//UNSUP %right yUNTIL yS_UNTIL yUNTIL_WITH yS_UNTIL_WITH yIMPLIES +//UNSUP %right yIFF +//UNSUP %left yOR +//UNSUP %left yAND +//UNSUP %nonassoc yNOT yNEXTTIME yS_NEXTTIME +//UNSUP %left yINTERSECT +//UNSUP %left yWITHIN +//UNSUP %right yTHROUGHOUT +//UNSUP %left prPOUNDPOUND_MULTI +//UNSUP %left yP_POUNDPOUND +//UNSUP %left yP_BRASTAR yP_BRAEQ yP_BRAMINUSGT yP_BRAPLUSKET + +// Not specified, but needed higher than yOR, lower than normal non-pexpr expressions +//UNSUP %left yPOSEDGE yNEGEDGE yEDGE + +//UNSUP %left '{' '}' // Verilog op precedence -%right yP_MINUSGT yP_LTMINUSGT -%right '?' ':' -%left yP_OROR -%left yP_ANDAND -%left '|' yP_NOR -%left '^' yP_XNOR -%left '&' yP_NAND -%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL -%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE -%left yP_SLEFT yP_SRIGHT yP_SSRIGHT -%left '+' '-' -%left '*' '/' '%' -%left yP_POW -%left prUNARYARITH yP_MINUSMINUS yP_PLUSPLUS prREDUCTION prNEGATION -%left '.' +%right yP_MINUSGT yP_LTMINUSGT +%right '?' ':' +%left yP_OROR +%left yP_ANDAND +%left '|' yP_NOR +%left '^' yP_XNOR +%left '&' yP_NAND +%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL +%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE yDIST +%left yP_SLEFT yP_SRIGHT yP_SSRIGHT +%left '+' '-' +%left '*' '/' '%' +%left yP_POW +%left prUNARYARITH yP_MINUSMINUS yP_PLUSPLUS prREDUCTION prNEGATION +%left '.' // Not in IEEE, but need to avoid conflicts; TICK should bind tightly just lower than COLONCOLON -%left yP_TICK -//%left '(' ')' '[' ']' yP_COLONCOLON '.' +%left yP_TICK +//%left '(' ')' '[' ']' yP_COLONCOLON '.' %nonassoc prLOWER_THAN_ELSE %nonassoc yELSE @@ -830,6 +1024,9 @@ description: // ==IEEE: description // unsupported // IEEE: config_declaration // // Verilator only | yaT_RESETALL { } // Else, under design, and illegal based on IEEE 22.3 + | yaT_NOUNCONNECTED { PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); } + | yaT_UNCONNECTED_PULL0 { PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); } + | yaT_UNCONNECTED_PULL1 { PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); } | vltItem { } | error { } ; @@ -916,7 +1113,7 @@ package_import_itemList: ; package_import_item: // ==IEEE: package_import_item - idAny/*package_identifier*/ yP_COLONCOLON package_import_itemObj + idCC/*package_identifier*/ yP_COLONCOLON package_import_itemObj { if (!VN_CAST($1, Package)) { $$ = NULL; @@ -943,7 +1140,7 @@ package_export_itemList: ; package_export_item: // ==IEEE: package_export_item - idAny yP_COLONCOLON package_import_itemObj + idCC yP_COLONCOLON package_import_itemObj { $$ = new AstPackageExport($3, VN_CAST($1, Package), *$3); SYMP->exportItem($1,*$3); } ; @@ -982,7 +1179,7 @@ modFront: yMODULE lifetimeE idAny { $$ = new AstModule($3,*$3); $$->lifetime($2); - $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); + $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); @@ -1052,19 +1249,25 @@ paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaratio // // We combine the two as we can't tell which follows a comma parameter_port_declarationFrontE param_assignment { $$ = $2; } | parameter_port_declarationTypeFrontE type_assignment { $$ = $2; } + | vlTag { $$ = NULL; } ; portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty - /* empty */ { $$ = NULL; } - | '(' ')' { $$ = NULL; } + /* empty */ { $$ = NULL; } + | '(' ')' { $$ = NULL; } // // .* expanded from module_declaration //UNSUP '(' yP_DOTSTAR ')' { UNSUP } | '(' {VARRESET_LIST(PORT);} list_of_ports ')' { $$ = $3; VARRESET_NONLIST(UNKNOWN); } ; list_of_ports: // IEEE: list_of_ports + list_of_port_declarations + portAndTag { $$ = $1; } + | list_of_ports ',' portAndTag { $$ = $1->addNextNull($3); } + ; + +portAndTag: port { $$ = $1; } - | list_of_ports ',' port { $$ = $1->addNextNull($3); } + | vlTag port { $$ = $2; } // Tag will associate with previous port ; port: // ==IEEE: port @@ -1208,10 +1411,10 @@ interface_item: // IEEE: interface_item + non_port_interface_item // // IEEE: generate_region | interface_generate_region { $$ = $1; } | interface_or_generate_item { $$ = $1; } - | program_declaration { $$ = NULL; v3error("Unsupported: program decls within interface decls"); } + | program_declaration { $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: program decls within interface decls"); } // // IEEE 1800-2017: modport_item // // See instead old 2012 position in interface_or_generate_item - | interface_declaration { $$ = NULL; v3error("Unsupported: interface decls within interface decls"); } + | interface_declaration { $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: interface decls within interface decls"); } | timeunits_declaration { $$ = $1; } // // See note in interface_or_generate item | module_common_item { $$ = $1; } @@ -1234,7 +1437,7 @@ interface_or_generate_item: // ==IEEE: interface_or_generate_item anonymous_program: // ==IEEE: anonymous_program // // See the spec - this doesn't change the scope, items still go up "top" - yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM { $1->v3error("Unsupported: Anonymous programs"); $$ = NULL; } + yPROGRAM ';' anonymous_program_itemListE yENDPROGRAM { BBUNSUP($1, "Unsupported: Anonymous programs"); $$ = NULL; } ; anonymous_program_itemListE: // IEEE: { anonymous_program_item } @@ -1275,7 +1478,7 @@ pgmFront: yPROGRAM lifetimeE idAny/*new_program*/ { $$ = new AstModule($3,*$3); $$->lifetime($2); - $$->inLibrary(PARSEP->inLibrary() || PARSEP->inCellDefine()); + $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); PARSEP->rootp()->addModulep($$); @@ -1331,7 +1534,8 @@ modport_itemList: // IEEE: part of modport_declaration ; modport_item: // ==IEEE: modport_item - id/*new-modport*/ '(' { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } + id/*new-modport*/ '(' + /*mid*/ { VARRESET_NONLIST(UNKNOWN); VARIO(INOUT); } /*cont*/ modportPortsDeclList ')' { $$ = new AstModport($1, *$1, $4); } ; @@ -1502,17 +1706,23 @@ port_declaration: // ==IEEE: port_declaration // // IEEE: input_declaration // // IEEE: output_declaration // // IEEE: ref_declaration - port_directionReset port_declNetE data_type { VARDTYPE($3); } + port_directionReset port_declNetE data_type + /*mid*/ { VARDTYPE($3); } /*cont*/ list_of_variable_decl_assignments { $$ = $5; } - | port_directionReset port_declNetE yVAR data_type { VARDTYPE($4); } + | port_directionReset port_declNetE yVAR data_type + /*mid*/ { VARDTYPE($4); } /*cont*/ list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); } + | port_directionReset port_declNetE yVAR implicit_typeE + /*mid*/ { VARDTYPE($4); } /*cont*/ list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE signingE rangeList { VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3), $4, true)); } + | port_directionReset port_declNetE signingE rangeList + /*mid*/ { VARDTYPE_NDECL(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3), $4, true)); } /*cont*/ list_of_variable_decl_assignments { $$ = $6; } - | port_directionReset port_declNetE signing { VARDTYPE_NDECL(new AstBasicDType($3, LOGIC_IMPLICIT, $3)); } + | port_directionReset port_declNetE signing + /*mid*/ { VARDTYPE_NDECL(new AstBasicDType($3, LOGIC_IMPLICIT, $3)); } /*cont*/ list_of_variable_decl_assignments { $$ = $5; } - | port_directionReset port_declNetE /*implicit*/ { VARDTYPE_NDECL(NULL);/*default_nettype*/} + | port_directionReset port_declNetE /*implicit*/ + /*mid*/ { VARDTYPE_NDECL(NULL);/*default_nettype*/} /*cont*/ list_of_variable_decl_assignments { $$ = $4; } // // IEEE: interface_declaration // // Looks just like variable declaration unless has a period @@ -1572,7 +1782,7 @@ simple_type: // ==IEEE: simple_type // // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE) // // Even though we looked up the type and have a AstNode* to it, // // we can't fully resolve it because it may have been just a forward definition. - | package_scopeIdFollowsE idType + | packageClassScopeE idType { AstRefDType* refp = new AstRefDType($2, *$2); refp->packagep($1); $$ = refp; } // @@ -1590,11 +1800,11 @@ data_type: // ==IEEE: data_type // // IEEE: class_type // // IEEE: ps_covergroup_identifier // // Don't distinguish between types and classes so all these combined - | package_scopeIdFollowsE idType packed_dimensionListE + | packageClassScopeE idType packed_dimensionListE { AstRefDType* refp = new AstRefDType($2, *$2); refp->packagep($1); $$ = GRAMMARP->createArray(refp, $3, true); } - | package_scopeIdFollowsE idType parameter_value_assignmentClass packed_dimensionListE + | packageClassScopeE idType parameter_value_assignmentClass packed_dimensionListE { AstRefDType* refp = new AstRefDType($2, *$2); refp->packagep($1); BBUNSUP($3->fileline(), "Unsupported: Parameter classes"); @@ -1646,10 +1856,12 @@ type_reference: // ==IEEE: type_reference struct_unionDecl: // IEEE: part of data_type // // packedSigningE is NOP for unpacked - ySTRUCT packedSigningE '{' { $$ = new AstStructDType($1, $2); SYMP->pushNew($$); } + ySTRUCT packedSigningE '{' + /*mid*/ { $$ = new AstStructDType($1, $2); SYMP->pushNew($$); } /*cont*/ struct_union_memberList '}' { $$=$4; $$->addMembersp($5); SYMP->popScope($$); } - | yUNION taggedE packedSigningE '{' { $$ = new AstUnionDType($1, $3); SYMP->pushNew($$); } + | yUNION taggedE packedSigningE '{' + /*mid*/ { $$ = new AstUnionDType($1, $3); SYMP->pushNew($$); } /*cont*/ struct_union_memberList '}' { $$=$5; $$->addMembersp($6); SYMP->popScope($$); } ; @@ -1660,9 +1872,11 @@ struct_union_memberList: // IEEE: { struct_union_member } ; struct_union_member: // ==IEEE: struct_union_member + // // UNSUP random_qualifer not propagagted until have randomize support random_qualifierE data_type_or_void - { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. + /*mid*/ { GRAMMARP->m_memDTypep = $2; } // As a list follows, need to attach this dtype to each member. /*cont*/ list_of_member_decl_assignments ';' { $$ = $4; GRAMMARP->m_memDTypep = NULL; } + | vlTag { $$ = NULL; } ; list_of_member_decl_assignments: // Derived from IEEE: list_of_variable_decl_assignments @@ -1679,7 +1893,7 @@ member_decl_assignment: // Derived from IEEE: variable_decl_assignment PARSEP->tagNodep($$); } | id variable_dimensionListE '=' variable_declExpr - { $4->v3error("Unsupported: Initial values in struct/union members."); + { BBUNSUP($4, "Unsupported: Initial values in struct/union members."); // But still need error if packed according to IEEE 7.2.2 $$ = NULL; } | idSVKwd { $$ = NULL; } @@ -1695,9 +1909,9 @@ member_decl_assignment: // Derived from IEEE: variable_decl_assignment | '=' class_new { NULL; BBUNSUP($1, "Unsupported: member declaration assignment with new()"); } ; -list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments +list_of_variable_decl_assignments: // ==IEEE: list_of_variable_decl_assignments variable_decl_assignment { $$ = $1; } - | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = $1->addNextNull($3); } + | list_of_variable_decl_assignments ',' variable_decl_assignment { $$ = VN_CAST($1->addNextNull($3), Var); } ; variable_decl_assignment: // ==IEEE: variable_decl_assignment @@ -1750,26 +1964,25 @@ variable_dimension: // ==IEEE: variable_dimension '[' ']' { $$ = new AstUnsizedRange($1); } // // IEEE: unpacked_dimension | anyrange { $$ = $1; } - | '[' constExpr ']' { if (VN_IS($2, Unbounded)) { $2->deleteTree(); $$ = new AstQueueRange($1); } - else { $$ = new AstRange($1, new AstConst($1, 0), - new AstSub($1, $2, new AstConst($1, 1))); } } - // // IEEE: associative_dimension - | '[' data_type ']' { $$ = new AstAssocRange($1, $2); } - | yP_BRASTAR ']' { $$ = NULL; v3error("Unsupported: [*] wildcard associative arrays"); } - | '[' '*' ']' { $$ = NULL; v3error("Unsupported: [*] wildcard associative arrays"); } + // // IEEE: unpacked_dimension (if const_expr) + // // IEEE: associative_dimension (if data_type) + // // Can't tell which until see if expr is data type or not + | '[' exprOrDataType ']' { $$ = new AstBracketRange($1, $2); } + | yP_BRASTAR ']' { $$ = NULL; BBUNSUP($1, "Unsupported: [*] wildcard associative arrays"); } + | '[' '*' ']' { $$ = NULL; BBUNSUP($2, "Unsupported: [*] wildcard associative arrays"); } // // IEEE: queue_dimension // // '[' '$' ']' -- $ is part of expr, see '[' constExpr ']' // // '[' '$' ':' expr ']' -- anyrange:expr:$ ; -random_qualifierE: // IEEE: random_qualifier + empty - /*empty*/ { } - | random_qualifier { } +random_qualifierE: // IEEE: random_qualifier + empty + /*empty*/ { $$ = VMemberQualifiers::none(); } + | random_qualifier { $$ = $1; } ; -random_qualifier: // ==IEEE: random_qualifier - yRAND { } // Ignored until we support randomize() - | yRANDC { } // Ignored until we support randomize() +random_qualifier: // ==IEEE: random_qualifier + yRAND { $$ = VMemberQualifiers::none(); $$.m_rand = true; } + | yRANDC { $$ = VMemberQualifiers::none(); $$.m_randc = true; } ; taggedE: @@ -1807,7 +2020,7 @@ enum_base_typeE: // IEEE: enum_base_type // // however other simulators allow [ class_scope | package_scope ] type_identifier | idAny rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($1, *$1), $2, true); } - | package_scopeIdFollows idType rangeListE + | packageClassScope idAny rangeListE { AstRefDType* refp = new AstRefDType($2, *$2); refp->packagep($1); $$ = GRAMMARP->createArray(refp, $3, true); } @@ -1850,23 +2063,26 @@ data_declaration: // ==IEEE: data_declaration // // Therefore the virtual_interface_declaration term isn't used // // 1800-2009: //UNSUP net_type_declaration { $$ = $1; } + | vlTag { $$ = NULL; } ; class_property: // ==IEEE: class_property, which is {property_qualifier} data_declaration - memberQualResetListE data_declarationVarClass { $$ = $2; } - | memberQualResetListE type_declaration { $$ = $2; } - | memberQualResetListE package_import_declaration { $$ = $2; } + memberQualListE data_declarationVarClass { $$ = $2; $1.applyToNodes($2); } + // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others + | memberQualListE type_declaration { $$ = $2; } + // // UNSUP: Import needs to apply local/protected from memberQualList, and error on others + | memberQualListE package_import_declaration { $$ = $2; } // // IEEE: virtual_interface_declaration // // "yVIRTUAL yID yID" looks just like a data_declaration // // Therefore the virtual_interface_declaration term isn't used ; -data_declarationVar: // IEEE: part of data_declaration +data_declarationVar: // IEEE: part of data_declaration // // The first declaration has complications between assuming what's the type vs ID declaring data_declarationVarFront list_of_variable_decl_assignments ';' { $$ = $2; } ; -data_declarationVarClass: // IEEE: part of data_declaration (for class_property) +data_declarationVarClass: // IEEE: part of data_declaration (for class_property) // // The first declaration has complications between assuming what's the type vs ID declaring data_declarationVarFrontClass list_of_variable_decl_assignments ';' { $$ = $2; } ; @@ -1927,8 +2143,8 @@ data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_prop //UNSUPnet_type_declaration: // IEEE: net_type_declaration //UNSUP yNETTYPE data_type idAny/*net_type_identifier*/ ';' { } //UNSUP // // package_scope part of data_type -//UNSUP | yNETTYPE data_type idAny yWITH__ETC package_scopeIdFollows id/*tf_identifier*/ ';' { } -//UNSUP | yNETTYPE package_scopeIdFollows id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { } +//UNSUP | yNETTYPE data_type idAny yWITH__ETC packageClassScope id/*tf_identifier*/ ';' { } +//UNSUP | yNETTYPE packageClassScope id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { } //UNSUP ; implicit_typeE: // IEEE: part of *data_type_or_implicit @@ -1975,6 +2191,10 @@ dtypeAttr: yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::DT_PUBLIC); } ; +vlTag: // verilator tag handling + yVL_TAG { if (PARSEP->tagNodep()) PARSEP->tagNodep()->tag(*$1); } + ; + //************************************************ // Module Items @@ -1998,9 +2218,9 @@ non_port_module_item: // ==IEEE: non_port_module_item | module_or_generate_item { $$ = $1; } | specify_block { $$ = $1; } | specparam_declaration { $$ = $1; } - | program_declaration { $$ = NULL; v3error("Unsupported: program decls within module decls"); } - | module_declaration { $$ = NULL; v3error("Unsupported: module decls within module decls"); } - | interface_declaration { $$ = NULL; v3error("Unsupported: interface decls within module decls"); } + | program_declaration { $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: program decls within module decls"); } + | module_declaration { $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: module decls within module decls"); } + | interface_declaration { $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: interface decls within module decls"); } | timeunits_declaration { $$ = $1; } // // Verilator specific | yaSCHDR { $$ = new AstScHdr($1,*$1); } @@ -2040,9 +2260,9 @@ module_common_item: // ==IEEE: module_common_item | final_construct { $$ = $1; } // // IEEE: always_construct // // Verilator only - event_control attached to always - | yALWAYS event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, $2,$3); } - | yALWAYS_FF event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, $2,$3); } - | yALWAYS_LATCH event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); } + | yALWAYS stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, NULL, $2); } + | yALWAYS_FF stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, NULL, $2); } + | yALWAYS_LATCH stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, NULL, $2); } | yALWAYS_COMB stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, NULL, $2); } // | loop_generate_construct { $$ = $1; } @@ -2306,7 +2526,7 @@ delay_control: //== IEEE: delay_control delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier - ps_id_etc { $$ = $1; } + packageClassScopeE varRefBase { $$ = $2; $2->packagep($1); } | yaINTNUM { $$ = new AstConst($1, *$1); } | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } | timeNumAdjusted { $$ = $1; } @@ -2399,7 +2619,7 @@ packed_dimensionList: // IEEE: { packed_dimension } packed_dimension: // ==IEEE: packed_dimension anyrange { $$ = $1; } - | '[' ']' { $$ = NULL; $1->v3error("Unsupported: [] dimensions"); } + | '[' ']' { $$ = NULL; BBUNSUP($1, "Unsupported: [] dimensions"); } ; //************************************************ @@ -2408,8 +2628,15 @@ packed_dimension: // ==IEEE: packed_dimension param_assignment: // ==IEEE: param_assignment // // IEEE: constant_param_expression // // constant_param_expression: '$' is in expr - id/*new-parameter*/ variable_dimensionListE sigAttrListE exprEqE - { $$ = VARDONEA($1, *$1, $2, $3); if ($4) $$->valuep($4); } + id/*new-parameter*/ variable_dimensionListE sigAttrListE exprOrDataTypeEqE + { // To handle #(type A=int, B=A) and properly imply B + // as a type (for parsing) we need to detect "A" is a type + if (AstNodeDType* refp = VN_CAST($4, NodeDType)) { + if (VSymEnt* foundp = SYMP->symCurrentp()->findIdFallback(refp->name())) { + UINFO(9, "declaring type via param assignment" << foundp->nodep() << endl); + VARDTYPE(new AstParseTypeDType($1)) + SYMP->reinsert(foundp->nodep()->cloneTree(false), NULL, *$1); }} + $$ = VARDONEA($1, *$1, $2, $3); if ($4) $$->valuep($4); } ; list_of_param_assignments: // ==IEEE: list_of_param_assignments @@ -2455,6 +2682,9 @@ etcInst: // IEEE: module_instantiation + gate_instantiation + udp_insta ; instDecl: + // // Currently disambiguated from data_declaration based on + // // VARs being type, and cells non-type. + // // IEEE requires a '(' to disambiguate, we need TODO force this id parameter_value_assignmentE {INSTPREP($1,*$1,$2);} instnameList ';' { $$ = $4; GRAMMARP->m_impliedDecl=false; if (GRAMMARP->m_instParamp) { @@ -2463,7 +2693,7 @@ instDecl: } } // // IEEE: interface_identifier' .' modport_identifier list_of_interface_identifiers | id/*interface*/ '.' id/*modport*/ - { VARRESET_NONLIST(AstVarType::IFACEREF); + /*mid*/ { VARRESET_NONLIST(AstVarType::IFACEREF); VARDTYPE(new AstIfaceRefDType($1, $3, "", *$1, *$3)); } /*cont*/ mpInstnameList ';' { $$ = VARDONEP($5,NULL,NULL); } @@ -2518,7 +2748,7 @@ instRange: ; cellparamList: - {VARRESET_LIST(UNKNOWN);} cellparamItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } + { GRAMMARP->pinPush(); } cellparamItList { $$ = $2; GRAMMARP->pinPop(CRELINE()); } ; cellpinList: @@ -2552,7 +2782,7 @@ cellparamItemE: // IEEE: named_parameter_assignment + empty //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ')' { } //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ':' expr ')' { } // // data_type for 'parameter type' hookups - | exprOrDataType { $$ = new AstPin($1->fileline(), PINNUMINC(), "", $1); } + | exprOrDataType { $$ = new AstPin(FILELINE_OR_CRE($1), PINNUMINC(), "", $1); } //UNSUP exprOrDataType/*expr*/ ':' expr { } //UNSUP exprOrDataType/*expr*/ ':' expr ':' expr { } ; @@ -2589,11 +2819,6 @@ attr_event_control: // ==IEEE: event_control | '@' '*' { $$ = NULL; } ; -event_controlE: - /* empty */ { $$ = NULL; } - | event_control { $$ = $1; } - ; - event_control: // ==IEEE: event_control '@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); } | '@' '(' '*' ')' { $$ = NULL; } @@ -2608,17 +2833,17 @@ event_control: // ==IEEE: event_control // // 1995 delay with a sequence with parameters. // // Alternatively split this out of event_control, and delay_or_event_controlE // // and anywhere delay_or_event_controlE is called allow two expressions - //| '@' idClassSel '(' list_of_argumentsE ')' { } + //UNSUP '@' idClassSel '(' list_of_argumentsE ')' { } ; event_expression: // IEEE: event_expression - split over several //UNSUP // Below are all removed senitem { $$ = $1; } - | event_expression yOR senitem { $$ = VN_CAST($1->addNextNull($3), NodeSenItem); } - | event_expression ',' senitem { $$ = VN_CAST($1->addNextNull($3), NodeSenItem); } /* Verilog 2001 */ + | event_expression yOR senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } + | event_expression ',' senitem { $$ = VN_CAST($1->addNextNull($3), SenItem); } /* Verilog 2001 */ //UNSUP // Above are all removed, replace with: //UNSUP ev_expr { $$ = $1; } - //UNSUP event_expression ',' ev_expr %prec yOR { $$ = VN_CAST($1->addNextNull($3), NodeSenItem); } + //UNSUP event_expression ',' ev_expr %prec yOR { $$ = VN_CAST($1->addNextNull($3), SenItem); } ; senitem: // IEEE: part of event_expression, non-'OR' ',' terms @@ -2815,13 +3040,13 @@ statement_item: // IEEE: statement_item // // Because we've joined class_constructor_declaration into generic functions // // Way over-permissive; // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] - | fexpr '.' class_new ';' { $$ = NULL; BBUNSUP($1, "Unsupported: dotted new"); } + | fexpr '.' class_new ';' { $$ = new AstDot($2, false, $1, $3); } // | statementVerilatorPragmas { $$ = $1; } // // // IEEE: disable_statement | yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable($1,*$2); } - | yDISABLE yFORK ';' { $$ = NULL; BBUNSUP($1, "Unsupported: disable fork statements"); } + | yDISABLE yFORK ';' { $$ = new AstDisableFork($1); } // // IEEE: event_trigger | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' { // AssignDly because we don't have stratified queue, and need to @@ -2844,7 +3069,7 @@ statement_item: // IEEE: statement_item } else $$ = new AstWhile($1,$5,NULL); } // // IEEE says array_identifier here, but dotted accepted in VMM and 1800-2009 - | yFOREACH '(' idClassForeach '[' loop_variables ']' ')' stmtBlock { $$ = new AstForeach($1,$3,$5,$8); } + | yFOREACH '(' idClassSelForeach ')' stmtBlock { $$ = new AstForeach($1, $3, $5); } // // // IEEE: jump_statement | yRETURN ';' { $$ = new AstReturn($1); } @@ -2855,14 +3080,14 @@ statement_item: // IEEE: statement_item | par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control | delay_control stmtBlock { $$ = new AstDelay($1->fileline(), $1); $$->addNextNull($2); } - //UNSUP event_control stmtBlock { UNSUP } + | event_control stmtBlock { $$ = new AstTimingControl(FILELINE_OR_CRE($1), $1, $2); } //UNSUP cycle_delay stmtBlock { UNSUP } // | seq_block { $$ = $1; } // // // IEEE: wait_statement - | yWAIT '(' expr ')' stmtBlock { $$ = NULL; BBUNSUP($1, "Unsupported: wait statements"); } - | yWAIT yFORK ';' { $$ = NULL; BBUNSUP($1, "Unsupported: wait fork statements"); } + | yWAIT '(' expr ')' stmtBlock { $$ = new AstWait($1, $3, $5); } + | yWAIT yFORK ';' { $$ = new AstWaitFork($1); } //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { UNSUP } // // // IEEE: procedural_assertion_statement @@ -3056,11 +3281,11 @@ caseCondList: // IEEE: part of case_item ; patternNoExpr: // IEEE: pattern **Excluding Expr* - '.' id/*variable*/ { $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); } - | yP_DOTSTAR { $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); } + '.' id/*variable*/ { $$ = NULL; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } + | yP_DOTSTAR { $$ = NULL; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } // // IEEE: "expr" excluded; expand in callers // // "yTAGGED id [expr]" Already part of expr - //UNSUP yTAGGED id/*member_identifier*/ patternNoExpr { $$ = NULL; $1->v3error("Unsupported: '{} tagged patterns"); } + //UNSUP yTAGGED id/*member_identifier*/ patternNoExpr { $$ = NULL; BBUNSUP($1, "Unsupported: '{} tagged patterns"); } // // "yP_TICKBRA patternList '}'" part of expr under assignment_pattern ; @@ -3082,10 +3307,10 @@ patternMemberList: // IEEE: part of pattern and assignment_pattern patternMemberOne: // IEEE: part of pattern and assignment_pattern patternKey ':' expr { $$ = new AstPatMember($1->fileline(),$3,$1,NULL); } - | patternKey ':' patternNoExpr { $$ = NULL; $2->v3error("Unsupported: '{} .* patterns"); } + | patternKey ':' patternNoExpr { $$ = NULL; BBUNSUP($2, "Unsupported: '{} .* patterns"); } // // From assignment_pattern_key | yDEFAULT ':' expr { $$ = new AstPatMember($1,$3,NULL,NULL); $$->isDefault(true); } - | yDEFAULT ':' patternNoExpr { $$ = NULL; $2->v3error("Unsupported: '{} .* patterns"); } + | yDEFAULT ':' patternNoExpr { $$ = NULL; BBUNSUP($2, "Unsupported: '{} .* patterns"); } ; patternKey: // IEEE: merge structure_pattern_key, array_pattern_key, assignment_pattern_key @@ -3118,7 +3343,8 @@ assignment_pattern: // ==IEEE: assignment_pattern // // also IEEE "''{' array_pattern_key ':' ... | yP_TICKBRA patternMemberList '}' { $$ = new AstPattern($1,$2); } // // IEEE: Not in grammar, but in VMM - | yP_TICKBRA '}' { $$ = new AstPattern($1, NULL); $1->v3error("Unsupported: Empty '{}"); } + | yP_TICKBRA '}' + { $$ = new AstPattern($1, NULL); $1->v3warn(E_UNSUPPORTED, "Unsupported: Empty '{}"); } ; // "datatype id = x {, id = x }" | "yaId = x {, id=x}" is legal @@ -3131,7 +3357,7 @@ for_initialization: // ==IEEE: for_initialization + for_variable_declarat for_initializationItemList: // IEEE: [for_variable_declaration...] for_initializationItem { $$ = $1; } - | for_initializationItemList ',' for_initializationItem { $$ = $1; $2->v3error("Unsupported: for loop initialization after the first comma"); } + | for_initializationItemList ',' for_initializationItem { $$ = $1; BBUNSUP($2, "Unsupported: for loop initialization after the first comma"); } ; for_initializationItem: // IEEE: variable_assignment + for_variable_declaration @@ -3157,7 +3383,7 @@ for_stepE: // IEEE: for_step + empty for_step: // IEEE: for_step for_step_assignment { $$ = $1; } - | for_step ',' for_step_assignment { $$ = $1; $1->v3error("Unsupported: for loop step after the first comma"); } + | for_step ',' for_step_assignment { $$ = AstNode::addNextNull($1, $3); } ; for_step_assignment: // ==IEEE: for_step_assignment @@ -3185,8 +3411,8 @@ loop_variables: // IEEE: loop_variables taskRef: // IEEE: part of tf_call id { $$ = new AstTaskRef($1,*$1,NULL); } | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1,*$1,$3); } - | package_scopeIdFollows id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, $1, new AstTaskRef($2,*$2,$4)); } + | packageClassScope id '(' list_of_argumentsE ')' + { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), new AstTaskRef($2, *$2, $4)); } ; funcRef: // IEEE: part of tf_call @@ -3199,9 +3425,10 @@ funcRef: // IEEE: part of tf_call // // sequence_instance sequence_identifier sequence_actual_arg // // let_expression let_identifier let_actual_arg // - id '(' list_of_argumentsE ')' { $$ = new AstFuncRef($1, *$1, $3); } - | package_scopeIdFollows id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, $1, new AstFuncRef($2,*$2,$4)); } + id '(' list_of_argumentsE ')' + { $$ = new AstFuncRef($1, *$1, $3); } + | packageClassScope id '(' list_of_argumentsE ')' + { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), new AstFuncRef($2, *$2, $4)); } //UNSUP list_of_argumentE should be pev_list_of_argumentE //UNSUP: idDotted is really just id to allow dotted method calls ; @@ -3209,7 +3436,10 @@ funcRef: // IEEE: part of tf_call task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as task) // // IEEE: tf_call taskRef { $$ = $1; } - //UNSUP funcRef yWITH__PAREN '(' expr ')' { /*UNSUP*/ } + // // funcref below not task ref to avoid conflict, must later handle either + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, true, $1, $4); } + // // can call as method and yWITH without parenthesis + | id yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, true, new AstFuncRef($1, *$1, NULL), $4); } | system_t_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it @@ -3222,14 +3452,17 @@ task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as tas function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as function) // // IEEE: tf_call funcRef { $$ = $1; } - //UNSUP funcRef yWITH__PAREN '(' expr ')' { /*UNSUP*/ } + | funcRef yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, false, $1, $4); } + // // can call as method and yWITH without parenthesis + | id yWITH__PAREN '(' expr ')' { $$ = new AstWith($2, false, new AstFuncRef($1, *$1, NULL), $4); } | system_f_call { $$ = $1; } // // IEEE: method_call requires a "." so is in expr // // IEEE: ['std::'] not needed, as normal std package resolution will find it // // IEEE: randomize_call // // We implement randomize as a normal funcRef, since randomize isn't a keyword // // Note yNULL is already part of expressions, so they come for free - //UNSUP funcRef yWITH__CUR constraint_block { } + | funcRef yWITH__CUR constraint_block { $$ = $1; BBUNSUP($2, "Unsupported: randomize() 'with' constraint"); } + | funcRef yWITH__CUR '{' '}' { $$ = new AstWith($2, false, $1, NULL); } ; system_t_call: // IEEE: system_tf_call (as task) @@ -3269,11 +3502,11 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_STOP parenE { $$ = new AstStop($1, false); } | yD_STOP '(' expr ')' { $$ = new AstStop($1, false); DEL($3); } // - | yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6); } - | yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6); } - | yD_SWRITEB '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'b'); } - | yD_SWRITEH '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'h'); } - | yD_SWRITEO '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1, $3, *$5, $6, 'o'); } + | yD_SFORMAT '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5); } + | yD_SWRITE '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5); } + | yD_SWRITEB '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'b'); } + | yD_SWRITEH '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'h'); } + | yD_SWRITEO '(' expr ',' exprDispList ')' { $$ = new AstSFormat($1, $3, $5, 'o'); } // | yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, NULL); } | yD_DISPLAY '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, NULL, $3); } @@ -3325,9 +3558,12 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } | yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } // - | yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1,$3,$5,NULL,NULL); } - | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1,$3,$5,$7,NULL); } - | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1,$3,$5,$7,$9); } + | yD_WRITEMEMB '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, false, $3, $5, NULL, NULL); } + | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, NULL); } + | yD_WRITEMEMB '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, false, $3, $5, $7, $9); } + | yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1, true, $3, $5, NULL, NULL); } + | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1, true, $3, $5, $7, NULL); } + | yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1, true, $3, $5, $7, $9); } // // Any system function as a task | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } @@ -3359,6 +3595,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_BITS '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); } | yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); } | yD_BITSTOSHORTREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); UNSUPREAL($1); } + | yD_CAST '(' expr ',' expr ')' { $$ = new AstCastDynamic($1, $3, $5); } | yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); } | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } | yD_COS '(' expr ')' { $$ = new AstCosD($1,$3); } @@ -3368,7 +3605,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstCountBits($1,$3,$5,$7,$9); } | yD_COUNTBITS '(' expr ',' expr ',' expr ',' expr ',' exprList ')' { $$ = new AstCountBits($1, $3, $5, $7, $9); - $11->v3error("Unsupported: $countbits with more than 3 control fields"); } + BBUNSUP($11, "Unsupported: $countbits with more than 3 control fields"); } | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } | yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); } | yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); } @@ -3402,11 +3639,11 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); } | yD_PAST '(' expr ')' { $$ = new AstPast($1,$3, NULL); } | yD_PAST '(' expr ',' expr ')' { $$ = new AstPast($1,$3, $5); } - | yD_PAST '(' expr ',' expr ',' expr ')' { $1->v3error("Unsupported: $past expr2 and clock arguments"); $$ = $3; } - | yD_PAST '(' expr ',' expr ',' expr ',' expr')' { $1->v3error("Unsupported: $past expr2 and clock arguments"); $$ = $3; } + | yD_PAST '(' expr ',' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } + | yD_PAST '(' expr ',' expr ',' expr ',' expr')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); } // // Seeding is unsupported as would be slow to invalidate all per-thread RNGs - | yD_RANDOM '(' expr ')' { $$ = new AstRand($1); $1->v3error("Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag"); } + | yD_RANDOM '(' expr ')' { $$ = new AstRand($1); BBUNSUP($1, "Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag"); } | yD_RANDOM parenE { $$ = new AstRand($1); } | yD_REALTIME parenE { $$ = new AstTimeD($1, VTimescale(VTimescale::NONE)); } | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); } @@ -3415,7 +3652,7 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,$5); } | yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); } | yD_SAMPLED '(' expr ')' { $$ = new AstSampled($1, $3); } - | yD_SFORMATF '(' str commaEListE ')' { $$ = new AstSFormatF($1,*$3,false,$4); } + | yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF($1, AstSFormatF::NoFormat(), $3, 'd', false); } | yD_SHORTREALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); UNSUPREAL($1); } | yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); } | yD_SIN '(' expr ')' { $$ = new AstSinD($1,$3); } @@ -3533,9 +3770,9 @@ funcIsolateE: | yVL_ISOLATE_ASSIGNMENTS { $$ = 1; } ; -method_prototype: - task_prototype { } - | function_prototype { } +method_prototype: + task_prototype { $$ = $1; } + | function_prototype { $$ = $1; } ; lifetimeE: // IEEE: [lifetime] @@ -3545,14 +3782,14 @@ lifetimeE: // IEEE: [lifetime] lifetime: // ==IEEE: lifetime // // Note lifetime used by members is instead under memberQual - ySTATIC__ETC { $$ = VLifetime::STATIC; BBUNSUP($1, "Unsupported: Static in this context"); } + ySTATIC__ETC { $$ = VLifetime::STATIC; } | yAUTOMATIC { $$ = VLifetime::AUTOMATIC; } ; taskId: tfIdScoped { $$ = new AstTask($1, *$1, NULL); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $1); } ; funcId: // IEEE: function_data_type_or_implicit + part of function_body_declaration @@ -3561,22 +3798,22 @@ funcId: // IEEE: function_data_type_or_implicit + part of function_bod /**/ tfIdScoped { $$ = new AstFunc($1,*$1,NULL, new AstBasicDType($1, LOGIC_IMPLICIT)); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $1); } | signingE rangeList tfIdScoped { $$ = new AstFunc($3,*$3,NULL, GRAMMARP->addRange(new AstBasicDType($3, LOGIC_IMPLICIT, $1), $2,true)); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $3); } | signing tfIdScoped { $$ = new AstFunc($2,*$2,NULL, new AstBasicDType($2, LOGIC_IMPLICIT, $1)); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $2); } | data_type tfIdScoped { $$ = new AstFunc($2,*$2,NULL,$1); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $2); } // // To verilator tasks are the same as void functions (we separately detect time passing) | yVOID tfIdScoped { $$ = new AstTask($2, *$2, NULL); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $2); } ; funcIdNew: // IEEE: from class_constructor_declaration @@ -3588,19 +3825,25 @@ funcIdNew: // IEEE: from class_constructor_declaration { $$ = new AstFunc($1, "new", NULL, NULL); $$->isConstructor(true); SYMP->pushNewUnder($$, NULL); } - | class_scopeWithoutId yNEW__PAREN + | packageClassScopeNoId yNEW__PAREN { $$ = new AstFunc($2, "new", NULL, NULL); BBUNSUP($2, "Unsupported: scoped new constructor"); $$->isConstructor(true); - SYMP->pushNewUnder($$, NULL); } + SYMP->pushNewUnderNodeOrCurrent($$, $1); } ; tfIdScoped: // IEEE: part of function_body_declaration/task_body_declaration // // IEEE: [ interface_identifier '.' | class_scope ] function_identifier - id { $$=$1; $$ = $1; } - | id/*interface_identifier*/ '.' id { $$=$3; $$ = $3; BBUNSUP($2, "Unsupported: Out of block function declaration"); } - | class_scopeIdFollows id { $$=$2; $$=$1; $$=$2; - BBUNSUP($1, "Unsupported: Out of class block function declaration"); } + id + { $$ = $1; $$ = NULL; $$ = $1; } + // + | id/*interface_identifier*/ '.' id + { $$ = $3; $$ = NULL; $$ = $3; + BBUNSUP($2, "Unsupported: Out of block function declaration"); } + // + | packageClassScope id + { $$ = $2; $$ = $1; $$ = $2; + BBUNSUP($1, "Unsupported: Out of class block function declaration"); } ; tfGuts: @@ -3634,7 +3877,7 @@ tf_item_declarationVerilator: // Verilator extensions tf_port_listE: // IEEE: tf_port_list + empty // // Empty covered by tf_port_item /*empty*/ - { VARRESET_LIST(UNKNOWN); VARIO(INPUT); } + /*mid*/ { VARRESET_LIST(UNKNOWN); VARIO(INPUT); } /*cont*/ tf_port_listList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; @@ -3686,13 +3929,21 @@ parenE: // // IEEE: built_in_method_call // // method_call_root not needed, part of expr resolution // // What's left is below array_methodNoRoot -array_methodNoRoot: +array_methodNoRoot: yOR { $$ = new AstFuncRef($1, "or", NULL); } | yAND { $$ = new AstFuncRef($1, "and", NULL); } | yXOR { $$ = new AstFuncRef($1, "xor", NULL); } | yUNIQUE { $$ = new AstFuncRef($1, "unique", NULL); } ; +array_methodWith: + array_methodNoRoot { $$ = $1; } + | array_methodNoRoot parenE yWITH__PAREN '(' expr ')' + { $$ = new AstWith($3, false, $1, $5); } + | array_methodNoRoot '(' expr ')' yWITH__PAREN '(' expr ')' + { $$ = new AstWith($5, false, $1, $7); $1->addPinsp($3); } + ; + dpi_import_export: // ==IEEE: dpi_import_export yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype ';' { $$ = $5; if (*$4 != "") $5->cname(*$4); @@ -3742,6 +3993,12 @@ exprEqE: // IEEE: optional '=' expression (part of param_assignment) | '=' expr { $$ = $2; } ; +exprOrDataTypeEqE: // IEEE: optional '=' expression (part of param_assignment) + // // constant_param_expression: '$' is in expr + /*empty*/ { $$ = NULL; } + | '=' exprOrDataType { $$ = $2; } + ; + constExpr: expr { $$ = $1; } ; @@ -3842,7 +4099,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation) | '{' '}' { $$ = new AstConst($1, AstConst::LogicFalse()); - $1->v3error("Unsupported: empty queues (\"{ }\")"); } + BBUNSUP($1, "Unsupported: empty queues (\"{ }\")"); } // // // IEEE: concatenation/constant_concatenation // // Part of exprOkLvalue below @@ -3855,7 +4112,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // method_call | ~l~expr '.' function_subroutine_callNoMethod { $$ = new AstDot($2, false, $1, $3); } // // method_call:array_method requires a '.' - | ~l~expr '.' array_methodNoRoot { $$ = new AstDot($2, false, $1, $3); } + | ~l~expr '.' array_methodWith { $$ = new AstDot($2, false, $1, $3); } // // // IEEE: let_expression // // see funcRef @@ -3909,7 +4166,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // // IEEE: expression_or_dist - here to avoid reduce problems // // "expr yDIST '{' dist_list '}'" - //UNSUP ~l~expr yDIST '{' dist_list '}' { UNSUP } + | ~l~expr yDIST '{' dist_list '}' { $$ = $1; BBUNSUP($2, "Unsupported: dist"); } ; fexpr: // For use as first part of statement (disambiguates <=) @@ -4003,18 +4260,15 @@ exprScope: // scope and variable for use to inside an expression // // IEEE: [ implicit_class_handle . | class_scope | package_scope ] hierarchical_identifier select // // Or method_call_body without parenthesis // // See also varRefClassBit, which is the non-expr version of most of this - yTHIS { $$ = new AstConst($1, AstConst::LogicFalse()); - BBUNSUP($1, "Unsupported: this"); } + yTHIS { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "this"); } | yD_ROOT { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"); } | idArrayed { $$ = $1; } - | package_scopeIdFollows idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } - | class_scopeIdFollows idArrayed { $$ = $2; BBUNSUP($1, "Unsupported: scoped class reference"); } + | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), CAST_PACKAGE_CLASS($1), $2); } | ~l~expr '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } // // expr below must be a "yTHIS" | ~l~expr '.' ySUPER { $$ = $1; BBUNSUP($3, "Unsupported: super"); } // // Part of implicit_class_handle - | ySUPER { $$ = new AstConst($1, AstConst::LogicFalse()); - BBUNSUP($1, "Unsupported: super"); } + | ySUPER { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "super"); } ; fexprScope: // exprScope, For use as first part of statement (disambiguates <=) @@ -4073,11 +4327,6 @@ exprDispList: // exprList for within $display { $$ = $1; $1->addNext(new AstConst($2, AstConst::VerilogStringLiteral(), " ")); } ; -commaEListE: - /* empty */ { $$ = NULL; } - | ',' exprList { $$ = $2; } - ; - vrdList: idClassSel { $$ = $1; } | vrdList ',' idClassSel { $$ = $1;$1->addNext($3); } @@ -4432,12 +4681,13 @@ junkToSemi: id: yaID__ETC { $$ = $1; $$=$1; } + | idRandomize { $$ = $1; $$=$1; } ; idAny: // Any kind of identifier - yaID__aPACKAGE { $$ = $1; $$=$1; } + yaID__ETC { $$ = $1; $$=$1; } | yaID__aTYPE { $$ = $1; $$=$1; } - | yaID__ETC { $$ = $1; $$=$1; } + | idRandomize { $$ = $1; $$=$1; } ; idType: // IEEE: class_identifier or other type identifier @@ -4445,6 +4695,15 @@ idType: // IEEE: class_identifier or other type identifier yaID__aTYPE { $$ = $1; $$=$1; } ; +idCC: // IEEE: class/package then :: + // lexer matches this: yaID_LEX [ '#' '(' ... ')' ] yP_COLONCOLON + yaID__CC { $$ = $1; $$=$1; } + ; + +idRandomize: // Keyword as an identifier + yRANDOMIZE { static string s = "randomize"; $$ = &s; $$ = $1; } + ; + idSVKwd: // Warn about non-forward compatible Verilog 2001 code // // yBIT, yBYTE won't work here as causes conflicts yDO { static string s = "do" ; $$ = &s; ERRSVKWD($1,*$$); $$=$1; } @@ -4477,12 +4736,25 @@ variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variable_l idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged variable idDotted { $$ = $1; } // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select - | yTHIS '.' idDotted { $$ = $3; BBUNSUP($1, "Unsupported: this"); } - | ySUPER '.' idDotted { $$ = $3; BBUNSUP($1, "Unsupported: super"); } + | yTHIS '.' idDotted + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "this"), $3); } + | ySUPER '.' idDotted + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } | yTHIS '.' ySUPER '.' idDotted { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } // // Expanded: package_scope idDotted - | class_scopeIdFollows idDotted { $$ = $2; BBUNSUP($2, "Unsupported: package scoped id"); } - | package_scopeIdFollows idDotted { $$ = $2; BBUNSUP($2, "Unsupported: class scoped id"); } + | packageClassScope idDotted { $$ = $2; BBUNSUP($2, "Unsupported: package scoped id"); } + ; + +idClassSelForeach: + idDottedForeach { $$ = $1; } + // // IEEE: [ implicit_class_handle . | package_scope ] hierarchical_variable_identifier select + | yTHIS '.' idDottedForeach + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "this"), $3); } + | ySUPER '.' idDottedForeach + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } + | yTHIS '.' ySUPER '.' idDottedForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } + // // Expanded: package_scope idForeach + | packageClassScope idDottedForeach { $$ = $2; BBUNSUP($2, "Unsupported: package/class scoped id"); } ; idDotted: @@ -4491,37 +4763,51 @@ idDotted: | idDottedMore { $$ = $1; } ; +idDottedForeach: + yD_ROOT '.' idDottedMoreForeach + { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"), $3); } + | idDottedMoreForeach { $$ = $1; } + ; + idDottedMore: idArrayed { $$ = $1; } | idDottedMore '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } ; +idDottedMoreForeach: + idArrayedForeach { $$ = $1; } + | idDottedMoreForeach '.' idArrayedForeach { $$ = new AstDot($2, false, $1, $3); } + ; + // Single component of dotted path, maybe [#]. // Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part), // we'll assume so and cleanup later. // id below includes: // enum_identifier idArrayed: // IEEE: id + select - id { $$ = new AstParseRef($1,VParseRefExp::PX_TEXT,*$1,NULL,NULL); } + id { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); } // // IEEE: id + part_select_range/constant_part_select_range - | idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet. - | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); } + | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. + | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } // // IEEE: id + indexed_range/constant_indexed_range - | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); } - | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); } + | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); } + | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); } ; -idClassForeach: - idForeach { $$ = $1; } - | package_scopeIdFollows idForeach { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } +idArrayedForeach: // IEEE: id + select (under foreach expression) + id { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); } + // // IEEE: id + part_select_range/constant_part_select_range + | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. + | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } + // // IEEE: id + indexed_range/constant_indexed_range + | idArrayed '[' expr yP_PLUSCOLON constExpr ']' { $$ = new AstSelPlus($2, $1, $3, $5); } + | idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus($2, $1, $3, $5); } + // // IEEE: loop_variables (under foreach expression) + // // To avoid conflicts we allow expr as first element, must post-check + | idArrayed '[' expr ',' loop_variables ']' + { $3 = AstNode::addNextNull($3, $5); $$ = new AstSelLoopVars($2, $1, $3); } ; -idForeach: - varRefBase { $$ = $1; } - | idForeach '.' varRefBase { $$ = new AstDot($2, false, $1, $3); } - ; - - // VarRef without any dots or vectorizaion varRefBase: id { $$ = new AstVarRef($1,*$1,false);} @@ -5513,18 +5799,22 @@ class_declaration: // ==IEEE: part of class_declaration // // The classExtendsE rule relys on classFront having the // // new class scope correct via classFront classFront parameter_port_listE classExtendsE classImplementsE ';' + /*mid*/ { // Allow resolving types declared in base extends class + if ($3) SYMP->importExtends($3); + } /*cont*/ class_itemListE yENDCLASS endLabelE { $$ = $1; $1->addMembersp($2); $1->extendsp($3); $1->addMembersp($4); - $1->addMembersp($6); + $1->addMembersp($7); SYMP->popScope($$); - GRAMMARP->endLabel($7, $1, $8); } + GRAMMARP->endLabel($7, $1, $9); } ; classFront: // IEEE: part of class_declaration classVirtualE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass($2, *$4); + $$->isVirtual($1); $$->lifetime($3); SYMP->pushNew($$); } // // IEEE: part of interface_class_declaration @@ -5535,31 +5825,34 @@ classFront: // IEEE: part of class_declaration BBUNSUP($2, "Unsupported: interface classes"); } ; -classVirtualE: - /* empty */ { } - | yVIRTUAL__CLASS { BBUNSUP($1, "Unsupported: virtual classes"); } +classVirtualE: + /* empty */ { $$ = false; } + | yVIRTUAL__CLASS { $$ = true; } ; classExtendsE: // IEEE: part of class_declaration // // The classExtendsE rule relys on classFront having the // // new class scope correct via classFront - /* empty */ { $$ = NULL; } - | yEXTENDS classExtendsList { $$ = $2; } + /* empty */ { $$ = NULL; $$ = NULL; } + | yEXTENDS classExtendsList { $$ = $2; $$ = $2; } ; classExtendsList: // IEEE: part of class_declaration - classExtendsOne { $$ = $1; } + classExtendsOne { $$ = $1; $$ = $1; } | classExtendsList ',' classExtendsOne - { $$ = $3; BBUNSUP($3, "Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13)" - ", and unsupported for interface classes."); } + { $$ = $3; $$ = $3; + BBUNSUP($3, "Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), " + "and unsupported for interface classes."); } ; classExtendsOne: // IEEE: part of class_declaration class_typeExtImpList - { $$ = new AstClassExtends($1->fileline(), $1); } - // // IEEE: Might not be legal to have more than one set of parameters in an extends + { $$ = new AstClassExtends($1->fileline(), $1); + $$ = $1; } + // | class_typeExtImpList '(' list_of_argumentsE ')' { $$ = new AstClassExtends($1->fileline(), $1); + $$ = $1; if ($3) BBUNSUP($3, "Unsupported: extends with parameters"); } ; @@ -5578,9 +5871,9 @@ classImplementsList: // IEEE: part of class_declaration class_typeExtImpList: // IEEE: class_type: "[package_scope] id [ parameter_value_assignment ]" // // but allow yaID__aTYPE for extends/implements // // If you follow the rules down, class_type is really a list via ps_class_identifier - class_typeExtImpOne { $$ = $1; } + class_typeExtImpOne { $$ = $1; $$ = $1; } | class_typeExtImpList yP_COLONCOLON class_typeExtImpOne - { $$ = $3; + { $$ = $3; $$ = $1; // Cannot just add as next() as that breaks implements lists //UNSUP $$ = new AstDot($1, true, $1, $3); BBUNSUP($2, "Unsupported: Hierarchical class references"); } @@ -5592,14 +5885,23 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get a p // // If idAny below is a class, parameter_value is legal // // If idAny below is a package, parameter_value is not legal // // If idAny below is otherwise, not legal - idAny parameter_value_assignmentE + idAny + /*mid*/ { /* no nextId as not refing it above this*/ } + /*cont*/ parameter_value_assignmentE { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); - if ($2) BBUNSUP($2->fileline(), "Unsupported: Parameterized classes"); } + $$ = $1; + if ($3) BBUNSUP($3->fileline(), "Unsupported: Parameterized classes"); } + // // // package_sopeIdFollows expanded | yD_UNIT yP_COLONCOLON - { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, "$unit", NULL, NULL); } + { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, "$unit", NULL, NULL); + $$ = NULL; // No purpose otherwise, every symtab can see root + SYMP->nextId(PARSEP->rootp()); } + // | yLOCAL__COLONCOLON yP_COLONCOLON { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, "local", NULL, NULL); + $$ = NULL; // UNSUP + SYMP->nextId(PARSEP->rootp()); BBUNSUP($1, "Unsupported: Randomize 'local::'"); } ; @@ -5608,64 +5910,76 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get a p // must be included in the rules below. // Each of these must end with {symsPackageDone | symsClassDone} -ps_id_etc: // package_scope + general id - package_scopeIdFollowsE varRefBase { $$ = $2; $2->packagep($1); } - ; - //=== Below rules assume special scoping per above -class_scopeWithoutId: // class_type standalone without following id - // // and we thus don't need to resolve it in specified package - // // Used only where declare "function ::new" - class_scopeIdFollows { $$ = $1; } +packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID + packageClassScope { $$ = $1; $$ = $1; SYMP->nextId(NULL); } ; -class_scopeIdFollows: // IEEE: class_scope + type +packageClassScopeE: // IEEE: [package_scope] + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // TODO: To support classes should return generic type, not packagep + // // class_qualifier := [ yLOCAL '::' ] [ implicit_class_handle '.' class_scope ] + /* empty */ { $$ = NULL; $$ = NULL; } + | packageClassScope { $$ = $1; $$ = $1; } + ; + +packageClassScope: // IEEE: class_scope + type // // IEEE: "class_type yP_COLONCOLON" // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // But class_type:'::' conflicts with class_scope:'::' so expand here - package_scopeIdFollowsE class_typeOneListColonIdFollows - { $$ = NULL; BBUNSUP(CRELINE(), "Unsupported: scoped class reference"); } + // // if not needed must use packageClassScopeNoId + // // In this parser :: and :: are indistinguishible + // // This copies to document it is important + packageClassScopeList { $$ = $1; $$ = $1; } + | localNextId yP_COLONCOLON { $$ = $1; $$ = $1; } + | dollarUnitNextId yP_COLONCOLON { $$ = $1; $$ = $1; } + | dollarUnitNextId yP_COLONCOLON packageClassScopeList { $$ = $3; $$ = $3; } ; -class_typeOneListColonIdFollows: // IEEE: class_type :: but allow yaID__aTYPE - class_typeOneList yP_COLONCOLON { BBUNSUP($2, "Unsupported: Hierarchical class references"); } - ; - -class_typeOneList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE +packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE + // // Or IEEE: [package_scope] + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // In this parser :: and :: are indistinguishible // // If you follow the rules down, class_type is really a list via ps_class_identifier - // // Must propagate scp up for next id - class_typeOne { $$ = $1; } - | class_typeOneListColonIdFollows class_typeOne { $$ = $2; /*UNSUP*/ } + packageClassScopeItem { $$ = $1; $$ = $1; } + | packageClassScopeList packageClassScopeItem + { $$ = $2; $$ = $2; BBUNSUP($2, "Unsupported: Nested :: references"); } ; -class_typeOne: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE - // // If you follow the rules down, class_type is really a list via ps_class_identifier - // // Not listed in IEEE, but see bug627 any parameter type maybe a class - idType parameter_value_assignmentE - { $$ = new AstRefDType($1, *$1); +packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] + // // IMPORTANT: The lexer will parse the following ID to be in the found package + // // if not needed must use packageClassScopeNoId + // // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE + // //vv mid rule action needed otherwise we might not have NextId in time to parse the id token + idCC + /*mid*/ { SYMP->nextId($1); } + /*cont*/ yP_COLONCOLON + { $$ = VN_CAST($1, Package); $$ = $1; } // UNSUP classes + // + | idCC parameter_value_assignment + /*mid*/ { SYMP->nextId($1); } // Change next *after* we handle parameters, not before + /*cont*/ yP_COLONCOLON + { $$ = VN_CAST($1, Package); $$ = $1; // UNSUP classes if ($2) BBUNSUP($2->fileline(), "Unsupported: Parameterized classes"); } ; -package_scopeIdFollowsE: // IEEE: [package_scope] +dollarUnitNextId: // $unit // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // class_qualifier := [ yLOCAL '::' ] [ implicit_class_handle '.' class_scope ] - /* empty */ { $$ = NULL; } - | package_scopeIdFollows { $$ = $1; } + // // if not needed must use packageClassScopeNoId + // // Must call nextId without any additional tokens following + yD_UNIT + { $$ = GRAMMARP->unitPackage($1); SYMP->nextId(PARSEP->rootp()); } ; -package_scopeIdFollows: // IEEE: package_scope +localNextId: // local // // IMPORTANT: The lexer will parse the following ID to be in the found package - // // Also see class_typeExtImpOne which has these rules too - // //vv mid rule action needed otherwise we might not have NextId in time to parse the id token - yaID__aPACKAGE { SYMP->nextId($1); } - /*cont*/ yP_COLONCOLON - { $$ = VN_CAST($1, Package); } - | yD_UNIT yP_COLONCOLON - { SYMP->nextId(PARSEP->rootp()); $$ = GRAMMARP->unitPackage($1); } - | yLOCAL__COLONCOLON yP_COLONCOLON - { BBUNSUP($1, "Unsupported: Randomize 'local::'"); - SYMP->nextId(PARSEP->rootp()); $$ = GRAMMARP->unitPackage($1); } + // // if not needed must use packageClassScopeNoId + // // Must call nextId without any additional tokens following + yLOCAL__COLONCOLON + { $$ = GRAMMARP->unitPackage($1); SYMP->nextId(PARSEP->rootp()); + BBUNSUP($1, "Unsupported: Randomize 'local::'"); } ; //^^^========= @@ -5683,7 +5997,7 @@ class_itemList: class_item: // ==IEEE: class_item class_property { $$ = $1; } | class_method { $$ = $1; } - //UNSUP class_constraint { $$ = $1; } + | class_constraint { $$ = $1; } // | class_declaration { $$ = NULL; BBUNSUP($1, "Unsupported: class within class"); } | timeunits_declaration { $$ = $1; } @@ -5696,136 +6010,134 @@ class_item: // ==IEEE: class_item ; class_method: // ==IEEE: class_method - memberQualResetListE task_declaration { $$ = $2; } - | memberQualResetListE function_declaration { $$ = $2; } - | yPURE yVIRTUAL__ETC memberQualResetListE method_prototype ';' - { $$ = NULL; BBUNSUP($1, "Unsupported: pure virtual class method"); } - | yEXTERN memberQualResetListE method_prototype ';' - { $$ = NULL; BBUNSUP($1, "Unsupported: extern class method prototype"); } + memberQualListE task_declaration { $$ = $2; $1.applyToNodes($2); } + | memberQualListE function_declaration { $$ = $2; $1.applyToNodes($2); } + | yPURE yVIRTUAL__ETC memberQualListE method_prototype ';' + { $$ = $4; $3.applyToNodes($4); $4->pureVirtual(true); $4->isVirtual(true); } + | yEXTERN memberQualListE method_prototype ';' + { $$ = $3; $2.applyToNodes($3); $3->isExtern(true); } // // IEEE: "method_qualifierE class_constructor_declaration" // // part of function_declaration - | yEXTERN memberQualResetListE class_constructor_prototype - { $$ = NULL; BBUNSUP($1, "Unsupported: extern class"); } + | yEXTERN memberQualListE class_constructor_prototype + { $$ = $3; $2.applyToNodes($3); $3->isExtern(true); } ; // IEEE: class_constructor_prototype // See function_declaration -class_item_qualifier: // IEEE: class_item_qualifier minus ySTATIC - // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule - yPROTECTED { $$ = NULL; } // Ignoring protected until warning implemented - | yLOCAL__ETC { $$ = NULL; } // Ignoring local until warning implemented - | ySTATIC__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: 'static' class item"); } - ; - -memberQualResetListE: // Called from class_property for all qualifiers before yVAR +memberQualListE: // Called from class_property for all qualifiers before yVAR // // Also before method declarations, to prevent grammar conflict // // Thus both types of qualifiers (method/property) are here - /*empty*/ { $$ = NULL; } + /*empty*/ { $$ = VMemberQualifiers::none(); } | memberQualList { $$ = $1; } ; -memberQualList: +memberQualList: memberQualOne { $$ = $1; } - | memberQualList memberQualOne { $$ = AstNode::addNextNull($1, $2); } + | memberQualList memberQualOne { $$ = VMemberQualifiers::combine($1, $2); } ; -memberQualOne: // IEEE: property_qualifier + method_qualifier +memberQualOne: // IEEE: property_qualifier + method_qualifier // // Part of method_qualifier and property_qualifier - class_item_qualifier { $$ = $1; } + // // IMPORTANT: yPROTECTED | yLOCAL is in a lex rule + yPROTECTED { $$ = VMemberQualifiers::none(); $$.m_protected = true; } + | yLOCAL__ETC { $$ = VMemberQualifiers::none(); $$.m_local = true; } + | ySTATIC__ETC { $$ = VMemberQualifiers::none(); $$.m_static = true; } // // Part of method_qualifier only - | yVIRTUAL__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: virtual class member qualifier"); } + | yVIRTUAL__ETC { $$ = VMemberQualifiers::none(); $$.m_virtual = true; } // // Part of property_qualifier only - | random_qualifier { $$ = NULL; } + | random_qualifier { $$ = $1; } // // Part of lifetime, but here as ySTATIC can be in different positions - | yAUTOMATIC { $$ = NULL; BBUNSUP($1, "Unsupported: automatic class member qualifier"); } + | yAUTOMATIC { $$ = VMemberQualifiers::none(); $$.m_automatic = true; } // // Part of data_declaration, but not in data_declarationVarFrontClass - | yCONST__ETC { $$ = NULL; BBUNSUP($1, "Unsupported: const class member qualifier"); } + | yCONST__ETC { $$ = VMemberQualifiers::none(); $$.m_const = true; } ; //********************************************************************** // Constraints -//UNSUPclass_constraint: // ==IEEE: class_constraint -//UNSUP // // IEEE: constraint_declaration -//UNSUP constraintStaticE yCONSTRAINT idAny constraint_block { } -//UNSUP // // IEEE: constraint_prototype + constraint_prototype_qualifier -//UNSUP | constraintStaticE yCONSTRAINT idAny ';' { } -//UNSUP | yEXTERN constraintStaticE yCONSTRAINT idAny ';' { } -//UNSUP | yPURE constraintStaticE yCONSTRAINT idAny ';' { } -//UNSUP ; +class_constraint: // ==IEEE: class_constraint + // // IEEE: constraint_declaration + // // UNSUP: We have the unsupported warning on the randomize() call, so don't bother on + // // constraint blocks. When we support randomize we need to make AST nodes for below rules + constraintStaticE yCONSTRAINT idAny constraint_block { $$ = NULL; /*UNSUP*/ } + // // IEEE: constraint_prototype + constraint_prototype_qualifier + | constraintStaticE yCONSTRAINT idAny ';' { $$ = NULL; } + | yEXTERN constraintStaticE yCONSTRAINT idAny ';' { $$ = NULL; BBUNSUP($1, "Unsupported: extern constraint"); } + | yPURE constraintStaticE yCONSTRAINT idAny ';' { $$ = NULL; BBUNSUP($1, "Unsupported: pure constraint"); } + ; -//UNSUPconstraint_block: // ==IEEE: constraint_block -//UNSUP '{' constraint_block_itemList '}' { $$ = $1; } -//UNSUP ; +constraint_block: // ==IEEE: constraint_block + '{' constraint_block_itemList '}' { $$ = $2; } + ; -//UNSUPconstraint_block_itemList: // IEEE: { constraint_block_item } -//UNSUP constraint_block_item { $$ = $1; } -//UNSUP | constraint_block_itemList constraint_block_item { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +constraint_block_itemList: // IEEE: { constraint_block_item } + constraint_block_item { $$ = $1; } + | constraint_block_itemList constraint_block_item { $$ = AstNode::addNextNull($1, $2); } + ; -//UNSUPconstraint_block_item: // ==IEEE: constraint_block_item -//UNSUP ySOLVE solve_before_list yBEFORE solve_before_list ';' { } -//UNSUP | constraint_expression { $$ = $1; } -//UNSUP ; +constraint_block_item: // ==IEEE: constraint_block_item + constraint_expression { $$ = $1; } + | ySOLVE solve_before_list yBEFORE solve_before_list ';' { $$ = NULL; BBUNSUP($2, "Unsupported: solve before"); } + ; -//UNSUPsolve_before_list: // ==IEEE: solve_before_list -//UNSUP constraint_primary { $$ = $1; } -//UNSUP | solve_before_list ',' constraint_primary { } -//UNSUP ; +solve_before_list: // ==IEEE: solve_before_list + constraint_primary { $$ = $1; } + | solve_before_list ',' constraint_primary { $$ = AstNode::addNextNull($1, $3); } + ; -//UNSUPconstraint_primary: // ==IEEE: constraint_primary -//UNSUP // // exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select -//UNSUP exprScope { $$ = $1; } -//UNSUP ; +constraint_primary: // ==IEEE: constraint_primary + // // exprScope more general than: [ implicit_class_handle '.' | class_scope ] hierarchical_identifier select + exprScope { $$ = $1; } + ; -//UNSUPconstraint_expressionList: // ==IEEE: { constraint_expression } -//UNSUP constraint_expression { $$ = $1; } -//UNSUP | constraint_expressionList constraint_expression { $$ = AstNode::addNextNull($1, $2); } -//UNSUP ; +constraint_expressionList: // ==IEEE: { constraint_expression } + constraint_expression { $$ = $1; } + | constraint_expressionList constraint_expression { $$ = AstNode::addNextNull($1, $2); } + ; -//UNSUPconstraint_expression: // ==IEEE: constraint_expression -//UNSUP expr/*expression_or_dist*/ ';' { $$ = $1; } -//UNSUP // // 1800-2012: -//UNSUP | ySOFT expr/*expression_or_dist*/ ';' { } -//UNSUP // // 1800-2012: -//UNSUP // // IEEE: uniqueness_constraint ';' -//UNSUP | yUNIQUE '{' open_range_list '}' { } -//UNSUP // // IEEE: expr yP_MINUSGT constraint_set -//UNSUP // // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there -//UNSUP // -//UNSUP | yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { } -//UNSUP | yIF '(' expr ')' constraint_set yELSE constraint_set { } -//UNSUP // // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009 -//UNSUP | yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' constraint_set { } -//UNSUP // // soft is 1800-2012 -//UNSUP | yDISABLE ySOFT expr/*constraint_primary*/ ';' { } -//UNSUP ; +constraint_expression: // ==IEEE: constraint_expression + expr/*expression_or_dist*/ ';' { $$ = $1; } + // // 1800-2012: + | ySOFT expr/*expression_or_dist*/ ';' { $$ = NULL; /*UNSUP-no-UVM*/ } + // // 1800-2012: + // // IEEE: uniqueness_constraint ';' + | yUNIQUE '{' open_range_list '}' { $$ = NULL; /*UNSUP-no-UVM*/ } + // // IEEE: expr yP_MINUSGT constraint_set + // // Conflicts with expr:"expr yP_MINUSGT expr"; rule moved there + // + | yIF '(' expr ')' constraint_set %prec prLOWER_THAN_ELSE { $$ = NULL; /*UNSUP-UVM*/ } + | yIF '(' expr ')' constraint_set yELSE constraint_set { $$ = NULL; /*UNSUP-UVM*/ } + // // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009 + | yFOREACH '(' idClassSelForeach ')' constraint_set { $$ = NULL; /*UNSUP-UVM*/ } + // // soft is 1800-2012 + | yDISABLE ySOFT expr/*constraint_primary*/ ';' { $$ = NULL; /*UNSUP-no-UVM*/ } + ; -//UNSUPconstraint_set: // ==IEEE: constraint_set -//UNSUP constraint_expression { $$ = $1; } -//UNSUP | '{' constraint_expressionList '}' { $$ = $2; } -//UNSUP ; +constraint_set: // ==IEEE: constraint_set + constraint_expression { $$ = $1; } + | '{' constraint_expressionList '}' { $$ = $2; } + ; -//UNSUPdist_list: // ==IEEE: dist_list -//UNSUP dist_item { $$ = $1; } -//UNSUP | dist_list ',' dist_item { $$ = AstNode::addNextNull($1, $3); } -//UNSUP ; +dist_list: // ==IEEE: dist_list + dist_item { $$ = $1; } + | dist_list ',' dist_item { $$ = AstNode::addNextNull($1, $3); } + ; -//UNSUPdist_item: // ==IEEE: dist_item + dist_weight -//UNSUP value_range { $$ = $1; } -//UNSUP | value_range yP_COLONEQ expr { } -//UNSUP | value_range yP_COLONDIV expr { } -//UNSUP ; +dist_item: // ==IEEE: dist_item + dist_weight + value_range { $$ = $1; } + | value_range yP_COLONEQ expr { $$ = $1; BBUNSUP($1, "Unsupported: dist :="); } + | value_range yP_COLONDIV expr { $$ = $1; BBUNSUP($1, "Unsupported: dist :/"); } + ; //UNSUPextern_constraint_declaration: // ==IEEE: extern_constraint_declaration //UNSUP constraintStaticE yCONSTRAINT class_scope_id constraint_block { } //UNSUP ; -//UNSUPconstraintStaticE: // IEEE: part of extern_constraint_declaration -//UNSUP /* empty */ { $$ = false; } -//UNSUP | ySTATIC__CONSTRAINT { $$ = true; } -//UNSUP ; +constraintStaticE: // IEEE: part of extern_constraint_declaration + /* empty */ { $$ = false; } + | ySTATIC__CONSTRAINT { $$ = true; } + ; //********************************************************************** // Constants diff --git a/test_regress/.gdbinit b/test_regress/.gdbinit index 8b63c91ae..e960ad760 100644 --- a/test_regress/.gdbinit +++ b/test_regress/.gdbinit @@ -1 +1 @@ -source ../src/.gdbinit +source ~/SandBox/homecvs/v4/verilator/src/.gdbinit diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 8d1260cf8..d4b12ddb5 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -9,7 +9,8 @@ BEGIN { if (!$ENV{VERILATOR_ROOT} && -x "../bin/verilator") { $ENV{VERILATOR_ROOT} = Cwd::getcwd()."/.."; } - $ENV{MAKE} ||= "make" + $ENV{MAKE} ||= "make"; + $ENV{CXX} ||= "c++"; } use Getopt::Long; @@ -1156,7 +1157,7 @@ sub compile { if ($param{make_pli}) { $self->oprint("Compile vpi\n") if $self->{verbose}; - my @cmd = ('c++', @{$param{pli_flags}}, "-DIS_VPI", + my @cmd = ($ENV{CXX}, @{$param{pli_flags}}, "-DIS_VPI", "$self->{t_dir}/$self->{pli_filename}"); $self->_run(logfile=>"$self->{obj_dir}/pli_compile.log", @@ -2193,12 +2194,12 @@ sub fst2vcd { my $fn1 = shift; my $fn2 = shift; if (!-r $fn1) { $self->error("File does not exist $fn1\n"); return 0; } - my $cmd = qq{fst2vcd --help}; + my $cmd = qq{fst2vcd -h}; print "\t$cmd\n" if $::Debug; my $out = `$cmd`; if (!$out || $out !~ /Usage:/) { $self->skip("No fst2vcd installed\n"); return 1; } - $cmd = qq{fst2vcd -e "$fn1" -o "$fn2"}; + $cmd = qq{fst2vcd -e -f "$fn1" -o "$fn2"}; print "\t$cmd\n"; # Always print to help debug race cases $out = `$cmd`; return 1; @@ -2208,6 +2209,7 @@ sub fst_identical { my $self = (ref $_[0]? shift : $Self); my $fn1 = shift; my $fn2 = shift; + return 0 if $self->errors || $self->skips || $self->unsupporteds; my $tmp = $fn1.".vcd"; fst2vcd($fn1, $tmp); return vcd_identical($tmp, $fn2); diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h index 6a6803774..63d537eff 100644 --- a/test_regress/t/TestSimulator.h +++ b/test_regress/t/TestSimulator.h @@ -67,8 +67,8 @@ public: } // return absolute scope of obj static const char* rooted(const char* obj) { - static string buf; - ostringstream os; + static std::string buf; + std::ostringstream os; os< 1); +scenarios(linter => 1); lint( fails => $Self->{vlt_all}, diff --git a/test_regress/t/t_alias_unsup.out b/test_regress/t/t_alias_unsup.out index 2cee74f3f..c43253fa9 100644 --- a/test_regress/t/t_alias_unsup.out +++ b/test_regress/t/t_alias_unsup.out @@ -1,4 +1,4 @@ -%Error: t/t_alias_unsup.v:46:4: Unsupported: alias statements +%Error-UNSUPPORTED: t/t_alias_unsup.v:46:4: Unsupported: alias statements 46 | alias {a[7:0],a[15:8],a[23:16],a[31:24]} = b; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_alias_unsup.pl b/test_regress/t/t_alias_unsup.pl index ce380f717..06b988a99 100755 --- a/test_regress/t/t_alias_unsup.pl +++ b/test_regress/t/t_alias_unsup.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); +scenarios(linter => 1); lint( fails => $Self->{vlt_all}, diff --git a/test_regress/t/t_assoc_pattern_unsup.out b/test_regress/t/t_assoc_pattern_unsup.out index 6df0d8f82..05f437fa5 100644 --- a/test_regress/t/t_assoc_pattern_unsup.out +++ b/test_regress/t/t_assoc_pattern_unsup.out @@ -1,5 +1,5 @@ -%Error: t/t_assoc_pattern_unsup.v:19:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[string]' - : ... In instance t +%Error-UNSUPPORTED: t/t_assoc_pattern_unsup.v:19:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[string]' + : ... In instance t 19 | a = '{ "f": "fooed", "b": "bared", default: "defaulted" }; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_assoc_wildcard_unsup.out b/test_regress/t/t_assoc_wildcard_unsup.out index 92afb1b02..7d4edc557 100644 --- a/test_regress/t/t_assoc_wildcard_unsup.out +++ b/test_regress/t/t_assoc_wildcard_unsup.out @@ -1,2 +1,4 @@ -%Error: Unsupported: [*] wildcard associative arrays +%Error-UNSUPPORTED: t/t_assoc_wildcard_unsup.v:25:19: Unsupported: [*] wildcard associative arrays + 25 | string a [*]; + | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_case_huge_prof.pl b/test_regress/t/t_case_huge_prof.pl index 2514ab53e..9e75c590c 100755 --- a/test_regress/t/t_case_huge_prof.pl +++ b/test_regress/t/t_case_huge_prof.pl @@ -9,35 +9,43 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(vlt_all => 1); - top_filename("t/t_case_huge.v"); -compile( - verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"], - ); - -file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10); -file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10); - -unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); -setenv('GMON_OUT_PREFIX', "$Self->{obj_dir}/gmon.out"); - -execute( - check_finished => 1, - ); - -my $gmon_path; -$gmon_path = $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); -$gmon_path or error("Profiler did not create a gmon.out"); -(my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; - -run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"], - check_finished => 0); - -run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"], - check_finished => 0); - -file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/); +if ($ENV{VERILATOR_TEST_NO_GPROF}) { + skip("Skipping due to VERILATOR_TEST_NO_GPROF"); +} else { + dotest(); +} ok(1); + +sub dotest { + compile( + verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"], + ); + + file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10); + file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10); + + unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); + setenv('GMON_OUT_PREFIX', "$Self->{obj_dir}/gmon.out"); + + execute( + check_finished => 1, + ); + + my $gmon_path; + $gmon_path = $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); + $gmon_path or error("Profiler did not create a gmon.out"); + (my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; + + run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"], + check_finished => 0); + + run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"], + check_finished => 0); + + file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/); +} + 1; diff --git a/test_regress/t/t_castdyn.out b/test_regress/t/t_castdyn.out new file mode 100644 index 000000000..8f9e32b5e --- /dev/null +++ b/test_regress/t/t_castdyn.out @@ -0,0 +1,9 @@ +%Error-UNSUPPORTED: t/t_castdyn.v:12:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 12 | i = $cast(a, b); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn.v:14:7: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 14 | $cast(a, b); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_castdyn.pl b/test_regress/t/t_castdyn.pl new file mode 100755 index 000000000..61eb2deec --- /dev/null +++ b/test_regress/t/t_castdyn.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 2020 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, +# ); +# +#file_grep_not("$Self->{obj_dir}/V$Self->{name}__Syms.h", qr/Dead/x); + +ok(1); +1; diff --git a/test_regress/t/t_castdyn.v b/test_regress/t/t_castdyn.v new file mode 100644 index 000000000..3fd235e82 --- /dev/null +++ b/test_regress/t/t_castdyn.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + int i; + int a; + int b; + initial begin + i = $cast(a, b); + if (i != 1) $stop; + $cast(a, b); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_castdyn_bbox.pl b/test_regress/t/t_castdyn_bbox.pl new file mode 100755 index 000000000..59ccbb0ea --- /dev/null +++ b/test_regress/t/t_castdyn_bbox.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 2020 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(linter => 1); + +top_filename("t/t_castdyn.v"); + +lint( + verilator_flags2 => ['-bbox-unsup'], + fails => 0, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class2.out b/test_regress/t/t_class2.out index 7787ca18d..3444da0d9 100644 --- a/test_regress/t/t_class2.out +++ b/test_regress/t/t_class2.out @@ -1,10 +1,4 @@ -%Error: t/t_class2.v:35:14: Unsupported: Hierarchical class references - 35 | if (Cls::ENUM_VAL != 22) $stop; - | ^~ -%Error: t/t_class2.v:35:16: Unsupported: scoped class reference +%Error: t/t_class2.v:35:16: Can't find definition of variable: 'ENUM_VAL' 35 | if (Cls::ENUM_VAL != 22) $stop; | ^~~~~~~~ -%Error: t/t_class2.v:34:11: Unsupported: scoped class reference - 34 | if (Pkg::ENUMP_VAL != 33) $stop; - | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_class.out b/test_regress/t/t_class_class.out index 65f4f5ce1..0ea383361 100644 --- a/test_regress/t/t_class_class.out +++ b/test_regress/t/t_class_class.out @@ -1,4 +1,4 @@ -%Error: t/t_class_class.v:12:4: Unsupported: class within class +%Error-UNSUPPORTED: t/t_class_class.v:12:4: Unsupported: class within class 12 | class SubCls; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends.out b/test_regress/t/t_class_extends.out index 932119d8a..c839d805a 100644 --- a/test_regress/t/t_class_extends.out +++ b/test_regress/t/t_class_extends.out @@ -1,19 +1,28 @@ -%Error: t/t_class_extends.v:13:21: Unsupported: class extends +%Error-UNSUPPORTED: t/t_class_extends.v:13:21: Unsupported: class extends 13 | class Base1 extends Base0; | ^~~~~ %Error: t/t_class_extends.v:13:21: Found definition of 'Base0' as a CLASS but expected a variable 13 | class Base1 extends Base0; | ^~~~~ -%Error: t/t_class_extends.v:17:21: Unsupported: class extends - 17 | class Base2 extends Base1; +%Error-UNSUPPORTED: t/t_class_extends.v:18:21: Unsupported: class extends + 18 | class Base2 extends Base1; | ^~~~~ -%Error: t/t_class_extends.v:17:21: Found definition of 'Base1' as a CLASS but expected a variable - 17 | class Base2 extends Base1; +%Error: t/t_class_extends.v:18:21: Found definition of 'Base1' as a CLASS but expected a variable + 18 | class Base2 extends Base1; | ^~~~~ -%Error: t/t_class_extends.v:21:19: Unsupported: class extends - 21 | class Cls extends Base2; +%Error-UNSUPPORTED: t/t_class_extends.v:22:19: Unsupported: class extends + 22 | class Cls extends Base2; | ^~~~~ -%Error: t/t_class_extends.v:21:19: Found definition of 'Base2' as a CLASS but expected a variable - 21 | class Cls extends Base2; +%Error: t/t_class_extends.v:22:19: Found definition of 'Base2' as a CLASS but expected a variable + 22 | class Cls extends Base2; | ^~~~~ +%Error: t/t_class_extends.v:25:4: Can't find typedef: 'T' + 25 | T imemberc; + | ^ +%Error-UNSUPPORTED: t/t_class_extends.v:33:43: Unsupported: class extends + 33 | class uvm__registry #(type T=int) extends uvm_object_wrapper; + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_class_extends.v:33:43: Found definition of 'uvm_object_wrapper' as a CLASS but expected a variable + 33 | class uvm__registry #(type T=int) extends uvm_object_wrapper; + | ^~~~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends.v b/test_regress/t/t_class_extends.v index 66120b89c..f439ede91 100644 --- a/test_regress/t/t_class_extends.v +++ b/test_regress/t/t_class_extends.v @@ -12,6 +12,7 @@ endclass class Base1 extends Base0; int b1member; + typedef int T; endclass class Base2 extends Base1; @@ -21,8 +22,22 @@ endclass class Cls extends Base2; int imembera; int imemberb; + T imemberc; endclass : Cls +class uvm_object_wrapper; + function int create (); + endfunction +endclass + +class uvm__registry #(type T=int) extends uvm_object_wrapper; + // This override must be in the new symbol table, not + // under the extend's symbol table + function int create (); + T obj; + endfunction +endclass + module t (/*AUTOARG*/); initial begin Cls c; @@ -31,11 +46,13 @@ module t (/*AUTOARG*/); c.b2member = 30; c.imembera = 100; c.imemberb = 110; + c.imemberc = 120; $display("Display: set = \"%p\"", c); // '{all 4 members} if (c.b1member != 10) $stop; if (c.b2member != 30) $stop; if (c.imembera != 100) $stop; if (c.imemberb != 110) $stop; + if (c.imemberc != 120) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_extends_bad.out b/test_regress/t/t_class_extends_bad.out index 41a715c41..b382ead9d 100644 --- a/test_regress/t/t_class_extends_bad.out +++ b/test_regress/t/t_class_extends_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_class_extends_bad.v:13:26: Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), and unsupported for interface classes. +%Error-UNSUPPORTED: t/t_class_extends_bad.v:13:26: Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), and unsupported for interface classes. 13 | class Cls extends Base1, Base2; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_this.out b/test_regress/t/t_class_extends_this.out new file mode 100644 index 000000000..020f115a4 --- /dev/null +++ b/test_regress/t/t_class_extends_this.out @@ -0,0 +1,49 @@ +%Error-UNSUPPORTED: t/t_class_extends_this.v:13:11: Unsupported: this + 13 | if (this.value != 1) $stop; + | ^~~~ +%Error: t/t_class_extends_this.v:13:11: Can't find definition of scope/variable: 'this' + 13 | if (this.value != 1) $stop; + | ^~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:17:19: Unsupported: class extends + 17 | class Cls extends Base; + | ^~~~ +%Error: t/t_class_extends_this.v:17:19: Found definition of 'Base' as a CLASS but expected a variable + 17 | class Cls extends Base; + | ^~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:21:11: Unsupported: this + 21 | if (this.value != 2) $stop; + | ^~~~ +%Error: t/t_class_extends_this.v:21:11: Can't find definition of scope/variable: 'this' + 21 | if (this.value != 2) $stop; + | ^~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:22:11: Unsupported: super + 22 | if (super.value != 1) $stop; + | ^~~~~ +%Error: t/t_class_extends_this.v:22:11: Can't find definition of scope/variable: 'super' + 22 | if (super.value != 1) $stop; + | ^~~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:23:7: Unsupported: super + 23 | super.test(); + | ^~~~~ +%Error: t/t_class_extends_this.v:23:7: Can't find definition of scope/variable: 'super' + 23 | super.test(); + | ^~~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:24:7: Unsupported: super + 24 | super.value = 10; + | ^~~~~ +%Error: t/t_class_extends_this.v:24:7: Can't find definition of scope/variable: 'super' + 24 | super.value = 10; + | ^~~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:25:7: Unsupported: this + 25 | this.value = 20; + | ^~~~ +%Error: t/t_class_extends_this.v:25:7: Can't find definition of scope/variable: 'this' + 25 | this.value = 20; + | ^~~~ +%Error-UNSUPPORTED: t/t_class_extends_this.v:26:11: Unsupported: super + 26 | if (super.value != 10) $stop; + | ^~~~~ +%Error: t/t_class_extends_this.v:26:11: Can't find definition of scope/variable: 'super' + 26 | if (super.value != 10) $stop; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_this.pl b/test_regress/t/t_class_extends_this.pl new file mode 100755 index 000000000..b8b56e6f0 --- /dev/null +++ b/test_regress/t/t_class_extends_this.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 2020 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_this.v b/test_regress/t/t_class_extends_this.v new file mode 100644 index 000000000..4f72270e9 --- /dev/null +++ b/test_regress/t/t_class_extends_this.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef class Cls; + +class Base; + int value = 1; + function void test; + if (value != 1) $stop; + if (this.value != 1) $stop; + endfunction +endclass + +class Cls extends Base; + int value = 2; + function void test; + if (value != 2) $stop; + if (this.value != 2) $stop; + if (super.value != 1) $stop; + super.test(); + super.value = 10; + this.value = 20; + if (super.value != 10) $stop; + if (value != 20) $stop;; + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls c; + c = new; + c.test(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_extern.out b/test_regress/t/t_class_extern.out new file mode 100644 index 000000000..6adffc70c --- /dev/null +++ b/test_regress/t/t_class_extern.out @@ -0,0 +1,4 @@ +%Error-UNSUPPORTED: t/t_class_extern.v:11:15: Unsupported: Out of class block function declaration + 11 | function void Cls::extfunc(); + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extern.pl b/test_regress/t/t_class_extern.pl new file mode 100755 index 000000000..b8b56e6f0 --- /dev/null +++ b/test_regress/t/t_class_extern.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 2020 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extern.v b/test_regress/t/t_class_extern.v new file mode 100644 index 000000000..231031ff1 --- /dev/null +++ b/test_regress/t/t_class_extern.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + extern function void extfunc(); +endclass + +function void Cls::extfunc(); + $write("*-* All Finished *-*\n"); + $finish; +endfunction + +module t (/*AUTOARG*/); + initial begin + Cls c; + c.extfunc(); + end +endmodule diff --git a/test_regress/t/t_class_member_bad.out b/test_regress/t/t_class_member_bad.out index 22a47741b..eb6537580 100644 --- a/test_regress/t/t_class_member_bad.out +++ b/test_regress/t/t_class_member_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_class_member_bad.v:11:20: Unsupported: class extends +%Error-UNSUPPORTED: t/t_class_member_bad.v:11:20: Unsupported: class extends 11 | class Cls2 extends Base1; | ^~~~~ %Error: t/t_class_member_bad.v:11:20: Found definition of 'Base1' as a CLASS but expected a variable diff --git a/test_regress/t/t_class_method_bad.out b/test_regress/t/t_class_method_bad.out index 67d0928c8..88dcdf4f4 100644 --- a/test_regress/t/t_class_method_bad.out +++ b/test_regress/t/t_class_method_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_class_method_bad.v:11:20: Unsupported: class extends +%Error-UNSUPPORTED: t/t_class_method_bad.v:11:20: Unsupported: class extends 11 | class Cls2 extends Base1; | ^~~~~ %Error: t/t_class_method_bad.v:11:20: Found definition of 'Base1' as a CLASS but expected a variable diff --git a/test_regress/t/t_class_name.out b/test_regress/t/t_class_name.out index 3543b0eaf..8f5e19daa 100644 --- a/test_regress/t/t_class_name.out +++ b/test_regress/t/t_class_name.out @@ -1,4 +1,5 @@ -%Error: t/t_class_name.v:12:4: Unsupported: 'static' class item +%Error-UNSUPPORTED: t/t_class_name.v:12:16: Unsupported: 'static' class method + : ... In instance t 12 | static task static_name; - | ^~~~~~ + | ^~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_param.out b/test_regress/t/t_class_param.out index caccfa6de..f4aba8765 100644 --- a/test_regress/t/t_class_param.out +++ b/test_regress/t/t_class_param.out @@ -1,4 +1,4 @@ -%Error: t/t_class_param.v:20:11: Unsupported: Parameter classes +%Error-UNSUPPORTED: t/t_class_param.v:20:11: Unsupported: Parameter classes 20 | Cls #(.P(4)) c4; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_static_order.out b/test_regress/t/t_class_static_order.out index e1f427b0a..9565f5068 100644 --- a/test_regress/t/t_class_static_order.out +++ b/test_regress/t/t_class_static_order.out @@ -1,10 +1,13 @@ -%Error: t/t_class_static_order.v:23:4: Unsupported: 'static' class item +%Error-UNSUPPORTED: t/t_class_static_order.v:23:16: Unsupported: 'static' class members + : ... In instance t 23 | static ClsZ z = new; - | ^~~~~~ -%Error: t/t_class_static_order.v:34:4: Unsupported: 'static' class item + | ^ +%Error-UNSUPPORTED: t/t_class_static_order.v:34:16: Unsupported: 'static' class members + : ... In instance t 34 | static ClsA a = new; - | ^~~~~~ -%Error: t/t_class_static_order.v:35:4: Unsupported: 'static' class item + | ^ +%Error-UNSUPPORTED: t/t_class_static_order.v:35:16: Unsupported: 'static' class members + : ... In instance t 35 | static ClsB b = new; - | ^~~~~~ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_typedef.out b/test_regress/t/t_class_typedef.out new file mode 100644 index 000000000..bc468849c --- /dev/null +++ b/test_regress/t/t_class_typedef.out @@ -0,0 +1,4 @@ +%Error-UNSUPPORTED: t/t_class_typedef.v:14:24: Unsupported: Parameterized classes + 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_typedef.pl b/test_regress/t/t_class_typedef.pl new file mode 100755 index 000000000..b8b56e6f0 --- /dev/null +++ b/test_regress/t/t_class_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 2020 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_typedef.v b/test_regress/t/t_class_typedef.v new file mode 100644 index 000000000..ef6c86744 --- /dev/null +++ b/test_regress/t/t_class_typedef.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Parse check +class uvm_resource_types; + typedef int rsrc_q_t; +endclass +class uvm_resource_pool; + uvm_resource_types::rsrc_q_t rtab [string]; + + uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; +endclass + +module t (/*AUTOARG*/); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_unsup_bad.out b/test_regress/t/t_class_unsup_bad.out index 42116d10f..f5260c57b 100644 --- a/test_regress/t/t_class_unsup_bad.out +++ b/test_regress/t/t_class_unsup_bad.out @@ -1,28 +1,13 @@ -%Error: t/t_class_unsup_bad.v:7:1: Unsupported: virtual interface +%Error-UNSUPPORTED: t/t_class_unsup_bad.v:7:1: Unsupported: virtual interface 7 | virtual interface vi_t vi; | ^~~~~~~ -%Error: t/t_class_unsup_bad.v:8:1: Unsupported: virtual data type +%Error-UNSUPPORTED: t/t_class_unsup_bad.v:8:1: Unsupported: virtual data type 8 | virtual vi_t vi2; | ^~~~~~~ -%Error: t/t_class_unsup_bad.v:14:26: Unsupported: class parameters +%Error-UNSUPPORTED: t/t_class_unsup_bad.v:14:26: Unsupported: class parameters 14 | localparam LOCPAR = 10; | ^ -%Error: t/t_class_unsup_bad.v:25:4: Unsupported: virtual class member qualifier - 25 | virtual function void func_virtual; endfunction - | ^~~~~~~ -%Error: t/t_class_unsup_bad.v:26:4: Unsupported: pure virtual class method - 26 | pure virtual function void func_pure_virtual; - | ^~~~ -%Error: t/t_class_unsup_bad.v:27:4: Unsupported: automatic class member qualifier - 27 | automatic function void func_automatic; endfunction - | ^~~~~~~~~ -%Error: t/t_class_unsup_bad.v:28:4: Unsupported: const class member qualifier - 28 | const function void func_const; endfunction - | ^~~~~ -%Error: t/t_class_unsup_bad.v:29:4: Unsupported: extern class method prototype - 29 | extern task exttask; - | ^~~~~~ -%Error: t/t_class_unsup_bad.v:32:1: Unsupported: virtual classes - 32 | virtual class VC; - | ^~~~~~~ +%Error: t/t_class_unsup_bad.v:29:24: Syntax error: 'const'/'rand'/'randc' not allowed before function/task declaration + 29 | const function void func_const; endfunction + | ^~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_unsup_bad.v b/test_regress/t/t_class_unsup_bad.v index 7d4e032ce..dbfdbf310 100644 --- a/test_regress/t/t_class_unsup_bad.v +++ b/test_regress/t/t_class_unsup_bad.v @@ -13,6 +13,7 @@ typedef interface class ic; class C #(parameter P=1); localparam LOCPAR = 10; int imember; + static int istatic; local int loc; protected int prot; @@ -34,3 +35,13 @@ endclass module t (/*AUTOARG*/); endmodule + +typedef class uvm_root; +typedef class uvm_coreservice_t; + +class uvm_default_coreservice_t extends uvm_coreservice_t; + virtual function uvm_root get_root(); + uvm_root::m_forward_task_call(); + return uvm_root::m_uvm_get_root(); + endfunction +endclass diff --git a/test_regress/t/t_class_virtual.out b/test_regress/t/t_class_virtual.out new file mode 100644 index 000000000..7dbccdbfd --- /dev/null +++ b/test_regress/t/t_class_virtual.out @@ -0,0 +1,4 @@ +%Error-UNSUPPORTED: t/t_class_virtual.v:7:9: Unsupported: virtual class + 7 | virtual class VC; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_virtual.pl b/test_regress/t/t_class_virtual.pl new file mode 100755 index 000000000..009248fc5 --- /dev/null +++ b/test_regress/t/t_class_virtual.pl @@ -0,0 +1,19 @@ +#!/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. 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); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_virtual.v b/test_regress/t/t_class_virtual.v new file mode 100644 index 000000000..b386c6b8b --- /dev/null +++ b/test_regress/t/t_class_virtual.v @@ -0,0 +1,8 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +virtual class VC; +endclass diff --git a/test_regress/t/t_class_virtual_pure.out b/test_regress/t/t_class_virtual_pure.out new file mode 100644 index 000000000..ec7ef63ac --- /dev/null +++ b/test_regress/t/t_class_virtual_pure.out @@ -0,0 +1,7 @@ +%Error-UNSUPPORTED: t/t_class_virtual_pure.v:8:22: Unsupported: 'virtual' class method + 8 | pure virtual task hello(); + | ^~~~~ +%Error-UNSUPPORTED: t/t_class_virtual_pure.v:7:9: Unsupported: virtual class + 7 | virtual class VC; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_virtual_pure.pl b/test_regress/t/t_class_virtual_pure.pl new file mode 100755 index 000000000..009248fc5 --- /dev/null +++ b/test_regress/t/t_class_virtual_pure.pl @@ -0,0 +1,19 @@ +#!/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. 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); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_virtual_pure.v b/test_regress/t/t_class_virtual_pure.v new file mode 100644 index 000000000..a87698cb4 --- /dev/null +++ b/test_regress/t/t_class_virtual_pure.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +virtual class VC; + pure virtual task hello(); +endclass diff --git a/test_regress/t/t_class_vparam_unsup.out b/test_regress/t/t_class_vparam_unsup.out new file mode 100644 index 000000000..66f55b199 --- /dev/null +++ b/test_regress/t/t_class_vparam_unsup.out @@ -0,0 +1,4 @@ +%Error-UNSUPPORTED: t/t_class_vparam_unsup.v:13:58: Unsupported: Parameter classes + 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_vparam_unsup.pl b/test_regress/t/t_class_vparam_unsup.pl new file mode 100755 index 000000000..ce380f717 --- /dev/null +++ b/test_regress/t/t_class_vparam_unsup.pl @@ -0,0 +1,19 @@ +#!/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); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_vparam_unsup.v b/test_regress/t/t_class_vparam_unsup.v new file mode 100644 index 000000000..d19d0988e --- /dev/null +++ b/test_regress/t/t_class_vparam_unsup.v @@ -0,0 +1,32 @@ +// DESCRIPTION: Verilator: Verilog Test module for SystemVerilog 'alias' +// +// Simple bi-directional alias test. +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef class paramed_class_t; +typedef class arg_class_t; + +virtual class vclass #(type CTYPE_t = arg_class_t); + pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); +endclass + +class paramed_class_t #(type TYPE=int); +endclass + +class arg_class_t; +endclass + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + always @ (posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_debug_exit_parse.pl b/test_regress/t/t_debug_exit_parse.pl new file mode 100755 index 000000000..2d41185e7 --- /dev/null +++ b/test_regress/t/t_debug_exit_parse.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(vlt => 1); + +top_filename("t_EXAMPLE.v"); + +lint( + verilator_flags2 => ["--debug-exit-parse"], + expect => '--debug-exit-parse', + ); + +ok(1); +1; diff --git a/test_regress/t/t_delay.v b/test_regress/t/t_delay.v index 2c1d2d9c6..7434c1841 100644 --- a/test_regress/t/t_delay.v +++ b/test_regress/t/t_delay.v @@ -17,19 +17,29 @@ module t (/*AUTOARG*/ wire [31:0] dly1; wire [31:0] dly2 = dly1 + 32'h1; + typedef struct packed { int dly; } dly_s_t; + dly_s_t dly_s; + assign #(1.2000000000000000) dly1 = dly0 + 32'h1; always @ (posedge clk) begin cyc <= cyc + 1; - if (cyc==1) begin + if (cyc == 1) begin dly0 <= #0 32'h11; end - else if (cyc==2) begin + else if (cyc == 2) begin dly0 <= #0.12 dly0 + 32'h12; end - else if (cyc==3) begin + else if (cyc == 3) begin if (dly0 !== 32'h23) $stop; if (dly2 !== 32'h25) $stop; + end + else if (cyc == 4) begin + dly_s.dly = 55; + dly0 <= #(dly_s.dly) 32'h55; + //dly0 <= # dly_s.dly 32'h55; // Unsupported, issue-2410 + end + else if (cyc == 99) begin $write("*-* All Finished *-*\n"); #100 $finish; end diff --git a/test_regress/t/t_delay_stmtdly_bad.out b/test_regress/t/t_delay_stmtdly_bad.out index f52d97869..9a680e713 100644 --- a/test_regress/t/t_delay_stmtdly_bad.out +++ b/test_regress/t/t_delay_stmtdly_bad.out @@ -1,15 +1,26 @@ -%Warning-ASSIGNDLY: t/t_delay.v:20:13: Unsupported: Ignoring delay on this assignment/primitive. - 20 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; +%Warning-ASSIGNDLY: t/t_delay.v:23:13: Unsupported: Ignoring delay on this assignment/primitive. + 23 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; | ^~~~~~~~~~~~~~~~~~ ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_delay.v:25:19: Unsupported: Ignoring delay on this assignment/primitive. - 25 | dly0 <= #0 32'h11; - | ^ %Warning-ASSIGNDLY: t/t_delay.v:28:19: Unsupported: Ignoring delay on this assignment/primitive. - 28 | dly0 <= #0.12 dly0 + 32'h12; + 28 | dly0 <= #0 32'h11; + | ^ +%Warning-ASSIGNDLY: t/t_delay.v:31:19: Unsupported: Ignoring delay on this assignment/primitive. + 31 | dly0 <= #0.12 dly0 + 32'h12; | ^~~~ -%Warning-STMTDLY: t/t_delay.v:34:11: Unsupported: Ignoring delay on this delayed statement. +%Warning-ASSIGNDLY: t/t_delay.v:39:25: Unsupported: Ignoring delay on this assignment/primitive. + 39 | dly0 <= #(dly_s.dly) 32'h55; + | ^ +%Warning-STMTDLY: t/t_delay.v:44:11: Unsupported: Ignoring delay on this delayed statement. : ... In instance t - 34 | #100 $finish; + 44 | #100 $finish; | ^~~ +%Warning-UNUSED: t/t_delay.v:21:12: Signal is not used: 'dly_s' + : ... In instance t + 21 | dly_s_t dly_s; + | ^~~~~ +%Warning-BLKSEQ: t/t_delay.v:38:20: Blocking assignments (=) in sequential (flop or latch) block + : ... Suggest delayed assignments (<=) + 38 | dly_s.dly = 55; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_dist_tabs.pl b/test_regress/t/t_dist_tabs.pl index a7279d2b0..1d86b976b 100755 --- a/test_regress/t/t_dist_tabs.pl +++ b/test_regress/t/t_dist_tabs.pl @@ -13,6 +13,7 @@ scenarios(dist => 1); my $root = ".."; my $Tabs_Exempt_Re = qr!(\.out$)|(/gtkwave)|(Makefile)|(\.mk$)|(nodist/fastcov.py)!; +my $Wide_Exempt_Re = qr!(\.l$)|(\.y$)!; if (!-r "$root/.git") { skip("Not in a git repository"); @@ -68,7 +69,8 @@ if (!-r "$root/.git") { } my $len = length($1); if ($len >= 100 - && $file !~ $Tabs_Exempt_Re) { + && $file !~ $Tabs_Exempt_Re + && $file !~ $Wide_Exempt_Re) { print" Wide $line\n" if $Self->{verbose}; $summary = "File modification adds a new >100 column line:" if !$summary; $warns{$file} = "File modification adds a new >100 column line: $file:$lineno"; diff --git a/test_regress/t/t_dist_whitespace.pl b/test_regress/t/t_dist_whitespace.pl index 36e515a27..4056e1053 100755 --- a/test_regress/t/t_dist_whitespace.pl +++ b/test_regress/t/t_dist_whitespace.pl @@ -34,6 +34,7 @@ foreach my $file (sort keys %files) { my $eol_ws_exempt = ($file =~ /(\.txt|\.html)$/ || $file =~ m!^README$! || $file =~ m!/gtkwave/!); + next if $eol_ws_exempt; if ($ENV{HARNESS_UPDATE_GOLDEN}) { my $changes = undef; $changes = 1 if ($contents =~ s/[ \t]+\n/\n/g); diff --git a/test_regress/t/t_event_control_unsup.out b/test_regress/t/t_event_control_unsup.out new file mode 100644 index 000000000..7e0f28123 --- /dev/null +++ b/test_regress/t/t_event_control_unsup.out @@ -0,0 +1,9 @@ +%Error-UNSUPPORTED: t/t_event_control_unsup.v:14:7: Unsupported: timing control statement in this location + : ... Suggest have one timing control statement per procedure, at the top of the procedure + 14 | @(clk); + | ^ +%Error-UNSUPPORTED: t/t_event_control_unsup.v:16:7: Unsupported: timing control statement in this location + : ... Suggest have one timing control statement per procedure, at the top of the procedure + 16 | @(clk); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_event_control_unsup.pl b/test_regress/t/t_event_control_unsup.pl new file mode 100755 index 000000000..f4321c541 --- /dev/null +++ b/test_regress/t/t_event_control_unsup.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 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_event_control_unsup.v b/test_regress/t/t_event_control_unsup.v new file mode 100644 index 000000000..ec4d2004b --- /dev/null +++ b/test_regress/t/t_event_control_unsup.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + initial begin; + @(clk); + $write("[%0t] Got\n", $time); + @(clk); + $write("[%0t] Got\n", $time); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_event_copy.out b/test_regress/t/t_event_copy.out index 3c2a9775c..3e54190e6 100644 --- a/test_regress/t/t_event_copy.out +++ b/test_regress/t/t_event_copy.out @@ -1,9 +1,9 @@ -%Error: t/t_event_copy.v:100:13: Unsupported: assignment of event data type - : ... In instance t +%Error-UNSUPPORTED: t/t_event_copy.v:100:13: Unsupported: assignment of event data type + : ... In instance t 100 | e4 = e3; | ^ -%Error: t/t_event_copy.v:101:13: Unsupported: assignment of event data type - : ... In instance t +%Error-UNSUPPORTED: t/t_event_copy.v:101:13: Unsupported: assignment of event data type + : ... In instance t 101 | e3 = e2; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_flag_future_bad.out b/test_regress/t/t_flag_future_bad.out new file mode 100644 index 000000000..388ebe036 --- /dev/null +++ b/test_regress/t/t_flag_future_bad.out @@ -0,0 +1,10 @@ +%Error: t/t_flag_future.v:8:7: Unknown verilator lint message code: 'FUTURE1', in '/*verilator lint_off FUTURE1*/' + 8 | /*verilator lint_off FUTURE1*/ + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_flag_future.v:11:7: Unknown verilator comment: '/*verilator FUTURE2*/' + 11 | /*verilator FUTURE2*/ + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_flag_future.v:12:7: Unknown verilator comment: '/*verilator FUTURE2 blah blah*/' + 12 | /*verilator FUTURE2 blah blah*/ + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_flag_future_bad.pl b/test_regress/t/t_flag_future_bad.pl new file mode 100755 index 000000000..60a812ac4 --- /dev/null +++ b/test_regress/t/t_flag_future_bad.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(vlt => 1); + +top_filename("t/t_flag_future.v"); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_flag_ldflags.pl b/test_regress/t/t_flag_ldflags.pl index afb1ad462..db80da480 100755 --- a/test_regress/t/t_flag_ldflags.pl +++ b/test_regress/t/t_flag_ldflags.pl @@ -11,13 +11,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); run(cmd => ["cd $Self->{obj_dir}" - ." && c++ -c ../../t/t_flag_ldflags_a.cpp" + ." && $ENV{CXX} -c ../../t/t_flag_ldflags_a.cpp" ." && ar -cr t_flag_ldflags_a.a t_flag_ldflags_a.o" ." && ranlib t_flag_ldflags_a.a "], check_finished => 0); run(cmd => ["cd $Self->{obj_dir}" - ." && c++ -fPIC -c ../../t/t_flag_ldflags_so.cpp" - ." && c++ -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"], + ." && $ENV{CXX} -fPIC -c ../../t/t_flag_ldflags_so.cpp" + ." && $ENV{CXX} -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"], check_finished => 0); compile( @@ -28,6 +28,19 @@ compile( "t_flag_ldflags_so.so",], ); + +# On OS X, LD_LIBRARY_PATH is ignored, so set rpath of the exe to find the .so +if ($^O eq "darwin") { + run(cmd => ["cd $Self->{obj_dir}" + ." && install_name_tool -add_rpath \@executable_path/." + ." $Self->{VM_PREFIX}"], + check_finished => 0); + run(cmd => ["cd $Self->{obj_dir}" + ." && install_name_tool -change t_flag_ldflags_so.so" + ." \@rpath/t_flag_ldflags_so.so $Self->{VM_PREFIX}"], + check_finished => 0); +} + execute( check_finished => 1, run_env => "LD_LIBRARY_PATH=$Self->{obj_dir}", diff --git a/test_regress/t/t_flag_main_sc_bad.out b/test_regress/t/t_flag_main_sc_bad.out index aa5c05318..13ba2e390 100644 --- a/test_regress/t/t_flag_main_sc_bad.out +++ b/test_regress/t/t_flag_main_sc_bad.out @@ -1,2 +1,2 @@ -%Error: --main not usable with SystemC. Suggest see examples for sc_main(). +%Error-UNSUPPORTED: --main not usable with SystemC. Suggest see examples for sc_main(). %Error: Exiting due to diff --git a/test_regress/t/t_flag_wpedantic_bad.out b/test_regress/t/t_flag_wpedantic_bad.out index 4e9ac3f1b..707d92b51 100644 --- a/test_regress/t/t_flag_wpedantic_bad.out +++ b/test_regress/t/t_flag_wpedantic_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_flag_wpedantic_bad.v:8:14: syntax error, unexpected global, expecting IDENTIFIER or '=' or do or final +%Error: t/t_flag_wpedantic_bad.v:8:8: syntax error, unexpected global 8 | reg global; - | ^ + | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_for_comma_bad.out b/test_regress/t/t_for_comma_bad.out index 542c67fbb..6b5a4f416 100644 --- a/test_regress/t/t_for_comma_bad.out +++ b/test_regress/t/t_for_comma_bad.out @@ -1,28 +1,10 @@ -%Error: t/t_for_comma_bad.v:14:16: Unsupported: for loop step after the first comma - 14 | for (; ; a=a+1, b=b+1) ; - | ^ -%Error: t/t_for_comma_bad.v:17:19: Unsupported: for loop step after the first comma - 17 | for (; a<1; a=a+1, b=b+1) ; - | ^ -%Error: t/t_for_comma_bad.v:20:22: Unsupported: for loop step after the first comma - 20 | for (a=0; a<1; a=a+1, b=b+1) ; - | ^ -%Error: t/t_for_comma_bad.v:23:30: Unsupported: for loop step after the first comma - 23 | for (integer a=0; a<1; a=a+1, b=b+1) ; - | ^ -%Error: t/t_for_comma_bad.v:26:34: Unsupported: for loop step after the first comma - 26 | for (var integer a=0; a<1; a=a+1, b=b+1) ; - | ^ -%Error: t/t_for_comma_bad.v:27:23: Unsupported: for loop initialization after the first comma +%Error-UNSUPPORTED: t/t_for_comma_bad.v:27:23: Unsupported: for loop initialization after the first comma 27 | for (integer a=0, integer b=0; a<1; ) ; | ^ -%Error: t/t_for_comma_bad.v:28:23: Unsupported: for loop initialization after the first comma +%Error-UNSUPPORTED: t/t_for_comma_bad.v:28:23: Unsupported: for loop initialization after the first comma 28 | for (integer a=0, integer b=0; a<1; a=a+1) ; | ^ -%Error: t/t_for_comma_bad.v:29:23: Unsupported: for loop initialization after the first comma +%Error-UNSUPPORTED: t/t_for_comma_bad.v:29:23: Unsupported: for loop initialization after the first comma 29 | for (integer a=0, integer b=0; a<1; a=a+1, b=b+1) ; | ^ -%Error: t/t_for_comma_bad.v:29:43: Unsupported: for loop step after the first comma - 29 | for (integer a=0, integer b=0; a<1; a=a+1, b=b+1) ; - | ^ %Error: Exiting due to diff --git a/test_regress/t/t_for_loop.v b/test_regress/t/t_for_loop.v index 5de42aa49..24cd98a0c 100644 --- a/test_regress/t/t_for_loop.v +++ b/test_regress/t/t_for_loop.v @@ -101,6 +101,13 @@ module t (/*AUTOARG*/ if (i != 20) $stop; for (i=30; i<10; i++) ; if (i != 30) $stop; + // Comma + loops = 0; + for (i=0; i<20; ++i, ++loops); + if (loops !== 20) $stop; + loops = 0; + for (i=0; i<20; ++loops, ++i); + if (loops !== 20) $stop; // $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_foreach.v b/test_regress/t/t_foreach.v index 7055386c1..3d9b26afa 100644 --- a/test_regress/t/t_foreach.v +++ b/test_regress/t/t_foreach.v @@ -11,11 +11,20 @@ module t (/*AUTOARG*/); // verilator lint_off LITENDIAN // verilator lint_off WIDTH - reg [63:0] sum; + reg [63:0] sum; // Checked not in objects + reg [63:0] add; reg [2:1] [4:3] array [5:6] [7:8]; reg [1:2] [3:4] larray [6:5] [8:7]; bit [31:0] depth1_array [0:0]; + typedef struct packed { + reg [1:0] [63:0] subarray; + } str_t; + typedef struct packed { + str_t mid; + } mid_t; + mid_t strarray[3]; + function [63:0] crc (input [63:0] sum, input [31:0] a, input [31:0] b, input [31:0] c, input [31:0] d); crc = {sum[62:0],sum[63]} ^ {4'b0,a[7:0], 4'h0,b[7:0], 4'h0,c[7:0], 4'h0,d[7:0]}; endfunction @@ -87,6 +96,20 @@ module t (/*AUTOARG*/); end `checkh(sum, 64'h0020179aa7aa0aaa); + add = 0; + strarray[0].mid.subarray[0] = 1; + strarray[0].mid.subarray[1] = 2; + strarray[1].mid.subarray[0] = 4; + strarray[1].mid.subarray[1] = 5; + strarray[2].mid.subarray[0] = 6; + strarray[2].mid.subarray[1] = 7; +`ifndef VERILATOR // Unsupported + foreach (strarray[s]) + foreach (strarray[s].mid.subarray[ss]) + add += strarray[s].mid.subarray[ss]; + `checkh(add, 'h19); +`endif + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_foreach_bad.out b/test_regress/t/t_foreach_bad.out new file mode 100644 index 000000000..0a9fed94a --- /dev/null +++ b/test_regress/t/t_foreach_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_foreach_bad.v:14:7: Syntax error; foreach missing bracketed index variable (IEEE 1800-2017 12.7.3) + 14 | foreach (array); + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_foreach_bad.v:16:21: Unsupported: foreach on non-simple variable reference + 16 | foreach (array.array[a]); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_foreach_bad.pl b/test_regress/t/t_foreach_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_foreach_bad.pl @@ -0,0 +1,19 @@ +#!/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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_foreach_bad.v b/test_regress/t/t_foreach_bad.v new file mode 100644 index 000000000..be94993af --- /dev/null +++ b/test_regress/t/t_foreach_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + integer a, b; + + reg [2:0][2:0] array; + + initial begin + foreach (array); // no index + + foreach (array.array[a]); // not supported + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out index 5d76dd536..03e479d9f 100644 --- a/test_regress/t/t_fork.out +++ b/test_regress/t/t_fork.out @@ -1,5 +1,5 @@ -%Error: t/t_fork.v:10:14: Unsupported: fork statements - : ... In instance t +%Error-UNSUPPORTED: t/t_fork.v:10:14: Unsupported: fork statements + : ... In instance t 10 | fork : fblk | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_fork_disable.out b/test_regress/t/t_fork_disable.out new file mode 100644 index 000000000..20a700eb3 --- /dev/null +++ b/test_regress/t/t_fork_disable.out @@ -0,0 +1,13 @@ +%Error-UNSUPPORTED: t/t_fork_disable.v:12:7: Unsupported: fork statements + : ... In instance t + 12 | fork + | ^~~~ +%Error-UNSUPPORTED: t/t_fork_disable.v:16:7: Unsupported: disable fork statements + : ... In instance t + 16 | disable fork; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_fork_disable.v:17:7: Unsupported: wait fork statements + : ... In instance t + 17 | wait fork; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_fork_disable.pl b/test_regress/t/t_fork_disable.pl new file mode 100755 index 000000000..89ffd046b --- /dev/null +++ b/test_regress/t/t_fork_disable.pl @@ -0,0 +1,20 @@ +#!/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(linter => 1); + +lint( + verilator_flags2 => ['--lint-only'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_disable.v b/test_regress/t/t_fork_disable.v new file mode 100644 index 000000000..f404a53c2 --- /dev/null +++ b/test_regress/t/t_fork_disable.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + logic never; + + initial begin + fork + #10; + #10; + join_none + disable fork; + wait fork; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_func_bad.out b/test_regress/t/t_func_bad.out index bf300bf2e..68a2e95ab 100644 --- a/test_regress/t/t_func_bad.out +++ b/test_regress/t/t_func_bad.out @@ -10,8 +10,8 @@ : ... In instance t 11 | x; | ^ -%Error: t/t_func_bad.v:11:7: Unsupported: Function output argument 'y' requires 1 bits, but connection's CONST '?32?h0' generates 32 bits. - : ... In instance t +%Error-UNSUPPORTED: t/t_func_bad.v:11:7: Unsupported: Function output argument 'y' requires 1 bits, but connection's CONST '?32?h0' generates 32 bits. + : ... In instance t 11 | x; | ^ %Error: t/t_func_bad.v:14:17: No such argument 'no_such' in function call to FUNC 'f' diff --git a/test_regress/t/t_func_bad2.out b/test_regress/t/t_func_bad2.out index c354564b7..0666509d5 100644 --- a/test_regress/t/t_func_bad2.out +++ b/test_regress/t/t_func_bad2.out @@ -1,5 +1,5 @@ -%Error: t/t_func_bad2.v:8:13: Unsupported: Recursive function or task call - : ... In instance t +%Error-UNSUPPORTED: t/t_func_bad2.v:8:13: Unsupported: Recursive function or task call + : ... In instance t 8 | function recurse; | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_func_wide_out_bad.out b/test_regress/t/t_func_wide_out_bad.out index 956791a50..19c2df709 100644 --- a/test_regress/t/t_func_wide_out_bad.out +++ b/test_regress/t/t_func_wide_out_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_func_wide_out_bad.v:17:12: Unsupported: Function output argument 'data' requires 4352 bits, but connection's VARREF 'msg' generates 4350 bits. - : ... In instance t +%Error-UNSUPPORTED: t/t_func_wide_out_bad.v:17:12: Unsupported: Function output argument 'data' requires 4352 bits, but connection's VARREF 'msg' generates 4350 bits. + : ... In instance t 17 | func(msg); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_fuzz_always_bad.out b/test_regress/t/t_fuzz_always_bad.out index 6da8a3f17..c5691ffd4 100644 --- a/test_regress/t/t_fuzz_always_bad.out +++ b/test_regress/t/t_fuzz_always_bad.out @@ -4,7 +4,7 @@ %Error: t/t_fuzz_always_bad.v:10:19: Can't find definition of task/function: 'h' 10 | always @ c.a c:h; | ^ -%Error: t/t_fuzz_always_bad.v:10:14: Unsupported: Complex statement in sensitivity list +%Error-UNSUPPORTED: t/t_fuzz_always_bad.v:10:14: Unsupported: Complex statement in sensitivity list 10 | always @ c.a c:h; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_fuzz_genintf_bad.out b/test_regress/t/t_fuzz_genintf_bad.out index bd63bfbc4..e9ecf42b4 100644 --- a/test_regress/t/t_fuzz_genintf_bad.out +++ b/test_regress/t/t_fuzz_genintf_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_fuzz_genintf_bad.v:24:12: Unsupported: Member call on object 'VARREF 'j'' which is a 'BASICDTYPE 'integer'' - : ... In instance t +%Error-UNSUPPORTED: t/t_fuzz_genintf_bad.v:24:12: Unsupported: Member call on object 'VARREF 'j'' which is a 'BASICDTYPE 'integer'' + : ... In instance t 24 | j.e(0), | ^ %Error: Internal Error: t/t_fuzz_genintf_bad.v:24:11: ../V3Width.cpp:#: Unlinked pin data type diff --git a/test_regress/t/t_fuzz_triand_bad.out b/test_regress/t/t_fuzz_triand_bad.out index 4e3319976..c143c25ba 100644 --- a/test_regress/t/t_fuzz_triand_bad.out +++ b/test_regress/t/t_fuzz_triand_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_fuzz_triand_bad.v:8:12: Unsupported: Member call on object 'VARREF 'g'' which is a 'BASICDTYPE 'logic'' - : ... In instance t +%Error-UNSUPPORTED: t/t_fuzz_triand_bad.v:8:12: Unsupported: Member call on object 'VARREF 'g'' which is a 'BASICDTYPE 'logic'' + : ... In instance t 8 | tri g=g.and.g; | ^~~ %Error: Internal Error: t/t_fuzz_triand_bad.v:8:12: ../V3Width.cpp:#: Unlinked data type diff --git a/test_regress/t/t_gen_defparam_unsup_bad.out b/test_regress/t/t_gen_defparam_unsup_bad.out index 663a56e5c..c876f67af 100644 --- a/test_regress/t/t_gen_defparam_unsup_bad.out +++ b/test_regress/t/t_gen_defparam_unsup_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_gen_defparam_unsup_bad.v:9:16: Unsupported: defparam with more than one dot +%Error-UNSUPPORTED: t/t_gen_defparam_unsup_bad.v:9:16: Unsupported: defparam with more than one dot 9 | defparam a.b.W = 3; | ^ %Error: t/t_gen_defparam_unsup_bad.v:9:17: syntax error, unexpected IDENTIFIER, expecting ',' or ';' diff --git a/test_regress/t/t_genvar_misuse_bad.pl b/test_regress/t/t_genvar_misuse_bad.pl index 73b58f253..18a57407e 100755 --- a/test_regress/t/t_genvar_misuse_bad.pl +++ b/test_regress/t/t_genvar_misuse_bad.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); +scenarios(linter => 1); $Self->{vlt_all} and unsupported("Verilator unsupported, bug408"); lint( diff --git a/test_regress/t/t_increment_bad.out b/test_regress/t/t_increment_bad.out index 5664201ed..1c07b5c25 100644 --- a/test_regress/t/t_increment_bad.out +++ b/test_regress/t/t_increment_bad.out @@ -1,22 +1,22 @@ -%Error: t/t_increment_bad.v:15:31: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:15:31: Unsupported: Incrementation in this context. 15 | if (0 && test_string[pos++] != "e"); | ^~ -%Error: t/t_increment_bad.v:16:19: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:16:19: Unsupported: Incrementation in this context. 16 | if (1 || pos-- != 1); | ^~ -%Error: t/t_increment_bad.v:18:17: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:18:17: Unsupported: Incrementation in this context. 18 | if (a <-> --b); | ^~ -%Error: t/t_increment_bad.v:19:16: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:19:16: Unsupported: Incrementation in this context. 19 | if (0 -> ++b); | ^~ -%Error: t/t_increment_bad.v:21:24: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:21:24: Unsupported: Incrementation in this context. 21 | pos = (a > 0) ? a++ : --b; | ^~ -%Error: t/t_increment_bad.v:21:29: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:21:29: Unsupported: Incrementation in this context. 21 | pos = (a > 0) ? a++ : --b; | ^~ -%Error: t/t_increment_bad.v:23:24: Unsupported: Incrementation in this context. +%Error-UNSUPPORTED: t/t_increment_bad.v:23:24: Unsupported: Incrementation in this context. 23 | pos = array[0][0]++; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_recurse2_bad.out b/test_regress/t/t_inst_recurse2_bad.out index e44e2eaed..dbd22cb94 100644 --- a/test_regress/t/t_inst_recurse2_bad.out +++ b/test_regress/t/t_inst_recurse2_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_inst_recurse2_bad.v:18:8: Unsupported: Identically recursive module (module instantiates itself, without changing parameters): 'looped' - : ... In instance t.looped.looped +%Error-UNSUPPORTED: t/t_inst_recurse2_bad.v:18:8: Unsupported: Identically recursive module (module instantiates itself, without changing parameters): 'looped' + : ... In instance t.looped.looped 18 | module looped ( ); | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_recurse_bad.out b/test_regress/t/t_inst_recurse_bad.out index 2b2919a8c..68085b345 100644 --- a/test_regress/t/t_inst_recurse_bad.out +++ b/test_regress/t/t_inst_recurse_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_inst_recurse_bad.v:18:8: Unsupported: Recursive multiple modules (module instantiates something leading back to itself): 'looped' - ... note: self-recursion (module instantiating itself directly) is supported. +%Error-UNSUPPORTED: t/t_inst_recurse_bad.v:18:8: Unsupported: Recursive multiple modules (module instantiates something leading back to itself): 'looped' + ... note: self-recursion (module instantiating itself directly) is supported. 18 | module looped ( ); | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_interface_top_bad.out b/test_regress/t/t_interface_top_bad.out index 118e343f0..6947f5dea 100644 --- a/test_regress/t/t_interface_top_bad.out +++ b/test_regress/t/t_interface_top_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_interface_top_bad.v:17:19: Unsupported: Interfaced port on top level module +%Error-UNSUPPORTED: t/t_interface_top_bad.v:17:19: Unsupported: Interfaced port on top level module 17 | ifc.counter_mp c_data | ^~~~~~ %Error: t/t_interface_top_bad.v:17:4: Parent cell's interface is not found: 'ifc' diff --git a/test_regress/t/t_lint_comb_bad.out b/test_regress/t/t_lint_comb_bad.out index 902480d1d..391b09a97 100644 --- a/test_regress/t/t_lint_comb_bad.out +++ b/test_regress/t/t_lint_comb_bad.out @@ -1,4 +1,5 @@ -%Error: t/t_lint_comb_bad.v:14:16: syntax error, unexpected '@' +%Error: t/t_lint_comb_bad.v:14:4: Timing control statements not legal under always_comb + : ... Suggest use a normal 'always' 14 | always_comb @(*) begin - | ^ -%Error: Cannot continue + | ^~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_import_name2_bad.out b/test_regress/t/t_lint_import_name2_bad.out index b95efdba7..21eace02e 100644 --- a/test_regress/t/t_lint_import_name2_bad.out +++ b/test_regress/t/t_lint_import_name2_bad.out @@ -1,3 +1,6 @@ +%Error: t/t_lint_import_name2_bad.v:7:8: Package/class 'missing' not found, and needs to be predeclared (IEEE 1800-2017 26.3) + 7 | import missing::sigs; + | ^~~~~~~ %Error: t/t_lint_import_name2_bad.v:7:8: Importing from missing package 'missing' 7 | import missing::sigs; | ^~~~~~~ diff --git a/test_regress/t/t_lint_input_eq_bad.out b/test_regress/t/t_lint_input_eq_bad.out index c12a38f17..f189a6b88 100644 --- a/test_regress/t/t_lint_input_eq_bad.out +++ b/test_regress/t/t_lint_input_eq_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_lint_input_eq_bad.v:10:15: Unsupported: Default value on module input: 'i2' +%Error-UNSUPPORTED: t/t_lint_input_eq_bad.v:10:15: Unsupported: Default value on module input: 'i2' 10 | input wire i2 = i | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_mod_paren_bad.out b/test_regress/t/t_lint_mod_paren_bad.out index 682bb8951..177aa7c8d 100644 --- a/test_regress/t/t_lint_mod_paren_bad.out +++ b/test_regress/t/t_lint_mod_paren_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_lint_mod_paren_bad.v:14:7: syntax error, unexpected '(', expecting ';' - 14 | output bar - | ^~~~~~ +%Error: t/t_lint_mod_paren_bad.v:13:6: syntax error, unexpected '(', expecting ';' + 13 | ) ( + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_lint_pkg_colon_bad.out b/test_regress/t/t_lint_pkg_colon_bad.out index 9af5556c8..51ef13962 100644 --- a/test_regress/t/t_lint_pkg_colon_bad.out +++ b/test_regress/t/t_lint_pkg_colon_bad.out @@ -1,8 +1,7 @@ -%Error: t/t_lint_pkg_colon_bad.v:7:23: syntax error, unexpected ::, expecting ')' or ',' +%Error: t/t_lint_pkg_colon_bad.v:7:17: Package/class 'mispkg' not found, and needs to be predeclared (IEEE 1800-2017 26.3) 7 | module t (input mispkg::foo_t a); - | ^~ - : ... Perhaps 'mispkg' is a package which needs to be predeclared? (IEEE 1800-2017 26.3) -%Error: t/t_lint_pkg_colon_bad.v:8:15: syntax error, unexpected ::, expecting ',' or ';' - 8 | reg mispkgb::bar_t b; - | ^~ + | ^~~~~~ +%Error: t/t_lint_pkg_colon_bad.v:7:25: syntax error, unexpected IDENTIFIER, expecting TYPE-IDENTIFIER + 7 | module t (input mispkg::foo_t a); + | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_restore_prag_bad.out b/test_regress/t/t_lint_restore_prag_bad.out index 00ac14fc0..9221464af 100644 --- a/test_regress/t/t_lint_restore_prag_bad.out +++ b/test_regress/t/t_lint_restore_prag_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_lint_restore_prag_bad.v:10:4: /*verilator lint_restore*/ without matching save. +%Error: t/t_lint_restore_prag_bad.v:10:4: /*verilator lint_restore*/ without matching save 10 | /*verilator lint_restore*/ | ^~~~~~~~~~~~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_rsvd_bad.out b/test_regress/t/t_lint_rsvd_bad.out index 8cf338ee9..e1200e595 100644 --- a/test_regress/t/t_lint_rsvd_bad.out +++ b/test_regress/t/t_lint_rsvd_bad.out @@ -1,10 +1,10 @@ -%Error: t/t_lint_rsvd_bad.v:7:1: Unsupported: Verilog 2001-config reserved word not implemented: 'config' +%Error-UNSUPPORTED: t/t_lint_rsvd_bad.v:7:1: Unsupported: Verilog 2001-config reserved word not implemented: 'config' 7 | config cfgBad; | ^~~~~~ %Error: t/t_lint_rsvd_bad.v:7:8: syntax error, unexpected IDENTIFIER 7 | config cfgBad; | ^~~~~~ -%Error: t/t_lint_rsvd_bad.v:8:1: Unsupported: Verilog 2001-config reserved word not implemented: 'endconfig' +%Error-UNSUPPORTED: t/t_lint_rsvd_bad.v:8:1: Unsupported: Verilog 2001-config reserved word not implemented: 'endconfig' 8 | endconfig | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_mailbox.out b/test_regress/t/t_mailbox.out new file mode 100644 index 000000000..5a7cc1581 --- /dev/null +++ b/test_regress/t/t_mailbox.out @@ -0,0 +1,4 @@ +%Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' + 20 | mailbox m; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_mailbox.pl b/test_regress/t/t_mailbox.pl new file mode 100755 index 000000000..b8b56e6f0 --- /dev/null +++ b/test_regress/t/t_mailbox.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 2020 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_mailbox.v b/test_regress/t/t_mailbox.v new file mode 100644 index 000000000..21eadf323 --- /dev/null +++ b/test_regress/t/t_mailbox.v @@ -0,0 +1,86 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Methods defined by IEEE: +// class mailbox #(type T = dynamic_singular_type) ; +// function new(int bound = 0); +// function int num(); +// task put( T message); +// function int try_put( T message); +// task get( ref T message ); +// function int try_get( ref T message ); +// task peek( ref T message ); +// function int try_peek( ref T message ); +// endclass + +module t(/*AUTOARG*/); + mailbox m; + int msg; + int out; + + initial begin + m = new(4); + if (m.num() != 0) $stop; + if (m.try_get(msg) > 0) $stop; + + msg = 123; + m.put(msg); + msg = 0; + if (m.num() != 1) $stop; + if (m.try_peek(out) <= 0) $stop; + if (out != 123) $stop; + if (m.num() != 0) $stop; + out = 0; + if (m.try_peek(out) <= 0) $stop; + if (out != 123) $stop; + out = 0; + if (m.try_get(out) <= 0) $stop; + if (out != 123) $stop; + if (m.num() != 0) $stop; + + msg = 124; + m.put(msg); + out = 0; + m.get(out); + if (out != 124) $stop; + + msg = 125; + m.put(msg); + m.put(msg); + m.try_put(msg); + m.try_put(msg); + if (m.num() != 4) $stop; + if (m.try_put(msg) != 0) $stop; + if (m.num() != 4) $stop; + m.get(out); + m.get(out); + m.get(out); + m.get(out); + if (m.num() != 0) $stop; + + fork + begin + #10; // So later then get() starts below + msg = 130; + m.put(msg); + msg = 131; + m.put(msg); + end + begin + if (m.try_get(msg) != 0) $stop; + out = 0; + m.get(out); // Blocks until put + if (out != 130) $stop; + out = 0; + m.get(out); + if (out != 131) $stop; + end + join + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mailbox_parse.pl b/test_regress/t/t_mailbox_parse.pl new file mode 100755 index 000000000..99f2d36c4 --- /dev/null +++ b/test_regress/t/t_mailbox_parse.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +top_filename("t_mailbox.v"); + +lint( + verilator_flags2 => ["--debug-exit-parse"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_countbits_bad.out b/test_regress/t/t_math_countbits_bad.out index 9e676ad75..def07da32 100755 --- a/test_regress/t/t_math_countbits_bad.out +++ b/test_regress/t/t_math_countbits_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_math_countbits_bad.v:14:54: Unsupported: $countbits with more than 3 control fields +%Error-UNSUPPORTED: t/t_math_countbits_bad.v:14:54: Unsupported: $countbits with more than 3 control fields 14 | assign count = $countbits(32'h123456, '0, '1, 'x, 'z); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_math_div0.v b/test_regress/t/t_math_div0.v index 6cc635a9c..2612c5fb4 100644 --- a/test_regress/t/t_math_div0.v +++ b/test_regress/t/t_math_div0.v @@ -3,13 +3,30 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -module t(y); +module t(/*AUTOARG*/ + // Outputs + y, d2, m2, d3, m3 + ); output [3:0] y; + output [31:0] d2; + output [31:0] m2; + output [63:0] d3; + output [63:0] m3; // bug775 // verilator lint_off WIDTH assign y = ((0/0) ? 1 : 2) % 0; + // bug2460 + reg [31:0] b; + assign d2 = $signed(32'h80000000) / $signed(b); + assign m2 = $signed(32'h80000000) % $signed(b); + reg [63:0] b3; + assign d3 = $signed(64'h80000000_00000000) / $signed(b3); + assign m3 = $signed(64'h80000000_00000000) % $signed(b3); + initial begin + b = 32'hffffffff; + b3 = 64'hffffffff_ffffffff; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_merge_cond.pl b/test_regress/t/t_merge_cond.pl index 529b23ff4..834265b01 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, - 10); + 11); file_grep($Self->{stats}, qr/Optimizations, MergeCond merged items\s+(\d+)/i, - 640); + 644); file_grep($Self->{stats}, qr/Optimizations, MergeCond longest merge\s+(\d+)/i, 64); } diff --git a/test_regress/t/t_merge_cond.v b/test_regress/t/t_merge_cond.v index 10a12bb29..2484c11cc 100644 --- a/test_regress/t/t_merge_cond.v +++ b/test_regress/t/t_merge_cond.v @@ -162,32 +162,73 @@ module t (/*AUTOARG*/ // Things not to merge always @(posedge clk) begin - reg x; - reg y; - reg z; - reg w; + reg bits [63:0]; + + reg x; + reg y; + reg z; + reg w; + + // Unpack these to test core algorithm + for (int i = 0; i < 64; i = i + 1) begin + bits[i] = crc[i]; + end // Do not merge if condition appears in an LVALUE - x = crc[0]; - y = x ? crc[2] : crc[1]; - x = x ? crc[3] : crc[4]; - x = x ? crc[5] : crc[6]; + x = bits[0]; + y = x ? bits[2] : bits[1]; + x = x ? bits[3] : bits[4]; + x = x ? bits[5] : bits[6]; - `check(x, (crc[0] ? crc[3] : crc[4]) ? crc[5] : crc[6]); - `check(y, crc[0] ? crc[2] : crc[1]); + `check(x, (bits[0] ? bits[3] : bits[4]) ? bits[5] : bits[6]); + `check(y, bits[0] ? bits[2] : bits[1]); + + // However do merge when starting a new list in the same block with the + // previous condition variable, but without the condition being an LVALUE + x = cond2 ? bits[0] : bits[1]; + y = cond2 & bits[2]; + z = cond2 & bits[3]; + w = cond2 & bits[4]; + + `check(x, cond2 ? bits[0] : bits[1]); + `check(y, cond2 & bits[2]); + `check(z, cond2 & bits[3]); + `check(w, cond2 & bits[4]); // Do not merge if condition is not a pure expression $c("int _cnt = 0;"); - x = $c("_cnt++") ? crc[0] : crc[1]; - y = $c("_cnt++") ? crc[2] : crc[3]; - z = $c("_cnt++") ? crc[4] : crc[5]; - w = $c("_cnt++") ? crc[6] : crc[7]; + x = $c("_cnt++") ? bits[0] : bits[1]; + y = $c("_cnt++") ? bits[2] : bits[3]; + z = $c("_cnt++") ? bits[4] : bits[5]; + w = $c("_cnt++") ? bits[6] : bits[7]; $c("if (_cnt != 4) abort();"); - `check(x, crc[1]); - `check(y, crc[2]); - `check(z, crc[4]); - `check(w, crc[6]); + `check(x, bits[1]); + `check(y, bits[2]); + `check(z, bits[4]); + `check(w, bits[6]); + + // Do not merge with assignment under other statement + x = cond2 ? bits[0] : bits[1]; + if (bits[1]) begin + y = cond2 ? bits[2] : bits[3]; + end + + `check(x, cond2 ? bits[0] : bits[1]); + if (bits[1]) begin + `check(y, cond2 ? bits[2] : bits[3]); + end + + // Do not merge with assignment under other statement + x = cond2 ? bits[0] : bits[1]; + if (bits[1]) begin + y = cond2 & bits[2]; + end + + `check(x, cond2 ? bits[0] : bits[1]); + if (bits[1]) begin + `check(y, cond2 & bits[2]); + end end endmodule diff --git a/test_regress/t/t_metacmt_onoff.out b/test_regress/t/t_metacmt_onoff.out index d1233b4d7..5de179f75 100644 --- a/test_regress/t/t_metacmt_onoff.out +++ b/test_regress/t/t_metacmt_onoff.out @@ -1,8 +1,10 @@ %Warning-LITENDIAN: t/t_metacmt_onoff.v:8:8: Little bit endian vector: MSB < LSB of bit range: 0:1 + : ... In instance t 8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; | ^ ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. %Warning-LITENDIAN: t/t_metacmt_onoff.v:8:109: Little bit endian vector: MSB < LSB of bit range: 0:3 + : ... In instance t 8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_mod_interface_array3.out b/test_regress/t/t_mod_interface_array3.out index 80bde9afc..f0fd8215e 100644 --- a/test_regress/t/t_mod_interface_array3.out +++ b/test_regress/t/t_mod_interface_array3.out @@ -1,7 +1,7 @@ -%Error: t/t_mod_interface_array3.v:25:20: Unsupported: Multidimensional cells/interfaces. +%Error-UNSUPPORTED: t/t_mod_interface_array3.v:25:20: Unsupported: Multidimensional cells/interfaces. 25 | a_if iface [2:0][1:0]; | ^ -%Error: t/t_mod_interface_array3.v:27:18: Unsupported: Multidimensional cells/interfaces. +%Error-UNSUPPORTED: t/t_mod_interface_array3.v:27:18: Unsupported: Multidimensional cells/interfaces. 27 | sub i_sub[2:0][1:0] (.s(str)); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_multitop_sig_bad.pl b/test_regress/t/t_multitop_sig_bad.pl index e5bc6cac7..f3b7679b6 100755 --- a/test_regress/t/t_multitop_sig_bad.pl +++ b/test_regress/t/t_multitop_sig_bad.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); +scenarios(linter => 1); top_filename("t/t_multitop_sig.v"); diff --git a/test_regress/t/t_number_bad.out b/test_regress/t/t_number_bad.out index dedb6786d..4a4568375 100644 --- a/test_regress/t/t_number_bad.out +++ b/test_regress/t/t_number_bad.out @@ -13,4 +13,13 @@ %Error: t/t_number_bad.v:14:29: Illegal character in octal constant 14 | parameter integer FOO6 = 32'o8; | ^~~~~ +%Error: t/t_number_bad.v:17:33: Illegal character in binary constant: 4 + 17 | parameter logic [3:0] FOO7 = 1'b1?4'hF:4'h1; + | ^~~~~~ +%Error: t/t_number_bad.v:17:33: Too many digits for 1 bit number: 1'b1?4 + 17 | parameter logic [3:0] FOO7 = 1'b1?4'hF:4'h1; + | ^~~~~~ +%Error: t/t_number_bad.v:17:39: syntax error, unexpected INTEGER NUMBER, expecting ';' + 17 | parameter logic [3:0] FOO7 = 1'b1?4'hF:4'h1; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_number_bad.v b/test_regress/t/t_number_bad.v index 0ed4ef7a2..736a4c45e 100644 --- a/test_regress/t/t_number_bad.v +++ b/test_regress/t/t_number_bad.v @@ -13,4 +13,7 @@ module t (/*AUTOARG*/); parameter integer FOO5 = 32'b2; parameter integer FOO6 = 32'o8; + // See bug2432, this is questionable, some simulators take this, others do not + parameter logic [3:0] FOO7 = 1'b1?4'hF:4'h1; // bug2432 - intentionally no spaces near ? + endmodule diff --git a/test_regress/t/t_param_bracket.pl b/test_regress/t/t_param_bracket.pl new file mode 100755 index 000000000..09b2ce4eb --- /dev/null +++ b/test_regress/t/t_param_bracket.pl @@ -0,0 +1,17 @@ +#!/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(linter => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_bracket.v b/test_regress/t/t_param_bracket.v new file mode 100644 index 000000000..b2890ad9a --- /dev/null +++ b/test_regress/t/t_param_bracket.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder; +// SPDX-License-Identifier: CC0-1.0 + +module t + #(parameter WIDTH = 8) + (/*AUTOARG*/ + // Outputs + o + ); + output [WIDTH-1:0] o; + localparam DEPTH = $clog2(5); + // Note single bracket below + reg [WIDTH-1:0] arid [1< 1); +scenarios(linter => 1); lint( fails => 1, diff --git a/test_regress/t/t_param_noval_bad.out b/test_regress/t/t_param_noval_bad.out index 82cc48819..988947e3a 100644 --- a/test_regress/t/t_param_noval_bad.out +++ b/test_regress/t/t_param_noval_bad.out @@ -15,8 +15,8 @@ : ... In instance t 10 | for (j=0; P; j++) | ^~~ -%Error: t/t_param_noval_bad.v:10:7: Unsupported: Can't unroll generate for; Unable to unroll loop - : ... In instance t +%Error-UNSUPPORTED: t/t_param_noval_bad.v:10:7: Unsupported: Can't unroll generate for; Unable to unroll loop + : ... In instance t 10 | for (j=0; P; j++) | ^~~ %Error: t/t_param_noval_bad.v:10:7: For loop doesn't have genvar index, or is malformed diff --git a/test_regress/t/t_param_type.v b/test_regress/t/t_param_type.v index a61fb1b77..9fbeaa969 100644 --- a/test_regress/t/t_param_type.v +++ b/test_regress/t/t_param_type.v @@ -73,13 +73,14 @@ module mod_typ #( endmodule -module mod_typ2 #( - parameter int WIDTH1 = 0, - parameter int WIDTH2 = WIDTH1, - parameter type TYP1 = byte, - //UNSUP not needing 'parameter type' below and implying it - parameter type TYP2 = TYP1 - )(); +module mod_typ2 + #( + parameter int WIDTH1 = 0, + parameter int WIDTH2 = WIDTH1, + parameter type TYP1 = byte, + // Below we need to imply that TYP2 is a type + TYP2 = TYP1 + )(); TYP1 t1; TYP2 t2; diff --git a/test_regress/t/t_param_type_bad2.out b/test_regress/t/t_param_type_bad2.out index 381c74e76..9d199c249 100644 --- a/test_regress/t/t_param_type_bad2.out +++ b/test_regress/t/t_param_type_bad2.out @@ -1,7 +1,9 @@ -%Error: t/t_param_type_bad2.v:8:24: syntax error, unexpected ';', expecting "'{" +%Error: t/t_param_type_bad2.v:8:19: Operator VAR 't' expected non-datatype Initial value but 'logic' is a datatype. + : ... In instance t 8 | localparam t = logic; - | ^ -%Error: t/t_param_type_bad2.v:9:28: syntax error, unexpected ';', expecting "'{" + | ^~~~~ +%Error: t/t_param_type_bad2.v:9:20: Operator VAR 't2' expected non-datatype Initial value but 'real' is a datatype. + : ... In instance t 9 | localparam t2 = realtime; - | ^ + | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_past_unsup_bad.out b/test_regress/t/t_past_unsup_bad.out index d4a86b845..6d635d12b 100644 --- a/test_regress/t/t_past_unsup_bad.out +++ b/test_regress/t/t_past_unsup_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_past_unsup_bad.v:13:11: Unsupported: $past expr2 and clock arguments +%Error-UNSUPPORTED: t/t_past_unsup_bad.v:13:11: Unsupported: $past expr2 and clock arguments 13 | if ($past(d, 0, 0, 0)) $stop; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_pp_circdef_bad.out b/test_regress/t/t_pp_circdef_bad.out deleted file mode 100644 index 68de58b97..000000000 --- a/test_regress/t/t_pp_circdef_bad.out +++ /dev/null @@ -1,3 +0,0 @@ -%Error: t/t_pp_circdef_bad.v:14:21985: Recursive `define or other nested inclusion -%Error: t/t_pp_circdef_bad.v:15:1: syntax error, unexpected $end, expecting TYPE-IDENTIFIER -%Error: Exiting due to diff --git a/test_regress/t/t_pp_circdef_bad.pl b/test_regress/t/t_pp_circdef_bad.pl index a5846c699..98a317817 100755 --- a/test_regress/t/t_pp_circdef_bad.pl +++ b/test_regress/t/t_pp_circdef_bad.pl @@ -12,7 +12,8 @@ scenarios(vlt => 1); lint( fails => 1, - expect_filename => $Self->{golden_filename}, + # EOF result varies with Bison version, so can't use .out + expect => qr/define or other nested inclusion/, ); ok(1); diff --git a/test_regress/t/t_pp_defparen_bad.out b/test_regress/t/t_pp_defparen_bad.out index c6c16d023..bf1efdb68 100644 --- a/test_regress/t/t_pp_defparen_bad.out +++ b/test_regress/t/t_pp_defparen_bad.out @@ -1,7 +1,7 @@ %Error: t/t_pp_defparen_bad.v:10:2: Illegal text before '(' that starts define arguments 10 | ( 1,2) | ^ -%Error: t/t_pp_defparen_bad.v:10:2: syntax error, unexpected '(' +%Error: t/t_pp_defparen_bad.v:10:1: syntax error, unexpected '(' 10 | ((val 1) + (2)) - | ^ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_pp_underline_bad.out b/test_regress/t/t_pp_underline_bad.out index b68627482..d2bd08689 100644 --- a/test_regress/t/t_pp_underline_bad.out +++ b/test_regress/t/t_pp_underline_bad.out @@ -1,7 +1,7 @@ %Error: t/t_pp_underline_bad.v:8:4: Extra underscore in meta-comment; use /*verilator {...}*/ not /*verilator_{...}*/ 8 | // verilator_no_inline_module | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -%Error: t/t_pp_underline_bad.v:8:4: Unknown verilator comment: /*verilator _no_inline_module*/ +%Error: t/t_pp_underline_bad.v:8:4: Unknown verilator comment: '/*verilator _no_inline_module*/' 8 | /*verilator _no_inline_module*/ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_preproc_inc_bad.out b/test_regress/t/t_preproc_inc_bad.out index 295d92512..b03e7f868 100644 --- a/test_regress/t/t_preproc_inc_bad.out +++ b/test_regress/t/t_preproc_inc_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting IDENTIFIER +%Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting IDENTIFIER or randomize 11 | endmodule | ^~~~~~~~~ t/t_preproc_inc_bad.v:10:1: ... note: In file included from t_preproc_inc_bad.v diff --git a/test_regress/t/t_process.out b/test_regress/t/t_process.out new file mode 100644 index 000000000..c024cca10 --- /dev/null +++ b/test_regress/t/t_process.out @@ -0,0 +1,22 @@ +%Error: t/t_process.v:22:4: Can't find typedef: 'process' + 22 | process p; + | ^~~~~~~ +%Error: t/t_process.v:26:20: Can't find definition of task/function: 'self' + 26 | p = process::self(); + | ^~~~ +%Error: t/t_process.v:27:34: Can't find definition of variable: 'RUNNING' + 27 | if (p.status() != process::RUNNING) $stop; + | ^~~~~~~ +%Error: t/t_process.v:28:34: Can't find definition of variable: 'WAITING' + 28 | if (p.status() == process::WAITING) $stop; + | ^~~~~~~ +%Error: t/t_process.v:29:34: Can't find definition of variable: 'SUSPENDED' + 29 | if (p.status() == process::SUSPENDED) $stop; + | ^~~~~~~~~ +%Error: t/t_process.v:30:34: Can't find definition of variable: 'KILLED' + 30 | if (p.status() == process::KILLED) $stop; + | ^~~~~~ +%Error: t/t_process.v:31:34: Can't find definition of variable: 'FINISHED' + 31 | if (p.status() == process::FINISHED) $stop; + | ^~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_process.pl b/test_regress/t/t_process.pl new file mode 100755 index 000000000..b8b56e6f0 --- /dev/null +++ b/test_regress/t/t_process.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 2020 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_process.v b/test_regress/t/t_process.v new file mode 100644 index 000000000..301cb878b --- /dev/null +++ b/test_regress/t/t_process.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, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Methods defined by IEEE: +// class process; +// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; +// static function process self(); +// function state status(); +// function void kill(); +// task await(); // Warn as unsupported (no UVM library use) +// function void suspend(); // Warn as unsupported (no UVM library use) +// function void resume(); // Warn as unsupported (no UVM library use) +// function void srandom( int seed ); // Just ignore? +// function string get_randstate(); // Just ignore? +// function void set_randstate( string state ); // Just ignore? +// endclass + +module t(/*AUTOARG*/); + process p; + + initial begin + if (p != null) $stop; + p = process::self(); + if (p.status() != process::RUNNING) $stop; + if (p.status() == process::WAITING) $stop; + if (p.status() == process::SUSPENDED) $stop; + if (p.status() == process::KILLED) $stop; + if (p.status() == process::FINISHED) $stop; + + if (0) p.kill(); + if (0) p.await(); + if (0) p.suspend(); + if (0) p.resume(); + p.srandom(0); + p.set_randstate(p.get_randstate()); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process_parse.pl b/test_regress/t/t_process_parse.pl new file mode 100755 index 000000000..b06c6fba8 --- /dev/null +++ b/test_regress/t/t_process_parse.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +top_filename("t_process.v"); + +lint( + verilator_flags2 => ["--debug-exit-parse"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_prot_lib.pl b/test_regress/t/t_prot_lib.pl index 993d8fb75..7f2b9b352 100755 --- a/test_regress/t/t_prot_lib.pl +++ b/test_regress/t/t_prot_lib.pl @@ -51,7 +51,7 @@ while (1) { compile( verilator_flags2 => ["$secret_dir/secret.sv", "-LDFLAGS", - "'-L$secret_prefix -lsecret -static'"], + "$secret_prefix/libsecret.a"], xsim_flags2 => ["$secret_dir/secret.sv"], ); diff --git a/test_regress/t/t_prot_lib_clk_gated.pl b/test_regress/t/t_prot_lib_clk_gated.pl index 69b9e9ccc..8bb14ba16 100755 --- a/test_regress/t/t_prot_lib_clk_gated.pl +++ b/test_regress/t/t_prot_lib_clk_gated.pl @@ -54,7 +54,7 @@ while (1) { verilator_flags2 => ["$secret_dir/secret.sv", "-GGATED_CLK=1", "-LDFLAGS", - "'-L$secret_prefix -lsecret -static'"], + "$secret_prefix/libsecret.a"], xsim_flags2 => ["$secret_dir/secret.sv"], ); diff --git a/test_regress/t/t_prot_lib_inout_bad.out b/test_regress/t/t_prot_lib_inout_bad.out index 681f98209..b33360f10 100644 --- a/test_regress/t/t_prot_lib_inout_bad.out +++ b/test_regress/t/t_prot_lib_inout_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_prot_lib_inout_bad.v:9:28: Unsupported: protect-lib port direction: INOUT +%Error-UNSUPPORTED: t/t_prot_lib_inout_bad.v:9:28: Unsupported: protect-lib port direction: INOUT 9 | inout z, | ^ %Error: Exiting due to diff --git a/test_regress/t/t_prot_lib_unpacked_bad.out b/test_regress/t/t_prot_lib_unpacked_bad.out index afd642456..f48917027 100644 --- a/test_regress/t/t_prot_lib_unpacked_bad.out +++ b/test_regress/t/t_prot_lib_unpacked_bad.out @@ -1,7 +1,7 @@ -%Error: t/t_prot_lib_unpacked_bad.v:7:28: Unsupported: unpacked arrays with protect-lib on 'unpacked_in' +%Error-UNSUPPORTED: t/t_prot_lib_unpacked_bad.v:7:28: Unsupported: unpacked arrays with protect-lib on 'unpacked_in' 7 | input unpacked_in [7:0], | ^~~~~~~~~~~ -%Error: t/t_prot_lib_unpacked_bad.v:8:28: Unsupported: unpacked arrays with protect-lib on 'unpacked_out' +%Error-UNSUPPORTED: t/t_prot_lib_unpacked_bad.v:8:28: Unsupported: unpacked arrays with protect-lib on 'unpacked_out' 8 | output unpacked_out [7:0]); | ^~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_protect_ids_bad.out b/test_regress/t/t_protect_ids_bad.out index ae7d64f3b..da5ad8345 100644 --- a/test_regress/t/t_protect_ids_bad.out +++ b/test_regress/t/t_protect_ids_bad.out @@ -1,5 +1,5 @@ -%Error: Unsupported: Using --protect-ids with --public - ... Suggest remove --public. +%Error-UNSUPPORTED: Unsupported: Using --protect-ids with --public + ... Suggest remove --public. %Warning-INSECURE: Using --protect-ids with --trace may expose private design details ... Suggest remove --trace. ... Use "/* verilator lint_off INSECURE */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_queue_unsup_bad.out b/test_regress/t/t_queue_unsup_bad.out index 7ba5976d4..91430c035 100644 --- a/test_regress/t/t_queue_unsup_bad.out +++ b/test_regress/t/t_queue_unsup_bad.out @@ -1,37 +1,37 @@ -%Error: t/t_queue_unsup_bad.v:21:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:21:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 21 | q = {"q", "b", "c", "d", "e", "f"}; | ^ -%Error: t/t_queue_unsup_bad.v:24:9: Unsupported: Queue .delete(index) method, as is O(n) complexity and slow. - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:24:9: Unsupported: Queue .delete(index) method, as is O(n) complexity and slow. + : ... In instance t 24 | q.delete(1); | ^~~~~~ -%Error: t/t_queue_unsup_bad.v:28:9: Unsupported: Queue .insert method, as is O(n) complexity and slow. - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:28:9: Unsupported: Queue .insert method, as is O(n) complexity and slow. + : ... In instance t 28 | q.insert(2, "ins2"); | ^~~~~~ -%Error: t/t_queue_unsup_bad.v:34:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:34:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 34 | q = {q, "f1"}; | ^ -%Error: t/t_queue_unsup_bad.v:35:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:35:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 35 | q = {q, "f2"}; | ^ -%Error: t/t_queue_unsup_bad.v:36:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:36:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 36 | q = {"b1", q}; | ^ -%Error: t/t_queue_unsup_bad.v:37:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:37:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 37 | q = {"b2", q}; | ^ -%Error: t/t_queue_unsup_bad.v:38:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:38:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 38 | q = {q[0], q[2:$]}; | ^ -%Error: t/t_queue_unsup_bad.v:38:22: Unsupported/illegal unbounded ('$') in this context. - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:38:22: Unsupported/illegal unbounded ('$') in this context. + : ... In instance t 38 | q = {q[0], q[2:$]}; | ^ %Error: t/t_queue_unsup_bad.v:38:22: First value of [a:b] isn't a constant, maybe you want +: or -: @@ -42,16 +42,16 @@ : ... In instance t 38 | q = {q[0], q[2:$]}; | ^ -%Error: t/t_queue_unsup_bad.v:42:25: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:42:25: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 42 | string ai[$] = { "Foo", "Bar" }; | ^ -%Error: t/t_queue_unsup_bad.v:47:14: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:47:14: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' + : ... In instance t 47 | q = '{ "BB", "CC" }; | ^~ -%Error: t/t_queue_unsup_bad.v:50:14: Unsupported: Replication to form 'string[$]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:50:14: Unsupported: Replication to form 'string[$]' data type + : ... In instance t 50 | q = { "BB", "CC" }; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_randomize.out b/test_regress/t/t_randomize.out new file mode 100644 index 000000000..ae473f217 --- /dev/null +++ b/test_regress/t/t_randomize.out @@ -0,0 +1,19 @@ +%Error-UNSUPPORTED: t/t_randomize.v:11:4: Unsupported: extern constraint + 11 | extern constraint ex; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_randomize.v:29:29: Unsupported: solve before + 29 | constraint order { solve length before header; } + | ^~~~~~ +%Error-UNSUPPORTED: t/t_randomize.v:32:16: Unsupported: dist :/ + 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + | ^ +%Error-UNSUPPORTED: t/t_randomize.v:32:32: Unsupported: dist := + 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + | ^~~ +%Error-UNSUPPORTED: t/t_randomize.v:32:42: Unsupported: dist := + 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + | ^~~ +%Error-UNSUPPORTED: t/t_randomize.v:32:9: Unsupported: dist + 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randomize.pl b/test_regress/t/t_randomize.pl new file mode 100755 index 000000000..63947fd00 --- /dev/null +++ b/test_regress/t/t_randomize.pl @@ -0,0 +1,19 @@ +#!/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); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randomize.v b/test_regress/t/t_randomize.v new file mode 100644 index 000000000..adc5bfcca --- /dev/null +++ b/test_regress/t/t_randomize.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Packet; + rand int header; + rand int length; + + extern constraint ex; + + constraint a { header > 0 && header < 1000; } + constraint b { + if (64 > header) { + header < (64'h1 << length); + } + } + constraint b { + header >= length - 10; + header <= length; + } + constraint c { + foreach (in_use[i]) { + !(start_offset <= in_use[i].Xend_offsetX && + start_offset + len - 1 >= in_use[i].Xstart_offsetX); + } + } + constraint order { solve length before header; } + constraint dis { + disable soft x; + x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + } + +endclass + +module t (/*AUTOARG*/); + + Packet p; + + initial begin + + int v; + v = p.randomize(); + if (v != 1) $stop; + v = p.randomize(1); + if (v != 1) $stop; + v = p.randomize(1, 2); + if (v != 1) $stop; + v = p.randomize() with {}; + if (v != 1) $stop; + // Not testing other randomize forms as unused in UVM + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_randomize_bbox.pl b/test_regress/t/t_randomize_bbox.pl new file mode 100755 index 000000000..2f89e3fb1 --- /dev/null +++ b/test_regress/t/t_randomize_bbox.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 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); + +top_filename("t/t_randomize.v"); + +lint( + verilator_flags => ["--bbox-unsup"], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_savable_class_bad.out b/test_regress/t/t_savable_class_bad.out index 8128ec348..08c051e17 100644 --- a/test_regress/t/t_savable_class_bad.out +++ b/test_regress/t/t_savable_class_bad.out @@ -1,2 +1,2 @@ -%Error: Unsupported: --savable with dynamic new +%Error-UNSUPPORTED: Unsupported: --savable with dynamic new %Error: Exiting due to diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index ca00e8cb0..65fcd125a 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -14,8 +14,6 @@ #include "Vt_scope_map.h" -using namespace std; - unsigned long long main_time = 0; double sc_time_stamp() { return (double)main_time; } diff --git a/test_regress/t/t_select_bad_msb.out b/test_regress/t/t_select_bad_msb.out index 98533f4d2..f31c7e096 100644 --- a/test_regress/t/t_select_bad_msb.out +++ b/test_regress/t/t_select_bad_msb.out @@ -1,4 +1,5 @@ %Warning-LITENDIAN: t/t_select_bad_msb.v:12:8: Little bit endian vector: MSB < LSB of bit range: 0:22 + : ... In instance t 12 | reg [0:22] backwd; | ^ ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_select_plus_mul_pow2.pl b/test_regress/t/t_select_plus_mul_pow2.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_select_plus_mul_pow2.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 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_select_plus_mul_pow2.v b/test_regress/t/t_select_plus_mul_pow2.v new file mode 100644 index 000000000..d533b88ab --- /dev/null +++ b/test_regress/t/t_select_plus_mul_pow2.v @@ -0,0 +1,54 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Conor McCullough. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + reg [63:0] from = 64'h0706050403020100; + reg [7:0] to; + reg [2:0] bitn; + reg [7:0] cyc; initial cyc=0; + + always @* begin + to = from[bitn * 8 +: 8]; + end + + always @ (posedge clk) begin + cyc <= cyc + 8'd1; + case (cyc) + 8'd00: begin bitn<=3'd0; end + 8'd01: begin bitn<=3'd1; end + 8'd02: begin bitn<=3'd2; end + 8'd03: begin bitn<=3'd3; end + 8'd04: begin bitn<=3'd4; end + 8'd05: begin bitn<=3'd5; end + 8'd06: begin bitn<=3'd6; end + 8'd07: begin bitn<=3'd7; end + 8'd08: begin + $write("*-* All Finished *-*\n"); + $finish; + end + default: ; + endcase + case (cyc) + 8'd00: ; + 8'd01: begin if (to !== 8'h00) $stop; end + 8'd02: begin if (to !== 8'h01) $stop; end + 8'd03: begin if (to !== 8'h02) $stop; end + 8'd04: begin if (to !== 8'h03) $stop; end + 8'd05: begin if (to !== 8'h04) $stop; end + 8'd06: begin if (to !== 8'h05) $stop; end + 8'd07: begin if (to !== 8'h06) $stop; end + 8'd08: begin if (to !== 8'h07) $stop; end + default: $stop; + endcase + end + +endmodule diff --git a/test_regress/t/t_semaphore.out b/test_regress/t/t_semaphore.out new file mode 100644 index 000000000..21345fd35 --- /dev/null +++ b/test_regress/t/t_semaphore.out @@ -0,0 +1,4 @@ +%Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' + 17 | semaphore s; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_semaphore.pl b/test_regress/t/t_semaphore.pl new file mode 100755 index 000000000..b8b56e6f0 --- /dev/null +++ b/test_regress/t/t_semaphore.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 2020 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, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_semaphore.v b/test_regress/t/t_semaphore.v new file mode 100644 index 000000000..322a8541a --- /dev/null +++ b/test_regress/t/t_semaphore.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Methods defined by IEEE: +// class semaphore; +// function new(int keyCount = 0); +// function void put(int keyCount = 1); +// task get(int keyCount = 1); +// function int try_get(int keyCount = 1); +// endclass + +module t(/*AUTOARG*/); + //From UVM: + semaphore s; + int msg; + + initial begin + s = new(4); + if (s.try_get() != 0) $stop; + + s.put(); + s.get(); + + s.put(2); + s.get(2); + + s.put(2); + if (s.try_get(2) <= 0) $stop; + + fork + begin + #10; // So later then get() starts below + s.put(1); + s.put(1); + end + begin + if (s.try_get(1) != 0) $stop; + s.get(); // Blocks until put + s.get(); + end + join + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_semaphore_parse.pl b/test_regress/t/t_semaphore_parse.pl new file mode 100755 index 000000000..abc1f79f3 --- /dev/null +++ b/test_regress/t/t_semaphore_parse.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +top_filename("t_semaphore.v"); + +lint( + verilator_flags2 => ["--debug-exit-parse"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_split_var_0.v b/test_regress/t/t_split_var_0.v index 507b5469e..c28e03c67 100644 --- a/test_regress/t/t_split_var_0.v +++ b/test_regress/t/t_split_var_0.v @@ -180,7 +180,7 @@ module barshift_2d_packed_array #(parameter DEPTH = 2, localparam WIDTH = 2**DEP generate for(genvar i = 0; i < DEPTH; ++i) begin - always_comb + always @(shift or tmp) /*verilator lint_off ALWCOMBORDER*/ if (shift[i]) begin tmp[i+1+OFFSET] = {tmp[i+OFFSET][(1 << i)-1:0], tmp[i+OFFSET][WIDTH-1:(2**i)]}; diff --git a/test_regress/t/t_split_var_1_bad.out b/test_regress/t/t_split_var_1_bad.out index 96b602356..d606c7a08 100644 --- a/test_regress/t/t_split_var_1_bad.out +++ b/test_regress/t/t_split_var_1_bad.out @@ -1,48 +1,77 @@ - : ... In instance t - : ... In instance t - : ... In instance t - : ... In instance t - : ... In instance t.i_sub0 - : ... In instance t.i_sub1 - : ... In instance t.i_sub1 - : ... In instance t.i_sub3 - : ... In instance t.i_sub3 - : ... In instance t - : ... In instance t - : ... In instance t.i_sub2 - ... Use "/* verilator lint_off SPLITVAR */" and lint_on around source to disable this message. - | ^~~~~~~~~~ - | ^~~~~~~~ - | ^~ - | ^ - | ^ - | ^~~~ - | ^ - | ^ - | ^~~~~~~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~~ - | ^~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:7:13: 'should_show_warning_global0' has split_var metacomment, but will not be split because it is not declared in a module. 7 | logic [7:0] should_show_warning_global0 /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + ... Use "/* verilator lint_off SPLITVAR */" and lint_on around source to disable this message. +%Warning-SPLITVAR: t/t_split_var_1_bad.v:8:13: 'should_show_warning_global1' has split_var metacomment, but will not be split because it is not declared in a module. 8 | logic [7:0] should_show_warning_global1 [1:0] /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:11:16: 'should_show_warning_ifs0' has split_var metacomment, but will not be split because it is not declared in a module. 11 | logic [7:0] should_show_warning_ifs0 /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:12:16: 'should_show_warning_ifs1' has split_var metacomment, but will not be split because it is not declared in a module. 12 | logic [7:0] should_show_warning_ifs1 [1:0] /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:40:14: 'cannot_split1' has split_var metacomment but will not be split because it is accessed from another module via a dot. + 40 | i_sub0.cannot_split1[0] = 0; + | ^~~~~~~~~~~~~ +%Warning-SELRANGE: t/t_split_var_1_bad.v:90:33: Selection index out of range: 13 outside 12:10 + : ... In instance t.i_sub3 + 90 | assign outwires[12] = inwires[13]; + | ^ +%Warning-WIDTH: t/t_split_var_1_bad.v:41:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's FUNCREF 'bad_func' generates 32 bits. + : ... In instance t + 41 | i_sub0.cannot_split1[1] = bad_func(addr, rd_data0); + | ^ +%Error: t/t_split_var_1_bad.v:79:16: Illegal assignment of constant to unpacked array + : ... In instance t.i_sub2 + 79 | assign b = a[0]; + | ^ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:56:31: 'cannot_split0' has split_var metacomment but will not be split because index cannot be determined statically. + : ... In instance t.i_sub0 + 56 | rd_data = cannot_split0[addr]; + | ^~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:90:34: 'inwires' has split_var metacomment but will not be split because index is out of range. + : ... In instance t.i_sub3 + 90 | assign outwires[12] = inwires[13]; + | ^~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:17:9: 'should_show_warning0' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic + : ... In instance t 17 | real should_show_warning0 /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:18:11: 'should_show_warning1' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic + : ... In instance t 18 | string should_show_warning1 /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:19:11: 'should_show_warning2' has split_var metacomment but will not be split because its bitwidth is 1 + : ... In instance t 19 | wire should_show_warning2 /*verilator split_var*/ ; - 30 | function int bad_func(inout logic [3:0] inout_port /*verilator split_var*/ , - 31 | ref logic [7:0] ref_port /*verilator split_var*/ ); - 38 | i_sub0.cannot_split1[0] = 0; - 39 | i_sub0.cannot_split1[1] = bad_func(addr, rd_data0); - 51 | rd_data = cannot_split0[addr]; - 57 | genvar cannot_split_genvar /*verilator split_var*/ ; - 60 | rd_data = cannot_split[addr]; - 72 | assign b = a[0]; - 83 | assign outwires[12] = inwires[13]; - 83 | assign outwires[12] = inwires[13]; + | ^~~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:23:16: 'public_signal' has split_var metacomment but will not be split because it is public + : ... In instance t + 23 | logic [1:0] public_signal /*verilator public*/ /*verilator split_var*/ ; + | ^~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:31:44: 'inout_port' has split_var metacomment but will not be split because it is an inout port + : ... In instance t + 31 | function int bad_func(inout logic [3:0] inout_port /*verilator split_var*/ , + | ^~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:32:42: 'ref_port' has split_var metacomment but will not be split because it is a ref argument + : ... In instance t + 32 | ref logic [7:0] ref_port /*verilator split_var*/ ); + | ^~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:37:19: 'loop_idx' has split_var metacomment but will not be split because it is used as a loop variable + : ... In instance t + 37 | logic [7:0] loop_idx /*verilator split_var*/ ; + | ^~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:62:11: 'cannot_split_genvar' has split_var metacomment but will not be split because it is not an aggregate type of bit nor logic + : ... In instance t.i_sub1 + 62 | genvar cannot_split_genvar /*verilator split_var*/ ; + | ^~~~~~~~~~~~~~~~~~~ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:65:65: 'cannot_split' has split_var metacomment but will not be split because its bit range cannot be determined statically. + : ... In instance t.i_sub1 + 65 | logic [8:0] rd_tmp /*verilator split_var*/ = cannot_split[addr]; + | ^ +%Warning-SPLITVAR: t/t_split_var_1_bad.v:66:23: 'rd_tmp' has split_var metacomment but will not be split because its bit range cannot be determined statically. + : ... In instance t.i_sub1 + 66 | rd_data = rd_tmp[{3'b0, addr[0]}+:8]; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_split_var_1_bad.pl b/test_regress/t/t_split_var_1_bad.pl index bbfbd2b0c..cb986145a 100755 --- a/test_regress/t/t_split_var_1_bad.pl +++ b/test_regress/t/t_split_var_1_bad.pl @@ -13,12 +13,8 @@ scenarios(linter => 1); lint( fails => 1, verilator_flags2 => ['--stats'], - # When issue-2407 resolved, decomment and update golden file - #expect_filename => $Self->{golden_filename}, + expect_filename => $Self->{golden_filename}, ); -# When issue-2407 resolved, remove -files_identical_sorted("$Self->{obj_dir}/vlt_compile.log", $Self->{golden_filename}, 1); - ok(1); 1; diff --git a/test_regress/t/t_split_var_1_bad.v b/test_regress/t/t_split_var_1_bad.v index 27868479a..110bd2c68 100644 --- a/test_regress/t/t_split_var_1_bad.v +++ b/test_regress/t/t_split_var_1_bad.v @@ -20,6 +20,7 @@ module t(); logic [3:0] addr; logic [7:0] rd_data0, rd_data1, rd_data2; + logic [1:0] public_signal /*verilator public*/ /*verilator split_var*/; sub0 i_sub0(.addr(addr), .rd_data(rd_data0)); sub1 i_sub1(.addr(addr), .rd_data(rd_data2)); @@ -33,10 +34,14 @@ module t(); endfunction initial begin + logic [7:0] loop_idx /*verilator split_var*/; addr = 0; addr = 1; i_sub0.cannot_split1[0] = 0; i_sub0.cannot_split1[1] = bad_func(addr, rd_data0); + for (loop_idx = 0; loop_idx < 8'd4; loop_idx = loop_idx + 2) begin + addr += 1; + end $finish; end @@ -55,9 +60,11 @@ endmodule module sub1(input [3:0]addr, output logic [7:0] rd_data); genvar cannot_split_genvar /*verilator split_var*/; - logic [15:0] [7:0] cannot_split /*verilator split_var*/; - always_comb - rd_data = cannot_split[addr]; + logic [15:0] [8:0] cannot_split /*verilator split_var*/; + always_comb begin + logic [8:0] rd_tmp /*verilator split_var*/ = cannot_split[addr]; + rd_data = rd_tmp[{3'b0, addr[0]}+:8]; + end endmodule diff --git a/test_regress/t/t_split_var_3_wreal.pl b/test_regress/t/t_split_var_3_wreal.pl new file mode 100755 index 000000000..8baf1786c --- /dev/null +++ b/test_regress/t/t_split_var_3_wreal.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 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( + verilator_flags2 => ['--stats'], + ); + +execute( + check_finished => 1, + ); + +file_grep($Self->{stats}, qr/SplitVar,\s+Split packed variables\s+(\d+)/i, 0); +file_grep($Self->{stats}, qr/SplitVar,\s+Split unpacked arrays\s+(\d+)/i, 3); +ok(1); +1; diff --git a/test_regress/t/t_split_var_3_wreal.v b/test_regress/t/t_split_var_3_wreal.v new file mode 100644 index 000000000..068fe0c7b --- /dev/null +++ b/test_regress/t/t_split_var_3_wreal.v @@ -0,0 +1,54 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Yutetsu TAKATSUKASA. +// SPDX-License-Identifier: CC0-1.0 + +`begin_keywords "VAMS-2.3" + +module t (/*autoarg*/ + // Inputs + clk + ); + + input clk; + + integer cyc=0; + + real vin[0:1] /*verilator split_var*/; + wreal vout[0:1] /*verilator split_var*/; + swap i_swap(.in0(vin[0]), .in1(vin[1]), .out0(vout[0]), .out1(vout[1])); + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc==0) begin + // Setup + vin[0] = 1.0; + vin[1] = 2.0; + end + else if (cyc==2) begin + vin[0] = 3.0; + vin[1] = 4.0; + end + else if (cyc==3) begin + if (vout[0] == vin[1] && vout[1] == vin[0]) begin + $write("*-* All Finished *-*\n"); + $finish; + end else begin + $write("Mismatch %f %f\n", vout[0], vout[1]); + $stop; + end + end + end + +endmodule + +module swap + (input wreal in0, in1, + output wreal out0, out1); + wreal tmp[0:1] /* verilator split_var*/; + assign tmp[0] = in0; + assign tmp[1] = in1; + assign out0 = tmp[1]; + assign out1 = tmp[0]; +endmodule diff --git a/test_regress/t/t_struct_unpacked2.out b/test_regress/t/t_struct_unpacked2.out index 3d938df82..aa812216b 100644 --- a/test_regress/t/t_struct_unpacked2.out +++ b/test_regress/t/t_struct_unpacked2.out @@ -3,6 +3,7 @@ | ^ ... Use "/* verilator lint_off UNPACKED */" and lint_on around source to disable this message. %Warning-UNPACKED: t/t_struct_unpacked2.v:9:12: Unsupported: Unpacked struct/union + : ... In instance x 9 | typedef struct { | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_struct_unpacked_bad.out b/test_regress/t/t_struct_unpacked_bad.out index 96bc2b963..6e9356b6d 100644 --- a/test_regress/t/t_struct_unpacked_bad.out +++ b/test_regress/t/t_struct_unpacked_bad.out @@ -1,4 +1,5 @@ %Warning-UNPACKED: t/t_struct_unpacked_bad.v:9:12: Unsupported: Unpacked struct/union + : ... In instance x 9 | typedef struct { | ^~~~~~ ... Use "/* verilator lint_off UNPACKED */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_sys_rand_seed.out b/test_regress/t/t_sys_rand_seed.out index 26738d308..c227b2acd 100644 --- a/test_regress/t/t_sys_rand_seed.out +++ b/test_regress/t/t_sys_rand_seed.out @@ -1,7 +1,7 @@ -%Error: t/t_sys_rand_seed.v:13:16: Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag +%Error-UNSUPPORTED: t/t_sys_rand_seed.v:13:16: Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag 13 | valuea = $random(10); | ^~~~~~~ -%Error: t/t_sys_rand_seed.v:14:16: Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag +%Error-UNSUPPORTED: t/t_sys_rand_seed.v:14:16: Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag 14 | valueb = $random(10); | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_sys_readmem.v b/test_regress/t/t_sys_readmem.v index d128dfb4e..ca79d8b0c 100644 --- a/test_regress/t/t_sys_readmem.v +++ b/test_regress/t/t_sys_readmem.v @@ -4,6 +4,14 @@ // any use, without warranty, 2003 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`ifdef WRITEMEM_BIN + `define READMEMX $readmemb + `define WRITEMEMX $writememb +`else + `define READMEMX $readmemh + `define WRITEMEMX $writememh +`endif + module t; // verilator lint_off LITENDIAN @@ -53,14 +61,16 @@ module t; begin `ifdef WRITEMEM_READ_BACK $readmemb("t/t_sys_readmem_b.mem", binary_nostart_tmp); - // Do a round-trip $writememh and $readmemh cycle. + // Do a round-trip $writememh(b) and $readmemh(b) cycle. // This covers $writememh and ensures we can read our // own memh output file. + // If WRITEMEM_BIN is also defined, use $writememb and + // $readmemb, otherwise use $writememh and $readmemh. `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP1); `endif - $writememh(`OUT_TMP1, binary_nostart_tmp); - $readmemh(`OUT_TMP1, binary_nostart); + `WRITEMEMX(`OUT_TMP1, binary_nostart_tmp); + `READMEMX(`OUT_TMP1, binary_nostart); `else $readmemb("t/t_sys_readmem_b.mem", binary_nostart); `endif @@ -86,8 +96,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP2); `endif - $writememh(`OUT_TMP2, binary_start_tmp, 4, 4+7); - $readmemh(`OUT_TMP2, binary_start, 4, 4+7); + `WRITEMEMX(`OUT_TMP2, binary_start_tmp, 4, 4+7); + `READMEMX(`OUT_TMP2, binary_start, 4, 4+7); `else $readmemb("t/t_sys_readmem_b_8.mem", binary_start, 4, 4+7); // 4-11 `endif @@ -114,8 +124,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP3); `endif - $writememh(`OUT_TMP3, hex_tmp, 0); - $readmemh(`OUT_TMP3, hex, 0); + `WRITEMEMX(`OUT_TMP3, hex_tmp, 0); + `READMEMX(`OUT_TMP3, hex, 0); `else $readmemh("t/t_sys_readmem_h.mem", hex, 0); `endif @@ -136,8 +146,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP4); `endif - $writememh(`OUT_TMP4, hex_align_tmp, 0); - $readmemh(`OUT_TMP4, hex_align, 0); + `WRITEMEMX(`OUT_TMP4, hex_align_tmp, 0); + `READMEMX(`OUT_TMP4, hex_align, 0); `else $readmemh("t/t_sys_readmem_align_h.mem", hex_align, 0); `endif @@ -158,8 +168,8 @@ module t; `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP5); `endif - $writememh(fns_tmp, binary_string_tmp); - $readmemh(fns_tmp, binary_string); + `WRITEMEMX(fns_tmp, binary_string_tmp); + `READMEMX(fns_tmp, binary_string); `else $readmemb(fns, binary_string); `endif diff --git a/test_regress/t/t_sys_readmem_assoc_bad.out b/test_regress/t/t_sys_readmem_assoc_bad.out index ccb95325d..bc09fd9cd 100644 --- a/test_regress/t/t_sys_readmem_assoc_bad.out +++ b/test_regress/t/t_sys_readmem_assoc_bad.out @@ -2,8 +2,8 @@ : ... In instance t 13 | $readmemb("not", assoc_bad_key); | ^~~~~~~~~~~~~ -%Error: t/t_sys_readmem_assoc_bad.v:14:24: Unsupported: $readmemb array values must be integral - : ... In instance t +%Error-UNSUPPORTED: t/t_sys_readmem_assoc_bad.v:14:24: Unsupported: $readmemb array values must be integral + : ... In instance t 14 | $readmemb("not", assoc_bad_value); | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_sys_sformat.v b/test_regress/t/t_sys_sformat.v index ecd5f8eb3..d4da7ac54 100644 --- a/test_regress/t/t_sys_sformat.v +++ b/test_regress/t/t_sys_sformat.v @@ -43,6 +43,11 @@ module t; $swrite(str2, "e=%f", r); $swrite(str2, "e=%g", r); + str3 = "hello"; + $swrite(str2, {str3, str3}); +`ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif + if (str2 !== "hellohello") $stop; + r = 0.01; $swrite(str2, "e=%e f=%f g=%g", r, r, r); `ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif @@ -57,11 +62,11 @@ module t; if (str2 !== "lib=t") $stop; str3 = $sformatf("u=%u", {"a","b","c","d"}); // Value selected so is printable -`ifdef TEST_VERBOSE $display("chku %s %s",str3,str3); `endif +`ifdef TEST_VERBOSE $display("chku %s", str3); `endif if (str3 !== "u=dcba") $stop; str3 = $sformatf("v=%v", {"a","b","c","d"}); // Value selected so is printable -`ifdef TEST_VERBOSE $display("chkv %s %s",str3,str3); `endif +`ifdef TEST_VERBOSE $display("chkv %s", str3); `endif $sformat(ochar,"%s","c"); if (ochar != "c") $stop; diff --git a/test_regress/t/t_sys_writemem_b.gold1.mem b/test_regress/t/t_sys_writemem_b.gold1.mem new file mode 100644 index 000000000..6e4fbbfe0 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold1.mem @@ -0,0 +1,14 @@ +000010 +000011 +000100 +000101 +000110 +000111 +010000 +000000 +000000 +000000 +010100 +010101 +000000 +000000 diff --git a/test_regress/t/t_sys_writemem_b.gold2.mem b/test_regress/t/t_sys_writemem_b.gold2.mem new file mode 100644 index 000000000..490b61837 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold2.mem @@ -0,0 +1,8 @@ +010000 +010001 +010010 +010011 +010100 +010101 +010110 +010111 diff --git a/test_regress/t/t_sys_writemem_b.gold3.mem b/test_regress/t/t_sys_writemem_b.gold3.mem new file mode 100644 index 000000000..d83d7279c --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold3.mem @@ -0,0 +1,16 @@ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +01000000000001000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +01000000000010100011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010001 +01000000000010110011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010010 +01000000000011000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010011 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold4.mem b/test_regress/t/t_sys_writemem_b.gold4.mem new file mode 100644 index 000000000..3bc80dcf3 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold4.mem @@ -0,0 +1,16 @@ +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +011101110101010101000000000001000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +011101110101010101000000000010100011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010001 +011101110101010101000000000010110011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010010 +011101110101010101000000000011000011011101100101010000110010000100100111011001010100001100100001000101110110010101000011001000010000011101100101010000110010000110101011110011011110111100010011 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold5.mem b/test_regress/t/t_sys_writemem_b.gold5.mem new file mode 100644 index 000000000..6e4fbbfe0 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold5.mem @@ -0,0 +1,14 @@ +000010 +000011 +000100 +000101 +000110 +000111 +010000 +000000 +000000 +000000 +010100 +010101 +000000 +000000 diff --git a/test_regress/t/t_sys_writemem_b.pl b/test_regress/t/t_sys_writemem_b.pl new file mode 100755 index 000000000..c5b47759f --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.pl @@ -0,0 +1,40 @@ +#!/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); + +top_filename("t/t_sys_readmem.v"); + +# Use random reset to ensure we're fully initializing arrays before +# $writememh, to avoid miscompares with X's on 4-state simulators. +$Self->{verilated_randReset} = 2; # 2 == truly random + +compile(v_flags2 => [ + "+define+WRITEMEM_READ_BACK=1", + "+define+WRITEMEM_BIN=1", + "+define+OUT_TMP1=\\\"$Self->{obj_dir}/tmp1.mem\\\"", + "+define+OUT_TMP2=\\\"$Self->{obj_dir}/tmp2.mem\\\"", + "+define+OUT_TMP3=\\\"$Self->{obj_dir}/tmp3.mem\\\"", + "+define+OUT_TMP4=\\\"$Self->{obj_dir}/tmp4.mem\\\"", + "+define+OUT_TMP5=\\\"$Self->{obj_dir}/tmp5.mem\\\"", + ]); + +execute( + check_finished => 1, + ); + +for (my $i = 1; $i <= 5; $i++) { + my $gold = "$Self->{t_dir}/t_sys_writemem_b.gold${i}.mem"; + my $out = "$Self->{obj_dir}/tmp${i}.mem"; + files_identical($out, $gold); +} + +ok(1); +1; diff --git a/test_regress/t/t_timescale.cpp b/test_regress/t/t_timescale.cpp index f0bddf194..1471cc2d3 100644 --- a/test_regress/t/t_timescale.cpp +++ b/test_regress/t/t_timescale.cpp @@ -11,14 +11,13 @@ unsigned long long main_time = 0; double sc_time_stamp() { return (double)main_time; } #include -using namespace std; #define FILENM "t_timescale.cpp" #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } diff --git a/test_regress/t/t_timescale_lint_bad.pl b/test_regress/t/t_timescale_lint_bad.pl index 54c63c732..7ad36d5cd 100755 --- a/test_regress/t/t_timescale_lint_bad.pl +++ b/test_regress/t/t_timescale_lint_bad.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); +scenarios(linter => 1); lint( verilator_flags2 => ["--lint-only"], diff --git a/test_regress/t/t_timing_clkgen.pl b/test_regress/t/t_timing_clkgen.pl new file mode 100755 index 000000000..e1998178c --- /dev/null +++ b/test_regress/t/t_timing_clkgen.pl @@ -0,0 +1,29 @@ +#!/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(simulator => 1); + +$Self->{vlt_all} and unsupported("Verilator unsupported, clocking"); + +compile( + #verilator_flags2 => ['--exe --build --main --timing'], # Unsupported + verilator_flags2 => ['--exe --build --main --bbox-unsup -Wno-STMTDLY -Wno-INITIALDLY'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + make_top => 1, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_clkgen.v b/test_regress/t/t_timing_clkgen.v new file mode 100644 index 000000000..12cc19a41 --- /dev/null +++ b/test_regress/t/t_timing_clkgen.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module clkgen(output bit clk); + initial begin + #(8.0:5:3) clk = 1; // Middle is default + forever begin + #5 clk = ~clk; + end + end +endmodule + +module t(/*AUTOARG*/); + wire logic clk; + + clkgen clkgen (.clk); + + int cyc; + always @ (posedge clk) begin + cyc <= cyc + 1; +`ifdef TEST_VERBOSE + $display("[%0t] cyc=%0d", $time, cyc); +`endif + if (cyc == 0) begin + if ($time != 5) $stop; + end + else if (cyc == 1) begin + if ($time != 15) $stop; + end + else if (cyc == 2) begin + if ($time != 25) $stop; + end + else if (cyc == 9) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_timing_long.pl b/test_regress/t/t_timing_long.pl new file mode 100755 index 000000000..031575331 --- /dev/null +++ b/test_regress/t/t_timing_long.pl @@ -0,0 +1,71 @@ +#!/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 +use IO::File; + +scenarios(simulator => 1); + +# Look for O(n^2) problems in process handling + +sub gen { + my $filename = shift; + + my $fh = IO::File->new(">$filename"); + $fh->print("// Generated by t_timing_long.pl\n"); + + $fh->print("\n"); + $fh->print("`ifdef TEST_VERBOSE\n"); + $fh->print(" `define MSG(m) \$display m\n"); + $fh->print("`else\n"); + $fh->print(" `define MSG(m)\n"); + $fh->print("`endif\n"); + $fh->print("\n"); + + $fh->print("module t;\n"); + $fh->print("\n"); + $fh->print(" int cnt;\n"); + $fh->print("\n"); + $fh->print(" initial begin\n"); + + my $n = 100; + for (my $i=1; $i<$n; ++$i) { + # If statement around the timing is important to make the code scheduling + # mostly unpredictable + $fh->printf(" if (cnt == %d) begin\n", $i-1); + $fh->printf(" #1; ++cnt; `MSG((\"[%0t] cnt?=${i}\", \$time));" + ." if (cnt != %d) \$stop;\n", $i); + $fh->printf(" end\n"); + } + + $fh->print("\n"); + $fh->print(' $write("*-* All Finished *-*\n");',"\n"); + $fh->print(' $finish;',"\n"); + $fh->print(" end\n"); + $fh->print("endmodule\n"); +} + +top_filename("$Self->{obj_dir}/t_timing_long.v"); + +gen($Self->{top_filename}); + +compile( + #verilator_flags2=>["--exe --build --main --timing"], # Unsupported + verilator_flags2=>["--exe --build --main -Wno-STMTDLY"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + make_top => 1, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_reentry.pl b/test_regress/t/t_timing_reentry.pl new file mode 100755 index 000000000..cf634ac0e --- /dev/null +++ b/test_regress/t/t_timing_reentry.pl @@ -0,0 +1,28 @@ +#!/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(simulator => 1); + +compile( + #verilator_flags2 => ['--exe --build --main --timing'], # Unsupported + verilator_flags2 => ['--exe --build --main --bbox-unsup -Wno-STMTDLY -Wno-INITIALDLY'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + make_top => 1, + ); + +# Will fail, unsupported +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_reentry.v b/test_regress/t/t_timing_reentry.v new file mode 100644 index 000000000..c3a7bb16d --- /dev/null +++ b/test_regress/t/t_timing_reentry.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + event a, b; + + int order = 0; + + initial begin + order++; if (order != 1) $stop; + #10; + $display("[%0t]%0d -> a", $time, order); + order++; if (order != 2) $stop; + -> a; + #10; + $display("[%0t]%0d -> b", $time, order); + order++; if (order != 4) $stop; + -> b; + #100; + order++; if (order != 6) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + always @ (a or b) begin + $display("[%0t]%0d entering", $time, order); + order++; if (order != 3) $stop; + #15; + $display("[%0t]%0d 15 later", $time, order); + order++; if (order != 5) $stop; + end +endmodule diff --git a/test_regress/t/t_trace_abort.out b/test_regress/t/t_trace_abort.out new file mode 100644 index 000000000..b25a07948 --- /dev/null +++ b/test_regress/t/t_trace_abort.out @@ -0,0 +1,53 @@ +$version Generated by VerilatedVcd $end +$date Wed Jun 10 17:27:15 2020 + $end +$timescale 1ps $end + + $scope module top $end + $var wire 1 # clk $end + $scope module t $end + $var wire 1 # clk $end + $var wire 3 $ cyc [2:0] $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +0# +b000 $ +#10 +1# +b001 $ +#15 +0# +#20 +1# +b010 $ +#25 +0# +#30 +1# +b011 $ +#35 +0# +#40 +1# +b100 $ +#45 +0# +#50 +1# +b101 $ +#55 +0# +#60 +1# +b110 $ +#65 +0# +#70 +1# +b111 $ +#75 +0# diff --git a/test_regress/t/t_trace_abort.pl b/test_regress/t/t_trace_abort.pl new file mode 100755 index 000000000..78c5ee50c --- /dev/null +++ b/test_regress/t/t_trace_abort.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 Geza Lore. 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( + verilator_flags2 => ['--cc --trace'], + ); + +execute( + fails => 1, + ); + +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_abort.v b/test_regress/t/t_trace_abort.v new file mode 100644 index 000000000..b39927aad --- /dev/null +++ b/test_regress/t/t_trace_abort.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + reg [2:0] cyc = 0; + + always @(posedge clk) begin + cyc <= cyc + 3'd1; + // Exit via abort to make sure trace is flushed + if (&cyc) $stop; + end + +endmodule diff --git a/test_regress/t/t_trace_abort_fst.out b/test_regress/t/t_trace_abort_fst.out new file mode 100644 index 000000000..af9505556 --- /dev/null +++ b/test_regress/t/t_trace_abort_fst.out @@ -0,0 +1,58 @@ +$date + Wed Jun 10 20:47:01 2020 + +$end +$version + fstWriter +$end +$timescale + 1ps +$end +$scope module top $end +$var wire 1 ! clk $end +$scope module t $end +$var wire 1 ! clk $end +$var logic 3 " cyc $end +$upscope $end +$upscope $end +$enddefinitions $end +#0 +$dumpvars +b000 " +0! +$end +#10 +1! +b001 " +#15 +0! +#20 +1! +b010 " +#25 +0! +#30 +1! +b011 " +#35 +0! +#40 +1! +b100 " +#45 +0! +#50 +1! +b101 " +#55 +0! +#60 +1! +b110 " +#65 +0! +#70 +1! +b111 " +#75 +0! diff --git a/test_regress/t/t_trace_abort_fst.pl b/test_regress/t/t_trace_abort_fst.pl new file mode 100755 index 000000000..a57dec132 --- /dev/null +++ b/test_regress/t/t_trace_abort_fst.pl @@ -0,0 +1,26 @@ +#!/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 Geza Lore. 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_trace_abort.v"); + +compile( + verilator_flags2 => ['--cc --trace-fst'], + ); + +execute( + fails => 1, + ); + +fst_identical("$Self->{obj_dir}/simx.fst", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_tri_compass_bad.out b/test_regress/t/t_tri_compass_bad.out index a7cdf0192..b07623a7d 100644 --- a/test_regress/t/t_tri_compass_bad.out +++ b/test_regress/t/t_tri_compass_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_tri_compass_bad.v:16:12: Unsupported: tristate in top-level IO: '__pinNumber1' - : ... In instance t +%Error-UNSUPPORTED: t/t_tri_compass_bad.v:16:12: Unsupported: tristate in top-level IO: '__pinNumber1' + : ... In instance t 16 | sub sub(i, o); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_tri_pull2_bad.out b/test_regress/t/t_tri_pull2_bad.out index f80de4b1f..98baf9520 100644 --- a/test_regress/t/t_tri_pull2_bad.out +++ b/test_regress/t/t_tri_pull2_bad.out @@ -1,8 +1,8 @@ -%Error: t/t_tri_pull2_bad.v:12:11: Unsupported: Conflicting pull directions. - : ... In instance t +%Error-UNSUPPORTED: t/t_tri_pull2_bad.v:12:11: Unsupported: Conflicting pull directions. + : ... In instance t 12 | pullup p1(A); | ^~ - t/t_tri_pull2_bad.v:22:13: ... Location of conflicting pull. + t/t_tri_pull2_bad.v:22:13: ... Location of conflicting pull. 22 | pulldown p2(A); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_tri_pull2_bad.pl b/test_regress/t/t_tri_pull2_bad.pl index c213189c1..59ba0d6c6 100755 --- a/test_regress/t/t_tri_pull2_bad.pl +++ b/test_regress/t/t_tri_pull2_bad.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); +scenarios(linter => 1); lint( fails => $Self->{vlt_all}, diff --git a/test_regress/t/t_tri_pull_bad.out b/test_regress/t/t_tri_pull_bad.out index f9e60554b..e59dcf535 100644 --- a/test_regress/t/t_tri_pull_bad.out +++ b/test_regress/t/t_tri_pull_bad.out @@ -1,8 +1,8 @@ -%Error: t/t_tri_pull_bad.v:13:13: Unsupported: Conflicting pull directions. - : ... In instance t +%Error-UNSUPPORTED: t/t_tri_pull_bad.v:13:13: Unsupported: Conflicting pull directions. + : ... In instance t 13 | pulldown p2(A); | ^~ - t/t_tri_pull_bad.v:12:11: ... Location of conflicting pull. + t/t_tri_pull_bad.v:12:11: ... Location of conflicting pull. 12 | pullup p1(A); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_tri_pull_bad.pl b/test_regress/t/t_tri_pull_bad.pl index c213189c1..59ba0d6c6 100755 --- a/test_regress/t/t_tri_pull_bad.pl +++ b/test_regress/t/t_tri_pull_bad.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); +scenarios(linter => 1); lint( fails => $Self->{vlt_all}, diff --git a/test_regress/t/t_tri_pullvec_bad.out b/test_regress/t/t_tri_pullvec_bad.out index 68bf7c55d..1c5594298 100644 --- a/test_regress/t/t_tri_pullvec_bad.out +++ b/test_regress/t/t_tri_pullvec_bad.out @@ -1,15 +1,15 @@ -%Error: t/t_tri_pullvec_bad.v:13:13: Unsupported: Conflicting pull directions. - : ... In instance t +%Error-UNSUPPORTED: t/t_tri_pullvec_bad.v:13:13: Unsupported: Conflicting pull directions. + : ... In instance t 13 | pulldown p1 (w[1]); | ^~ - t/t_tri_pullvec_bad.v:12:11: ... Location of conflicting pull. + t/t_tri_pullvec_bad.v:12:11: ... Location of conflicting pull. 12 | pullup p0 (w[0]); | ^~ -%Error: t/t_tri_pullvec_bad.v:14:13: Unsupported: Conflicting pull directions. - : ... In instance t +%Error-UNSUPPORTED: t/t_tri_pullvec_bad.v:14:13: Unsupported: Conflicting pull directions. + : ... In instance t 14 | pulldown p2 (w[2]); | ^~ - t/t_tri_pullvec_bad.v:12:11: ... Location of conflicting pull. + t/t_tri_pullvec_bad.v:12:11: ... Location of conflicting pull. 12 | pullup p0 (w[0]); | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_udp.out b/test_regress/t/t_udp.out index ff1599baa..852e2eef0 100644 --- a/test_regress/t/t_udp.out +++ b/test_regress/t/t_udp.out @@ -1,4 +1,4 @@ -%Error: t/t_udp.v:104:4: Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables. +%Error-UNSUPPORTED: t/t_udp.v:104:4: Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables. 104 | table | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_udp_noname.out b/test_regress/t/t_udp_noname.out index c82b2ceaf..14eb3efdb 100644 --- a/test_regress/t/t_udp_noname.out +++ b/test_regress/t/t_udp_noname.out @@ -1,4 +1,4 @@ -%Error: t/t_udp_noname.v:15:9: syntax error, unexpected '(', expecting IDENTIFIER +%Error: t/t_udp_noname.v:15:8: syntax error, unexpected '(', expecting IDENTIFIER or randomize 15 | udp (o, a); - | ^ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index f47940153..67309b1bd 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -1,5 +1,5 @@ -%Error: t/t_unpacked_concat_bad.v:17:46: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:17:46: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type + : ... In instance t 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ %Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:17:47: Unsized numbers/parameters not allowed in replications. @@ -7,8 +7,8 @@ 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^~~~~ ... Use "/* verilator lint_off WIDTHCONCAT */" and lint_on around source to disable this message. -%Error: t/t_unpacked_concat_bad.v:18:45: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type - : ... In instance t +%Error-UNSUPPORTED: t/t_unpacked_concat_bad.v:18:45: Unsupported: Replication to form 'bit[31:0]$[1:0]' data type + : ... In instance t 18 | localparam bit_int_t count_bitsc [1:0] = {$bits(count_t), $bits(count_t)}; | ^ %Warning-WIDTHCONCAT: t/t_unpacked_concat_bad.v:18:46: Unsized numbers/parameters not allowed in concatenations. diff --git a/test_regress/t/t_vams_kwd_bad.out b/test_regress/t/t_vams_kwd_bad.out index 739550c49..cc4a86cc1 100644 --- a/test_regress/t/t_vams_kwd_bad.out +++ b/test_regress/t/t_vams_kwd_bad.out @@ -1,199 +1,199 @@ -%Error: t/t_vams_kwd_bad.v:12:8: Unsupported: AMS reserved word not implemented: 'above' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:12:8: Unsupported: AMS reserved word not implemented: 'above' 12 | int above; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:12:13: syntax error, unexpected ';', expecting IDENTIFIER +%Error: t/t_vams_kwd_bad.v:12:13: syntax error, unexpected ';', expecting IDENTIFIER or randomize 12 | int above; | ^ -%Error: t/t_vams_kwd_bad.v:13:8: Unsupported: AMS reserved word not implemented: 'abs' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:13:8: Unsupported: AMS reserved word not implemented: 'abs' 13 | int abs; | ^~~ -%Error: t/t_vams_kwd_bad.v:14:8: Unsupported: AMS reserved word not implemented: 'absdelay' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:14:8: Unsupported: AMS reserved word not implemented: 'absdelay' 14 | int absdelay; | ^~~~~~~~ -%Error: t/t_vams_kwd_bad.v:15:8: Unsupported: AMS reserved word not implemented: 'abstol' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:15:8: Unsupported: AMS reserved word not implemented: 'abstol' 15 | int abstol; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:16:8: Unsupported: AMS reserved word not implemented: 'ac_stim' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:16:8: Unsupported: AMS reserved word not implemented: 'ac_stim' 16 | int ac_stim; | ^~~~~~~ -%Error: t/t_vams_kwd_bad.v:17:8: Unsupported: AMS reserved word not implemented: 'access' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:17:8: Unsupported: AMS reserved word not implemented: 'access' 17 | int access; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:18:8: Unsupported: AMS reserved word not implemented: 'acos' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:18:8: Unsupported: AMS reserved word not implemented: 'acos' 18 | int acos; | ^~~~ -%Error: t/t_vams_kwd_bad.v:19:8: Unsupported: AMS reserved word not implemented: 'acosh' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:19:8: Unsupported: AMS reserved word not implemented: 'acosh' 19 | int acosh; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:20:8: Unsupported: AMS reserved word not implemented: 'aliasparam' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:20:8: Unsupported: AMS reserved word not implemented: 'aliasparam' 20 | int aliasparam; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:21:8: Unsupported: AMS reserved word not implemented: 'analog' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:21:8: Unsupported: AMS reserved word not implemented: 'analog' 21 | int analog; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:22:8: Unsupported: AMS reserved word not implemented: 'analysis' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:22:8: Unsupported: AMS reserved word not implemented: 'analysis' 22 | int analysis; | ^~~~~~~~ -%Error: t/t_vams_kwd_bad.v:23:8: Unsupported: AMS reserved word not implemented: 'assert' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:23:8: Unsupported: AMS reserved word not implemented: 'assert' 23 | int assert; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:24:8: Unsupported: AMS reserved word not implemented: 'branch' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:24:8: Unsupported: AMS reserved word not implemented: 'branch' 24 | int branch; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:25:8: Unsupported: AMS reserved word not implemented: 'connect' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:25:8: Unsupported: AMS reserved word not implemented: 'connect' 25 | int connect; | ^~~~~~~ -%Error: t/t_vams_kwd_bad.v:26:8: Unsupported: AMS reserved word not implemented: 'connectmodule' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:26:8: Unsupported: AMS reserved word not implemented: 'connectmodule' 26 | int connectmodule; | ^~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:27:8: Unsupported: AMS reserved word not implemented: 'connectrules' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:27:8: Unsupported: AMS reserved word not implemented: 'connectrules' 27 | int connectrules; | ^~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:28:8: Unsupported: AMS reserved word not implemented: 'continuous' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:28:8: Unsupported: AMS reserved word not implemented: 'continuous' 28 | int continuous; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:29:8: Unsupported: AMS reserved word not implemented: 'cross' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:29:8: Unsupported: AMS reserved word not implemented: 'cross' 29 | int cross; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:30:8: Unsupported: AMS reserved word not implemented: 'ddt' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:30:8: Unsupported: AMS reserved word not implemented: 'ddt' 30 | int ddt; | ^~~ -%Error: t/t_vams_kwd_bad.v:31:8: Unsupported: AMS reserved word not implemented: 'ddt_nature' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:31:8: Unsupported: AMS reserved word not implemented: 'ddt_nature' 31 | int ddt_nature; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:32:8: Unsupported: AMS reserved word not implemented: 'ddx' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:32:8: Unsupported: AMS reserved word not implemented: 'ddx' 32 | int ddx; | ^~~ -%Error: t/t_vams_kwd_bad.v:33:8: Unsupported: AMS reserved word not implemented: 'discipline' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:33:8: Unsupported: AMS reserved word not implemented: 'discipline' 33 | int discipline; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:34:8: Unsupported: AMS reserved word not implemented: 'discrete' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:34:8: Unsupported: AMS reserved word not implemented: 'discrete' 34 | int discrete; | ^~~~~~~~ -%Error: t/t_vams_kwd_bad.v:35:8: Unsupported: AMS reserved word not implemented: 'domain' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:35:8: Unsupported: AMS reserved word not implemented: 'domain' 35 | int domain; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:36:8: Unsupported: AMS reserved word not implemented: 'driver_update' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:36:8: Unsupported: AMS reserved word not implemented: 'driver_update' 36 | int driver_update; | ^~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:37:8: Unsupported: AMS reserved word not implemented: 'endconnectrules' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:37:8: Unsupported: AMS reserved word not implemented: 'endconnectrules' 37 | int endconnectrules; | ^~~~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:38:8: Unsupported: AMS reserved word not implemented: 'enddiscipline' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:38:8: Unsupported: AMS reserved word not implemented: 'enddiscipline' 38 | int enddiscipline; | ^~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:39:8: Unsupported: AMS reserved word not implemented: 'endnature' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:39:8: Unsupported: AMS reserved word not implemented: 'endnature' 39 | int endnature; | ^~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:40:8: Unsupported: AMS reserved word not implemented: 'endparamset' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:40:8: Unsupported: AMS reserved word not implemented: 'endparamset' 40 | int endparamset; | ^~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:41:8: Unsupported: AMS reserved word not implemented: 'exclude' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:41:8: Unsupported: AMS reserved word not implemented: 'exclude' 41 | int exclude; | ^~~~~~~ -%Error: t/t_vams_kwd_bad.v:42:8: Unsupported: AMS reserved word not implemented: 'final_step' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:42:8: Unsupported: AMS reserved word not implemented: 'final_step' 42 | int final_step; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:43:8: Unsupported: AMS reserved word not implemented: 'flicker_noise' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:43:8: Unsupported: AMS reserved word not implemented: 'flicker_noise' 43 | int flicker_noise; | ^~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:44:8: Unsupported: AMS reserved word not implemented: 'flow' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:44:8: Unsupported: AMS reserved word not implemented: 'flow' 44 | int flow; | ^~~~ -%Error: t/t_vams_kwd_bad.v:45:8: Unsupported: AMS reserved word not implemented: 'from' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:45:8: Unsupported: AMS reserved word not implemented: 'from' 45 | int from; | ^~~~ -%Error: t/t_vams_kwd_bad.v:46:8: Unsupported: AMS reserved word not implemented: 'ground' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:46:8: Unsupported: AMS reserved word not implemented: 'ground' 46 | int ground; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:47:8: Unsupported: AMS reserved word not implemented: 'idt' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:47:8: Unsupported: AMS reserved word not implemented: 'idt' 47 | int idt; | ^~~ -%Error: t/t_vams_kwd_bad.v:48:8: Unsupported: AMS reserved word not implemented: 'idt_nature' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:48:8: Unsupported: AMS reserved word not implemented: 'idt_nature' 48 | int idt_nature; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:49:8: Unsupported: AMS reserved word not implemented: 'idtmod' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:49:8: Unsupported: AMS reserved word not implemented: 'idtmod' 49 | int idtmod; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:50:8: Unsupported: AMS reserved word not implemented: 'inf' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:50:8: Unsupported: AMS reserved word not implemented: 'inf' 50 | int inf; | ^~~ -%Error: t/t_vams_kwd_bad.v:51:8: Unsupported: AMS reserved word not implemented: 'initial_step' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:51:8: Unsupported: AMS reserved word not implemented: 'initial_step' 51 | int initial_step; | ^~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:52:8: Unsupported: AMS reserved word not implemented: 'laplace_nd' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:52:8: Unsupported: AMS reserved word not implemented: 'laplace_nd' 52 | int laplace_nd; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:53:8: Unsupported: AMS reserved word not implemented: 'laplace_np' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:53:8: Unsupported: AMS reserved word not implemented: 'laplace_np' 53 | int laplace_np; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:54:8: Unsupported: AMS reserved word not implemented: 'laplace_zd' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:54:8: Unsupported: AMS reserved word not implemented: 'laplace_zd' 54 | int laplace_zd; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:55:8: Unsupported: AMS reserved word not implemented: 'laplace_zp' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:55:8: Unsupported: AMS reserved word not implemented: 'laplace_zp' 55 | int laplace_zp; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:56:8: Unsupported: AMS reserved word not implemented: 'last_crossing' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:56:8: Unsupported: AMS reserved word not implemented: 'last_crossing' 56 | int last_crossing; | ^~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:57:8: Unsupported: AMS reserved word not implemented: 'limexp' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:57:8: Unsupported: AMS reserved word not implemented: 'limexp' 57 | int limexp; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:58:8: Unsupported: AMS reserved word not implemented: 'max' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:58:8: Unsupported: AMS reserved word not implemented: 'max' 58 | int max; | ^~~ -%Error: t/t_vams_kwd_bad.v:59:8: Unsupported: AMS reserved word not implemented: 'merged' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:59:8: Unsupported: AMS reserved word not implemented: 'merged' 59 | int merged; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:60:8: Unsupported: AMS reserved word not implemented: 'min' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:60:8: Unsupported: AMS reserved word not implemented: 'min' 60 | int min; | ^~~ -%Error: t/t_vams_kwd_bad.v:61:8: Unsupported: AMS reserved word not implemented: 'nature' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:61:8: Unsupported: AMS reserved word not implemented: 'nature' 61 | int nature; | ^~~~~~ -%Error: t/t_vams_kwd_bad.v:62:8: Unsupported: AMS reserved word not implemented: 'net_resolution' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:62:8: Unsupported: AMS reserved word not implemented: 'net_resolution' 62 | int net_resolution; | ^~~~~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:63:8: Unsupported: AMS reserved word not implemented: 'noise_table' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:63:8: Unsupported: AMS reserved word not implemented: 'noise_table' 63 | int noise_table; | ^~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:64:8: Unsupported: AMS reserved word not implemented: 'paramset' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:64:8: Unsupported: AMS reserved word not implemented: 'paramset' 64 | int paramset; | ^~~~~~~~ -%Error: t/t_vams_kwd_bad.v:65:8: Unsupported: AMS reserved word not implemented: 'potential' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:65:8: Unsupported: AMS reserved word not implemented: 'potential' 65 | int potential; | ^~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:66:8: Unsupported: AMS reserved word not implemented: 'resolveto' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:66:8: Unsupported: AMS reserved word not implemented: 'resolveto' 66 | int resolveto; | ^~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:67:8: Unsupported: AMS reserved word not implemented: 'slew' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:67:8: Unsupported: AMS reserved word not implemented: 'slew' 67 | int slew; | ^~~~ -%Error: t/t_vams_kwd_bad.v:68:8: Unsupported: AMS reserved word not implemented: 'split' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:68:8: Unsupported: AMS reserved word not implemented: 'split' 68 | int split; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:69:8: Unsupported: AMS reserved word not implemented: 'timer' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:69:8: Unsupported: AMS reserved word not implemented: 'timer' 69 | int timer; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:70:8: Unsupported: AMS reserved word not implemented: 'transition' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:70:8: Unsupported: AMS reserved word not implemented: 'transition' 70 | int transition; | ^~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:71:8: Unsupported: AMS reserved word not implemented: 'units' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:71:8: Unsupported: AMS reserved word not implemented: 'units' 71 | int units; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:72:8: Unsupported: AMS reserved word not implemented: 'white_noise' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:72:8: Unsupported: AMS reserved word not implemented: 'white_noise' 72 | int white_noise; | ^~~~~~~~~~~ -%Error: t/t_vams_kwd_bad.v:73:8: Unsupported: AMS reserved word not implemented: 'zi_nd' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:73:8: Unsupported: AMS reserved word not implemented: 'zi_nd' 73 | int zi_nd; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:74:8: Unsupported: AMS reserved word not implemented: 'zi_np' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:74:8: Unsupported: AMS reserved word not implemented: 'zi_np' 74 | int zi_np; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:75:8: Unsupported: AMS reserved word not implemented: 'zi_zd' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:75:8: Unsupported: AMS reserved word not implemented: 'zi_zd' 75 | int zi_zd; | ^~~~~ -%Error: t/t_vams_kwd_bad.v:76:8: Unsupported: AMS reserved word not implemented: 'zi_zp' +%Error-UNSUPPORTED: t/t_vams_kwd_bad.v:76:8: Unsupported: AMS reserved word not implemented: 'zi_zp' 76 | int zi_zp; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_bad_sv.out b/test_regress/t/t_var_bad_sv.out index c27c1e81c..7a5ff2358 100644 --- a/test_regress/t/t_var_bad_sv.out +++ b/test_regress/t/t_var_bad_sv.out @@ -5,7 +5,7 @@ %Error: t/t_var_bad_sv.v:9:14: Unexpected 'do': 'do' is a SystemVerilog keyword misused as an identifier. 9 | mod mod (.do(bar)); | ^~ -%Error: t/t_var_bad_sv.v:9:17: syntax error, unexpected '(', expecting ')' +%Error: t/t_var_bad_sv.v:9:16: syntax error, unexpected '(', expecting ')' 9 | mod mod (.do(bar)); - | ^~~ + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_var_ref_bad3.out b/test_regress/t/t_var_ref_bad3.out index 967d473af..6ae8e9307 100644 --- a/test_regress/t/t_var_ref_bad3.out +++ b/test_regress/t/t_var_ref_bad3.out @@ -1,4 +1,4 @@ -%Error: t/t_var_ref_bad3.v:10:18: Unsupported: ref/const ref as primary input/output: 'bad_primary_ref' +%Error-UNSUPPORTED: t/t_var_ref_bad3.v:10:18: Unsupported: ref/const ref as primary input/output: 'bad_primary_ref' 10 | module t(ref int bad_primary_ref | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_static.out b/test_regress/t/t_var_static.out index 3103c2e9b..982ff5970 100644 --- a/test_regress/t/t_var_static.out +++ b/test_regress/t/t_var_static.out @@ -1,22 +1,17 @@ -%Error: t/t_var_static.v:20:7: Unsupported: Static in this context +%Error-UNSUPPORTED: t/t_var_static.v:20:18: Unsupported: 'static' function/task variables + : ... In instance t 20 | static int st = 2; st++; return st; - | ^~~~~~ -%Error: t/t_var_static.v:26:13: Unsupported: Static in this context - 26 | function static int f_st_no (); - | ^~~~~~ -%Error: t/t_var_static.v:29:13: Unsupported: Static in this context - 29 | function static int f_st_st (); - | ^~~~~~ -%Error: t/t_var_static.v:30:7: Unsupported: Static in this context + | ^~ +%Error-UNSUPPORTED: t/t_var_static.v:27:11: Unsupported: 'static' function/task variables + : ... In instance t + 27 | int st = 2; st++; return st; + | ^~ +%Error-UNSUPPORTED: t/t_var_static.v:30:18: Unsupported: 'static' function/task variables + : ... In instance t 30 | static int st = 2; st++; return st; - | ^~~~~~ -%Error: t/t_var_static.v:32:13: Unsupported: Static in this context - 32 | function static int f_st_au (); - | ^~~~~~ -%Error: t/t_var_static.v:40:7: Unsupported: Static in this context + | ^~ +%Error-UNSUPPORTED: t/t_var_static.v:40:18: Unsupported: 'static' function/task variables + : ... In instance t 40 | static int st = 2; st++; return st; - | ^~~~~~ -%Error: t/t_var_static.v:73:7: Unsupported: Static in this context - 73 | static int ist2; - | ^~~~~~ + | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 0dd2e7541..9a18662f6 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -30,7 +30,6 @@ #include #include #include -using namespace std; #include "TestSimulator.h" #include "TestVpi.h" @@ -60,15 +59,15 @@ unsigned int main_time = 0; // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } #define CHECK_RESULT_HEX(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << hex << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \ + << ": GOT = " << (got) << " EXP = " << (exp) << endl; \ return __LINE__; \ } @@ -82,7 +81,9 @@ unsigned int main_time = 0; #define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int scalar, int type) { - s_vpi_value value = {.format = vpiIntVal, .value = {.integer = 0}}; + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = 0; // check size of object int vpisize = vpi_get(vpiSize, handle); CHECK_RESULT(vpisize, size); diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 1f8882a4d..60891c5a6 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -30,7 +30,6 @@ #include #include #include -using namespace std; #include "TestSimulator.h" #include "TestVpi.h" @@ -60,15 +59,15 @@ unsigned int main_time = 0; // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } #define CHECK_RESULT_HEX(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << hex << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \ + << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } @@ -83,7 +82,9 @@ unsigned int main_time = 0; int _mon_check_range(TestVpiHandle& handle, int size, int left, int right) { TestVpiHandle iter_h, left_h, right_h; - s_vpi_value value = {.format = vpiIntVal, .value = {.integer = 0}}; + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = 0; // check size of object int vpisize = vpi_get(vpiSize, handle); CHECK_RESULT(vpisize, size); @@ -109,7 +110,11 @@ int _mon_check_memory() { int cnt; TestVpiHandle mem_h, lcl_h, side_h; vpiHandle iter_h; // Icarus does not like auto free of iterator handles - s_vpi_value value = {.format = vpiIntVal, .value = {.integer = 0}}; + s_vpi_value value; + value.format = vpiIntVal; + value.value.integer = 0; + s_vpi_error_info e; + vpi_printf((PLI_BYTE8*)"Check memory vpi ...\n"); mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted("mem0"), NULL); CHECK_RESULT_NZ(mem_h); @@ -170,6 +175,10 @@ int _mon_check_memory() { vpi_get_value(side_h, &value); CHECK_RESULT(value.value.integer, 1); + // check writing to vpiConstant + vpi_put_value(side_h, &value, NULL, vpiNoDelay); + CHECK_RESULT_NZ(vpi_chk_error(&e)); + return 0; // Ok } diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index d0559b26e..abbb9fc8a 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -30,7 +30,6 @@ #include #include #include -using namespace std; #include "TestSimulator.h" #include "TestVpi.h" diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp new file mode 100644 index 000000000..f2b5f4e10 --- /dev/null +++ b/test_regress/t/t_vpi_param.cpp @@ -0,0 +1,276 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-2011 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 +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" +#include + +#else + +#include "Vt_vpi_param.h" +#include "verilated.h" +#include "svdpi.h" + +#include "Vt_vpi_param__Dpi.h" + +#include "verilated_vpi.h" +#include "verilated_vcd_c.h" + +#endif + +#include +#include +#include + +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_param.cpp" + +#define DEBUG \ + if (0) printf + +unsigned int main_time = 0; + +//====================================================================== + +#define CHECK_RESULT_VH(got, exp) \ + if ((got) != (exp)) { \ + printf("%%Error: %s:%d: GOT = %p EXP = %p\n", FILENM, __LINE__, (got), (exp)); \ + return __LINE__; \ + } + +#define CHECK_RESULT_NZ(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)) { \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_HEX(got, exp) \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::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", FILENM, __LINE__, \ + (got) ? (got) : "", (exp) ? (exp) : ""); \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) + + +int check_param_int(std::string name, PLI_INT32 format, int exp_value, bool verbose) { + int vpi_type; + TestVpiHandle param_h; + s_vpi_value value; + value.format = format; + value.value.integer = 0; + s_vpi_error_info e; + const char* p; + + vpi_printf((PLI_BYTE8*)"Check parameter %s vpi ...\n", name.c_str()); + param_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(name.c_str()), NULL); + CHECK_RESULT_NZ(param_h); + vpi_type = vpi_get(vpiType, param_h); + CHECK_RESULT(vpi_type, vpiParameter); + if (verbose) {vpi_printf((PLI_BYTE8*)" vpiType: %s (%d)\n", vpi_get_str(vpiType, param_h), vpi_type); } + + // attributes + p = vpi_get_str(vpiName, param_h); + CHECK_RESULT_CSTR(p, name.c_str()); + p = vpi_get_str(vpiFullName, param_h); + CHECK_RESULT_CSTR(p, std::string("t." + name).c_str()); + p = vpi_get_str(vpiType, param_h); + CHECK_RESULT_CSTR(p, "vpiParameter"); + vpi_type = vpi_get(vpiLocalParam, param_h); + CHECK_RESULT_NZ(vpi_chk_error(&e)); + if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + + // values + 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)); + if (verbose && vpi_chk_error(&e)) {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()); } + vpi_get_value(param_h, &value); + CHECK_RESULT_NZ(!vpi_chk_error(&e)); + if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + if (verbose) {vpi_printf((PLI_BYTE8*)" value of %s: %d\n", name.c_str(), value.value.integer); } + CHECK_RESULT(value.value.integer, exp_value); + + return 0; +} + +int check_param_str(std::string name, PLI_INT32 format, std::string exp_value, bool verbose) { + int vpi_type; + TestVpiHandle param_h; + s_vpi_value value; + value.format = format; + value.value.integer = 0; + s_vpi_error_info e; + const char* p; + + vpi_printf((PLI_BYTE8*)"Check parameter %s vpi ...\n", name.c_str()); + param_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(name.c_str()), NULL); + CHECK_RESULT_NZ(param_h); + vpi_type = vpi_get(vpiType, param_h); + CHECK_RESULT(vpi_type, vpiParameter); + if (verbose) {vpi_printf((PLI_BYTE8*)" vpiType: %s (%d)\n", vpi_get_str(vpiType, param_h), vpi_type); } + + // attributes + p = vpi_get_str(vpiName, param_h); + CHECK_RESULT_CSTR(p, name.c_str()); + p = vpi_get_str(vpiFullName, param_h); + CHECK_RESULT_CSTR(p, std::string("t." + name).c_str()); + p = vpi_get_str(vpiType, param_h); + CHECK_RESULT_CSTR(p, "vpiParameter"); + vpi_type = vpi_get(vpiLocalParam, param_h); + CHECK_RESULT_NZ(vpi_chk_error(&e)); + if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + + // values + 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)); + if (verbose && vpi_chk_error(&e)) {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()); } + vpi_get_value(param_h, &value); + CHECK_RESULT_NZ(!vpi_chk_error(&e)); + if (verbose && vpi_chk_error(&e)) {vpi_printf((PLI_BYTE8*)" vpi_chk_error: %s\n", e.message); } + if (verbose) {vpi_printf((PLI_BYTE8*)" value of %s: %s\n", name.c_str(), value.value.str); } + CHECK_RESULT_CSTR(value.value.str, exp_value.c_str()); + + return 0; +} + +int _mon_check_param() { + int status = 0; +#ifdef TEST_VERBOSE + bool verbose = true; +#else + bool verbose = false; +#endif + + status += check_param_int("WIDTH", vpiIntVal, 32, verbose); + status += check_param_int("DEPTH", vpiIntVal, 16, verbose); + status += check_param_str("PARAM_LONG", vpiHexStrVal, "fedcba9876543210", verbose); + status += check_param_str("PARAM_STR", vpiStringVal, "'some string value'", verbose); + return status; +} + +int mon_check() { + // Callback from initial block in monitor + if (int status = _mon_check_param()) return status; + return 0; // Ok +} + +//====================================================================== + +#ifdef IS_VPI + +static int mon_check_vpi() { + vpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} + +static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", + (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0}, + 0}; + +// cver entry +void vpi_compat_bootstrap(void) { + p_vpi_systf_data systf_data_p; + systf_data_p = &(vpi_systf_data[0]); + while (systf_data_p->type != 0) + vpi_register_systf(systf_data_p++); +} + +// icarus entry +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; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + // we're going to be checking for these errors do don't crash out + Verilated::fatalOnVpiError(0); + + VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out + +#ifdef VERILATOR +#ifdef TEST_VERBOSE + Verilated::scopesDump(); +#endif +#endif + +#if VM_TRACE + Verilated::traceEverOn(true); + VL_PRINTF("Enabling waves...\n"); + VerilatedVcdC* tfp = new VerilatedVcdC; + topp->trace(tfp, 99); + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +#endif + + topp->eval(); + topp->clk = 0; + main_time += 10; + + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + main_time += 1; + topp->eval(); + VerilatedVpi::callValueCbs(); + topp->clk = !topp->clk; + // mon_do(); +#if VM_TRACE + if (tfp) tfp->dump(main_time); +#endif + } + if (!Verilated::gotFinish()) { + vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + +#if VM_TRACE + if (tfp) tfp->close(); +#endif + + VL_DO_DANGLING(delete topp, topp); + exit(0L); +} + +#endif diff --git a/test_regress/t/t_vpi_param.pl b/test_regress/t/t_vpi_param.pl new file mode 100755 index 000000000..f6900846a --- /dev/null +++ b/test_regress/t/t_vpi_param.pl @@ -0,0 +1,31 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_param.cpp"], + ); + +execute( + iv_pli => 1, + check_finished => 1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_param.v b/test_regress/t/t_vpi_param.v new file mode 100644 index 000000000..082658ff6 --- /dev/null +++ b/test_regress/t/t_vpi_param.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2010 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 + +`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(); +`endif + + +module t #( + parameter int WIDTH /* verilator public_flat_rd */ = 32 + ) (/*AUTOARG*/ + // Inputs + clk + ); + +`ifdef VERILATOR +`systemc_header +extern "C" int mon_check(); +`verilog +`endif + + input clk; + + localparam int DEPTH /* verilator public_flat_rd */ = 16; + localparam longint PARAM_LONG /* verilator public_flat_rd */ = 64'hFEDCBA9876543210; + localparam string PARAM_STR /* verilator public_flat_rd */ = "'some string value'"; + + reg [WIDTH-1:0] mem0 [DEPTH:1] /*verilator public_flat_rw @(posedge clk) */; + integer i, status; + + // Test loop + initial begin +`ifdef VERILATOR + status = $c32("mon_check()"); +`endif +`ifdef IVERILOG + status = $mon_check(); +`endif +`ifndef USE_VPI_NOT_DPI + status = mon_check(); +`endif + + if (status!=0) begin + $write("%%Error: t_vpi_param.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule : t diff --git a/test_regress/t/t_vpi_time_cb.cpp b/test_regress/t/t_vpi_time_cb.cpp index 12a5e774b..110f0a160 100644 --- a/test_regress/t/t_vpi_time_cb.cpp +++ b/test_regress/t/t_vpi_time_cb.cpp @@ -31,7 +31,6 @@ #include #include #include -using namespace std; #include "TestSimulator.h" #include "TestVpi.h" @@ -61,15 +60,15 @@ unsigned int callback_count_start_of_sim = 0; // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } #define CHECK_RESULT_HEX(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << __FILE__ << ":" << __LINE__ << hex << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << hex \ + << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } @@ -218,7 +217,7 @@ int main(int argc, char** argv, char** env) { void* lib = dlopen(filenamep, RTLD_LAZY); void* bootstrap = dlsym(lib, "vpi_compat_bootstrap"); if (!bootstrap) { - string msg = string("%Error: Could not dlopen ") + filenamep; + std::string msg = std::string("%Error: Could not dlopen ") + filenamep; vl_fatal(__FILE__, __LINE__, "main", msg.c_str()); } ((void (*)(void))bootstrap)(); diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index d268261ae..0b067dab6 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -30,7 +30,6 @@ #include #include #include -using namespace std; #include "TestSimulator.h" #include "TestVpi.h" @@ -65,15 +64,15 @@ unsigned int callback_count_strs_max = 500; // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } #define CHECK_RESULT_HEX(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << FILENM << ":" << __LINE__ << hex << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \ + << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } diff --git a/test_regress/t/t_vpi_zero_time_cb.cpp b/test_regress/t/t_vpi_zero_time_cb.cpp index 94f7bf46c..a553bec45 100644 --- a/test_regress/t/t_vpi_zero_time_cb.cpp +++ b/test_regress/t/t_vpi_zero_time_cb.cpp @@ -31,7 +31,6 @@ #include #include #include -using namespace std; #include "TestSimulator.h" #include "TestVpi.h" @@ -60,15 +59,15 @@ unsigned int callback_count_start_of_sim = 0; // Use cout to avoid issues with %d/%lx etc #define CHECK_RESULT(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } #define CHECK_RESULT_HEX(got, exp) \ if ((got) != (exp)) { \ - cout << dec << "%Error: " << __FILE__ << ":" << __LINE__ << hex << ": GOT = " << (got) \ - << " EXP = " << (exp) << endl; \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << hex \ + << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } @@ -168,7 +167,7 @@ int main(int argc, char** argv, char** env) { void* lib = dlopen(filenamep, RTLD_LAZY); void* bootstrap = dlsym(lib, "vpi_compat_bootstrap"); if (!bootstrap) { - string msg = string("%Error: Could not dlopen ") + filenamep; + std::string msg = std::string("%Error: Could not dlopen ") + filenamep; vl_fatal(__FILE__, __LINE__, "main", msg.c_str()); } ((void (*)(void))bootstrap)(); diff --git a/test_regress/t/t_wait.out b/test_regress/t/t_wait.out new file mode 100644 index 000000000..bc88a4f78 --- /dev/null +++ b/test_regress/t/t_wait.out @@ -0,0 +1,13 @@ +%Error-UNSUPPORTED: t/t_wait.v:12:7: Unsupported: wait statements + 12 | wait (value == 1); + | ^~~~ +%Error-UNSUPPORTED: t/t_wait.v:14:7: Unsupported: wait statements + 14 | wait (0); + | ^~~~ +%Error-UNSUPPORTED: t/t_wait.v:17:7: Unsupported: wait statements + 17 | wait (value == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_wait.v:20:7: Unsupported: wait statements + 20 | wait (value == 3) if (value != 3) $stop; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_wait.pl b/test_regress/t/t_wait.pl new file mode 100755 index 000000000..89ffd046b --- /dev/null +++ b/test_regress/t/t_wait.pl @@ -0,0 +1,20 @@ +#!/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(linter => 1); + +lint( + verilator_flags2 => ['--lint-only'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_wait.v b/test_regress/t/t_wait.v new file mode 100644 index 000000000..ce59deadc --- /dev/null +++ b/test_regress/t/t_wait.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + int value; + + initial begin + wait (value == 1); + if (value != 1) $stop; + wait (0); + if (value != 1) $stop; + // + wait (value == 2); + if (value != 2) $stop; + // + wait (value == 3) if (value != 3) $stop; + if (value != 3) $stop; + end + + initial begin + #10; + value = 1; + #10; + value = 2; + #10; + value = 3; + #10; + value = 4; + #10; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_with_bbox.pl b/test_regress/t/t_with_bbox.pl new file mode 100755 index 000000000..cc3646920 --- /dev/null +++ b/test_regress/t/t_with_bbox.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(vlt => 1); + +top_filename("t/t_with_unsup.v"); + +lint( + verilator_flags => ["--bbox-unsup"], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_with_unsup.out b/test_regress/t/t_with_unsup.out new file mode 100644 index 000000000..62705e280 --- /dev/null +++ b/test_regress/t/t_with_unsup.out @@ -0,0 +1,31 @@ +%Error-UNSUPPORTED: t/t_with_unsup.v:19:31: Unsupported: with statements + 19 | found = aliases.find(i) with (i == to_find); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:21:23: Unsupported: with statements + 21 | aliases.find(i) with (i == to_find); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:24:28: Unsupported: with statements + 24 | found = aliases.find with (item == i); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:25:20: Unsupported: with statements + 25 | aliases.find with (item == i); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:29:30: Unsupported: with statements + 29 | found = aliases.unique with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:30:32: Unsupported: with statements + 30 | found = aliases.unique() with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:31:33: Unsupported: with statements + 31 | found = aliases.unique(i) with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:32:26: Unsupported: with statements + 32 | found = aliases.or with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:33:27: Unsupported: with statements + 33 | found = aliases.and with (id); + | ^~~~ +%Error-UNSUPPORTED: t/t_with_unsup.v:34:27: Unsupported: with statements + 34 | found = aliases.xor with (id); + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_with_unsup.pl b/test_regress/t/t_with_unsup.pl new file mode 100755 index 000000000..ce380f717 --- /dev/null +++ b/test_regress/t/t_with_unsup.pl @@ -0,0 +1,19 @@ +#!/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); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_with_unsup.v b/test_regress/t/t_with_unsup.v new file mode 100644 index 000000000..1c9c1a2d7 --- /dev/null +++ b/test_regress/t/t_with_unsup.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module for SystemVerilog 'alias' +// +// Simple bi-directional alias test. +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + int tofind; + int aliases[$]; + int found[$]; + int id; + int i; + aliases = '{ 1, 4, 6, 8}; + tofind = 6; + found = aliases.find(i) with (i == to_find); + // And as function + aliases.find(i) with (i == to_find); + + // No parenthesis + found = aliases.find with (item == i); + aliases.find with (item == i); + + // Unique (array method) + id = 4; + found = aliases.unique with (id); + found = aliases.unique() with (id); + found = aliases.unique(i) with (id); + found = aliases.or with (id); + found = aliases.and with (id); + found = aliases.xor with (id); + end + +endmodule diff --git a/test_regress/t/t_x_assign.cpp b/test_regress/t/t_x_assign.cpp new file mode 100644 index 000000000..760b6f7ec --- /dev/null +++ b/test_regress/t/t_x_assign.cpp @@ -0,0 +1,53 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Geza Lore. 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 + +#include "verilated.h" +#include VM_PREFIX_INCLUDE + +// clang-format off +#if defined(T_X_ASSIGN_0) +# define EXPECTED 0 +#elif defined(T_X_ASSIGN_1) +# define EXPECTED 1 +#elif defined(T_X_ASSIGN_UNIQUE_0) +# define EXPECTED 0 +#elif defined(T_X_ASSIGN_UNIQUE_1) +# define EXPECTED 1 +#else +# error "Don't know expectd output for test" #TEST +#endif +// clang-format on + +int main(int argc, const char** argv) { + VM_PREFIX* top = new VM_PREFIX(); + +#if defined(T_X_ASSIGN_UNIQUE_0) + Verilated::randReset(0); +#elif defined(T_X_ASSIGN_UNIQUE_1) + Verilated::randReset(1); +#endif + + // Evaluate one clock posedge + top->clk = 0; + top->eval(); + top->clk = 1; + top->eval(); + + if (top->o != EXPECTED) { + vl_fatal(__FILE__, __LINE__, "TOP.t", "incorrect module output"); + exit(1); + } + + std::cout << "*-* All Finished *-*" << std::endl; + return 0; +} diff --git a/test_regress/t/t_x_assign.v b/test_regress/t/t_x_assign.v new file mode 100644 index 000000000..dd40e363f --- /dev/null +++ b/test_regress/t/t_x_assign.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. 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 + +module t_x_assign( + input wire clk, + output reg o +); + always @(posedge clk) begin + if (1'bx) o <= 1'd1; else o <= 1'd0; + end +endmodule diff --git a/test_regress/t/t_x_assign_0.pl b/test_regress/t/t_x_assign_0.pl new file mode 100755 index 000000000..6f9e1347f --- /dev/null +++ b/test_regress/t/t_x_assign_0.pl @@ -0,0 +1,26 @@ +#!/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 Geza Lore. 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_x_assign.v"); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--x-assign 0 --exe $Self->{t_dir}/t_x_assign.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_x_assign_1.pl b/test_regress/t/t_x_assign_1.pl new file mode 100755 index 000000000..2a6ffe0a8 --- /dev/null +++ b/test_regress/t/t_x_assign_1.pl @@ -0,0 +1,26 @@ +#!/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 Geza Lore. 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_x_assign.v"); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--x-assign 1 --exe $Self->{t_dir}/t_x_assign.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_x_assign_unique_0.pl b/test_regress/t/t_x_assign_unique_0.pl new file mode 100755 index 000000000..bef9e2495 --- /dev/null +++ b/test_regress/t/t_x_assign_unique_0.pl @@ -0,0 +1,26 @@ +#!/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 Geza Lore. 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_x_assign.v"); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--x-assign unique --exe $Self->{t_dir}/t_x_assign.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_x_assign_unique_1.pl b/test_regress/t/t_x_assign_unique_1.pl new file mode 100755 index 000000000..bef9e2495 --- /dev/null +++ b/test_regress/t/t_x_assign_unique_1.pl @@ -0,0 +1,26 @@ +#!/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 Geza Lore. 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_x_assign.v"); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--x-assign unique --exe $Self->{t_dir}/t_x_assign.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_xml_tag.out b/test_regress/t/t_xml_tag.out index 30f20a7ca..7c50f6d85 100644 --- a/test_regress/t/t_xml_tag.out +++ b/test_regress/t/t_xml_tag.out @@ -55,27 +55,27 @@ - + + + + - - - - + + + + - - - - + + - - + + -