Compare commits

...
34 Commits
Author SHA1 Message Date
Wilson Snyder 58fc922737 Test fix
git-svn-id: file://localhost/svn/verilator/trunk/verilator@825 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:56:54 +00:00
Wilson Snyder 3b5c791332 Test fix
git-svn-id: file://localhost/svn/verilator/trunk/verilator@824 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:54:36 +00:00
Wilson Snyder 6e16bc1b7b Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@823 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:50:44 +00:00
Wilson Snyder 1aba0f6379 Show error code on non-generic errors; add TASKNSVAR
git-svn-id: file://localhost/svn/verilator/trunk/verilator@822 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 13:45:50 +00:00
Wilson Snyder 11cfa3c072 Suppress unused warnings using attribute
git-svn-id: file://localhost/svn/verilator/trunk/verilator@821 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-18 12:59:30 +00:00
Wilson Snyder 59141b1678 Fix --skip-identical
git-svn-id: file://localhost/svn/verilator/trunk/verilator@820 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-12 14:01:06 +00:00
Wilson Snyder 2083c071ce Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@817 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 15:42:32 +00:00
Wilson Snyder 3ad5872d30 Add verilator no_inline_task
git-svn-id: file://localhost/svn/verilator/trunk/verilator@816 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 15:41:42 +00:00
Wilson Snyder ea6bb21cdc Fix V3Subst mis-optimizing concats in t_case_write
git-svn-id: file://localhost/svn/verilator/trunk/verilator@815 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 15:34:50 +00:00
Wilson Snyder 3d4fe0364a No functional change; have V3Subst use a sub-structure.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@814 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-11 14:13:37 +00:00
Wilson Snyder 710d7c0ee5 Fix link error when using --exe with --trace.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@813 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-09 13:38:15 +00:00
Wilson Snyder 1c8fd37745 Fix some Coverity Prevent warnings
git-svn-id: file://localhost/svn/verilator/trunk/verilator@812 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-06 16:08:46 +00:00
Wilson Snyder 956c854662 Add t_case_write test
git-svn-id: file://localhost/svn/verilator/trunk/verilator@811 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-05 17:54:52 +00:00
Wilson Snyder 318a6e348c Support wide public task outputs.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@810 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-05 14:53:17 +00:00
Wilson Snyder e471a34323 Add maybePointedTo to v3Broken for better and faster checks
git-svn-id: file://localhost/svn/verilator/trunk/verilator@809 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-05 00:45:39 +00:00
Wilson Snyder 95c5b85e88 Unlink .vpp files without --debug
git-svn-id: file://localhost/svn/verilator/trunk/verilator@808 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-04 18:46:42 +00:00
Wilson Snyder a46a556a64 Don't coredump without --debug
git-svn-id: file://localhost/svn/verilator/trunk/verilator@807 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-04 15:46:13 +00:00
Wilson Snyder fa3e03e071 version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@804 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-04 12:57:29 +00:00
Wilson Snyder 74d7c55f1b Fix dotted variables in always sensitivity lists.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@803 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-03 13:02:21 +00:00
Wilson Snyder 79e02858cb Add --debug-check flag
git-svn-id: file://localhost/svn/verilator/trunk/verilator@802 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-02 17:09:56 +00:00
Wilson Snyder 7738b202ac Remove --bin from perl shell, use argv[0] instead
git-svn-id: file://localhost/svn/verilator/trunk/verilator@801 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-30 00:27:05 +00:00
Wilson Snyder b4d4917c6c Fix coredump in XREFs under FUNCREF's
git-svn-id: file://localhost/svn/verilator/trunk/verilator@800 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-30 00:08:09 +00:00
Wilson Snyder 5c93520b27 Associative same variable elimination
git-svn-id: file://localhost/svn/verilator/trunk/verilator@799 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-28 14:37:28 +00:00
Wilson Snyder 94f0809d33 Add more boolean identity fixes
git-svn-id: file://localhost/svn/verilator/trunk/verilator@798 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-27 18:00:53 +00:00
Wilson Snyder ca4e3c1737 Eliminate assigned only variables
git-svn-id: file://localhost/svn/verilator/trunk/verilator@797 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-26 17:05:08 +00:00
Wilson Snyder ba7b4f261a Redo V3Life to also do constant propagation
git-svn-id: file://localhost/svn/verilator/trunk/verilator@796 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-26 15:05:35 +00:00
Wilson Snyder 4f42c25c7c Fix inout task arguments
git-svn-id: file://localhost/svn/verilator/trunk/verilator@795 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-25 20:40:52 +00:00
Wilson Snyder 621ef70c31 Allow overriding PERL, YACC, LEX versions.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@794 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-25 15:58:17 +00:00
Wilson Snyder e3f17e7853 Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@791 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-20 13:25:03 +00:00
Wilson Snyder 73c897ac69 Fix printf ULL warnings with a cast.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@790 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-20 13:24:18 +00:00
Wilson Snyder a4db880809 Use vluint8/16/64 in source code
git-svn-id: file://localhost/svn/verilator/trunk/verilator@789 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-19 15:27:15 +00:00
Wilson Snyder f9697463cc Have preprocessor strip all DOS returns
git-svn-id: file://localhost/svn/verilator/trunk/verilator@788 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-13 14:38:48 +00:00
Wilson Snyder f283076570 Rename {newline} in lex; no functional change
git-svn-id: file://localhost/svn/verilator/trunk/verilator@787 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-13 13:18:24 +00:00
Wilson Snyder e15228498d Define VL_PRINTF by default, and remove old coverageRequest
git-svn-id: file://localhost/svn/verilator/trunk/verilator@786 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-12 00:55:27 +00:00
86 changed files with 9763 additions and 601 deletions
+49 -2
View File
@@ -3,7 +3,54 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.602 09/11/2006
* Verilator 3.622 10/17/2006 Stable
**** Fix --skip-identical without --debug, broken in 3.621. [Andy Meier]
* Verilator 3.621 10/11/2006 Beta
** Add /*verilator no_inline_task*/ to prevent over-expansion. [Eugene Weber]
*** Public functions now allow > 64 bit arguments.
**** Remove .vpp intermediate files when not under --debug.
**** Fix link error when using --exe with --trace. [Eugene Weber]
**** Fix mis-optimization of wide concats with constants.
**** Fix core dump on printing error when not under --debug. [Allan Cochrane]
* Verilator 3.620 10/04/2006 Stable
*** Support simple inout task ports. [Eugene Weber]
*** Allow overriding Perl, Flex and Bison versions. [by Robert Farrell]
*** Optimize variables set to constants within basic blocks for ~3%.
**** Default make no longer makes the docs; if you edit the documentation.
sources, run "make info" to get them.
**** Optimize additional boolean identities (a|a = a, etc.)
**** Fix coredump when dotted cross-ref inside task call. [Eugene Weber]
**** Fix dotted variables in always sensitivity lists. [Allan Cochrane]
* Verilator 3.610 09/20/2006 Stable
*** Verilator now works under DJGPP (Pentium GCC). [John Stroebel]
**** Add default define for VL_PRINTF. [John Stroebel]
**** Removed coverage request variable; see Coverage limitations in docs.
**** Fix DOS carrage returns in multiline defines. [Ralf Karge]
**** Fix printf format warnings on 64-bit linux.
* Verilator 3.602 09/11/2006 Stable
**** Fix function references under top inlined module. [David Hewson]
@@ -397,7 +444,7 @@ indicates the contributor was also the author of the fix; Thanks!
**** Added NC Verilog as alternative to VCS for reference tests.
**** Support implicit wire declarations on input-only signals.
(Dangerous, as leads to wires without drivers, but allowed by spec.)
(Dangerous, as leads to wires without drivers, but allowed by spec.)
**** Fixed compile warnings on Suse 9.1
+3 -3
View File
@@ -91,7 +91,7 @@ SUBDIRS = src test_verilated test_c test_sc test_sp test_regress test_vcs
INFOS = README verilator.txt verilator.html verilator.1 verilator.pdf
# Files that can be generated, but should be up to date for a distribution.
DISTDEP = $(INFOS) Makefile
DISTDEP = info Makefile
# Files to distribute.
DISTBIN = $(wildcard bin/verilator-*)
@@ -126,7 +126,7 @@ INST_PROJ_BIN_FILES = \
DISTFILES := $(DISTFILES_INC)
all: all_nomsg msg_test
all_nomsg: verilator_exe info
all_nomsg: verilator_exe
.PHONY:verilator_exe
verilator_exe verilator_bin verilator_bin_dbg:
@@ -218,7 +218,7 @@ installman:
$(INSTALL_PROGRAM) $$p $(mandir)/man1/$$p; \
done
install: all_nomsg info installdirs installbin installman install-msg
install: all_nomsg installdirs installbin installman install-msg
install-here: installman ftp
+1
View File
@@ -97,6 +97,7 @@ Performance:
Track recirculation and convert into clock-enables
Clock enables should become new clocking domains for speed
If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
//**********************************************************************
//* Detailed notes on 'todo' features
+175 -64
View File
@@ -113,7 +113,6 @@ if ($Opt_Sp eq 'sp' || $Opt_Trace) {
# Determine runtime flags
my $vcmd =(($opt_gdb?"$opt_gdb ":"")
.verilator_bin()
." --bin ".verilator_bin() # So we get binary name into .d file
." ".join(' ',@Opt_Verilator_Sw)
);
@@ -169,7 +168,7 @@ sub run {
warn "%Error: export VERILATOR_ROOT=$ENV{VERILATOR_ROOT}\n";
warn "%Error: $command\n";
}
die "%Error: Command Failed $command, $status, stopped";
die "%Error: Command Failed $command\n";
}
}
@@ -234,6 +233,13 @@ linking with make rules you write yourself.
Enable all assertions, includes enabling the --psl flag. (If psl is not
desired, but other assertions are, use --assert --nopsl.)
=item --bin I<filename>
Rarely needed. Override the default filename for Verilator itself. When a
dependancy (.d) file is created, this filename will become a source
dependency, such that a change in this binary will have make rebuild the
output files.
=item --cc
Specifies C++ without SystemC output mode; see also --sc and --sp.
@@ -248,9 +254,9 @@ 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 superset of normal Verilog Line
Coverage. At each such branch a C++ macro is called, which SystemPerl uses
to increment an array. At the end of a test, logs/coverage.pl is written
with the data from the array.
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
corresponding to each counter are written into logs/coverage.pl.
After running multiple tests, the vcoverage utility (from the SystemPerl
package) is executed. Vcoverage reads the logs/coverage.pl file(s), and
@@ -261,6 +267,10 @@ them, as it is assumed $stop branches contain an error check that should
not occur. A /*verilator coverage_block_off*/ comment will perform a
similar function on any code in that block or below.
Note Verilator may over-count combinatorial (non-clocked) blocks when those
blocks receive signals which have had the UNOPTFLAT warning disabled; for
most accurate results do not disable this warning when using coverage.
For an example, after running 'make test' in the Verilator distribution,
see the test_sp/logs/coverage_source directory. Grep for lines starting
with '%' to see what lines Verilator believes need more coverage.
@@ -279,8 +289,13 @@ the comment "DefaultClock":
=item --debug
Select the debug built image of Verilator (if available), and enable
debugging messages and intermediate form dump files.
Select the debug built image of Verilator (if available), and enable more
internal assertions, debugging messages, and intermediate form dump files.
=item --debug-check
Rarely needed. Enable internal debugging assertion checks, without
changing debug verbosity. Enabled automatically when --debug specified.
=item -E
@@ -299,10 +314,10 @@ Displays this message and program version and exits.
=item --inhibit-sim
Create a "inhibitSim(bool)" function to enable and disable evaluation.
This allows a upper level testbench to disable modules that are not
important in a given simulation, without needing to recompile or change the
SystemC modules instantiated.
Rarely needed. Create a "inhibitSim(bool)" function to enable and disable
evaluation. This allows a upper level testbench to disable modules that
are not important in a given simulation, without needing to recompile or
change the SystemC modules instantiated.
=item --inline-mult I<value>
@@ -335,8 +350,8 @@ the same as --prefix.
=item --no-skip-identical
Disables skipping execution of Verilator if all source files are identical,
and all output files exist with newer dates.
Rarely needed. Disables skipping execution of Verilator if all source
files are identical, and all output files exist with newer dates.
=item -O0
@@ -349,11 +364,11 @@ cost of compile time. This currently sets --inline-mult -1.
=item -OI<optimization-letter>
Enables or disables a specific optimizations, with the optimization
selected based on the letter passed. A lowercase letter disables an
optimization, an upper case letter enables it. This is intended for
debugging use only; see the source code for version-dependent mappings of
optimizations to -O letters.
Rarely needed. Enables or disables a specific optimizations, with the
optimization selected based on the letter passed. A lowercase letter
disables an optimization, an upper case letter enables it. This is
intended for debugging use only; see the source code for version-dependent
mappings of optimizations to -O letters.
=item --output-split I<bytes>
@@ -392,17 +407,20 @@ compatibility.
=item --psl
Enable PSL parsing. Without this switch, psl meta-comments are ignored.
Enable PSL parsing. Without this switch, PSL meta-comments are ignored.
See the --assert flag to enable all assertions, and --coverage-user to
enable functional coverage.
=item --public
This is only for debug, and may result in mis-simulation of generated
clocks.
Declares all signals and modules public. This will turn off signal
optimizations as if all signals had a /*verilator public*/ comments. This
will also turn off inlining as if all modules had a /*verilator
public_module*/, unless the module specifically enabled it with /*verilator
inline_module*/.
optimizations as if all signals had a /*verilator public*/ comments and
inlining. This will also turn off inlining as if all modules had a
/*verilator public_module*/, unless the module specifically enabled it with
/*verilator inline_module*/.
=item --sc
@@ -424,10 +442,10 @@ on during model execution.
=item --underline-zero
Signals starting with a underline should be initialized to zero, as was
done in Verilator 2. Default is for all signals including those with
underlines being randomized. This option may be depreciated in future
versions.
Rarely needed. Signals starting with a underline should be initialized to
zero, as was done in Verilator 2. Default is for all signals including
those with underlines being randomized. This option may be depreciated in
future versions.
=item -Werror-I<message>
@@ -548,7 +566,7 @@ And we get as output
Hello World
- our.v:2: Verilog $finish
Really, you're better off using a Makefile to do all this for you. Then,
Really, you're better off writing a Makefile to do all this for you. Then,
when your source changes it will automatically run all of these steps. See
the test_c directory in the distribution for an example.
@@ -591,7 +609,7 @@ Then we convert the SystemPerl output to SystemC.
$SYSTEMPERL/sp_preproc --preproc *.sp
(You can also skip the above sp_preproc by getting pure SystemC from
verilator by replacing the verilator --sp flag in the previous step with
Verilator by replacing the verilator --sp flag in the previous step with
-sc.)
We then can compile it
@@ -702,7 +720,7 @@ In certain optimization modes, it also creates:
It also creates internal files that can be mostly ignored:
{each_verilog_module}.vpp // Post-processed verilog source code
{each_verilog_module}.vpp // Post-processed verilog (--debug)
{prefix}.flags_vbin // Verilator dependencies
{prefix}.flags_vpp // Pre-processor dependencies
{prefix}{misc}.d // Make dependencies (-MMD)
@@ -920,7 +938,7 @@ call C++ functions from your Verilog code.
String arguments will be put directly into the output C++ code. Expression
arguments will have the code to evaluate the expression inserted. Thus to
call a C++ function, $c("func(",a,")") will result in 'func(a)' in the
output C++ code. For input arguments, rather then hardcoding variable
output C++ code. For input arguments, rather then hard-coding variable
names in the string $c("func(a)"), instead pass the variable as an
expression $c("func(",a,")"). This will allow the call to work inside
Verilog functions where the variable is flattened out, and also enable
@@ -936,9 +954,9 @@ each different output width.
=item $display, $write, $fdisplay, $fwrite
$display format arguments may use C fprintf sizes after the % escape. Per
the Verilog standard, %x prints a number with the natural width, %0x prints
a number with minimum width, however %5x prints 5 digits per the C standard
Format arguments may use C fprintf sizes after the % escape. Per the
Verilog standard, %x prints a number with the natural width, %0x prints a
number with minimum width, however %5x prints 5 digits per the C standard
(it's unspecified in Verilog).
=item $fopen, $fclose, $fdisplay, $fwrite
@@ -1038,6 +1056,14 @@ Disable the specified warning message for any warnings following the comment.
Re-enable the specified warning message for any warnings following the comment.
=item /*verilator no_inline_task*/
Used in a function or task variable definition section to specify the
function or task should not be inlined into where it is used. This may
reduce the size of the final executable when a task is used a very large
number of times. For this flag to work, the task and tasks below it must
be pure; they cannot reference any variables outside the task itself.
=item /*verilator sc_clock*/
Used after a input declaration to indicate the signal should be declared in
@@ -1057,7 +1083,7 @@ Re-enable waveform tracing for all future signals that are declared.
Used after a input, output, register, or wire declaration to indicate the
signal should be declared so that C code may read or write the value
of the signal. Set for all signals when using the --public switch.
of the signal.
=item /*verilator public*/ (task/function)
@@ -1070,9 +1096,9 @@ function. Any output arguments will become C++ reference arguments. Any
local registers/integers will become function automatic variables on the
stack.
Wide variables over 64 bits cannot be I/O to the module, to avoid exposing
complexities; generally the cleanest technique is to pass a word number to
the function, and do appropriate bit selection.
Wide variables over 64 bits cannot be function returns, to avoid exposing
complexities. However, wide variables can be input/outputs; they will be
passed as references to an array of 32 bit numbers.
This feature is still somewhat experimental. Generally, only the values of
stored state (flops) should be written, as the model will NOT notice
@@ -1248,7 +1274,12 @@ will give a width warning and wrap around the power-of-2 size. For
non-power-of-2 sizes, it will return a unspecified constant of the
appropriate width.
=head1 ERRORS
=item $display, $write, $fdisplay, $fwrite
$display and friends must have a constant format string as the first
argument (as with C's printf), you cannot simply list variables standalone.
=head1 ERRORS AND WARNINGS
Warnings may be disabled in two ways. First, when the warning is
printed it will include a warning code. Simply surround the offending
@@ -1258,13 +1289,13 @@ line with a warn_off/warn_on pair:
if (`DEF_THAT_IS_EQ_ZERO <= 3) $stop;
// verilator lint_on UNSIGNED
They may also be globally disabled by invoking Verilator with the
C<-Wno-I<warning>> switch. This should be avoided, as it removes
all checking across the designs, and prevents other users from
compiling your code without knowing the magic set of disables needed
to successfully compile your design.
Warnings may also be globally disabled by invoking Verilator with the
C<-Wno-I<warning>> switch. This should be avoided, as it removes all
checking across the designs, and prevents other users from compiling your
code without knowing the magic set of disables needed to successfully
compile your design.
Warnings:
List of all warnings:
=over 4
@@ -1321,12 +1352,41 @@ signal before it is implicitly declared by a cell, and can lead to dangling
nets. A better option is the /*AUTOWIRE*/ feature of Verilog-Mode for
Emacs, available from L<http://www.veripool.com/>
=item IMPURE
Warns that a task or function that has been marked with /*verilator
no_inline_task*/ references variables that are not local to the task.
Verilator cannot schedule these variables correctly.
=item MULTIDRIVEN
Warns that the specified signal comes from multiple always blocks. This is
often unsupported by synthesis tools, and is considered bad style. It will
also cause longer runtimes due to reduced optimizations.
=item TASKNSVAR
Error when a call to a task or function has a output from that task tied to
a non-simple signal. Instead connect the task output to a temporary signal
of the appropriate width, and use that signal to set the appropriate
expression as the next statement. For example:
task foo; output sig; ... endtask
always @* begin
foo(bus_we_select_from[2]); // Will get TASKNSVAR error
end
Change this to:
reg foo_temp_out;
always @* begin
foo(foo_temp_out);
bus_we_select_from[2] = foo_temp_out;
end
Verilator doesn't do this conversion for you, as some more complicated
cases would result in simulator mismatches.
=item UNDRIVEN
Warns that the specified signal is never sourced.
@@ -1352,11 +1412,11 @@ may be only one particular usage of a multiply instantiated block. The
construct should be cleaned up to improve runtime; two times better
performance may be possible by fixing these warnings.
Unlike UNOPT this occurs after netlist flattening, and indicates a more
basic problem, as the less obvious case described under UNOPT does not
apply.
Unlike the UNOPT warning, this occurs after netlist flattening, and
indicates a more basic problem, as the less obvious case described under
UNOPT does not apply.
Often this is caused by logic that isn't truly circular as viewed by
Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
synthesis which analyzes interconnection per-bit, but is circular to
simulation which analyzes per-bus:
@@ -1364,12 +1424,25 @@ simulation which analyzes per-bus:
This statement needs to be evaluated multiple times, as a change in
"shift_in" requires "x" to be computed 3 times before it becomes stable.
For significantly better performance, split this into 2 separate signals:
For significantly better performance, split this into 2 separate signals,
and then if necessary generate the original signal:
wire [2:1] x_21 = x[1:0];
wire [0:0] x_0 = shift_in;
wire [2:0] x = {x_21, x_0};
This warning may also be due to clock enables. To fix these, use the
This logic needs to be evaluated only once. These sort of changes may also
speed up your traditional event driven simulator, as it will result in
fewer events per cycle.
The most complicated UNOPTFLAT path we've seen was due to low bits of a bus
being generated from an always statement that consumed high bits of the
same bus processed by another series of always blocks. The fix is the
same; split it into two separate signals, then create the bus from the two
separate signals.
The UNOPTFLAT warning may also be due to clock enables, identified from the
reported path going through a clock gating cell. To fix these, use the
clock_enable meta comment described above.
=item UNSIGNED
@@ -1427,8 +1500,8 @@ that is not yet supported in Verilator. See the Limitations chapter.
=item Verilated model didn't converge
Verilator sometimes has to evaluate combinatorial logic multiple times,
usually around code where a UNOPT warning was issued, but disabled. For
example:
usually around code where a UNOPTFLAT warning was issued, but disabled.
For example:
always @ (a) b=~a;
always @ (b) a=b
@@ -1474,18 +1547,32 @@ 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.
=item How do I generate waveforms (traces)?
=item How do I generate waveforms (traces) in C++?
See the next question for SystemC mode.
Add the --trace switch to Verilator, and make sure the SystemPerl package
is installed (SystemC itself isn't required for C++ only tracing.) In your
top level C code, call Verilated::traceEverOn(true).
is installed. SystemC itself does not need to be installed for C++ only
tracing. You do not even need to compile SystemPerl; you may simply untar
the SystemPerl kit and point the SYSTEMPERL environment variable to the
untarred directory.
Then, in SystemC mode, create a SpTraceFile object. For an example, see
the call to SpTraceFile in the test_sp/sc_main.cpp file of the
distribution.
In your top level C code, call Verilated::traceEverOn(true). Then create a
SpTraceVcdC object. For an example, see the call to SpTraceVcdC in the
test_c/sc_main.cpp file of the distribution.
Or, in C++ mode, create a SpTraceVcdCFile object, and see
test_c/sim_main.cpp.
You also need to compile SpTraceVcdC.cpp and add it to your link. This is
done for you if using the Verilator --exe flag.
=item How do I generate waveforms (traces) in SystemC?
Add the --trace switch to Verilator, and make sure the SystemPerl package
is installed.
In your top level C sc_main code, call Verilated::traceEverOn(true). Then
create a SpTraceFile object as you would create a normal SystemC trace
file. For an example, see the call to SpTraceFile in the
test_sp/sc_main.cpp file of the distribution.
=item Where is the translate_off command? (How do I ignore a construct?)
@@ -1504,6 +1591,11 @@ Call Verilated::assertOn(false) before you first call the model, then turn
it back on after reset. It defaults to true. When false, all assertions
controlled by --assert are disabled.
=item Why do I get "undefined reference to `sc_time_stamp()'"?
In C++ (non SystemC) code you need to define this function so that the
simulator knows the current time. See the "CONNECTING TO C++" examples.
=item Is the PLI supported?
No.
@@ -1563,6 +1655,25 @@ In this example, clk is a bool you can read or set as any other variable.
The value of normal signals may be set, though clocks shouldn't be changed
by your code or you'll get strange results.
=item Should a module be in Verilog or SystemC?
Sometimes there is a block that just interconnects cells, and have a choice
as to if you write it in Verilog or SystemC. Everything else being equal,
best performance is when Verilator sees all of the design. So, look at the
hierarchy of your design, labeling cells as to if they are SystemC or
Verilog. Then:
A module with only SystemC cells below must be SystemC.
A module with a mix of Verilog and SystemC cells below must be SystemC. (As
Verilator cannot connect to lower-level SystemC cells.)
A module with only Verilog cells below can be either, but for best
performance should be Verilog. (The exception is if you have a design that
is instantiated many times; in this case Verilating one of the lower
modules and instantiating that Verilated cells multiple times into a
SystemC module *may* be faster.)
=back
=head1 BUGS
@@ -1587,7 +1698,7 @@ outputs. Now, the following should fail:
cd test_regress
t/t_BUG.pl
Finally, Mail the bug report to C<[email protected]>
Finally, Mail the bug report to C<[email protected]>.
=head1 HISTORY
@@ -1614,8 +1725,8 @@ scratch in C++. This added many optimizations, yielding about a 2-5x
performance gain.
Currently, various language features and performance enhancements are added
as the need arises. Verilator is now about 2x faster then in 2002, and
as fast as most popular commercial simulators.
as the need arises. Verilator is now about 2x faster then in 2002, and is
faster then many popular commercial simulators.
=head1 CONTRIBUTORS
+1 -1
View File
@@ -192,5 +192,5 @@ C<verilator>
######################################################################
### Local Variables:
### compile-command: "$V4/bin/verilator_difftree ~/SandBox/workwsnyder/verilator/test_c/obj_dir/V*_03_*.tree $V4/test_c/obj_dir/V*_03_*.tree"
### compile-command: "$V4/bin/verilator_difftree $V4/test_c/obj_dir/V*_03_*.tree $V4N/test_c/obj_dir/V*_03_*.tree"
### End:
+2
View File
@@ -16,6 +16,8 @@ AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_PATH_PROG(PERL,perl)
AC_PATH_PROG(YACC,bison)
AC_PATH_PROG(LEX,flex)
dnl Checks for libraries.
+44 -5
View File
@@ -40,11 +40,11 @@ using namespace std;
//=========================================================================
// Basic types
typedef uint8_t CData; ///< Verilated data, 1-8 bits
typedef uint16_t SData; ///< Verilated data, 9-16 bits
typedef uint32_t IData; ///< Verilated data, 17-32 bits
typedef vluint64_t QData; ///< Verilated data, 33-64 bits
typedef uint32_t WData; ///< Verilated data, >64 bits, as an array
typedef vluint8_t CData; ///< Verilated data, 1-8 bits
typedef vluint16_t SData; ///< Verilated data, 9-16 bits
typedef vluint32_t IData; ///< Verilated data, 17-32 bits
typedef vluint64_t QData; ///< Verilated data, 33-64 bits
typedef vluint32_t WData; ///< Verilated data, >64 bits, as an array
typedef const WData* WDataInP; ///< Array input to a function
typedef WData* WDataOutP; ///< Array output from a function
@@ -115,6 +115,13 @@ public:
#endif
//=========================================================================
// Functions overridable by user defines
#ifndef VL_PRINTF
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired
#endif
//===========================================================================
/// Verilator global static information class
@@ -1321,6 +1328,38 @@ static inline WDataOutP VL_CONST_W_16X(int obits, WDataOutP o,
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
_END(obits,16); }
static inline WDataOutP VL_CONST_W_17X(int obits, WDataOutP o,
I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16;
_END(obits,17); }
static inline WDataOutP VL_CONST_W_18X(int obits, WDataOutP o,
I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16; o[17]=d17;
_END(obits,18); }
static inline WDataOutP VL_CONST_W_19X(int obits, WDataOutP o,
I d18,I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16; o[17]=d17; o[18]=d18;
_END(obits,19); }
static inline WDataOutP VL_CONST_W_20X(int obits, WDataOutP o,
I d19,I d18,I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
I d7,I d6,I d5,I d4,I d3,I d2,I d1,I d0) {
o[0]=d0; o[1]=d1; o[2]=d2; o[3]=d3; o[4]=d4; o[5]=d5; o[6]=d6; o[7]=d7;
o[8]=d8; o[9]=d9; o[10]=d10; o[11]=d11; o[12]=d12; o[13]=d13; o[14]=d14; o[15]=d15;
o[16]=d16; o[17]=d17; o[18]=d18; o[19]=d19;
_END(obits,20); }
static inline WDataOutP VL_CONST_W_24X(int obits, WDataOutP o,
I d23,I d22,I d21,I d20,I d19,I d18,I d17,I d16,
I d15,I d14,I d13,I d12,I d11,I d10,I d9,I d8,
+22 -12
View File
@@ -68,24 +68,34 @@
#ifdef VL_UINTS_DEFINED
#elif defined(__CYGWIN__)
# include <stdint.h>
typedef unsigned char uint8_t; ///< 8-bit basic type
typedef unsigned short int uint16_t; ///< 16-bit basic type
typedef unsigned long uint32_t; ///< 32-bit basic type
typedef unsigned long long vluint64_t; ///< 64-bit basic type
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#elif defined(_WIN32)
typedef unsigned char uint8_t; ///< 8-bit basic type
typedef unsigned short int uint16_t; ///< 16-bit basic type
typedef unsigned int uint32_t; ///< 32-bit basic type
typedef unsigned __int64 vluint64_t; ///< 64-bit basic type
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
typedef unsigned int vluint32_t; ///< 32-bit unsigned type
typedef __int64 vlsint64_t; ///< 64-bit signed type
#else // Linux or compliant Unix flavors
# include <stdint.h>
typedef unsigned long long vluint64_t; ///< 64-bit basic type
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
#else // Linux or compliant Unix flavors, -m64
# include <stdint.h> // Linux and most flavors
# include <inttypes.h> // Solaris
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit signed type
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#endif
//=========================================================================
+3
View File
@@ -85,3 +85,6 @@ clean mostlyclean distclean maintainer-clean::
-rm -f *__gen*
-rm -f *.yy.* y.output y.tab.[cho] *_test
-rm -f .objcache*
distclean maintainer-clean::
-rm -f Makefile Makefile_obj
+3 -3
View File
@@ -48,10 +48,10 @@ COPT = -ggdb -DVL_DEBUG
endif
#################
LEX = flex
LEX = @LEX@
LFLAGS = -d
YACC = bison -y
YFLAGS = -d -v
YACC = @YACC@
YFLAGS = -y -d -v
#LIBS += -ldl
#CCMALLOC = /usr/local/lib/ccmalloc-gcc.o -lccmalloc -ldl
+2
View File
@@ -298,8 +298,10 @@ private:
// OPTIMIZE: We could substitute a constant for things in the sense list, for example
// always (posedge RESET) { if (RESET).... } we know RESET is true.
// Summarize a long list of combo inputs as just "combo"
#ifndef __COVERITY__ // Else dead code on next line.
if (combo) nodep->sensesp()->addSensesp
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
#endif
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp());
}
+6 -4
View File
@@ -33,8 +33,8 @@
//======================================================================
// Statics
uint64_t AstNode::s_editCntGbl=0;
uint64_t AstNode::s_editCntLast=0;
vluint64_t AstNode::s_editCntGbl=0;
vluint64_t AstNode::s_editCntLast=0;
// To allow for fast clearing of all user pointers, we keep a "timestamp"
// along with each userp, and thus by bumping this count we can make it look
@@ -784,14 +784,16 @@ void AstNode::dumpTreeFile(const string& filename, bool append) {
dumpTree(*logsp);
}
}
}
if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
// set by other steps if it is called in the middle of other operations
if (AstNetlist* netp=this->castNetlist()) V3Broken::brokenAll(netp);
// Next dump can indicate start from here
editCountSetLast();
}
// Next dump can indicate start from here
editCountSetLast();
}
void AstNode::v3errorEnd(ostringstream& str) {
+9 -6
View File
@@ -57,6 +57,7 @@ public:
COVERAGE_BLOCK_OFF,
INLINE_MODULE,
NO_INLINE_MODULE,
NO_INLINE_TASK,
PUBLIC_MODULE,
PUBLIC_TASK
};
@@ -391,9 +392,9 @@ private:
static int s_cloneCntGbl; // Count of which userp is set
FileLine* m_fileline; // Where it was declared
uint64_t m_editCount; // When it was last edited
static uint64_t s_editCntGbl;// Global edit counter
static uint64_t s_editCntLast;// Global edit counter, last value for printing * near node #s
vluint64_t m_editCount; // When it was last edited
static vluint64_t s_editCntGbl; // Global edit counter
static vluint64_t s_editCntLast;// Global edit counter, last value for printing * near node #s
// Attributes
bool m_signed; // Node is signed
@@ -539,10 +540,10 @@ public:
void user5(int val) { user5p(AstNUser::fromInt(val)); }
static void user5ClearTree() { s_user5CntGbl++; } // Clear userp()'s across the entire tree
uint64_t editCount() const { return m_editCount; }
vluint64_t editCount() const { return m_editCount; }
void editCountInc() { m_editCount = s_editCntGbl++; }
static uint64_t editCountLast() { return s_editCntLast; }
static uint64_t editCountGbl() { return s_editCntGbl; }
static vluint64_t editCountLast() { return s_editCntLast; }
static vluint64_t editCountGbl() { return s_editCntGbl; }
static void editCountSetLast() { s_editCntLast = editCountGbl(); }
// ACCESSORS for specific types
@@ -585,6 +586,7 @@ public:
virtual int instrCount() const { return 0; }
virtual V3Hash sameHash() const { return V3Hash(V3Hash::Illegal()); } // Not a node that supports it
virtual bool same(AstNode* otherp) const { return true; }
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
virtual bool broken() const { return false; }
virtual bool emitWordForm() { return false; }
@@ -922,6 +924,7 @@ public:
virtual ~AstNodeFTask() {}
virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; } // * = Var name
virtual bool maybePointedTo() const { return true; }
// {AstFunc only} op1 = Range output variable
// op3 = Statements/Ports/Vars
void name(const string& name) { m_name = name; }
+25 -6
View File
@@ -85,7 +85,7 @@ int AstVar::widthTotalBytes() const {
}
string AstVar::verilogKwd() const {
if (isTristate()) {
if (isInout()) {
return "inout";
} else if (isInput()) {
return "input";
@@ -93,6 +93,8 @@ string AstVar::verilogKwd() const {
return "output";
} else if (isInteger()) {
return "integer";
} else if (isTristate()) {
return "tri";
} else if (varType()==AstVarType::WIRE) {
return "wire";
} else {
@@ -101,6 +103,18 @@ string AstVar::verilogKwd() const {
}
string AstVar::cType() const {
if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_WORDSIZE) {
return "uint32_t";
} else if (isScWide()) {
return "uint32_t"; // []'s added later
} else {
return "uint64_t";
}
}
string AstVar::scType() const {
if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_WORDSIZE) {
@@ -130,7 +144,7 @@ uint32_t AstVar::arrayElements() const {
bool AstScope::broken() const {
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|| !m_modp || !((AstNode*)m_modp)->brokeExists());
|| !m_modp || !m_modp->brokeExists());
}
void AstScope::cloneRelink() {
@@ -325,14 +339,18 @@ void AstVarRef::dump(ostream& str) {
void AstVar::dump(ostream& str) {
this->AstNode::dump(str);
if (isSc()) str<<" [SC]";
if (isInput()) str<<" [I]";
if (isPrimaryIO()) str<<(isInput()?" [PI]":" [PO]");
if (isOutput()) str<<" [O]";
if (isPrimaryIO()) str<<(isInout()?" [PIO]":(isInput()?" [PI]":" [PO]"));
else {
if (isInout()) str<<" [IO]";
else if (isInput()) str<<" [I]";
else if (isOutput()) str<<" [O]";
}
if (isUsedClock()) str<<" [C]";
if (isSigPublic()) str<<" [P]";
if (attrClockEn()) str<<" [aCLKEN]";
if (attrFileDescr()) str<<" [aFD]";
if (isFuncLocal() || isFuncReturn()) str<<" [FUNC]";
if (isFuncReturn()) str<<" [FUNCRTN]";
else if (isFuncLocal()) str<<" [FUNC]";
str<<" "<<varType();
}
void AstSenTree::dump(ostream& str) {
@@ -358,6 +376,7 @@ void AstNodeFTaskRef::dump(ostream& str) {
}
void AstNodeFTask::dump(ostream& str) {
this->AstNode::dump(str);
if (taskPublic()) str<<" [PUBLIC]";
}
void AstCoverDecl::dump(ostream& str) {
this->AstNode::dump(str);
+26 -6
View File
@@ -286,8 +286,10 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual string name() const { return m_name; } // * = Var name
virtual bool maybePointedTo() const { return true; }
AstVarType varType() const { return m_varType; } // * = Type of variable
string cType() const; // Return C type: bool, uint32_t, uint64_t, etc.
string cType() const; // Return C type for declaration: bool, uint32_t, uint64_t, etc.
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
void combineType(AstVarType type);
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
AstRange* arraysp() const { return op2p()->castRange(); } // op2 = Array(s) of variable
@@ -314,10 +316,13 @@ public:
void name(const string& name) { m_name = name; }
bool isInput() const { return m_input; }
bool isOutput() const { return m_output; }
bool isTristate() const { return (m_tristate); }
bool isInOnly() const { return m_input && !m_output; }
bool isOutOnly() const { return m_output && !m_input; }
bool isInout() const { return m_input && m_output; }
bool isTristate() const { return m_tristate; }
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output||m_tristate); }
bool isIO() const { return (m_input||m_output); }
bool isSignal() const { return (varType()==AstVarType::WIRE || varType()==AstVarType::IMPLICIT
|| varType()==AstVarType::REG || varType()==AstVarType::INTEGER); }
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
@@ -419,6 +424,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void cloneRelink();
virtual bool broken() const;
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; } // * = Scope name
void name(const string& name) { m_name = name; }
string nameDotless() const;
@@ -480,6 +486,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual bool broken() const { return ( (m_varp && !m_varp->brokeExists())
|| (m_scopep && !m_scopep->brokeExists())); }
virtual bool maybePointedTo() const { return true; }
virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name
virtual void dump(ostream& str);
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
@@ -604,6 +611,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual bool broken() const { return (m_clkReqVarp && !m_clkReqVarp->brokeExists()); }
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; }
AstNode* stmtsp() const { return op2p()->castNode(); } // op2 = List of statements
AstActive* activesp() const { return op3p()->castActive(); } // op3 = List of i/sblocks
@@ -648,6 +656,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
virtual bool maybePointedTo() const { return true; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
void name(const string& name) { m_name = name; }
@@ -806,7 +815,7 @@ public:
class Initial {}; // for creator type-overload selection
class Settle {}; // for creator type-overload selection
class Never {}; // for creator type-overload selection
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstVarRef* varrefp)
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNodeVarRef* varrefp)
: AstNode(fl) {
m_edgeType = edgeType;
setOp1p(varrefp);
@@ -839,7 +848,7 @@ public:
AstEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge
void edgeType(AstEdgeType type) { m_edgeType=type; editCountInc(); }// * = Posedge/negedge
AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized
AstVarRef* varrefp() const { return op1p()->castVarRef(); } // op1 = Signal sensitized
AstNodeVarRef* varrefp() const { return op1p()->castNodeVarRef(); } // op1 = Signal sensitized
//
bool isClocked() const { return edgeType().clockedStmt(); }
bool isCombo() const { return edgeType()==AstEdgeType::COMBO; }
@@ -865,6 +874,7 @@ public:
virtual AstNode* clone() { return new AstSenTree(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual bool maybePointedTo() const { return true; }
bool isMulti() const { return m_multi; }
AstSenItem* sensesp() const { return op1p()->castSenItem(); } // op1 = Sensitivity list
void addSensesp(AstSenItem* nodep) { addOp1p(nodep); }
@@ -1050,6 +1060,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
virtual bool maybePointedTo() const { return true; }
int column() const { return m_column; }
const string& comment() const { return m_text; } // text to insert in code
const string& typeText() const { return m_typeText; }
@@ -1503,6 +1514,7 @@ public:
virtual AstNode* clone() { return new AstTraceDecl(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string name() const { return m_showname; }
virtual bool maybePointedTo() const { return true; }
string showname() const { return m_showname; } // * = Var name
virtual bool same(AstNode* samep) const { return false; }
// Details on what we're tracing
@@ -1594,7 +1606,8 @@ public:
bool hasClocked() const { return m_sensesp->hasClocked(); }
};
class AstAttrOf : public AstNode {
struct AstAttrOf : public AstNode {
private:
// Return a value of a attribute, for example a LSB or array LSB of a signal
AstAttrType m_attrType; // What sort of extraction
int m_dimension; // Dimension number (0 is leftmost), for ARRAY_LSB extractions
@@ -1736,6 +1749,7 @@ struct AstRedXor : public AstNodeUniop {
virtual int instrCount() const { return 1+V3Number::log2b(width()); }
};
struct AstRedXnor : public AstNodeUniop {
// AstRedXnors are replaced with AstRedXors in V3Const.
AstRedXnor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(1,1); }
virtual ~AstRedXnor() {}
@@ -2773,6 +2787,7 @@ private:
bool m_funcPublic:1; // From user public task/function
bool m_isStatic:1; // Function is declared static (no this)
bool m_symProlog:1; // Setup symbol table for later instructions
bool m_entryPoint:1; // User may call into this top level function
public:
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="")
: AstNode(fl) {
@@ -2788,12 +2803,15 @@ public:
m_funcPublic = false;
m_isStatic = true; // Note defaults to static, later we see where thisp is needed
m_symProlog = false;
m_entryPoint = false;
}
virtual ~AstCFunc() {}
virtual AstType type() const { return AstType::CFUNC;}
virtual AstNode* clone() { return new AstCFunc(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string name() const { return m_name; }
virtual bool broken() const { return ( (m_scopep && !m_scopep->brokeExists())); }
virtual bool maybePointedTo() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return ((funcType()==samep->castCFunc()->funcType())
&& (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid())
@@ -2823,6 +2841,8 @@ public:
void isStatic(bool flag) { m_isStatic = flag; }
bool symProlog() const { return m_symProlog; }
void symProlog(bool flag) { m_symProlog = flag; }
bool entryPoint() const { return m_entryPoint; }
void entryPoint(bool flag) { m_entryPoint = flag; }
//
// If adding node accessors, see below
AstNode* argsp() const { return op1p()->castNode(); }
+6 -4
View File
@@ -81,13 +81,15 @@ private:
// // so userp and friends may not be used
// VISITORS
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::add(nodep);
if (nodep->maybePointedTo()) {
BrokenTable::add(nodep);
}
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
BrokenMarkVisitor(AstNode* nodep) {
nodep->iterateAndNext(*this, NULL);
BrokenMarkVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~BrokenMarkVisitor() {}
};
@@ -99,7 +101,7 @@ class BrokenCheckVisitor : public AstNVisitor {
private:
virtual void visit(AstNode* nodep, AstNUser*) {
if (nodep->broken()) {
nodep->v3fatalSrc("Broken link in node\n");
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
}
if (v3Global.assertWidthsSame()) {
if (nodep->width() != nodep->widthMin()) {
+16 -15
View File
@@ -29,12 +29,12 @@
// (other items))
// body
// Or, converts to a if/else tree.
// Constants:
// RHS, Replace 5'bx_1_x with a module global we init to a random value
// CONST(5'bx_1_x) -> VARREF(_{numberedtemp})
// -> VAR(_{numberedtemp})
// -> INITIAL(VARREF(_{numberedtemp}), OR(5'bx_1_x,AND(random,5'b0_1_x))
// OPTIMIZE: Must not collapse this initial back into the equation.
// FUTURES:
// Large 16+ bit tables with constants and no masking (address muxes)
// Enter all into multimap, sort by value and use a tree of < and == compares.
// "Diagonal" find of {rightmost,leftmost} bit {set,clear}
// Ignoring mask, check each value is unique (using multimap as above?)
// Each branch is then mask-and-compare operation (IE <000000001_000000000 at midpoint.)
//
//*************************************************************************
@@ -49,7 +49,8 @@
#include "V3Ast.h"
#include "V3Stats.h"
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
//######################################################################
@@ -126,22 +127,22 @@ private:
//int debug() { return 9; }
// METHODS
bool checkCaseTree(AstCase* nodep) {
bool isCaseTreeFast(AstCase* nodep) {
int width = 0;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (!icondp->castConst()) width = 999; // Can't parse; not a constant
if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant
m_caseItems++;
}
}
m_caseWidth = width;
if (width==0 || width > CASE_OVERLAP_WIDTH) {
m_caseNoOverlapsAllCovered = false;
return false; // Too wide for analysis
}
m_caseWidth = width;
UINFO(8,"Simple case statement: "<<nodep<<endl);
// Zero list of items for each value
for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) m_valueItem[i] = NULL;
@@ -172,7 +173,7 @@ private:
}
}
// Defaults were moved to last in the caseitem list by V3Link
if (!itemp->condsp()) { // Case statement's default... Fill the table
if (itemp->isDefault()) { // Case statement's default... Fill the table
for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
if (!m_valueItem[i]) m_valueItem[i] = itemp;
}
@@ -207,7 +208,7 @@ private:
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));
if (tree0p == tree1p) {
// Same logic on both sides, so we can just return one of em
// Same logic on both sides, so we can just return one of 'em
return tree0p;
}
// We could have a "checkerboard" with A B A B, we can use the same IF on both edges
@@ -357,7 +358,7 @@ private:
V3Case::caseLint(nodep);
nodep->iterateChildren(*this);
if (debug()>=9) nodep->dumpTree(cout," case_old: ");
if (checkCaseTree(nodep) && v3Global.opt.oCase()) {
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
// It's a simple priority encoder or complete statement
// we can make a tree of statements to avoid extra comparisons
m_statCaseFast++;
@@ -375,13 +376,13 @@ private:
public:
// CONSTUCTORS
CaseVisitor(AstNode* nodep) {
CaseVisitor(AstNetlist* nodep) {
m_caseNoOverlapsAllCovered = false;
nodep->accept(*this);
}
virtual ~CaseVisitor() {
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
V3Stats::addStat("Optimizations, Cases priority-encoded", m_statCaseSlow);
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
}
};
+4
View File
@@ -239,6 +239,10 @@ private:
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->bodysp());
}
virtual void visit(AstCCall* nodep, AstNUser*) {
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->argsp());
}
//--------------------
// Default: Just iterate
+4
View File
@@ -192,6 +192,7 @@ private:
funcp->dontCombine(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_evalFuncp = funcp;
}
@@ -202,6 +203,7 @@ private:
funcp->slow(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_initFuncp = funcp;
}
@@ -211,6 +213,7 @@ private:
funcp->dontCombine(true);
funcp->slow(true);
funcp->isStatic(false);
funcp->entryPoint(true);
funcp->addInitsp(
new AstCStmt(nodep->fileline(),
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
@@ -225,6 +228,7 @@ private:
funcp->slow(true);
funcp->isStatic(true);
funcp->symProlog(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_settleFuncp = funcp;
}
+60 -16
View File
@@ -70,6 +70,16 @@ private:
if (!rnodep->lhsp()->castConst()) return false;
return true;
}
bool operandAsvSame (AstNode* nodep) {
// BIASV(SAMEa, BIASV(SAMEb,...)) -> BIASV( BIASV(SAMEa,SAMEb), ...)
AstNodeBiComAsv* bnodep = nodep->castNodeBiComAsv();
if (!bnodep) return false;
AstNodeBiComAsv* rnodep = bnodep->rhsp()->castNodeBiComAsv();
if (!rnodep) return false;
if (rnodep->type() != bnodep->type()) return false;
if (rnodep->width() != bnodep->width()) return false;
return operandsSame(bnodep->lhsp(), rnodep->lhsp());
}
bool operandHugeShiftL(AstNodeBiop* nodep) {
return (nodep->rhsp()->castConst()
&& nodep->rhsp()->castConst()->asInt() >= (uint32_t)(nodep->width()));
@@ -170,15 +180,10 @@ private:
static bool operandsSame(AstNode* node1p, AstNode* node2p) {
// For now we just detect constants & simple vars, though it could be more generic
if (node1p->castConst() && node2p->castConst()) {
// Match ignoring any X values
V3Number num (node1p->fileline(), 1);
num.opCaseEq(node1p->castConst()->num(), node2p->castConst()->num());
return num.isNeqZero();
return node1p->sameTree(node2p);
}
else if (node1p->castVarRef() && node2p->castVarRef()
&& node1p->sameTree(node2p)) {
// Same variable
return true;
else if (node1p->castVarRef() && node2p->castVarRef()) {
return node1p->sameTree(node2p);
} else {
return false;
}
@@ -239,6 +244,12 @@ private:
void replaceZero(AstNode* nodep) {
replaceNum(nodep, 0); nodep=NULL;
}
void replaceAllOnes (AstNode* nodep) {
V3Number num (nodep->fileline(), nodep->width(), 0);
V3Number ones (nodep->fileline(), nodep->width());
ones.opNot(num);
replaceNum(nodep, ones); nodep=NULL;
}
void replaceConst(AstNodeUniop* nodep) {
V3Number num (nodep->fileline(), nodep->width());
nodep->numberOperate(num, nodep->lhsp()->castConst()->num());
@@ -283,8 +294,9 @@ private:
// Keep RHS, remove LHS
replaceWChild(nodep, nodep->rhsp());
}
void replaceAsvConst (AstNodeBiop* nodep) {
void replaceAsv (AstNodeBiop* nodep) {
// BIASV(CONSTa, BIASV(CONSTb, c)) -> BIASV( BIASV_CONSTED(a,b), c)
// BIASV(SAMEa, BIASV(SAMEb, c)) -> BIASV( BIASV(SAMEa,SAMEb), c)
//nodep->dumpTree(cout, " repAsvConst_old: ");
AstNode* ap = nodep->lhsp();
AstNodeBiop* rp = nodep->rhsp()->castNodeBiop();
@@ -298,7 +310,7 @@ private:
nodep->rhsp(cp);
rp->lhsp(ap);
rp->rhsp(bp);
replaceConst(rp);
if (rp->lhsp()->castConst() && rp->rhsp()->castConst()) replaceConst(rp);
//nodep->dumpTree(cout, " repAsvConst_new: ");
}
void replaceExtend (AstNode* nodep, AstNode* arg0p) {
@@ -803,7 +815,7 @@ private:
}
UINFO(8,"senItem(NOT...) "<<nodep<<" "<<invert<<endl);
if (invert) nodep->edgeType( nodep->edgeType().invert() );
AstVarRef* senvarp = lastSensp->unlinkFrBack()->castVarRef();
AstNodeVarRef* senvarp = lastSensp->unlinkFrBack()->castNodeVarRef();
if (!senvarp) sensp->v3fatalSrc("Non-varref sensitivity variable");
sensp->replaceWith(senvarp);
sensp->deleteTree(); sensp=NULL;
@@ -945,6 +957,7 @@ private:
// }" # bracket not paren
// ,"function to call"
// or ,"AstREPLACEMENT_TYPE{ $accessor }"
// or ,"! # Print line number when matches, so can see operations
// Lint Checks
// v--- *1* These ops are always first, as we warn before replacing
@@ -969,6 +982,7 @@ private:
TREEOP("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
TREEOP("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
TREEOP("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}");
TREEOP("AstSub {$lhsp.isZero, $rhsp}", "AstUnaryMin{$rhsp}");
TREEOP("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
@@ -982,6 +996,7 @@ private:
TREEOP("AstShiftRS{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstSub {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstXor {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstXnor {$lhsp, $rhsp.isZero}", "AstNot{$lhsp}");
// Non-zero on one side or the other
TREEOP("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhs(nodep)");
@@ -992,6 +1007,7 @@ private:
TREEOP("AstOr {$lhsp, $rhsp.isAllOnes}", "replaceWRhs(nodep)"); //->allOnes
TREEOP("AstLogOr {$lhsp, $rhsp.isNeqZero}", "replaceNum(nodep,1)");
TREEOP("AstXor {$lhsp.isAllOnes, $rhsp}", "AstNot{$rhsp}");
TREEOP("AstXnor {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
@@ -1012,8 +1028,9 @@ private:
TREEOP("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isZero, $expr2p}", "AstAnd{AstNot{$condp}, $expr2p}"); // a?0:b == ~a&b
TREEOP("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())");
// Prefer constants on left, since that often needs a shift, it lets constant red remove the shift
TREEOP("AstNodeBiCom{$lhsp, $rhsp.castConst}", "swapSides(nodep)");
TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsvConst(nodep)");
TREEOP("AstNodeBiCom{!$lhsp.castConst, $rhsp.castConst}", "swapSides(nodep)");
TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsv(nodep)");
TREEOP("AstNodeBiComAsv{operandAsvSame(nodep)}", "replaceAsv(nodep)");
// v--- *1* as These ops are always first, as we warn before replacing
TREEOP1("AstLt {$lhsp, $rhsp.isZero}", "replaceNumSigned(nodep,0)");
TREEOP1("AstGte {$lhsp, $rhsp.isZero}", "replaceNumSigned(nodep,1)");
@@ -1058,6 +1075,31 @@ private:
TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
TREEOP ("AstShiftR{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
TREEOP ("AstWordSel{operandWordOOB(nodep)}", "replaceZero(nodep)");
// Identical operands on both sides
// AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules
// AstAdd->ShiftL(#,1) but uncommon
TREEOP("AstAnd {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)");
TREEOP("AstChangeXor{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstDiv {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstDivS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstOr {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)");
TREEOP("AstSub {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstXnor {operandsSame($lhsp,,$rhsp)}", "replaceAllOnes(nodep)");
TREEOP("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP("AstEqCase {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstGt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstGteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstLt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstLtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstLte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
TREEOP("AstLogOr {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
///=== Verilog operators
// Comparison against 1'b0/1'b1; must be careful about widths.
// These use Not, so must be Verilog only
@@ -1075,7 +1117,6 @@ private:
TREEOPV("AstLte {$lhsp->width()==$rhsp->width(), $rhsp.isAllOnes}", "replaceNum(nodep,1)");
// Simplify reduction operators
// This also gets &{...,0,....} => const 0 (Common for unused_ok signals)
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
TREEOPV("AstRedAnd{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
TREEOPV("AstRedOr {$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
TREEOPV("AstRedXor{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
@@ -1108,6 +1149,7 @@ private:
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)");
// Conversions
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
TREEOPV("AstLogIff{$lhsp, $rhsp}", "AstLogNot{AstXor{$lhsp,$rhsp}}");
@@ -1171,12 +1213,14 @@ void V3Const::constifyAll(AstNetlist* nodep) {
visitor.main(nodep);
}
void V3Const::constifyAllLint(AstNode* nodep) {
void V3Const::constifyAllLint(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,true,false);
visitor.main(nodep);
}
void V3Const::constifyCpp(AstNode* nodep) {
void V3Const::constifyCpp(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,false,true);
visitor.main(nodep);
}
+2 -2
View File
@@ -34,9 +34,9 @@ public:
// Everything that's possible
static void constifyAll(AstNetlist* nodep);
// Also, warn
static void constifyAllLint(AstNode* nodep);
static void constifyAllLint(AstNetlist* nodep);
// C++ datatypes
static void constifyCpp(AstNode* nodep);
static void constifyCpp(AstNetlist* nodep);
// Only the current node and lower
static void constifyTree(AstNode* nodep);
};
+37 -3
View File
@@ -29,6 +29,7 @@
#include <stdarg.h>
#include <unistd.h>
#include <vector>
#include <map>
#include "V3Global.h"
#include "V3Dead.h"
@@ -70,10 +71,15 @@ private:
// AstVar::user() -> int. Count of number of references
// AstVarScope::user() -> int. Count of number of references
// TYPES
typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap;
// STATE
vector<AstVar*> m_varsp; // List of all encountered to avoid another loop through tree
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
bool m_elimUserVars; // Allow removal of user's vars
bool m_sideEffect; // Side effects discovered in assign RHS
//int debug() { return 9; }
// METHODS
@@ -102,6 +108,25 @@ private:
m_varsp.push_back(nodep);
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// See if simple assignments to variables may be eliminated because that variable is never used.
// Similar code in V3Life
m_sideEffect = false;
nodep->rhsp()->iterateAndNext(*this);
// Has to be direct assignment without any EXTRACTing.
AstVarRef* varrefp = nodep->lhsp()->castVarRef();
if (varrefp && !m_sideEffect
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
m_assignMap.insert(make_pair(varrefp->varScopep(), nodep));
} else { // Track like any other statement
nodep->lhsp()->iterateAndNext(*this);
}
}
virtual void visit(AstUCFunc* nodep, AstNUser*) {
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
nodep->iterateChildren(*this);
}
//-----
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
@@ -131,14 +156,22 @@ private:
}
bool canElim(AstVar* nodep) {
return (!nodep->isSigPublic() // Can't elim publics!
&& !nodep->isIO()
&& (nodep->isTemp() || nodep->isParam() || m_elimUserVars));
}
void deadCheckVar() {
// Delete any unused varscopes
for (vector<AstVarScope*>::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) {
if ((*it)->user() == 0 && canElim((*it)->varp())) {
UINFO(4," Dead "<<(*it)<<endl);
(*it)->unlinkFrBack()->deleteTree(); (*it)=NULL;
AstVarScope* vscp = *it;
if (vscp->user() == 0 && canElim(vscp->varp())) {
UINFO(4," Dead "<<vscp<<endl);
pair <AssignMap::iterator,AssignMap::iterator> eqrange = m_assignMap.equal_range(vscp);
for (AssignMap::iterator it = eqrange.first; it != eqrange.second; ++it) {
AstNodeAssign* assp = it->second;
UINFO(4," Dead assign "<<assp<<endl);
assp->unlinkFrBack()->deleteTree(); assp=NULL;
}
vscp->unlinkFrBack()->deleteTree(); vscp=NULL;
}
}
for (vector<AstVar*>::iterator it = m_varsp.begin(); it!=m_varsp.end(); ++it) {
@@ -153,6 +186,7 @@ public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars) {
m_elimUserVars = elimUserVars;
m_sideEffect = false;
// Operate on whole netlist
AstNode::userClearTree(); // userp() used on entire tree
nodep->accept(*this);
+7 -6
View File
@@ -224,12 +224,13 @@ private:
if (m_scopep) {
nodep->unlinkFrBack();
m_modp->addStmtp(nodep);
}
if (nodep->funcPublic()) {
// There may be multiple public functions by the same name;
// record for later correction or making of shells
m_modFuncs.insert(make_pair(nodep->name(), nodep));
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
if (nodep->funcPublic()) {
// There may be multiple public functions by the same name;
// record for later correction or making of shells
m_modFuncs.insert(make_pair(nodep->name(), nodep));
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
}
}
}
}
+24 -18
View File
@@ -96,12 +96,17 @@ public:
string cFuncArgs(AstCFunc* nodep) {
// Return argument list for given C function
string args = nodep->argTypes();
if (args=="") {
// Might be a user function with argument list.
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args+= ", ";
// Might be a user function with argument list.
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args+= ", ";
if (portp->isWide()) {
if (portp->isInOnly()) args += "const ";
args += portp->cType();
args += " (& "+portp->name();
args += ")["+cvtToStr(portp->widthWords())+"]";
} else {
args += portp->cType();
if (portp->isOutput()) args += "&";
args += " "+portp->name();
@@ -217,8 +222,7 @@ public:
puts(");\n");
}
virtual void visit(AstCoverInc* nodep, AstNUser*) {
puts("if (VL_LIKELY(vlSymsp->__Vm_coverageRequest))");
puts(" ++this->__Vcoverage[");
puts("++this->__Vcoverage[");
puts(cvtToStr(m_coverIds.remap(nodep->declp()))); puts("];\n");
}
virtual void visit(AstCReturn* nodep, AstNUser*) {
@@ -703,19 +707,19 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (nodep->attrScClocked() && nodep->isInput()) {
puts("sc_in_clk\t");
} else {
if (nodep->isTristate()) puts("sc_inout<");
if (nodep->isInout()) puts("sc_inout<");
else if (nodep->isInput()) puts("sc_in<");
else if (nodep->isOutput()) puts("sc_out<");
else nodep->v3fatalSrc("Unknown type");
puts(nodep->cType());
puts(nodep->scType());
puts(">\t");
}
puts(nodep->name());
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes());
if (nodep->isTristate()) puts("VL_INOUT");
if (nodep->isInout()) puts("VL_INOUT");
else if (nodep->isInput()) puts("VL_IN");
else if (nodep->isOutput()) puts("VL_OUT");
else nodep->v3fatalSrc("Unknown type");
@@ -910,7 +914,6 @@ string EmitCStmts::displayFormat(AstNode* widthNodep, string in,
} else {
fmt=in;
}
if (widthNodep->isQuad() && fmtLetter!='c' && fmtLetter!='s' && !reallyString) fmt+="ll";
return fmt;
}
@@ -941,10 +944,17 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string fmt, cha
emitDispState.pushFormat(pfmt);
emitDispState.pushArg(*elistp,func);
} else {
string func;
string nfmt = displayFormat(*elistp, fmt, fmtLetter, true, false);
// We don't need to check for fmtLetter=='d', as it is above.
if ((*elistp)->isQuad() && (fmtLetter=='u'||fmtLetter=='o'||fmtLetter=='x')) {
nfmt+="ll";
func="(unsigned long long)("; // Must match %ull to avoid warnings
}
string pfmt = "%"+nfmt+fmtLetter;
emitDispState.pushFormat(pfmt);
emitDispState.pushArg(*elistp,"");
emitDispState.pushArg(*elistp,func);
}
// Next parameter
*elistp = (*elistp)->nextp();
@@ -1246,12 +1256,8 @@ void EmitCImp::emitWrapEval(AstModule* modp) {
puts("while (VL_LIKELY(__Vchange)) {\n");
puts( "VL_DEBUG_IF(cout<<\" Clock loop\"<<endl;);\n");
#endif
// Not exactly correct for coverage. w/combo logic interspersed, this is complicated. Punt.
// Perhaps have temp & each _combo_ turn it on or off
if (v3Global.opt.coverage()) puts( "vlSymsp->__Vm_coverageRequest = true;\n");
puts( "vlSymsp->__Vm_activity = true;\n");
puts( "_eval(vlSymsp);\n");
if (v3Global.opt.coverage()) puts( "vlSymsp->__Vm_coverageRequest = false;\n");
#ifndef NEW_ORDERING
puts( "__Vchange = _change_request(vlSymsp);\n");
puts( "if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n");
@@ -1284,7 +1290,7 @@ void EmitCImp::emitWrapEval(AstModule* modp) {
void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp) {
// Put out a list of signal declarations
// in order of 0:clocks, 1:uint8, 2:uint16, 4:uint32, 5:uint64, 6:wide, 7:arrays
// in order of 0:clocks, 1:vluint8, 2:vluint16, 4:vluint32, 5:vluint64, 6:wide, 7:arrays
// This aids cache packing and locality
// Largest->smallest reduces the number of pad variables.
// But for now, Smallest->largest makes it more likely a small offset will allow access to the signal.
+1 -1
View File
@@ -109,7 +109,7 @@ public:
bool optSystemPerl() { return v3Global.opt.systemPerl(); }
static string symClassName() { return v3Global.opt.prefix()+"__Syms"; }
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp = vlSymsp->TOPp;"; }
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
static string modClassName(AstModule* modp) { // Return name of current module being processed
if (modp->isTop()) {
return v3Global.opt.prefix();
+2 -7
View File
@@ -124,18 +124,14 @@ void EmitCSyms::emitInt() {
//puts("\n// STATIC STATE\n");
puts("\n// LOCAL STATE\n");
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint64_t));
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t));
puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert.
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n");
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
puts("bool\t__Vm_didInit;\n");
if (v3Global.opt.coverage()) {
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
puts("bool __Vm_coverageRequest;\n");
}
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint64_t));
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t));
puts("\n// SUBCELL STATE\n");
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstModule* modp = it->second;
@@ -184,7 +180,6 @@ void EmitCSyms::emitImp() {
puts("\t: __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed
puts("\t, __Vm_activity(false)\n");
puts("\t, __Vm_didInit(false)\n");
if (v3Global.opt.coverage()) puts("\t, __Vm_coverageRequest(false)\n");
puts("\t// Setup submodule names\n");
char comma=',';
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
+3
View File
@@ -96,6 +96,9 @@ public:
// Imply generating verilated.o
if (v3Global.opt.exe()) {
v3Global.opt.addCppFile("verilated.cpp");
if (v3Global.opt.trace()) {
v3Global.opt.addCppFile("SpTraceVcdC.cpp");
}
}
V3StringSet dirs;
+15 -7
View File
@@ -92,7 +92,7 @@ void FileLine::lineDirective(const char* textp) {
bool FileLine::warnOff(const string& msg, bool flag) {
V3ErrorCode code (msg.c_str());
if (code == V3ErrorCode::ERROR) {
if (code < V3ErrorCode::FIRST_WARN) {
return false;
} else {
warnOff(code, flag);
@@ -168,9 +168,8 @@ void FileLine::v3errorEnd(ostringstream& str) {
void V3Error::init() {
for (int i=0; i<V3ErrorCode::MAX; i++) {
s_describedEachWarn[i] = false;
s_pretendError[i] = false;
s_pretendError[i] = V3ErrorCode(i).pretendError();
}
pretendError(V3ErrorCode::BLKANDNBLK, true);
if (string(V3ErrorCode(V3ErrorCode::MAX).ascii()) != " MAX") {
v3fatalSrc("Enum table in V3ErrorCode::ascii() is munged");
@@ -204,8 +203,9 @@ void V3Error::abortIfErrors() {
string V3Error::msgPrefix(V3ErrorCode code) {
if (code==V3ErrorCode::SUPPRESS) return "-arning-suppressed: ";
else if (code==V3ErrorCode::FATAL) return "%Error: ";
else if (code==V3ErrorCode::ERROR
|| s_pretendError[code]) return "%Error: ";
else if (code==V3ErrorCode::ERROR) return "%Error: ";
else if (code<V3ErrorCode::FIRST_WARN
|| s_pretendError[code]) return "%Error-"+(string)code.ascii()+": ";
else return "%Warning-"+(string)code.ascii()+": ";
}
@@ -236,6 +236,9 @@ void V3Error::v3abort () {
}
void V3Error::v3errorEnd (ostringstream& sstr) {
#ifdef __COVERITY__
if (s_errorCode==V3ErrorCode::FATAL) __coverity_panic__(x);
#endif
if (s_errorCode!=V3ErrorCode::SUPPRESS || debug()) {
cerr<<msgPrefix()<<sstr.str();
if (sstr.str()[sstr.str().length()-1] != '\n') {
@@ -268,8 +271,13 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
}
#endif
}
abort();
// exit(10);
if (V3Error::debugDefault()) {
cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
abort();
} else {
exit(10);
}
}
}
}
+10 -2
View File
@@ -34,9 +34,12 @@ public:
enum en {
SUPPRESS, // Warning suppressed by user
FATAL, // Kill the program
ERROR, // Error out, can't suppress
ERROR, // General error out, can't suppress
// Error codes:
TASKNSVAR, // Error: Task I/O not simple
// Warning codes:
FIRST_WARN, // Just a code so the program knows where to start warnings
//
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
CASEINCOMPLETE, // Case statement has missing values
CASEOVERLAP, // Case statements overlap
@@ -45,6 +48,7 @@ public:
COMBDLY, // Combinatorial delayed assignment
GENCLK, // Generated Clock
IMPLICIT, // Implicit wire
IMPURE, // Impure function not being inlined
MULTIDRIVEN, // Driven from multiple blocks
UNDRIVEN, // No drivers
UNOPT, // Unoptimizable block
@@ -66,10 +70,11 @@ public:
const char* names[] = {
// Leading spaces indicate it can't be disabled.
" SUPPRESS", " FATAL", " ERROR",
"TASKNSVAR",
" FIRST_WARN",
"BLKANDNBLK",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEX", "CMPCONST",
"COMBDLY", "GENCLK", "IMPLICIT",
"COMBDLY", "GENCLK", "IMPLICIT", "IMPURE",
"MULTIDRIVEN",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH",
@@ -79,6 +84,9 @@ public:
};
// Warnings that warn about nasty side effects
bool dangerous() const { return ( m_e==COMBDLY );};
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const { return ( m_e==BLKANDNBLK || m_e==IMPURE); };
};
inline bool operator== (V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); }
+3
View File
@@ -660,6 +660,9 @@ private:
// Lhs or Rhs may be word, long, or quad.
// newAstWordSelClone nicely abstracts the difference.
int rhsshift = rhsp->rhsp()->widthMin();
// Sometimes doing the words backwards is preferrable.
// When we have x={x,foo} backwards is better, when x={foo,x} forward is better
// However V3Subst tends to rip this up, so not worth optimizing now.
for (int w=0; w<rhsp->widthWords(); w++) {
addWordAssign(nodep, w,
new AstOr (rhsp->fileline(),
+3
View File
@@ -42,6 +42,9 @@ public:
}
static ofstream* new_ofstream(const string& filename, bool append=false) {
addTgtDepend(filename);
return new_ofstream_nodepend (filename, append);
}
static ofstream* new_ofstream_nodepend(const string& filename, bool append=false) {
if (append) {
return new ofstream(filename.c_str(), ios::app);
} else {
+1 -1
View File
@@ -64,7 +64,7 @@ class GraphNfaToDfa : GraphAlg {
private:
// TYPES
typedef deque<DfaVertex*> DfaStates;
typedef multimap<uint64_t,DfaVertex*> HashMap;
typedef multimap<vluint64_t,DfaVertex*> HashMap;
// MEMBERS
uint32_t m_step; // Processing step, so we can avoid clearUser all the time
+1 -3
View File
@@ -111,7 +111,6 @@ private:
nodep->name(), nodep->modp()->origName());
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
// Create assignments to the pins
AstNode* assignlistsp = NULL;
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
UINFO(6," Pin change from "<<pinp->modVarp()<<endl);
// First, simplify it
@@ -142,13 +141,11 @@ private:
// Cleanup var names, etc, to not conflict
m_cellp = nodep;
newmodp->iterateAndNext(*this);
if (assignlistsp) assignlistsp->iterateAndNext(*this); // And cleanup any varrefs under assigns we created...
m_cellp = NULL;
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
AstNode* stmtsp = newmodp->stmtsp();
if (stmtsp) stmtsp->unlinkFrBackWithNext();
if (assignlistsp) m_modp->addStmtp(assignlistsp);
if (stmtsp) m_modp->addStmtp(stmtsp);
// Remove the cell
newmodp->deleteTree(); newmodp=NULL; // Clear any leftover ports, etc
@@ -353,6 +350,7 @@ private:
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
nodep->taskp(NULL);
nodep->iterateChildren(*this);
}
// Nop's to speed up the loop
virtual void visit(AstAlways* nodep, AstNUser*) {
+9 -5
View File
@@ -79,7 +79,7 @@ private:
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
UINFO(4," PIN "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
if (nodep->modVarp()->isOutput() && nodep->exprp()->castConst())
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
nodep->v3error("Output pin is assigned to a constant, electrical short");
// Use userp on the PIN to indicate we created an assign for this pin
if (!nodep->user()) {
@@ -90,7 +90,9 @@ private:
AstNode* exprp = nodep->exprp()->cloneTree(false);
if (nodep->width() != nodep->modVarp()->width())
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple\n");
if (nodep->modVarp()->isOutput()) {
if (nodep->modVarp()->isInout()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isOutput()) {
AstNode* rhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
rhsp->widthSignedFrom(nodep);
AstAssignW* assp = new AstAssignW (exprp->fileline(), exprp, rhsp);
@@ -236,12 +238,14 @@ void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstModule* modp) {
} else {
// Make a new temp wire
//if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); }
AstAssignW* assignp;
AstAssignW* assignp = NULL;
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
string newvarname = "__Vcellinp__"+cellp->name()+"__"+pinp->name();
AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
modp->addStmtp(newvarp);
if (pinVarp->isOutput()) {
if (pinVarp->isInout()) {
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
} else if (pinVarp->isOutput()) {
// See also V3Inst
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
if (pinp->width() > rhsp->width()) {
@@ -265,7 +269,7 @@ void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstModule* modp) {
pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
}
pinp->widthSignedFrom(pinp->exprp());
modp->addStmtp(assignp);
if (assignp) modp->addStmtp(assignp);
//if (1||debug()) { pinp->dumpTree(cout," out:"); }
//if (1||debug()) { assignp->dumpTree(cout," aout:"); }
}
+297 -136
View File
@@ -38,152 +38,243 @@
#include "V3Life.h"
#include "V3Stats.h"
#include "V3Ast.h"
#include "V3Const.h"
//######################################################################
// Life state, as a visitor of each AstNode
// Structure for global state
class LifeVarEntry {
AstNode* m_assignp; // Last assignment to this varscope
bool m_firstSet; // True if creation was a set (and thus block above may have a set that can be deleted
class LifeState {
// STATE
public:
LifeVarEntry() { // Construction for when a var is used
clearAssign();
m_firstSet = false;
V3Double0 m_statAssnDel; // Statistic tracking
V3Double0 m_statAssnCon; // Statistic tracking
public:
LifeState() {}
~LifeState() {
V3Stats::addStat("Optimizations, Lifetime assign deletions", m_statAssnDel);
V3Stats::addStat("Optimizations, Lifetime constant prop", m_statAssnCon);
}
LifeVarEntry(AstNode* assp) { // Construction for when a var is set
m_assignp = assp;
m_firstSet = true;
}
LifeVarEntry(bool) { // Construction for when a var is set, but ass isn't
m_assignp = NULL;
m_firstSet = true;
}
AstNode* assignp() const { return m_assignp; }
bool firstSet() const { return m_firstSet; }
void clearAssign() { m_assignp = NULL; }
void newerAssign(AstNode* assp) { m_assignp = assp; }
};
class LifeVisitor : public AstNVisitor {
private:
// NODE STATE
// AstVarScope::user() -> int. Used in combining to detect duplicates
//######################################################################
// Structure for each variable encountered
// STATE
//static int debug() { return 9; }
int m_ifCount; // If counter
V3Double0 m_statAssnDel; // Statistic tracking
class LifeVarEntry {
AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant
AstConst* m_constp; // Known constant value
bool m_setBeforeUse; // First access was a set (and thus block above may have a set that can be deleted
bool m_everSet; // Was ever assigned (and thus above block may not preserve constant propagation)
inline void init (bool setBeforeUse) {
m_assignp = NULL;
m_constp = NULL;
m_setBeforeUse = setBeforeUse;
m_everSet = false;
}
public:
class SIMPLEASSIGN {};
class COMPLEXASSIGN {};
class CONSUMED {};
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) {
init(true); simpleAssign(assp);
}
LifeVarEntry(COMPLEXASSIGN) {
init(false); complexAssign();
}
LifeVarEntry(CONSUMED) {
init(false); consumed();
}
~LifeVarEntry() {}
inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment
m_assignp = assp;
m_constp = NULL;
m_everSet = true;
if (assp->rhsp()->castConst()) m_constp = assp->rhsp()->castConst();
}
inline void complexAssign() { // A[x]=... or some complicated assignment
m_assignp = NULL;
m_constp = NULL;
m_everSet = true;
}
inline void consumed() { // Rvalue read of A
m_assignp = NULL;
}
AstNodeAssign* assignp() const { return m_assignp; }
AstConst* constNodep() const { return m_constp; }
bool setBeforeUse() const { return m_setBeforeUse; }
bool everSet() const { return m_everSet; }
};
//######################################################################
// Structure for all variables under a given meta-basic block
class LifeBlock {
// NODE STATE
// Cleared each AstIf:
// AstVarScope::user() -> int. Used in combining to detect duplicates
// LIFE MAP
// For each basic block, we'll make a new map of what variables that if/else is changing
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
LifeMap *m_lifep; // Current active lifetime map for current scope
LifeMap m_map; // Current active lifetime map for current scope
LifeBlock* m_aboveLifep; // Upper life, or NULL
LifeState* m_statep; // Current global state
public:
LifeBlock(LifeBlock* aboveLifep, LifeState* statep) {
m_aboveLifep = aboveLifep; // Null if top
m_statep = statep;
}
~LifeBlock() {}
// METHODS
void checkRemoveAssign(LifeVarEntry* entp) {
// Check the var entry, and remove if appropriate
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
// Redundant assignment, in same level block
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->clearAssign();
oldassp->unlinkFrBack();
pushDeletep(oldassp);
m_statAssnDel++;
void checkRemoveAssign(const LifeMap::iterator& it) {
AstVar* varp = it->first->varp();
LifeVarEntry* entp = &(it->second);
if (!varp->isSigPublic()) {
// Rather then track what sigs AstUCFunc/AstUCStmt may change,
// we just don't optimize any public sigs
// Check the var entry, and remove if appropriate
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
// Redundant assignment, in same level block
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->complexAssign();
oldassp->unlinkFrBack()->deleteTree(); oldassp=NULL;
m_statep->m_statAssnDel++;
}
}
}
void setLast(AstVarScope* nodep, AstNode* assp) {
void simpleAssign(AstVarScope* nodep, AstNodeAssign* assp) {
// Do we have a old assignment we can nuke?
UINFO(4," ASSIGNof: "<<nodep<<endl);
UINFO(7," new: "<<assp<<endl);
LifeMap::iterator iter = m_lifep->find(nodep);
if (iter != m_lifep->end()) {
checkRemoveAssign(&(iter->second));
iter->second.newerAssign(assp);
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
checkRemoveAssign(it);
it->second.simpleAssign(assp);
} else {
m_lifep->insert(make_pair(nodep,LifeVarEntry(assp)));
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::SIMPLEASSIGN(), assp)));
}
//lifeDump();
}
void clearLastAssign(AstVarScope* nodep) {
void complexAssign(AstVarScope* nodep) {
UINFO(4," clearof: "<<nodep<<endl);
LifeMap::iterator iter = m_lifep->find(nodep);
if (iter != m_lifep->end()) {
iter->second.clearAssign();
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
it->second.complexAssign();
} else {
m_lifep->insert(make_pair(nodep,LifeVarEntry()));
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())));
}
}
void lifeDump(LifeMap* lifep) {
void varUsageReplace (AstVarScope* nodep, AstVarRef* varrefp) {
// Variable rvalue. If it references a constant, we can simply replace it
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
if (AstConst* constp = it->second.constNodep()) {
if (!varrefp->varp()->isSigPublic()) {
// Aha, variable is constant; substitute in.
// We'll later constant propagate
UINFO(4," replaceconst: "<<varrefp<<endl);
varrefp->replaceWith(constp->cloneTree(false));
varrefp->deleteTree(); varrefp=NULL;
m_statep->m_statAssnCon++;
return; // **DONE, no longer a var reference**
}
}
UINFO(4," usage: "<<nodep<<endl);
it->second.consumed();
} else {
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::CONSUMED())));
}
}
void complexAssignFind(AstVarScope* nodep) {
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
UINFO(4," casfind: "<<it->first<<endl);
it->second.complexAssign();
} else {
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())));
}
}
void consumedFind(AstVarScope* nodep) {
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
it->second.consumed();
} else {
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::CONSUMED())));
}
}
void lifeToAbove() {
// Any varrefs under a if/else branch affect statements outside and after the if/else
if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level");
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
AstVarScope* nodep = it->first;
m_aboveLifep->complexAssignFind(nodep);
if (it->second.everSet()) {
// Record there may be an assignment, so we don't constant propagate across the if.
complexAssignFind(nodep);
} else {
// Record consumption, so we don't eliminate earlier assignments
consumedFind(nodep);
}
}
}
void dualBranch (LifeBlock* life1p, LifeBlock* life2p) {
// Find any common sets on both branches of IF and propagate upwards
//life1p->lifeDump();
//life2p->lifeDump();
AstNode::userClearTree(); // userp() used on entire tree
for (LifeMap::iterator it = life1p->m_map.begin(); it!=life1p->m_map.end(); ++it) {
// When the if branch sets a var before it's used, mark that variable
if (it->second.setBeforeUse()) it->first->user(1);
}
for (LifeMap::iterator it = life2p->m_map.begin(); it!=life2p->m_map.end(); ++it) {
// When the else branch sets a var before it's used
AstVarScope* nodep = it->first;
if (it->second.setBeforeUse() && nodep->user()) {
// Both branches set the var, we can remove the assignment before the IF.
UINFO(4,"DUALBRANCH "<<nodep<<endl);
LifeMap::iterator itab = m_map.find(nodep);
if (itab != m_map.end()) {
checkRemoveAssign(itab);
}
}
}
//this->lifeDump();
}
// DEBUG
void lifeDump() {
UINFO(5, " LifeMap:"<<endl);
for (LifeMap::iterator it = lifep->begin(); it!=lifep->end(); ++it) {
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
UINFO(5, " Ent: "
<<(it->second.firstSet()?"[F] ":" ")
<<(it->second.setBeforeUse()?"[F] ":" ")
<<it->first<<endl);
if (it->second.assignp()) {
UINFO(5, " Ass: "<<it->second.assignp()<<endl);
}
}
}
void clearLifeFromSublife (LifeMap* sublifep) {
// Any varrefs under a if/else branch affect statements outside and after the if/else
for (LifeMap::iterator it = sublifep->begin(); it!=sublifep->end(); ++it) {
clearLastAssign(it->first);
}
}
void dualBranch (LifeMap* life1p, LifeMap* life2p) {
// Find any common sets on both branches of IF and propagate upwards
//lifeDump(life1p);
//lifeDump(life2p);
m_ifCount++;
for (LifeMap::iterator it = life1p->begin(); it!=life1p->end(); ++it) {
// When the if branch sets a var before it's used, mark that variable
if (it->second.firstSet()) it->first->user(m_ifCount);
}
for (LifeMap::iterator it = life2p->begin(); it!=life2p->end(); ++it) {
// When the else branch sets a var before it's used
AstVarScope* nodep = it->first;
if (it->second.firstSet()
&& nodep->user()==m_ifCount) { // And the if hit the same var
UINFO(4,"DUALBRANCH "<<nodep<<endl);
LifeMap::iterator iter = m_lifep->find(nodep);
if (iter != m_lifep->end()) {
checkRemoveAssign(&(iter->second));
iter->second.clearAssign();
} else {
m_lifep->insert(make_pair(nodep,LifeVarEntry(true)));
}
}
}
//lifeDump(m_lifep);
}
};
//######################################################################
// Life state, as a visitor of each AstNode
class LifeVisitor : public AstNVisitor {
private:
// STATE
LifeState* m_statep; // Current state
bool m_sideEffect; // Side effects discovered in assign RHS
//static int debug() { return 9; }
// LIFE MAP
// For each basic block, we'll make a new map of what variables that if/else is changing
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
LifeBlock* m_lifep; // Current active lifetime map for current scope
// METHODS
// VISITORS
virtual void visit(AstModule* nodep, AstNUser*) {
// Only track the top scopes, not lower level functions
if (nodep->isTop()) nodep->iterateChildren(*this);
}
virtual void visit(AstTopScope* nodep, AstNUser*) {
AstNode::userClearTree(); // userp() used on entire tree
AstNode::user2ClearTree(); // userp() used on entire tree
AstNode::user3ClearTree(); // userp() used on entire tree
AstNode::user4ClearTree(); // userp() used on entire tree
AstScope* scopep = nodep->scopep();
if (!scopep) nodep->v3fatalSrc("TopScope has no scope\n");
AstCFunc* evalp = NULL;
for (AstNode* searchp = scopep->blocksp(); searchp; searchp=searchp->nextp()) {
if (AstCFunc* funcp = searchp->castCFunc()) {
if (funcp->name() == "_eval") {
evalp = funcp;
break;
}
}
}
if (!evalp) nodep->v3fatalSrc("Top _eval entry function not found\n");
evalp->iterateChildren(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// Consumption/generation of a variable,
// it's used so can't elim assignment before this use.
@@ -191,44 +282,61 @@ private:
//
AstVarScope* vscp = nodep->varScopep();
if (!vscp) nodep->v3fatalSrc("Scope not assigned");
clearLastAssign(vscp);
if (nodep->lvalue()) {
m_lifep->complexAssign(vscp);
} else {
m_lifep->varUsageReplace(vscp, nodep); nodep=NULL;
}
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// Collect any used variables first, as lhs may also be on rhs
// Similar code in V3Dead
vluint64_t lastEdit = AstNode::editCountGbl(); // When it was last edited
m_sideEffect = false;
nodep->rhsp()->iterateAndNext(*this);
if (lastEdit != AstNode::editCountGbl()) {
// We changed something, try to constant propagate, but don't delete the
// assignment as we still need nodep to remain.
V3Const::constifyTree(nodep->rhsp());
}
// Has to be direct assignment without any EXTRACTing.
if (nodep->lhsp()->castVarRef()) {
if (nodep->lhsp()->castVarRef() && !m_sideEffect) {
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
if (!vscp) vscp->v3fatalSrc("Scope lost on variable");
setLast(vscp, nodep);
m_lifep->simpleAssign(vscp, nodep);
} else {
nodep->lhsp()->iterateAndNext(*this);
}
}
virtual void visit(AstAssignDly* nodep, AstNUser*) {
// Don't treat as normal assign; V3Life doesn't understand time sense
nodep->iterateChildren(*this);
}
//---- Track control flow changes
virtual void visit(AstNodeIf* nodep, AstNUser*) {
UINFO(4," IF "<<nodep<<endl);
// Condition is part of PREVIOUS block
nodep->condp()->iterateAndNext(*this);
LifeMap* prevLifeMapp = m_lifep;
LifeMap* ifLifep = new LifeMap;
LifeMap* elseLifep = new LifeMap;
LifeBlock* prevLifep = m_lifep;
LifeBlock* ifLifep = new LifeBlock (prevLifep, m_statep);
LifeBlock* elseLifep = new LifeBlock (prevLifep, m_statep);
{
m_lifep = ifLifep;
nodep->ifsp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
{
m_lifep = elseLifep;
nodep->elsesp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
UINFO(4," join "<<endl);
m_lifep = prevLifeMapp;
// Find sets on both flows
dualBranch (ifLifep, elseLifep);
m_lifep->dualBranch (ifLifep, elseLifep);
// For the next assignments, clear any variables that were read or written in the block
clearLifeFromSublife(ifLifep);
clearLifeFromSublife(elseLifep);
ifLifep->lifeToAbove();
elseLifep->lifeToAbove();
delete ifLifep;
delete elseLifep;
}
@@ -240,24 +348,25 @@ private:
// assignment in the body that's used in the cond. (And otherwise
// would because it only appears used after-the-fact. So, we model
// it as a IF statement, and just don't allow elimination of
// variables in the body.
LifeMap* prevLifeMapp = m_lifep;
LifeMap* condLifep = new LifeMap;
LifeMap* bodyLifep = new LifeMap;
// variables across the body.
LifeBlock* prevLifep = m_lifep;
LifeBlock* condLifep = new LifeBlock (prevLifep, m_statep);
LifeBlock* bodyLifep = new LifeBlock (prevLifep, m_statep);
{
m_lifep = condLifep;
nodep->precondsp()->iterateAndNext(*this);
nodep->condp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
{
m_lifep = bodyLifep;
nodep->bodysp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
UINFO(4," joinfor"<<endl);
m_lifep = prevLifeMapp;
// For the next assignments, clear any variables that were read or written in the block
clearLifeFromSublife(condLifep);
clearLifeFromSublife(bodyLifep);
condLifep->lifeToAbove();
bodyLifep->lifeToAbove();
delete condLifep;
delete bodyLifep;
}
@@ -265,8 +374,15 @@ private:
//UINFO(4," CCALL "<<nodep<<endl);
nodep->iterateChildren(*this);
// Enter the function and trace it
nodep->funcp()->accept(*this);
if (!nodep->funcp()->entryPoint()) { // else is non-inline or public function we optimize separately
nodep->funcp()->accept(*this);
}
}
virtual void visit(AstUCFunc* nodep, AstNUser*) {
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
nodep->iterateChildren(*this);
}
virtual void visit(AstVar*, AstNUser*) {} // Don't want varrefs under it
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
@@ -274,15 +390,60 @@ private:
public:
// CONSTRUCTORS
LifeVisitor(AstNetlist* nodep) {
m_ifCount = 1;
m_lifep = new LifeMap;
LifeVisitor(AstNode* nodep, LifeState* statep) {
UINFO(4," LifeVisitor on "<<nodep<<endl);
m_statep = statep;
m_sideEffect = false;
{
m_lifep = new LifeBlock (NULL, m_statep);
nodep->accept(*this);
delete m_lifep; m_lifep=NULL;
}
}
virtual ~LifeVisitor() {}
};
//######################################################################
class LifeTopVisitor : public AstNVisitor {
// Visit all top nodes searching for functions that are entry points we want to start
// finding code within.
private:
// STATE
LifeState* m_statep; // Current state
// VISITORS
virtual void visit(AstCFunc* nodep, AstNUser*) {
if (nodep->entryPoint()) {
// Usage model 1: Simulate all C code, doing lifetime analysis
LifeVisitor visitor (nodep, m_statep);
}
}
virtual void visit(AstAlways* nodep, AstNUser*) {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
}
virtual void visit(AstInitial* nodep, AstNUser*) {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
}
virtual void visit(AstFinal* nodep, AstNUser*) {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
}
virtual void visit(AstVar*, AstNUser*) {} // Accelerate
virtual void visit(AstNodeStmt*, AstNUser*) {} // Accelerate
virtual void visit(AstNodeMath*, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTRUCTORS
LifeTopVisitor(AstNetlist* nodep, LifeState* statep) {
m_statep = statep;
nodep->accept(*this);
delete m_lifep;
}
virtual ~LifeVisitor() {
V3Stats::addStat("Optimizations, Lifetime assign deletions", m_statAssnDel);
}
virtual ~LifeTopVisitor() {}
};
//######################################################################
@@ -290,6 +451,6 @@ public:
void V3Life::lifeAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
// Delete lifelicate assignments
LifeVisitor visitor (nodep);
LifeState state;
LifeTopVisitor visitor (nodep, &state);
}
+1 -1
View File
@@ -140,7 +140,7 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
AstVar* varp = oldvarp->cloneTree(false)->castVar();
newmodp->addStmtp(varp);
varp->sigPublic(true); // User needs to be able to get to it...
if (oldvarp->isInput() || oldvarp->isOutput()) {
if (oldvarp->isIO()) {
oldvarp->primaryIO(true);
varp->primaryIO(true);
}
+2 -2
View File
@@ -104,14 +104,14 @@ private:
nodep->v3error("Arrayed variables may not be inputs nor outputs");
}
if (m_ftaskp) nodep->funcLocal(true);
if (nodep && nodep->isSigPublic()) m_modp->modPublic(true); // Avoid flattening if signals are exposed
if (nodep->isSigPublic()) m_modp->modPublic(true); // Avoid flattening if signals are exposed
}
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
// VarRef: Resolve its reference
if (nodep->varp()) {
nodep->varp()->usedParam(true);
if (nodep->lvalue() && nodep->varp()->isInput()) {
if (nodep->lvalue() && nodep->varp()->isInOnly()) {
nodep->v3error("Assigning to input variable: "<<nodep->prettyName());
}
}
+4 -4
View File
@@ -62,7 +62,7 @@ private:
// "this" must be a element inside of *basep
// Use that to determine a structure offset, then apply to the new base
// to get our new pointer information
return (V3ListEnt*) ( ((uint8_t*)newbasep) + offset);
return (V3ListEnt*) ( ((vluint8_t*)newbasep) + offset);
}
public:
V3ListEnt()
@@ -78,7 +78,7 @@ public:
// METHODS
void pushBack (V3List<T>& listr, T newp) {
// "this" must be a element inside of *newp
uint32_t offset = (uint8_t*)(this) - (uint8_t*)(newp);
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
m_nextp = NULL;
if (!listr.m_headp) listr.m_headp = newp;
m_prevp = listr.m_tailp;
@@ -87,7 +87,7 @@ public:
}
void pushFront (V3List<T>& listr, T newp) {
// "this" must be a element inside of *newp
uint32_t offset = (uint8_t*)(this) - (uint8_t*)(newp);
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
m_nextp = listr.m_headp;
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = newp;
listr.m_headp = newp;
@@ -97,7 +97,7 @@ public:
// Unlink from side
void unlink (V3List<T>& listr, T oldp) {
// "this" must be a element inside of *oldp
uint32_t offset = (uint8_t*)(this) - (uint8_t*)(oldp);
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(oldp);
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = m_prevp;
else listr.m_tailp = m_prevp;
if (m_prevp) baseToListEnt(m_prevp,offset)->m_nextp = m_nextp;
-2
View File
@@ -115,9 +115,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
// Otherwise...
else if (!m_sized) {
width(32, false); // Says the spec.
#ifndef VL_UNSIGNED
if (unbased) isSigned(true); // Also says the spec.
#endif
}
// Ignore leading blanks
+3
View File
@@ -366,6 +366,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( onoff (sw, "-coverage-line", flag/*ref*/) ){ m_coverageLine = flag; }
else if ( onoff (sw, "-coverage-user", flag/*ref*/) ){ m_coverageUser = flag; }
else if ( onoff (sw, "-covsp", flag/*ref*/) ) { } // TBD
else if ( onoff (sw, "-debug-check", flag/*ref*/) ){ m_debugCheck = flag; }
else if ( onoff (sw, "-dump-tree", flag/*ref*/) ) { m_dumpTree = flag; }
else if ( onoff (sw, "-exe", flag/*ref*/) ) { m_exe = flag; }
else if ( onoff (sw, "-ignc", flag/*ref*/) ) { m_ignc = flag; }
@@ -557,6 +558,7 @@ V3Options::V3Options() {
m_coverageLine = false;
m_coverageUser = false;
m_debugCheck = false;
m_dumpTree = false;
m_exe = false;
m_ignc = false;
@@ -603,6 +605,7 @@ void V3Options::setDebugMode(int level) {
V3Error::debugDefault(level);
m_dumpTree = true;
m_stats = true;
m_debugCheck = true;
cout << "Starting "<<version()<<endl;
}
+4
View File
@@ -49,6 +49,7 @@ class V3Options {
bool m_assert; // main switch: --assert
bool m_coverageLine; // main switch: --coverage-block
bool m_coverageUser; // main switch: --coverage-func
bool m_debugCheck; // main switch: --debug-check
bool m_dumpTree; // main switch: --dump-tree
bool m_exe; // main switch: --exe
bool m_ignc; // main switch: --ignc
@@ -134,11 +135,13 @@ class V3Options {
bool coverage() const { return m_coverageUser || m_coverageLine; }
bool coverageLine() const { return m_coverageLine; }
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool dumpTree() const { return m_dumpTree; }
bool exe() const { return m_exe; }
bool trace() const { return m_trace; }
bool traceDups() const { return m_traceDups; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool pins64() const { return m_pins64; }
bool profileCFuncs() const { return m_profileCFuncs; }
bool psl() const { return m_psl; }
@@ -181,6 +184,7 @@ class V3Options {
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
void bin(const string& flag) { m_bin = flag; }
void parseOpts(FileLine* fl, int argc, char** argv);
void parseOptsList (FileLine* fl, int argc, char** argv);
void parseOptsFile (FileLine* fl, const string& filename);
+24 -24
View File
@@ -58,8 +58,9 @@ static void pslMoreNeeded(bool flag) { V3PreLex::s_currentLexp->m_pslMoreNeeded
%x ARGMODE
%x INCMODE
ws [ \t\r\f]
newline [\n]
ws [ \t\f\r]
wsn [ \t\f]
crnl [\r]*[\n]
quote [\"]
backslash [\\]
symb [a-zA-Z_][a-zA-Z0-9_$]*
@@ -68,7 +69,7 @@ psl [p]sl
/**************************************************************/
%%
<INITIAL>^{ws}*"`line"{ws}+.*{newline} { V3PreLex::s_currentLexp->lineDirective(yytext); }
<INITIAL>^{ws}*"`line"{ws}+.*{crnl} { V3PreLex::s_currentLexp->lineDirective(yytext); }
/* Special directives we recognise */
<INITIAL>"`include" { return(VP_INCLUDE); }
@@ -95,7 +96,7 @@ psl [p]sl
/* Pass-through strings */
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
<STRMODE><<EOF>> { linenoInc(); yyerror("EOF in unterminated string"); yyleng=0; yyterminate(); }
<STRMODE>{newline} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); }
<STRMODE>{crnl} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); }
<STRMODE>[^\"\\] { yymore(); }
<STRMODE>{backslash}. { yymore(); }
<STRMODE>{quote} { yy_pop_state();
@@ -104,28 +105,26 @@ psl [p]sl
/* Pass-through include <> filenames */
<INCMODE><<EOF>> { linenoInc(); yyerror("EOF in unterminated include filename"); yyleng=0; yyterminate(); }
<INCMODE>{newline} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); }
<INCMODE>{crnl} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); }
<INCMODE>[^\>\\] { yymore(); }
<INCMODE>{backslash}. { yymore(); }
<INCMODE>[\>] { yy_pop_state(); return (VP_STRING); }
/* Reading definition */
<DEFMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
<DEFMODE>"//"[^\n]* { return (VP_COMMENT);}
<DEFMODE>"//"[^\n\r]* { return (VP_COMMENT);}
<DEFMODE><<EOF>> { linenoInc(); yyerror("EOF (missing return?) in define value"); yyleng=0; yyterminate(); }
<DEFMODE>{newline} { linenoInc();
yy_pop_state();
return (VP_DEFVALUE); } /* Note contains a return */
<DEFMODE>[^\/\*\n\m\\]+ |
<DEFMODE>[\\][^\n] |
<DEFMODE>{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return (VP_DEFVALUE); }
<DEFMODE>[\\]{crnl} { linenoInc(); appendDefValue("\n",1); } /* Include return so can maintain output line count */
<DEFMODE>[^\/\*\n\r\\]+ |
<DEFMODE>[\\][^\n\r] |
<DEFMODE>. { appendDefValue(yytext,yyleng); }
<DEFMODE>[\\]\n { linenoInc(); appendDefValue("\n",1); }
/* Define arguments */
<ARGMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
<ARGMODE>"//"[^\n]* { return (VP_COMMENT);}
<ARGMODE>"//"[^\n\r]* { return (VP_COMMENT);}
<ARGMODE><<EOF>> { yyerror("EOF in define argument list\n"); yyleng = 0; yyterminate(); }
<ARGMODE>{newline} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); }
<ARGMODE>{crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); }
<ARGMODE>{quote} { yy_push_state(STRMODE); yymore(); }
<ARGMODE>[(] { V3PreLex::s_currentLexp->m_parenLevel++; appendDefValue(yytext,yyleng); }
<ARGMODE>[,)] { if (V3PreLex::s_currentLexp->m_parenLevel>1) {
@@ -134,26 +133,26 @@ psl [p]sl
} else {
unput(yytext[0]); yy_pop_state(); return (VP_DEFARG);
}}
<ARGMODE>[^\/\*\n\m\\(,)\"]+ |
<ARGMODE>[^\/\*\n\r\\(,)\"]+ |
<ARGMODE>. { appendDefValue(yytext,yyleng); }
/* One line comments. */
<INITIAL>"//"{ws}*{psl} { if (optPsl()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
else { yy_push_state(CMTONEM); yymore(); } }
<INITIAL>"//"{newline} { linenoInc(); yytext="\n"; yyleng=1; return (VP_WHITE); }
<INITIAL>"//"{ws}*{crnl} { linenoInc(); yytext="\n"; yyleng=1; return (VP_WHITE); }
<INITIAL>"//" { if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
else { yy_push_state(CMTONEM); yymore(); } }
<CMTONEM>[^\n]* { yy_pop_state(); return (VP_COMMENT); }
<CMTONEM>[^\n\r]* { yy_pop_state(); return (VP_COMMENT); }
/* Psl oneline comments */
<PSLONEM>[{(] { pslParenLevelInc(); return (VP_TEXT); }
<PSLONEM>[})] { pslParenLevelDec(); return (VP_TEXT); }
<PSLONEM>[;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); }
<PSLONEM><<EOF>> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
<PSLONEM>{newline} { linenoInc(); yy_pop_state(); return(VP_WHITE); }
<PSLONEM>{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); }
/* Completed psl oneline comments */
<PSLONEE>{newline} { linenoInc(); yy_pop_state(); return(VP_WHITE); }
<PSLONEE>{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); }
<PSLONEE>{ws}+ { yymore(); }
<PSLONEE>. { yyerror("Unexpected text following psl assertion\n"); }
@@ -163,24 +162,25 @@ psl [p]sl
<CMTBEGM>{psl} { yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); }
<CMTBEGM>{ws}+ { yymore(); }
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
<CMTBEGM,CMTMODE>{newline} { linenoInc(); yymore(); }
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
<CMTBEGM,CMTMODE><<EOF>> { yyerror("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
<CMTMODE>. { yymore(); }
/* Psl C-style comments. */
<PSLMUL1>.|{newline} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
<PSLMUL1>.|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
<PSLMULM>"*/" { yy_pop_state(); return(VP_COMMENT); }
<PSLMULM>"//"[^\n]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
<PSLMULM><<EOF>> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
/* Define calls */
<INITIAL,PSLMULM,PSLONEM>"`"{symb} { return (VP_DEFREF); }
/* Generics */
<INITIAL,PSLMULM>{newline} { linenoInc(); return(VP_WHITE); }
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
<INITIAL,PSLMULM,PSLONEM>{ws}+ { return (VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM>[\r] { }
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM>. { return (VP_TEXT); }
%%
+10 -8
View File
@@ -537,10 +537,12 @@ int V3PreProcImp::getRawToken() {
int tok = yylex();
if (debug()>4) {
char buf[10000]; strncpy(buf, yytext, yyleng); buf[yyleng] = '\0';
for (char* cp=buf; *cp; cp++) if (*cp=='\n') *cp='$';
string buf = string (yytext, yyleng);
string::size_type pos;
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
fprintf (stderr, "%d: RAW %d %d: %-10s: %s\n",
fileline()->lineno(), m_off, m_state, tokenName(tok), buf);
fileline()->lineno(), m_off, m_state, tokenName(tok), buf.c_str());
}
// On EOF, try to pop to upper level includes, as needed.
@@ -867,12 +869,12 @@ string V3PreProcImp::getline() {
while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n'))) {
int tok = getToken();
if (debug()>4) {
char buf[100000];
strncpy(buf, yytext, yyleng);
buf[yyleng] = '\0';
for (char* cp=buf; *cp; cp++) if (*cp=='\n') *cp='$';
string buf = string (yytext, yyleng);
string::size_type pos;
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
fprintf (stderr,"%d: GETFETC: %-10s: %s\n",
fileline()->lineno(), tokenName(tok), buf);
fileline()->lineno(), tokenName(tok), buf.c_str());
}
if (tok==VP_EOF) {
// Add a final newline, in case the user forgot the final \n.
+2
View File
@@ -79,6 +79,8 @@ protected:
ostream* osp;
if (v3Global.opt.preprocOnly()) {
osp = &cout;
} else if (!v3Global.opt.keepTempFiles()) { // Must match unlink rule in V3Read.cpp
osp = ofp = V3File::new_ofstream_nodepend(vppFilename);
} else {
osp = ofp = V3File::new_ofstream(vppFilename);
}
+4
View File
@@ -91,6 +91,10 @@ void V3Read::readFile(FileLine* fileline, const string& modfilename, bool inLibr
if (!v3Global.opt.preprocOnly()) {
lexFile (vppfilename, modfilename);
}
if (!v3Global.opt.keepTempFiles()) { // Must match new_ofstream_nodepend rule in V3PreShell.cpp
unlink (vppfilename.c_str());
}
}
void V3Read::lexFile(const string& vppfilename, const string& modname) {
-10
View File
@@ -284,9 +284,7 @@ private:
// VISITORS - defaults
virtual void visit(AstNodeMath* nodep, AstNUser*) {
#ifndef VL_UNSIGNED
nodep->v3fatalSrc("Visit function missing? Signedness unknown for this node: "<<nodep);
#endif
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
@@ -347,12 +345,6 @@ public:
class SignedRemoveVisitor : public AstNVisitor {
private:
// METHODS
void supportCheck(AstNode* nodep) {
#ifdef VL_UNSIGNED
if (nodep->isSigned()) nodep->v3error("Unsupported: signed numbers");
#endif
}
// VISITORS
virtual void visit(AstSigned* nodep, AstNUser*) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
@@ -362,13 +354,11 @@ private:
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
supportCheck(nodep);
}
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
nodep->replaceWith(newp);
newp->widthSignedFrom(nodep);
supportCheck(nodep);
pushDeletep(nodep); nodep=NULL;
}
public:
+1 -1
View File
@@ -36,7 +36,7 @@ public:
~V3Double0() {}
// Implicit conversion operators:
inline V3Double0 (const uint64_t v) : m_d(v) { };
inline V3Double0 (const vluint64_t v) : m_d(v) { };
inline operator const double () const { return m_d; };
// Explicit operators:
+153 -52
View File
@@ -19,10 +19,11 @@
//
//*************************************************************************
// V3Subst's Transformations:
//
//
// Each module:
// Search all ASSIGN(WORDSEL(...)) and build what it's assigned to
// Later usages of that word may then be replaced
// Later usages of that word may then be replaced as long as
// the RHS hasn't changed value.
//
//*************************************************************************
@@ -44,76 +45,97 @@
class SubstBaseVisitor : public AstNVisitor {
public:
static int debug() { return 0; }
static int debug() { return V3Error::debugDefault(); }
// static int debug() { return 9; }
};
//######################################################################
// Subst state, as a visitor of each AstNode
// Class for each word of a multi-word variable
class SubstVarWord {
protected:
// MEMBERS
AstNodeAssign* m_assignp; // Last assignment to each word of this var
int m_step; // Step number of last assignment
bool m_use; // True if each word was consumed
bool m_complex; // True if each word is complex
friend class SubstVarEntry;
// METHODS
void clear() {
m_assignp = NULL;
m_step = 0;
m_use = false;
m_complex = false;
}
};
//######################################################################
// Class for every variable we may process
class SubstVarEntry {
// MEMBERS
AstVar* m_varp; // Variable this tracks
bool m_complexAssign;// True if assigned multiple times or in complex mannor
AstNodeAssign* m_wholeAssignp; // Last assignment to entire array
bool m_wholeUse; // True if used as entire wide array
bool m_wordAssign; // True if any word assignments
bool m_wordUse; // True if any individual word usage
vector<AstNodeAssign*> m_wordAssignps; // Last assignment to each word of this var
vector<bool> m_wordUses; // True if each word was consumed
vector<bool> m_wordComplex; // True if each word is complex
SubstVarWord m_whole; // Data for whole vector used at once
vector<SubstVarWord> m_words; // Data for every word, if multi word variable
int debug() { return SubstBaseVisitor::debug(); }
public:
// CONSTRUCTORS
SubstVarEntry (AstVar* varp) { // Construction for when a var is used
m_varp = varp;
m_complexAssign = false;
m_wholeAssignp = NULL;
m_wholeUse = false;
m_whole.m_use = false;
m_wordAssign = false;
m_wordUse = false;
m_wordAssignps.resize(varp->widthWords());
m_wordUses.resize(varp->widthWords());
m_wordComplex.resize(varp->widthWords());
m_words.resize(varp->widthWords());
m_whole.clear();
for (int i=0; i<varp->widthWords(); i++) {
m_wordAssignps[i] = NULL;
m_wordUses[i] = false;
m_wordComplex[i] = false;
m_words[i].clear();
}
}
bool wordNumOk(int word) {
~SubstVarEntry() {}
private:
// METHODS
bool wordNumOk(int word) const {
return word < m_varp->widthWords();
}
AstNodeAssign* getWordAssignp(int word) {
AstNodeAssign* getWordAssignp(int word) const {
if (!wordNumOk(word)) return NULL;
else return m_wordAssignps[word];
else return m_words[word].m_assignp;
}
void assignWhole (AstNodeAssign* assp) {
if (m_wholeAssignp) m_complexAssign = true;
m_wholeAssignp = assp;
public:
void assignWhole (int step, AstNodeAssign* assp) {
if (m_whole.m_assignp) m_whole.m_complex = true;
m_whole.m_assignp = assp;
m_whole.m_step = step;
}
void assignWord (int word, AstNodeAssign* assp) {
if (!wordNumOk(word) || getWordAssignp(word) || m_wordComplex[word]) m_complexAssign = true;
void assignWord (int step, int word, AstNodeAssign* assp) {
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) m_whole.m_complex = true;
m_wordAssign = true;
if (wordNumOk(word)) m_wordAssignps[word] = assp;
if (wordNumOk(word)) {
m_words[word].m_assignp = assp;
m_words[word].m_step = step;
}
}
void assignWordComplex (int word) {
if (!wordNumOk(word) || getWordAssignp(word) || m_wordComplex[word]) m_complexAssign = true;
m_wordComplex[word] = true;
void assignWordComplex (int step, int word) {
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) m_whole.m_complex = true;
m_words[word].m_complex = true;
}
void assignComplex() {
m_complexAssign = true;
void assignComplex(int step) {
m_whole.m_complex = true;
}
void consumeWhole() { //==consumeComplex as we don't know the difference
m_wholeUse = true;
m_whole.m_use = true;
}
void consumeWord(int word) {
m_wordUses[word] = true;
m_words[word].m_use = true;
m_wordUse = true;
}
// ACCESSORS
AstNode* substWhole(AstNode* errp) {
if (!m_varp->isWide()
&& !m_complexAssign && m_wholeAssignp && !m_wordAssign) {
AstNodeAssign* assp = m_wholeAssignp;
&& !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
AstNodeAssign* assp = m_whole.m_assignp;
if (!assp) errp->v3fatalSrc("Reading whole that was never assigned");
return (assp->rhsp());
} else {
@@ -121,7 +143,7 @@ public:
}
}
AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for
if (!m_complexAssign && !m_wholeAssignp && !m_wordComplex[word]) {
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
AstNodeAssign* assp = getWordAssignp(word);
if (!assp) errp->v3fatalSrc("Reading a word that was never assigned, or bad word #");
return (assp->rhsp());
@@ -129,34 +151,90 @@ public:
return NULL;
}
}
int getWholeStep() const {
return m_whole.m_step;
}
int getWordStep(int word) const {
if (!wordNumOk(word)) return 0; else return m_words[word].m_step;
}
void deleteAssign (AstNodeAssign* nodep) {
UINFO(5, "Delete "<<nodep<<endl);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
void deleteUnusedAssign() {
// If there are unused assignments in this var, kill them
if (!m_wholeUse && !m_wordUse && m_wholeAssignp) {
deleteAssign (m_wholeAssignp); m_wholeAssignp=NULL;
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
deleteAssign (m_whole.m_assignp); m_whole.m_assignp=NULL;
}
for (unsigned i=0; i<m_wordUses.size(); i++) {
if (!m_wholeUse && !m_wordUses[i] && m_wordAssignps[i] && !m_wordComplex[i]) {
deleteAssign (m_wordAssignps[i]); m_wordAssignps[i]=NULL;
for (unsigned i=0; i<m_words.size(); i++) {
if (!m_whole.m_use && !m_words[i].m_use && m_words[i].m_assignp && !m_words[i].m_complex) {
deleteAssign (m_words[i].m_assignp); m_words[i].m_assignp=NULL;
}
}
}
};
//######################################################################
// See if any variables have changed value since we determined subst value, as a visitor of each AstNode
class SubstUseVisitor : public SubstBaseVisitor {
private:
// NODE STATE
// See SubstVisitor
//
// STATE
int m_origStep; // Step number where subst was recorded
bool m_ok; // No misassignments found
// METHODS
SubstVarEntry* findEntryp(AstVarRef* nodep) {
return (SubstVarEntry*)(nodep->varp()->userp()); // Might be NULL
}
// VISITORS
virtual void visit(AstVarRef* nodep, AstNUser*) {
SubstVarEntry* entryp = findEntryp (nodep);
if (entryp) {
// Don't sweat it. We assign a new temp variable for every new assignment,
// so there's no way we'd ever replace a old value.
} else {
// A simple variable; needs checking.
if (m_origStep < nodep->varp()->user2()) {
if (m_ok) UINFO(9," RHS variable changed since subst recorded: "<<nodep<<endl);
m_ok = false;
}
}
}
virtual void visit(AstConst* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
SubstUseVisitor(AstNode* nodep, int origStep) {
UINFO(9, " SubstUseVisitor "<<origStep<<" "<<nodep<<endl);
m_ok = true;
m_origStep = origStep;
nodep->accept(*this);
}
virtual ~SubstUseVisitor() {}
// METHODS
bool ok() const { return m_ok; }
};
//######################################################################
// Subst state, as a visitor of each AstNode
class SubstVisitor : public SubstBaseVisitor {
private:
// NODE STATE
// Passed to SubstElimVisitor
// Passed to SubstUseVisitor
// AstVar::userp -> SubstVar* for usage var, 0=not set yet
// AstVar::user2 -> int step number for last assignment, 0=not set yet
//
// STATE
vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
int m_ops; // Number of operators on assign rhs
int m_assignStep; // Assignment number to determine var lifetime
V3Double0 m_statSubsts; // Statistic tracking
enum { SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
@@ -178,6 +256,7 @@ private:
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
m_ops = 0;
m_assignStep++;
nodep->rhsp()->iterateAndNext(*this);
bool hit=false;
if (AstVarRef* varrefp = nodep->lhsp()->castVarRef()) {
@@ -186,10 +265,10 @@ private:
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
entryp->assignComplex();
entryp->assignComplex(m_assignStep);
} else {
UINFO(8," ASSIGNwhole "<<varrefp<<endl);
entryp->assignWhole(nodep);
entryp->assignWhole(m_assignStep, nodep);
}
}
}
@@ -202,10 +281,10 @@ private:
hit = true;
if (m_ops > SUBST_MAX_OPS_SUBST) {
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
entryp->assignWordComplex(word);
entryp->assignWordComplex(m_assignStep, word);
} else {
UINFO(8," ASSIGNword"<<word<<" "<<varrefp<<endl);
entryp->assignWord(word, nodep);
entryp->assignWord(m_assignStep, word, nodep);
}
}
}
@@ -238,7 +317,13 @@ private:
UINFO(8," USEword"<<word<<" "<<varrefp<<endl);
SubstVarEntry* entryp = getEntryp(varrefp);
if (AstNode* substp = entryp->substWord (nodep, word)) {
replaceSubstEtc(nodep, substp); nodep=NULL;
// Check that the RHS hasn't changed value since we recorded it.
SubstUseVisitor visitor (substp, entryp->getWordStep(word));
if (visitor.ok()) {
replaceSubstEtc(nodep, substp); nodep=NULL;
} else {
entryp->consumeWord(word);
}
} else {
entryp->consumeWord(word);
}
@@ -247,14 +332,27 @@ private:
}
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// Any variable
if (nodep->lvalue()) {
m_assignStep++;
nodep->varp()->user2(m_assignStep);
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
}
if (nodep->varp()->isStatementTemp()) {
SubstVarEntry* entryp = getEntryp (nodep);
if (nodep->lvalue()) {
UINFO(8," ASSIGNcpx "<<nodep<<endl);
entryp->assignComplex();
entryp->assignComplex(m_assignStep);
} else if (AstNode* substp = entryp->substWhole(nodep)) {
UINFO(8," USEwhole "<<nodep<<endl);
replaceSubstEtc(nodep, substp); nodep=NULL;
// Check that the RHS hasn't changed value since we recorded it.
SubstUseVisitor visitor (substp, entryp->getWholeStep());
if (visitor.ok()) {
UINFO(8," USEwhole "<<nodep<<endl);
replaceSubstEtc(nodep, substp); nodep=NULL;
} else {
UINFO(8," USEwholeButChg "<<nodep<<endl);
entryp->consumeWhole();
}
} else { // Consumed w/o substitute
UINFO(8," USEwtf "<<nodep<<endl);
entryp->consumeWhole();
@@ -262,6 +360,7 @@ private:
}
}
virtual void visit(AstVar* nodep, AstNUser*) {}
virtual void visit(AstConst* nodep, AstNUser*) {}
virtual void visit(AstNode* nodep, AstNUser*) {
m_ops++;
if (!nodep->isSubstOptimizable()) {
@@ -273,7 +372,9 @@ public:
// CONSTUCTORS
SubstVisitor(AstNode* nodep) {
AstNode::userClearTree(); // userp() used on entire tree
AstNode::user2ClearTree(); // user2p() used on entire tree
m_ops = 0;
m_assignStep = 0;
nodep->accept(*this);
}
virtual ~SubstVisitor() {
+311 -101
View File
@@ -39,6 +39,54 @@
#include "V3Inst.h"
#include "V3Ast.h"
#include "V3EmitCBase.h"
#include "V3Graph.h"
//######################################################################
// Graph subclasses
class TaskBaseVertex : public V3GraphVertex {
AstNode* m_impurep; // Node causing impure function w/ outside references
bool m_noInline; // Marked with pragma
public:
TaskBaseVertex(V3Graph* graphp)
: V3GraphVertex(graphp), m_impurep(NULL), m_noInline(false) {}
virtual ~TaskBaseVertex() {}
bool pure() const { return m_impurep==NULL; }
AstNode* impureNode() const { return m_impurep; }
void impure(AstNode* nodep) { m_impurep = nodep; }
bool noInline() const { return m_noInline; }
void noInline(bool flag) { m_noInline = flag; }
};
class TaskFTaskVertex : public TaskBaseVertex {
// Every task gets a vertex, and we link tasks together based on funcrefs.
AstNodeFTask* m_nodep;
public:
TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep)
: TaskBaseVertex(graphp), m_nodep(nodep) {}
virtual ~TaskFTaskVertex() {}
AstNodeFTask* nodep() const { return m_nodep; }
virtual string name() const { return nodep()->name(); }
virtual string dotColor() const { return pure() ? "black" : "red"; }
};
class TaskCodeVertex : public TaskBaseVertex {
// Top vertex for all calls not under another task
public:
TaskCodeVertex(V3Graph* graphp)
: TaskBaseVertex(graphp) {}
virtual ~TaskCodeVertex() {}
virtual string name() const { return "*CODE*"; }
virtual string dotColor() const { return "green"; }
};
class TaskEdge : public V3GraphEdge {
public:
TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top)
: V3GraphEdge(graphp, fromp, top, 1, false) {}
virtual ~TaskEdge() {}
virtual string dotLabel() const { return "w"+cvtToStr(weight()); }
};
//######################################################################
@@ -47,12 +95,17 @@ private:
// NODE STATE
// Output:
// AstNodeFTask::user3p // AstScope* this FTask is under
// AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under
// AstVar::user4p // GraphFTaskVertex* this variable is declared in
// TYPES
typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap;
// MEMBERS
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
AstAssignW* m_assignwp; // Current assignment
V3Graph m_callGraph; // Task call graph
TaskBaseVertex* m_curVxp; // Current vertex we're adding to
public:
// METHODS
AstScope* getScope(AstNodeFTask* nodep) {
@@ -65,7 +118,30 @@ public:
if (iter == m_varToScopeMap.end()) nodep->v3fatalSrc("No scope for var");
return iter->second;
}
bool ftaskNoInline(AstNodeFTask* nodep) {
return (getFTaskVertex(nodep)->noInline());
}
void checkPurity(AstNodeFTask* nodep) {
checkPurity(nodep, getFTaskVertex(nodep));
}
void checkPurity(AstNodeFTask* nodep, TaskBaseVertex* vxp) {
if (!vxp->pure()) {
nodep->v3warn(IMPURE,"Unsupported: External variable referenced by non-inlined function/task: "<<nodep->prettyName());
vxp->impureNode()->v3warn(IMPURE,"... Location of the external reference: "<<vxp->impureNode()->prettyName());
}
// And, we need to check all tasks this task calls
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep=edgep->outNextp()) {
checkPurity(nodep, static_cast<TaskBaseVertex*>(edgep->top()));
}
}
private:
TaskBaseVertex* getFTaskVertex(AstNodeFTask* nodep) {
if (!nodep->user4p()) {
nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
}
return static_cast<TaskBaseVertex*>(nodep->user4p()->castGraphVertex());
}
// VISITORS
virtual void visit(AstScope* nodep, AstNUser*) {
// Each FTask is unique per-scope, so AstNodeFTaskRefs do not need
@@ -90,7 +166,7 @@ private:
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
m_assignwp = nodep;
nodep->iterateChildren(*this); // May delete nodep.
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
m_assignwp = NULL;
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
@@ -104,6 +180,37 @@ private:
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
}
// We make multiple edges if a task is called multiple times from another task.
new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp()));
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
UINFO(9," TASK "<<nodep<<endl);
TaskBaseVertex* lastVxp = m_curVxp;
m_curVxp = getFTaskVertex(nodep);
nodep->iterateChildren(*this);
m_curVxp = lastVxp;
}
virtual void visit(AstPragma* nodep, AstNUser*) {
if (nodep->pragType() == AstPragmaType::NO_INLINE_TASK) {
// Just mark for the next steps, and we're done with it.
m_curVxp->noInline(true);
nodep->unlinkFrBack()->deleteTree();
}
else {
nodep->iterateChildren(*this);
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
nodep->user4p(m_curVxp); // Remember what task it's under
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->varp()->user4p() != m_curVxp) {
if (m_curVxp->pure()) {
m_curVxp->impure(nodep);
}
}
}
//--------------------
// Default: Just iterate
@@ -112,10 +219,16 @@ private:
}
public:
// CONSTUCTORS
TaskStateVisitor(AstNode* nodep) {
TaskStateVisitor(AstNetlist* nodep) {
m_assignwp = NULL;
m_curVxp = new TaskCodeVertex(&m_callGraph);
AstNode::user3ClearTree();
AstNode::user4ClearTree();
//
nodep->iterateAndNext(*this, NULL);
//
m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue);
m_callGraph.dumpDotFilePrefixed("task_call");
}
virtual ~TaskStateVisitor() {}
};
@@ -165,6 +278,7 @@ private:
// AstNodeFTask::user // True if its been expanded
// Each funccall
// AstVar::user2p // AstVarScope* to replace varref with
// AstNodeFTask::user5p // AstCFunc* created for non-inlined tasks
// TYPES
enum InsertMode {
@@ -207,73 +321,81 @@ private:
//
// Create input variables
AstNode::user2ClearTree();
AstNode* pinp = refp->pinsp();
AstNode* nextpinp = pinp;
AstNode* nextstmtp;
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
nextstmtp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
portp->unlinkFrBack(); // Remove it from the clone (not original)
pushDeletep(portp);
if (portp->isIO()) {
if (pinp==NULL) {
refp->v3error("Too few arguments in function call");
pinp = new AstConst(refp->fileline(), 0);
m_modp->addStmtp(pinp); // For below unlink
}
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
//
nextpinp = pinp->nextp();
pinp->unlinkFrBack(); // Relinked to assignment below
//
if (portp->isTristate()) {
refp->v3error("Unsupported: Inouts in functions/tasks");
}
else if (portp->isOutput() && outvscp) {
refp->v3error("Outputs not allowed in function declarations");
}
else if (portp->isOutput()) {
// Make output variables
// Correct lvalue; we didn't know when we linked
if (AstVarRef* varrefp = pinp->castVarRef()) {
varrefp->lvalue(true);
} else {
pinp->v3error("Unsupported: Task output pin connected to non-variable");
{
AstNode* pinp = refp->pinsp();
AstNode* nextpinp = pinp;
AstNode* nextstmtp;
for (AstNode* stmtp = newbodysp; stmtp; pinp=nextpinp, stmtp=nextstmtp) {
nextstmtp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
portp->unlinkFrBack(); // Remove it from the clone (not original)
pushDeletep(portp);
if (portp->isIO()) {
if (pinp==NULL) {
refp->v3error("Too few arguments in function call");
pinp = new AstConst(refp->fileline(), 0);
m_modp->addStmtp(pinp); // For below unlink
}
// Even if it's referencing a varref, we still make a temporary
// Else task(x,x,x) might produce incorrect results
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(outvscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
pinp,
new AstVarRef(outvscp->fileline(), outvscp, false));
// Put assignment BEHIND of all other statements
beginp->addNext(assp);
}
else if (portp->isInput()) {
// Make input variable
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(inVscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
new AstVarRef(inVscp->fileline(), inVscp, true),
pinp);
// Put assignment in FRONT of all other statements
if (AstNode* afterp = beginp->nextp()) {
afterp->unlinkFrBackWithNext();
assp->addNext(afterp);
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
//
nextpinp = pinp->nextp();
pinp->unlinkFrBack(); // Relinked to assignment below
//
if (portp->isInout()) {
if (AstVarRef* varrefp = pinp->castVarRef()) {
// Connect to this exact variable
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
portp->user2p(localVscp);
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
}
}
else if (portp->isOutput() && outvscp) {
refp->v3error("Outputs not allowed in function declarations");
}
else if (portp->isOutput()) {
// Make output variables
// Correct lvalue; we didn't know when we linked
if (AstVarRef* varrefp = pinp->castVarRef()) {
varrefp->lvalue(true);
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Task output pin connected to non-variable");
}
// Even if it's referencing a varref, we still make a temporary
// Else task(x,x,x) might produce incorrect results
AstVarScope* outvscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(outvscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
pinp,
new AstVarRef(outvscp->fileline(), outvscp, false));
// Put assignment BEHIND of all other statements
beginp->addNext(assp);
}
else if (portp->isInput()) {
// Make input variable
AstVarScope* inVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(inVscp);
AstAssign* assp = new AstAssign (pinp->fileline(),
new AstVarRef(inVscp->fileline(), inVscp, true),
pinp);
// Put assignment in FRONT of all other statements
if (AstNode* afterp = beginp->nextp()) {
afterp->unlinkFrBackWithNext();
assp->addNext(afterp);
}
beginp->addNext(assp);
}
beginp->addNext(assp);
}
}
else { // Var is not I/O
// Move it to a new localized variable
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(localVscp);
else { // Var is not I/O
// Move it to a new localized variable
AstVarScope* localVscp = createVarScope (portp, namePrefix+"__"+portp->shortName());
portp->user2p(localVscp);
}
}
}
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
}
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
// Create function output variables
if (outvscp) {
//UINFO(0, "setflag on "<<funcp->fvarp()<<" to "<<outvscp<<endl);
@@ -286,9 +408,71 @@ private:
return beginp;
}
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
// outvscp is the variable for functions only, if NULL, it's a task
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?");
AstCFunc* cfuncp = refp->taskp()->user5p()->castNode()->castCFunc();
AstCFunc* makeUserFunc(AstNodeFTask* nodep) {
// Given a already cloned node, make a public C function.
if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?");
//
AstNode* beginp = new AstComment(refp->fileline(), (string)("Function: ")+refp->name());
AstCCall* ccallp = new AstCCall(refp->fileline(), cfuncp, NULL);
beginp->addNext(ccallp);
// Convert complicated outputs to temp signals
{
AstNode* pinp = refp->pinsp();
AstNode* nextpinp = pinp;
AstNode* nextstmtp;
for (AstNode* stmtp = refp->taskp()->stmtsp(); stmtp; pinp=nextpinp, stmtp=nextstmtp) {
nextstmtp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()) {
UINFO(9, " Port "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
//
nextpinp = pinp->nextp();
//
if (portp->isInout()) {
if (pinp->castVarRef()) {
// Connect to this exact variable
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Function/task input argument is not simple variable");
}
}
else if (portp->isOutput()) {
// Make output variables
// Correct lvalue; we didn't know when we linked
if (AstVarRef* varrefp = pinp->castVarRef()) {
varrefp->lvalue(true);
} else {
pinp->v3warn(TASKNSVAR,"Unsupported: Task output pin connected to non-variable");
}
}
}
}
}
if (pinp!=NULL) refp->v3error("Too many arguments in function call");
}
// First argument is symbol table, then output if a function
ccallp->argTypes("vlSymsp");
if (outvscp) {
ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true));
}
// Create connections
AstNode* nextpinp;
for (AstNode* pinp = refp->pinsp(); pinp; pinp=nextpinp) {
nextpinp = pinp->nextp();
// Move pin to the CCall
pinp->unlinkFrBack();
ccallp->addArgsp(pinp);
}
if (debug()>=9) { beginp->dumpTree(cout,"-nitask: "); }
return beginp;
}
AstCFunc* makeUserFunc(AstNodeFTask* nodep, bool forUser) {
// Given a already cloned node, make a public C function, or a non-inline C function
// Probably some of this work should be done later, but...
// should the type of the function be bool/uint32/64 etc (based on lookup) or IData?
AstNode::user2ClearTree();
@@ -298,7 +482,8 @@ private:
AstVar* portp = NULL;
if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) {
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
if (portp->isWide()) nodep->v3error("Unsupported: Public functions/tasks with inputs or outputs > 64 bits wide.");
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
if (!forUser) portp->funcReturn(false); // Converting return to 'outputs'
portp->unlinkFrBack();
rtnvarp = portp;
rtnvarp->funcLocal(true);
@@ -309,19 +494,28 @@ private:
nodep->v3fatalSrc("function without function output variable");
}
}
AstCFunc* funcp = new AstCFunc(nodep->fileline(), nodep->name(),
m_scopep,
(rtnvarp?rtnvarp->cType():""));
if (rtnvarp) funcp->addArgsp(rtnvarp);
funcp->dontCombine(true);
funcp->funcPublic(true);
funcp->isStatic(false);
AstCFunc* cfuncp = new AstCFunc(nodep->fileline(),
string(forUser?"":"__VnoInFunc_") + nodep->name(),
m_scopep,
((forUser && rtnvarp)?rtnvarp->cType():""));
cfuncp->dontCombine(true);
cfuncp->entryPoint(true);
cfuncp->funcPublic(forUser);
cfuncp->isStatic(!forUser);
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
funcp->addInitsp(
new AstCStmt(nodep->fileline(),
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
if (forUser) {
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
cfuncp->addInitsp(
new AstCStmt(nodep->fileline(),
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
} else {
// Need symbol table
cfuncp->argTypes(EmitCBaseVisitor::symClassVar());
}
// Fake output variable if was a function
if (rtnvarp) cfuncp->addArgsp(rtnvarp);
cfuncp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
// Create list of arguments and move to function
for (AstNode* nextp, *stmtp = nodep->stmtsp(); stmtp; stmtp=nextp) {
@@ -331,12 +525,7 @@ private:
// Move it to new function
portp->unlinkFrBack();
portp->funcLocal(true);
funcp->addArgsp(portp);
if (portp->isWide()) {
// As we don't want to export our WData arrays to users,
// and casting to sc_bv's is ugly, we'll just...
nodep->v3error("Unsupported: Public functions/tasks with inputs or outputs > 64 bits wide.");
}
cfuncp->addArgsp(portp);
} else {
// "Normal" variable, mark inside function
portp->funcLocal(true);
@@ -348,18 +537,19 @@ private:
}
// Move body
AstNode* bodysp = nodep->stmtsp();
if (bodysp) { bodysp->unlinkFrBackWithNext(); funcp->addStmtsp(bodysp); }
if (bodysp) { bodysp->unlinkFrBackWithNext(); cfuncp->addStmtsp(bodysp); }
// Return statement
if (rtnvscp) {
funcp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
if (rtnvscp && forUser) {
cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(),
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
}
// Replace variable refs
TaskRelinkVisitor visit (funcp);
TaskRelinkVisitor visit (cfuncp);
// Delete rest of cloned task and return new func
pushDeletep(nodep); nodep=NULL;
if (debug()>=9) { funcp->dumpTree(cout,"-userFunc: "); }
return funcp;
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
if (debug()>=9 && !forUser) { cfuncp->dumpTree(cout,"-noInFunc: "); }
return cfuncp;
}
void iterateIntoFTask(AstNodeFTask* nodep) {
@@ -419,7 +609,12 @@ private:
if (debug()>=9) { nodep->dumpTree(cout,"-inltask:"); }
// Create cloned statements
string namePrefix = "__Vtask_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
AstNode* beginp = createInlinedFTask(nodep, namePrefix, NULL);
AstNode* beginp;
if (m_statep->ftaskNoInline(nodep->taskp())) {
beginp = createNonInlinedFTask(nodep, namePrefix, NULL);
} else {
beginp = createInlinedFTask(nodep, namePrefix, NULL);
}
// Replace the ref
nodep->replaceWith(beginp);
nodep->deleteTree(); nodep=NULL;
@@ -440,7 +635,13 @@ private:
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
AstNode* beginp = createInlinedFTask(nodep, namePrefix, outvscp);
AstNode* beginp;
if (m_statep->ftaskNoInline(nodep->taskp())) {
// This may share VarScope's with a public task, if any. Yuk.
beginp = createNonInlinedFTask(nodep, namePrefix, outvscp);
} else {
beginp = createInlinedFTask(nodep, namePrefix, outvscp);
}
// Replace the ref
AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false);
nodep->replaceWith(outrefp);
@@ -448,27 +649,34 @@ private:
insertBeforeStmt(nodep, beginp);
// Cleanup
nodep->deleteTree(); nodep=NULL;
UINFO(4," Done.\n");
UINFO(4," Func REF Done.\n");
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
UINFO(4," Inline "<<nodep<<endl);
InsertMode prevInsMode = m_insMode;
AstNode* prevInsStmtp = m_insStmtp;
m_insMode = IM_BEFORE;
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
if (!nodep->user()) {
// Expand functions in it & Mark for later delete
// Expand functions in it
nodep->user(true);
if (!nodep->taskPublic()) {
nodep->unlinkFrBack();
} else {
if (nodep->taskPublic()) {
// Clone it first, because we may have later FTaskRef's that still need
// the original version.
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
AstCFunc* cfuncp = makeUserFunc(clonedFuncp);
// Replace it
nodep->replaceWith(cfuncp);
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, true);
nodep->addNextHere(cfuncp);
iterateIntoFTask(clonedFuncp); // Do the clone too
}
if (m_statep->ftaskNoInline(nodep)) {
m_statep->checkPurity(nodep);
AstNodeFTask* clonedFuncp = nodep->cloneTree(false)->castNodeFTask();
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false);
nodep->user5p(cfuncp);
nodep->addNextHere(cfuncp);
iterateIntoFTask(clonedFuncp); // Do the clone too
}
// Any variables inside the function still have varscopes pointing to them.
// We're going to delete the vars, so delete the varscopes.
if (nodep->castFunc()) {
@@ -487,6 +695,7 @@ private:
}
}
// Just push, as other references to func may remain until visitor exits
nodep->unlinkFrBack();
pushDeletep(nodep); nodep=NULL;
}
m_insMode = prevInsMode;
@@ -530,6 +739,7 @@ public:
m_scopep = NULL;
m_insStmtp = NULL;
AstNode::userClearTree();
AstNode::user5ClearTree();
nodep->accept(*this);
}
virtual ~TaskVisitor() {}
+2 -2
View File
@@ -298,9 +298,9 @@ private:
initp = NULL; if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
// Grab assignment
AstNode* incp = NULL; // Should be last statement
for (incp = nodep->bodysp(); incp->nextp(); incp = incp->nextp()) {}
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
if (incp) V3Const::constifyTree(incp);
for (incp = nodep->bodysp(); incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
// And check it
if (forUnrollCheck(nodep, initp,
nodep->precondsp(), nodep->condp(),
+10
View File
@@ -248,7 +248,13 @@ void process () {
V3Case::caseAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));
// Push constants across variables and remove redundant assignments
V3Const::constifyAll(v3Global.rootp());
if (v3Global.opt.oLife()) {
V3Life::lifeAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
}
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
// Make large low-fanin logic blocks into lookup tables
@@ -327,7 +333,9 @@ void process () {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clock.tree"));
// Cleanup any dly vars or other temps that are simple assignments
// Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
if (v3Global.opt.oLife()) {
V3Const::constifyAll(v3Global.rootp());
V3Life::lifeAll(v3Global.rootp());
}
if (v3Global.opt.oLifePost()) {
@@ -459,9 +467,11 @@ int main(int argc, char** argv, char** env) {
srand( (int) randseed);
// Preprocessor
// Before command parsing so we can handle -Ds on command line.
V3PreShell::boot(env);
// Command option parsing
v3Global.opt.bin(argv[0]);
string argString = V3Options::argString(argc-1, argv+1);
v3Global.opt.parseOpts(new FileLine("COMMAND_LINE",0), argc-1, argv+1);
if (v3Global.opt.coverage() && !v3Global.opt.systemPerl()) {
+13 -10
View File
@@ -324,6 +324,7 @@ sub tree_line {
match_func => "match_${type}_${n}",
match_if => $mif,
exec_func => $exec_func,
uinfo_level => ($to =~ /^!/ ? 0:7),
};
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
push @{$self->{treeop}{$type}}, $typefunc;
@@ -373,8 +374,11 @@ sub _exec_new_recurse {
sub treeop_exec_func {
my $self = shift;
my $func = shift;
my $out = "";
$func =~ s/^!//;
if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call
$func =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
$out .= $outl;
}
elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) {
@@ -419,23 +423,22 @@ sub treeop_exec_func {
$_Exec_Nsyms = 0;
_exec_syms_recurse($aref);
$func = "";
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
my $argnp = $_Exec_Syms{$sym};
my $arg = add_nodep($sym);
$func .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
}
$func .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
$func .= "nodep->replaceWith(newp);";
$func .= "nodep->deleteTree(); nodep=NULL;";
#print "FF $func\n" if $Debug;
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
$out .= "nodep->replaceWith(newp);";
$out .= "nodep->deleteTree(); nodep=NULL;";
#print "FF $out\n" if $Debug;
} elsif ($func eq "NEVER") {
$func = "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
} else {
$self->error("Unknown execution function format: $func\n");
}
return $func;
return $out;
}
sub tree_match {
@@ -448,7 +451,7 @@ sub tree_match {
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
"\t// $typefunc->{comment}\n",);
$self->print( "\tif ($typefunc->{match_if}) {\n");
$self->print( "\t UINFO(7,(void*)(nodep)<<\" $typefunc->{uinfo}\\n\");\n");
$self->print( "\t UINFO($typefunc->{uinfo_level},(void*)(nodep)<<\" $typefunc->{uinfo}\\n\");\n");
$self->print( "\t $typefunc->{exec_func};\n");
$self->print( "\t return true;\n");
$self->print( "\t}\n");
+1 -1
View File
@@ -24,7 +24,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.602 09/11/2006"
#define DTVERSION "Verilator 3.622 10/17/2006"
//**********************************************************************
//**** Functions
+1
View File
@@ -429,6 +429,7 @@ escid \\[^ \t\f\r\n]+
<VLG,PSL>"/*verilator full_case*/" {yylval.fileline = CRELINE(); return yVL_FULL_CASE;}
<VLG,PSL>"/*verilator inline_module*/" {yylval.fileline = CRELINE(); return yVL_INLINE_MODULE;}
<VLG,PSL>"/*verilator no_inline_module*/" {yylval.fileline = CRELINE(); return yVL_NO_INLINE_MODULE;}
<VLG,PSL>"/*verilator no_inline_task*/" {yylval.fileline = CRELINE(); return yVL_NO_INLINE_TASK;}
<VLG,PSL>"/*verilator one_cold*/" {yylval.fileline = CRELINE(); return yVL_ONE_COLD;}
<VLG,PSL>"/*verilator one_hot*/" {yylval.fileline = CRELINE(); return yVL_ONE_HOT;}
<VLG,PSL>"/*verilator parallel_case*/" {yylval.fileline = CRELINE(); return yVL_PARALLEL_CASE;}
+6 -6
View File
@@ -168,6 +168,7 @@ class AstSenTree;
%token<fileline> yVL_FULL_CASE "/*verilator full_case*/"
%token<fileline> yVL_INLINE_MODULE "/*verilator inline_module*/"
%token<fileline> yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/"
%token<fileline> yVL_NO_INLINE_TASK "/*verilator no_inline_task*/"
%token<fileline> yVL_ONE_COLD "/*verilator one_cold*/"
%token<fileline> yVL_ONE_HOT "/*verilator one_hot*/"
%token<fileline> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
@@ -627,11 +628,11 @@ senList: senitem { $$ = $1; }
;
senitem: senitemEdge { $$ = $1; }
| idVarRef ignoreRangeE { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); }
| idVarXRef ignoreRangeE { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); }
;
senitemEdge: yPOSEDGE idVarRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); }
| yNEGEDGE idVarRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); }
senitemEdge: yPOSEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); }
| yNEGEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); }
;
ignoreRangeE: /* empty */ { $$ = NULL; } /* ignored */
@@ -729,7 +730,8 @@ funcVarList: funcVar { $$ = $1; }
funcVar: ioDecl { $$ = $1; }
| varDecl { $$ = $1; }
| yVL_PUBLIC { $$ = new AstPragma ($1,AstPragmaType::PUBLIC_TASK); }
| yVL_PUBLIC { $$ = new AstPragma($1,AstPragmaType::PUBLIC_TASK); }
| yVL_NO_INLINE_TASK { $$ = new AstPragma($1,AstPragmaType::NO_INLINE_TASK); }
;
constExpr: expr { $$ = $1; }
@@ -1086,9 +1088,7 @@ AstVar* V3Parse::createVariable(FileLine* fileline, string name, AstRange* array
rangep->cloneTree(false),
arrayp);
nodep->isSigned(V3Parse::s_varSigned);
#ifndef VL_UNSIGNED
if (type == AstVarType::INTEGER) nodep->isSigned(true);
#endif
if (V3Parse::s_varDecl != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varDecl);
if (V3Parse::s_varIO != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varIO);
+5 -3
View File
@@ -17,6 +17,8 @@ VERILATOR_ROOT := $(shell pwd)/..
export VERILATOR_ROOT
PWD := $(shell pwd)
PERL = perl
DEBUG_ON = --debug --trace-dups
#DEBUG = $(DEBUG_ON)
VALGRIND_ON = $(DEBUG_ON) --gdb "valgrind -v --leak-check=yes"
@@ -31,11 +33,11 @@ VERILATOR_FLAGS = --cc -f $(PWD)/../test_v/input.vc top.v
#VERILATOR_FLAGS += --trace
prep:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG) $(VERILATOR_FLAGS)
prep_dbg:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
prep_vg:
perl $(VERILATOR_ROOT)/bin/verilator $(VALGRIND_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VALGRIND_ON) $(VERILATOR_FLAGS)
compile:
cd obj_dir ; $(MAKE) -j 3 -f ../Makefile_obj
+2 -2
View File
@@ -20,8 +20,8 @@ include Vtop.mk
CPPFLAGS += -DVL_DEBUG=1
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
CPPFLAGS += -DVL_THREADED=1
CPPFLAGS += -W
CPPFLAGS += -Werror
CPPFLAGS += -W -Werror -Wall
#CPPFLAGS += -Wno-unused-variable # Instead, add VL_ATTR_UNUSED in gen'ed code
#CPPFLAGS += -pedantic-errors
endif
+19 -10
View File
@@ -187,7 +187,7 @@ sub new {
make_top_shell => 1, # Make a default __top.v file
make_main => 1, # Make __main.cpp
# All compilers
v_flags => [split(/\s+/," -f input.vc")],
v_flags => [split(/\s+/," -f input.vc --debug-check")],
v_flags2 => [], # Overridden in some sim files
v_other_filenames => [], # After the filename so we can spec multiple files
# VCS
@@ -253,7 +253,7 @@ sub read {
sub write_status {
my $self = shift;
my $filename = $self->{status_filename};
my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,";
my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,";
print $fh Dumper($self);
print $fh "1;";
$fh->close();
@@ -373,7 +373,7 @@ sub execute {
my %param = (%{$self}, @_); # Default arguments are from $self
$self->oprint("Run\n");
if ($param{vcs}) {
#my $fh = IO::File->new("simv.key","w") or die "%Error: $! simv.key,";
#my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,";
#$fh->print("quit\n"); $fh->close;
$self->_run(logfile=>"obj_dir/".$self->{name}."_simv.log",
cmd=>["./simv",],
@@ -462,7 +462,7 @@ sub _run {
sleep 1 if ($try!=7);
my $moretry = $try!=0;
my $fh = IO::File->new($param{logfile},"r");
my $fh = IO::File->new("<$param{logfile}");
next if !$fh && $moretry;
local $/; undef $/;
my $wholefile = <$fh>;
@@ -508,7 +508,7 @@ sub _make_main {
$self->_read_inputs();
my $filename = "obj_dir/$self->{VM_PREFIX}__main.cpp";
my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,";
my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,";
my $VM_PREFIX = $self->{VM_PREFIX};
print $fh "#include \"$VM_PREFIX.h\"\n";
@@ -587,7 +587,7 @@ sub _make_top {
$self->_read_inputs();
my $fh = IO::File->new($self->{top_shell_filename},"w") or die "%Error: $! $self->{top_shell_filename},";
my $fh = IO::File->new(">$self->{top_shell_filename}") or die "%Error: $! $self->{top_shell_filename},";
print $fh "module top;\n";
foreach my $inp (sort (keys %{$self->{inputs}})) {
print $fh " reg ${inp};\n";
@@ -640,7 +640,7 @@ sub _read_inputs {
my $self = shift;
my $filename = $self->{top_filename};
$filename = "t/$filename" if !-r $filename;
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
while (defined(my $line = $fh->getline)) {
if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
$self->{inputs}{$1} = $1;
@@ -673,8 +673,8 @@ sub verilator_version {
sub files_identical {
my $fn1 = shift;
my $fn2 = shift;
my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,";
my $f2 = IO::File->new ($fn2) or die "%Error: $! $fn2,";
my $f1 = IO::File->new ("<$fn1"); if (!$f1) { warn "%Error: $! $fn1\n"; return 0; }
my $f2 = IO::File->new ("<$fn2"); if (!$f2) { warn "%Error: $! $fn2\n"; return 0; }
my @l1 = $f1->getlines();
my @l2 = $f2->getlines();
my $nl = $#l1; $nl = $#l2 if ($#l2 > $nl);
@@ -720,7 +720,7 @@ sub file_contents {
my $filename = shift;
if (!$_File_Contents_Cache{$filename}) {
my $fh = IO::File->new($filename,"r");
my $fh = IO::File->new("<$filename");
if (!$fh) {
$_File_Contents_Cache{$filename} = "_Already_Errored_";
$self->error("File_grep file not found: ".$filename."\n");
@@ -735,6 +735,15 @@ sub file_contents {
return $_File_Contents_Cache{$filename};
}
sub write_wholefile {
my $self = (ref $_[0]? shift : $Last_Self);
my $filename = shift;
my $contents = shift;
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename,";
print $fh $contents;
$fh->close;
}
#######################################################################
#######################################################################
#######################################################################
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# 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
# General Public License or the Perl Artistic License.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+109
View File
@@ -0,0 +1,109 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc; initial cyc=0;
reg [63:0] crc;
reg [63:0] sum;
reg out1;
sub sub (.in(crc[23:0]), .out1(out1));
always @ (posedge clk) begin
$write("[%0t] cyc==%0d crc=%x sum=%x out=%x\n",$time, cyc, crc, sum, out1);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {63'h0,out1};
if (cyc==1) begin
// Setup
crc <= 64'h00000000_00000097;
sum <= 64'h0;
end
else if (cyc==90) begin
if (sum != 64'h2e5cb972eb02b8a0) $stop;
end
else if (cyc==91) begin
end
else if (cyc==92) begin
end
else if (cyc==93) begin
end
else if (cyc==94) begin
end
else if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub (/*AUTOARG*/
// Outputs
out1,
// Inputs
in
);
input [23:0] in;
output reg [0:0] out1;
parameter [1023:0] RANDOM = 1024'b101011010100011011100111101001000000101000001111111111100110000110011011010110011101000100110000110101111101000111100100010111001001110001010101000111000100010000010011100001100011110110110000101100011111000110111110010110011000011111111010101110001101010010001111110111100000110111101100110101110001110110000010000110101110111001111001100001101110001011100111001001110101001010000110101010100101111000010000010110100101110100110000110110101000100011101111100011000110011001100010010011001101100100101110010100110101001110011111110010000111001111000010001101100101101110111110001000010110010011100101001011111110011010110111110000110010011110001110110011010011010110011011111001110100010110100011100001011000101111000010011111010111001110110011101110101011111001100011000101000001000100111110010100111011101010101011001101000100000101111110010011010011010001111010001110000110010100011110110011001010000011001010010110111101010010011111111010001000101100010100100010011001100110000111111000001000000001001111101110000100101;
always @* begin
casez (in[17:16])
2'b00: casez (in[2:0])
3'h0: out1[0] = in[0]^RANDOM[0];
3'h1: out1[0] = in[0]^RANDOM[1];
3'h2: out1[0] = in[0]^RANDOM[2];
3'h3: out1[0] = in[0]^RANDOM[3];
3'h4: out1[0] = in[0]^RANDOM[4];
3'h5: out1[0] = in[0]^RANDOM[5];
3'h6: out1[0] = in[0]^RANDOM[6];
3'h7: out1[0] = in[0]^RANDOM[7];
endcase
2'b01: casez (in[2:0])
3'h0: out1[0] = RANDOM[10];
3'h1: out1[0] = RANDOM[11];
3'h2: out1[0] = RANDOM[12];
3'h3: out1[0] = RANDOM[13];
3'h4: out1[0] = RANDOM[14];
3'h5: out1[0] = RANDOM[15];
3'h6: out1[0] = RANDOM[16];
3'h7: out1[0] = RANDOM[17];
endcase
2'b1?: casez (in[4])
1'b1: casez (in[2:0])
3'h0: out1[0] = RANDOM[20];
3'h1: out1[0] = RANDOM[21];
3'h2: out1[0] = RANDOM[22];
3'h3: out1[0] = RANDOM[23];
3'h4: out1[0] = RANDOM[24];
3'h5: out1[0] = RANDOM[25];
3'h6: out1[0] = RANDOM[26];
3'h7: out1[0] = RANDOM[27];
endcase
1'b0: casez (in[2:0])
3'h0: out1[0] = RANDOM[30];
3'h1: out1[0] = RANDOM[31];
3'h2: out1[0] = RANDOM[32];
3'h3: out1[0] = RANDOM[33];
3'h4: out1[0] = RANDOM[34];
3'h5: out1[0] = RANDOM[35];
3'h6: out1[0] = RANDOM[36];
3'h7: out1[0] = RANDOM[37];
endcase
endcase
endcase
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# 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
# General Public License or the Perl Artistic License.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+93
View File
@@ -0,0 +1,93 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc; initial cyc=0;
reg [63:0] crc;
reg [63:0] sum;
reg out1;
reg [4:0] out2;
sub sub (.in(crc[23:0]), .out1(out1), .out2(out2));
always @ (posedge clk) begin
//$write("[%0t] cyc==%0d crc=%x sum=%x out=%x,%x\n",$time, cyc, crc, sum, out1,out2);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {58'h0,out1,out2};
if (cyc==0) begin
// Setup
crc <= 64'h00000000_00000097;
sum <= 64'h0;
end
else if (cyc==90) begin
if (sum != 64'hf0afc2bfa78277c5) $stop;
end
else if (cyc==91) begin
end
else if (cyc==92) begin
end
else if (cyc==93) begin
end
else if (cyc==94) begin
end
else if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub (/*AUTOARG*/
// Outputs
out1, out2,
// Inputs
in
);
input [23:0] in;
output reg out1;
output reg [4:0] out2;
always @* begin
casez (in)
24'b0000_0000_0000_0000_0000_0000 : {out1,out2} = {1'b0,5'h00};
24'b????_????_????_????_????_???1 : {out1,out2} = {1'b1,5'h00};
24'b????_????_????_????_????_??10 : {out1,out2} = {1'b1,5'h01};
24'b????_????_????_????_????_?100 : {out1,out2} = {1'b1,5'h02};
24'b????_????_????_????_????_1000 : {out1,out2} = {1'b1,5'h03};
24'b????_????_????_????_???1_0000 : {out1,out2} = {1'b1,5'h04};
24'b????_????_????_????_??10_0000 : {out1,out2} = {1'b1,5'h05};
24'b????_????_????_????_?100_0000 : {out1,out2} = {1'b1,5'h06};
24'b????_????_????_????_1000_0000 : {out1,out2} = {1'b1,5'h07};
// Same pattern, but reversed to test we work OK.
24'b1000_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h17};
24'b?100_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h16};
24'b??10_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h15};
24'b???1_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h14};
24'b????_1000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h13};
24'b????_?100_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h12};
24'b????_??10_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h11};
24'b????_???1_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h10};
24'b????_????_1000_0000_0000_0000 : {out1,out2} = {1'b1,5'h0f};
24'b????_????_?100_0000_0000_0000 : {out1,out2} = {1'b1,5'h0e};
24'b????_????_??10_0000_0000_0000 : {out1,out2} = {1'b1,5'h0d};
24'b????_????_???1_0000_0000_0000 : {out1,out2} = {1'b1,5'h0c};
24'b????_????_????_1000_0000_0000 : {out1,out2} = {1'b1,5'h0b};
24'b????_????_????_?100_0000_0000 : {out1,out2} = {1'b1,5'h0a};
24'b????_????_????_??10_0000_0000 : {out1,out2} = {1'b1,5'h09};
24'b????_????_????_???1_0000_0000 : {out1,out2} = {1'b1,5'h08};
endcase
end
endmodule
+89
View File
@@ -0,0 +1,89 @@
[2] crc=0000000000000097 1410
[3] crc=000000000000012e 1410
[4] crc=000000000000025d 1410
[5] crc=00000000000004ba 1410
[6] crc=0000000000000974 1410
[7] crc=00000000000012e9 1410
[8] crc=00000000000025d3 1410
[9] crc=0000000000004ba7 1410
[10] crc=000000000000974e 1410
[11] crc=0000000000012e9d 1410
[12] crc=0000000000025d3a 1410
[13] crc=000000000004ba74 1410
[14] crc=00000000000974e9 1410
[15] crc=000000000012e9d3 1410
[16] crc=000000000025d3a7 1410
[17] crc=00000000004ba74e 1410
[18] crc=0000000000974e9d 1410
[19] crc=00000000012e9d3a 1410
[20] crc=00000000025d3a74 1410
[21] crc=0000000004ba74e9 1410
[22] crc=000000000974e9d3 1304a:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039;17 1304b:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039203233 1304c:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020313030392032332031333033;4 1304d:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002031303039203233203133303320313338 1304e:203130303920323320313330332031333820202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020 1304: 1009 23 1303 138
[23] crc=0000000012e9d3a7 1313: 1009 46 1309 1311 143 1312
[24] crc=0000000025d3a74e 1129: 1009 172 407 175 408 409 410 1106
[25] crc=000000004ba74e9d 1017: 1009 223 1014 880 885 1015 1016 1007
[26] crc=00000000974e9d3a 1231: 1229 967 1230 718
[27] crc=000000012e9d3a74 1410
[28] crc=000000025d3a74e9 1370: 1009 58 1369 19
[29] crc=00000004ba74e9d3 1036: 1009 194 1033 1034 1008 1035 880
[30] crc=0000000974e9d3a7 1409:i
[31] crc=00000012e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[32] crc=00000025d3a74e9d 1383:§
[33] crc=0000004ba74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[34] crc=000000974e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[35] crc=0000012e9d3a74e9 1231: 1228 979 1230 713
[36] crc=0000025d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[37] crc=000004ba74e9d3a7 1409:i
[38] crc=00000974e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[39] crc=000012e9d3a74e9d 1383:§
[40] crc=000025d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[41] crc=00004ba74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[42] crc=0000974e9d3a74e9 1231: 1228 979 1230 713
[43] crc=00012e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[44] crc=00025d3a74e9d3a7 1409:i
[45] crc=0004ba74e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[46] crc=000974e9d3a74e9d 1383:§
[47] crc=0012e9d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[48] crc=0025d3a74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[49] crc=004ba74e9d3a74e9 1231: 1228 979 1230 713
[50] crc=00974e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[51] crc=012e9d3a74e9d3a7 1409:i
[52] crc=025d3a74e9d3a74e 1321: 1009 29 1320 137 144 141 138 148
[53] crc=04ba74e9d3a74e9d 1383:§
[54] crc=0974e9d3a74e9d3a 1021: 1009 216 1018 882 884 1019 1020 1007
[55] crc=12e9d3a74e9d3a74 1017: 1009 197 1014 882 883 1015 1016 1008
[56] crc=25d3a74e9d3a74e9 1231: 1228 979 1230 713
[57] crc=4ba74e9d3a74e9d3 1013: 1009 194 1011 1006 1008 1012 880
[58] crc=974e9d3a74e9d3a7 1409:i
[59] crc=2e9d3a74e9d3a74f 1321: 1009 29 1320 137 144 141 138 149
[60] crc=5d3a74e9d3a74e9e 1383:§
[61] crc=ba74e9d3a74e9d3d 1021: 1009 216 1018 882 884 1019 1020 1007
[62] crc=74e9d3a74e9d3a7b 1017: 1009 197 1014 882 883 1015 1016 1008
[63] crc=e9d3a74e9d3a74f7 1231: 1228 979 1230 713
[64] crc=d3a74e9d3a74e9ef 1013: 1009 194 1011 1006 1008 1012 880
[65] crc=a74e9d3a74e9d3df 1409:i
[66] crc=4e9d3a74e9d3a7bf 1321: 1009 29 1320 137 144 141 145 149
[67] crc=9d3a74e9d3a74f7e 1383:§
[68] crc=3a74e9d3a74e9efc 1021: 1009 216 1018 882 884 1019 1020 1007
[69] crc=74e9d3a74e9d3df9 1017: 1009 197 1014 882 883 1015 1016 1008
[70] crc=e9d3a74e9d3a7bf3 1231: 1228 979 1230 713
[71] crc=d3a74e9d3a74f7e6 1013: 1009 194 1011 1006 1008 1012 880
[72] crc=a74e9d3a74e9efcc 1409:i
[73] crc=4e9d3a74e9d3df98 1321: 1009 29 1320 137 147 149 143 142
[74] crc=9d3a74e9d3a7bf30 1383:§
[75] crc=3a74e9d3a74f7e61 1021: 1009 216 1018 882 885 1019 1020 1007
[76] crc=74e9d3a74e9efcc3 1017: 1009 197 1014 882 884 1015 1016 1008
[77] crc=e9d3a74e9d3df987 1231: 1228 982 1230 713
[78] crc=d3a74e9d3a7bf30f 1013: 1009 194 1011 1006 1008 1012 881 885
[79] crc=a74e9d3a74f7e61f 1409:w
[80] crc=4e9d3a74e9efcc3f 1321: 1009 30 1320 149 146 146 137 149
[81] crc=9d3a74e9d3df987e 1383:ß
[82] crc=3a74e9d3a7bf30fc 1021: 1009 225 1018 882 885 1019 1020 1008
[83] crc=74e9d3a74f7e61f9 1017: 1009 218 1014 882 884 1015 1016 1008
[84] crc=e9d3a74e9efcc3f3 1231: 1228 981 1230 708
[85] crc=d3a74e9d3df987e6 1013: 1009 232 1011 1005 1008 1012 881 883
[86] crc=a74e9d3a7bf30fcc 1409:s
[87] crc=4e9d3a74f7e61f98 1262: 1009 1006 1258 846 1259 1006 1260 833 1261
[88] crc=9d3a74e9efcc3f30 1321: 1009 124 1320 146 137 149 137 134
[89] crc=3a74e9d3df987e61 1383:˜
[90] crc=74e9d3a7bf30fcc3 1036: 1009 215 1033 1034 1008 1035 879
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2006 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
$golden_out ||= "t/$Last_Self->{name}.out";
compile (
v_flags2 => [$Last_Self->{v3}?"--stats --O3 -x-assign 0":""],
);
execute (
check_finished=>1,
);
ok(files_identical("obj_dir/$Last_Self->{name}_logger.log", $golden_out));
1;
+44
View File
@@ -0,0 +1,44 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
`include "verilated.v"
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [63:0] crc;
`verilator_file_descriptor fd;
t_case_write1_tasks tasks ();
integer cyc; initial cyc=0;
always @ (posedge clk) begin
$fwrite(fd, "[%0d] crc=%x ", cyc, crc);
tasks.big_case(fd, crc[31:0]);
$fwrite(fd, "\n");
end
always @ (posedge clk) begin
//$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
if (cyc==1) begin
crc <= 64'h00000000_00000097;
$write("Open obj_dir/t_case_write1_logger.log\n");
fd = $fopen("obj_dir/t_case_write1_logger.log", "w");
end
if (cyc==90) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
File diff suppressed because it is too large Load Diff
+89
View File
@@ -0,0 +1,89 @@
[2] crc=0000000000000097 1009 1410
[3] crc=000000000000012e 1009 1410
[4] crc=000000000000025d 1009 1410
[5] crc=00000000000004ba 1009 1410
[6] crc=0000000000000974 1009 1410
[7] crc=00000000000012e9 1009 1410
[8] crc=00000000000025d3 1009 1410
[9] crc=0000000000004ba7 1009 1410
[10] crc=000000000000974e 1009 1410
[11] crc=0000000000012e9d 1009 1410
[12] crc=0000000000025d3a 1009 1410
[13] crc=000000000004ba74 1009 1410
[14] crc=00000000000974e9 1009 1410
[15] crc=000000000012e9d3 1009 1410
[16] crc=000000000025d3a7 1009 1410
[17] crc=00000000004ba74e 1009 1410
[18] crc=0000000000974e9d 1009 1410
[19] crc=00000000012e9d3a 1009 1410
[20] crc=00000000025d3a74 1009 1410
[21] crc=0000000004ba74e9 1009 1410
[22] crc=000000000974e9d3 1009 23 1303 138 dude 1304
[23] crc=0000000012e9d3a7 1009 46 1309 1311 143 1312 dude 1313
[24] crc=0000000025d3a74e 1009 172 407 175 408 409 410 1106 dude 1129
[25] crc=000000004ba74e9d 1009 223 1014 880 885 1015 1016:0 1007 dude 1017
[26] crc=00000000974e9d3a 1009 1229 967 1230 718 dude 1231
[27] crc=000000012e9d3a74 1009 1410
[28] crc=000000025d3a74e9 1009 58 1369 19 dude 1370
[29] crc=00000004ba74e9d3 1009 194 1033 1034 1008 1035 880 dude 1036
[30] crc=0000000974e9d3a7 1009 1409:69
[31] crc=00000012e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[32] crc=00000025d3a74e9d 1009 1383:3a7
[33] crc=0000004ba74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[34] crc=000000974e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[35] crc=0000012e9d3a74e9 1009 1228 979 1230 713 dude 1231
[36] crc=0000025d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[37] crc=000004ba74e9d3a7 1009 1409:69
[38] crc=00000974e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[39] crc=000012e9d3a74e9d 1009 1383:3a7
[40] crc=000025d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[41] crc=00004ba74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[42] crc=0000974e9d3a74e9 1009 1228 979 1230 713 dude 1231
[43] crc=00012e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[44] crc=00025d3a74e9d3a7 1009 1409:69
[45] crc=0004ba74e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[46] crc=000974e9d3a74e9d 1009 1383:3a7
[47] crc=0012e9d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[48] crc=0025d3a74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[49] crc=004ba74e9d3a74e9 1009 1228 979 1230 713 dude 1231
[50] crc=00974e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[51] crc=012e9d3a74e9d3a7 1009 1409:69
[52] crc=025d3a74e9d3a74e 1009 29 1320 137 144 141 138 148 dude 1321
[53] crc=04ba74e9d3a74e9d 1009 1383:3a7
[54] crc=0974e9d3a74e9d3a 1009 216 1018 882 884 1019 1020 1007 dude 1021
[55] crc=12e9d3a74e9d3a74 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[56] crc=25d3a74e9d3a74e9 1009 1228 979 1230 713 dude 1231
[57] crc=4ba74e9d3a74e9d3 1009 194 1011 1006 1008 1012 880 dude 1013
[58] crc=974e9d3a74e9d3a7 1009 1409:69
[59] crc=2e9d3a74e9d3a74f 1009 29 1320 137 144 141 138 149 dude 1321
[60] crc=5d3a74e9d3a74e9e 1009 1383:3a7
[61] crc=ba74e9d3a74e9d3d 1009 216 1018 882 884 1019 1020 1007 dude 1021
[62] crc=74e9d3a74e9d3a7b 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[63] crc=e9d3a74e9d3a74f7 1009 1228 979 1230 713 dude 1231
[64] crc=d3a74e9d3a74e9ef 1009 194 1011 1006 1008 1012 880 dude 1013
[65] crc=a74e9d3a74e9d3df 1009 1409:69
[66] crc=4e9d3a74e9d3a7bf 1009 29 1320 137 144 141 145 149 dude 1321
[67] crc=9d3a74e9d3a74f7e 1009 1383:3a7
[68] crc=3a74e9d3a74e9efc 1009 216 1018 882 884 1019 1020 1007 dude 1021
[69] crc=74e9d3a74e9d3df9 1009 197 1014 882 883 1015 1016:1 1008 dude 1017
[70] crc=e9d3a74e9d3a7bf3 1009 1228 979 1230 713 dude 1231
[71] crc=d3a74e9d3a74f7e6 1009 194 1011 1006 1008 1012 880 dude 1013
[72] crc=a74e9d3a74e9efcc 1009 1409:69
[73] crc=4e9d3a74e9d3df98 1009 29 1320 137 147 149 143 142 dude 1321
[74] crc=9d3a74e9d3a7bf30 1009 1383:3a7
[75] crc=3a74e9d3a74f7e61 1009 216 1018 882 885 1019 1020 1007 dude 1021
[76] crc=74e9d3a74e9efcc3 1009 197 1014 882 884 1015 1016:1 1008 dude 1017
[77] crc=e9d3a74e9d3df987 1009 1228 982 1230 713 dude 1231
[78] crc=d3a74e9d3a7bf30f 1009 194 1011 1006 1008 1012 881 885 dude 1013
[79] crc=a74e9d3a74f7e61f 1009 1409:77
[80] crc=4e9d3a74e9efcc3f 1009 30 1320 149 146 146 137 149 dude 1321
[81] crc=9d3a74e9d3df987e 1009 1383:3df
[82] crc=3a74e9d3a7bf30fc 1009 225 1018 882 885 1019 1020 1008 dude 1021
[83] crc=74e9d3a74f7e61f9 1009 218 1014 882 884 1015 1016:1 1008 dude 1017
[84] crc=e9d3a74e9efcc3f3 1009 1228 981 1230 708 dude 1231
[85] crc=d3a74e9d3df987e6 1009 232 1011 1005 1008 1012 881 883 dude 1013
[86] crc=a74e9d3a7bf30fcc 1009 1409:73
[87] crc=4e9d3a74f7e61f98 1009 1006 1258 846 1259 1006 1260 833 1261 dude 1262
[88] crc=9d3a74e9efcc3f30 1009 124 1320 146 137 149 137 134 dude 1321
[89] crc=3a74e9d3df987e61 1009 1383:f98
[90] crc=74e9d3a7bf30fcc3 1009 215 1033 1034 1008 1035 879 dude 1036
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2006 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
$golden_out ||= "t/$Last_Self->{name}.out";
compile (
v_flags2 => [$Last_Self->{v3}?"--stats --O3 -x-assign 0":""],
);
execute (
check_finished=>1,
);
ok(files_identical("obj_dir/$Last_Self->{name}_logger.log", $golden_out));
1;
+44
View File
@@ -0,0 +1,44 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
`include "verilated.v"
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [63:0] crc;
`verilator_file_descriptor fd;
t_case_write2_tasks tasks ();
integer cyc; initial cyc=0;
always @ (posedge clk) begin
$fwrite(fd, "[%0d] crc=%x ", cyc, crc);
tasks.big_case(fd, crc[31:0]);
$fwrite(fd, "\n");
end
always @ (posedge clk) begin
//$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
if (cyc==1) begin
crc <= 64'h00000000_00000097;
$write("Open obj_dir/t_case_write2_logger.log\n");
fd = $fopen("obj_dir/t_case_write2_logger.log", "w");
end
if (cyc==90) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# 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
# General Public License or the Perl Artistic License.
if ($Last_Self->{v3}) {
compile ();
my $outfile = "obj_dir/V".$Last_Self->{name}.".cpp";
my @oldstats = stat($outfile);
print "Old mtime=",$oldstats[9],"\n";
$oldstats[9] or $Last_Self->error("No output file found: $outfile\n");
sleep (1); # Or else it might take < 1 second to compile and see no diff.
compile ();
my @newstats = stat($outfile);
print "New mtime=",$newstats[9],"\n";
($oldstats[9] == $newstats[9])
or $Last_Self->error("--skip-identical was ignored -- recompiled\n");
}
ok(1);
1;
+9
View File
@@ -0,0 +1,9 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (/*AUTOARG*/);
endmodule
+1 -1
View File
@@ -13,7 +13,7 @@ compile (
fails=>$Last_Self->{v3},
verilator_flags=> [qw(-sp -Werror-WIDTH)],
expect=>
'%Error: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
'%Error-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
%Error: Exiting due to',
) if $Last_Self->{v3};
+35 -1
View File
@@ -1,4 +1,4 @@
// $Id:$
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
@@ -22,6 +22,15 @@ module t;
if (global != 32'h17) $stop;
nop(32'h11);
global = 32'h00000001;
flipupperbit(global,4'd4);
flipupperbit(global,4'd12);
if (global !== 32'h10100001) $stop;
if (nil_func(32'h12,32'h12) != 32'h24) $stop;
nil_task(32'h012,32'h112,global);
if (global !== 32'h124) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
@@ -70,4 +79,29 @@ module t;
end
endtask
task flipupperbit;
inout [31:0] vector;
input [3:0] bitnum;
reg [4:0] bitnum2;
begin
bitnum2 = {1'b1, bitnum}; // A little math to test constant propagation
vector[bitnum2] = vector[bitnum2] ^ 1'b1;
end
endtask
task nil_task;
input [31:0] a;
input [31:0] b;
output [31:0] q;
// verilator no_inline_task
q = nil_func(a, b);
endtask
function [31:0] nil_func;
input [31:0] fa;
input [31:0] fb;
// verilator no_inline_task
nil_func = fa + fb;
endfunction
endmodule
+2 -2
View File
@@ -1,6 +1,6 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id:$
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
@@ -13,7 +13,7 @@ compile (
'%Error: t/t_func_bad.v:\d+: Too few arguments in function call
%Error: t/t_func_bad.v:\d+: Too many arguments in function call
%Error: t/t_func_bad.v:\d+: Too few arguments in function call
%Error: t/t_func_bad.v:\d+: Unsupported: Task output pin connected to non-variable
%Error-TASKNSVAR: t/t_func_bad.v:\d+: Unsupported: Task output pin connected to non-variable
%Error: t/t_func_bad.v:\d+: Outputs not allowed in function declarations
%Error: Exiting due to',
);
+28 -2
View File
@@ -37,6 +37,11 @@ module t (/*AUTOARG*/
if (ma0.mb0.mc0.getP3(1'b0) !== 32'h0) $stop;
if (ma0.mb0.mc1.getP3(1'b0) !== 32'h1) $stop;
end
if (cyc==5) begin
ma0. checkName(ma0. getName(1'b0));
ma0.mb0. checkName(ma0.mb0. getName(1'b0));
ma0.mb0.mc0.checkName(ma0.mb0.mc0.getName(1'b0));
end
if (cyc==9) begin
$write("*-* All Finished *-*\n");
$finish;
@@ -72,7 +77,9 @@ module ma ();
`INLINE_MODULE
mb #(0) mb0 ();
reg [31:0] gName; initial gName = "ma ";
function [31:0] getName; input fake; getName = "ma "; endfunction
task checkName; input [31:0] name; if (name !== "ma ") $stop; endtask
initial begin
if (ma.getName(1'b0) !== "ma ") $stop;
@@ -89,13 +96,23 @@ module mb ();
mc #(P2,1) mc1 ();
global_mod #(32'hf33d) global_cell2 ();
reg [31:0] gName; initial gName = "mb ";
function [31:0] getName; input fake; getName = "mb "; endfunction
function [31:0] getP2 ; input fake; getP2 = P2; endfunction
task checkName; input [31:0] name; if (name !== "mb ") $stop; endtask
initial begin
if (ma.getName(1'b0) !== "ma ") $stop;
if (getName(1'b0) !== "mb ") $stop;
`ifndef verilator #1; `endif
if (ma. getName(1'b0) !== "ma ") $stop;
if ( getName(1'b0) !== "mb ") $stop;
if (mc1.getName(1'b0) !== "mc ") $stop;
ma. checkName (ma. gName);
/**/checkName ( gName);
mc1.checkName (mc1.gName);
ma. checkName (ma. getName(1'b0));
/**/checkName ( getName(1'b0));
mc1.checkName (mc1.getName(1'b0));
end
endmodule
@@ -104,12 +121,21 @@ module mc ();
parameter P2 = 0;
parameter P3 = 0;
reg [31:0] gName; initial gName = "mc ";
function [31:0] getName; input fake; getName = "mc "; endfunction
function [31:0] getP3 ; input fake; getP3 = P3; endfunction
task checkName; input [31:0] name; if (name !== "mc ") $stop; endtask
initial begin
`ifndef verilator #1; `endif
if (ma.getName(1'b0) !== "ma ") $stop;
if (mb.getName(1'b0) !== "mb ") $stop;
if (mc.getName(1'b0) !== "mc ") $stop;
ma.checkName (ma.gName);
mb.checkName (mb.gName);
mc.checkName (mc.gName);
ma.checkName (ma.getName(1'b0));
mb.checkName (mb.getName(1'b0));
mc.checkName (mc.getName(1'b0));
end
endmodule
+4 -4
View File
@@ -103,8 +103,8 @@ module tpub (
if (24'h11bca != got_long) $stop;
$c("{ uint64_t qq; publicGetQuad(qq); got_quad=qq; }");
if (60'haaaa_bbbb_cccc != got_quad) $stop;
//Unsupported: $c("publicGetWide(got_wide);");
//Unsupported: if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
$c("{ WData gw[3]; publicGetWide(gw); VL_ASSIGN_W(72,got_wide,gw); }");
if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
//Below doesn't work, because we're calling it inside the loop that sets var_flop
// if (12'h321 != var_flop) $stop;
end
@@ -154,7 +154,7 @@ module tpub (
endtask
task publicSetWide;
// Can't be public, as no wide return types in C++
// verilator public
input [71:0] in_wide;
var_wide = in_wide;
endtask
@@ -178,7 +178,7 @@ module tpub (
endtask
task publicGetWide;
// Can't be public, as no wide return types in C++
// verilator public
output [71:0] out_wide;
out_wide = var_wide;
endtask
-1
View File
@@ -39,7 +39,6 @@ module t (/*AUTOARG*/
a <= 256'h0e17c88f3d5fe51a982646c8e2bd68c3e236ddfddddbdad20a48e039c9f395b8;
divisor <= 61'h1238123771;
a[60] <= 1'b0; divisor[60] <= 1'b0; // Unsigned
//$display("FIX");
if (qq!==61'h00000403ad81c0da) $stop;
if (rq!==61'h00000000000090ec) $stop;
if (qqs!==61'h00000403ad81c0da) $stop;
+3 -2
View File
@@ -7,6 +7,7 @@ if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
$golden_out ||= "t/$Last_Self->{name}.out";
my $stdout_filename = "obj_dir/$Last_Self->{name}__test.vpp";
if (!$Last_Self->{v3}) {
@@ -17,8 +18,8 @@ if (!$Last_Self->{v3}) {
verilator_make_gcc=>0,
stdout_filename => $stdout_filename,
);
ok(preproc_check("t/$Last_Self->{name}.v", $stdout_filename)
&& files_identical($stdout_filename, "t/$Last_Self->{name}.out"));
ok(preproc_check($Last_Self->{top_filename}, $stdout_filename)
&& files_identical($stdout_filename, $golden_out));
}
sub preproc_check {
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2006-2006 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
top_filename("obj_dir/$Last_Self->{name}.v");
# Rather then having to maintain a new .v and .out, simply add returns
# to all lines of the existing t_preproc test.
$golden_out ||= "obj_dir/$Last_Self->{name}.out";
{
my $wholefile = file_contents("t/t_preproc.v");
$wholefile =~ s/\n/\r\n/og;
write_wholefile("obj_dir/$Last_Self->{name}.v", $wholefile);
}
{
my $wholefile = file_contents("t/t_preproc.out");
$wholefile =~ s!t/t_preproc.v!obj_dir/t_preproc_dos.v!og; # Fix `line's
write_wholefile($golden_out, $wholefile);
}
require 't/t_preproc.pl';
1;
+1 -2
View File
@@ -141,10 +141,9 @@ module mc (output reg [31:0] out);
end
// Can we look from the top module name down?
wire reach_up_clk = t.clk;
wire [31:0] reach_up_cyc = t.cyc;
always @ (posedge reach_up_clk) begin
always @ (posedge t.clk) begin
//$write("[%0t] %m: Got reachup, cyc=%0d\n", $time, reach_up_cyc);
if (reach_up_cyc==2) begin
if (global_cell.global != 32'hf00d) $stop;
+2 -1
View File
@@ -12,7 +12,8 @@ compile (
);
if ($Last_Self->{v3}) {
file_grep ($Last_Self->{stats}, qr/Optimizations, Lifetime assign deletions\s+3/i);
file_grep ($Last_Self->{stats}, qr/Optimizations, Lifetime assign deletions\s+4/i);
file_grep ($Last_Self->{stats}, qr/Optimizations, Lifetime constant prop\s+2/i);
}
execute (
+5 -3
View File
@@ -17,6 +17,8 @@ VERILATOR_ROOT := $(shell pwd)/..
export VERILATOR_ROOT
PWD := $(shell pwd)
PERL = perl
DEBUG_ON = --debug
######################################################################
@@ -32,11 +34,11 @@ obj_dir/sc_main.cpp: ../test_sp/sc_main.cpp
cp $^ $@
prep:
perl $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
prep_dbg:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
prep_dbg_np:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
preproc:
cd obj_dir ; $(MAKE) -j 1 -f ../Makefile_obj preproc
+5 -3
View File
@@ -17,6 +17,8 @@ VERILATOR_ROOT := $(shell pwd)/..
export VERILATOR_ROOT
PWD := $(shell pwd)
PERL = perl
DEBUG_ON = --debug --trace-dups --output-split 100
######################################################################
@@ -28,11 +30,11 @@ V_FLAGS = -f $(PWD)/../test_v/input.vc
VERILATOR_FLAGS = --public --sp --coverage --stats --trace $(V_FLAGS) top.v
prep:
perl $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
prep_dbg:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
prep_dbg_np:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
preproc:
cd obj_dir ; $(MAKE) -j 1 -f ../Makefile_obj preproc
+3
View File
@@ -21,6 +21,9 @@ CPPFLAGS += -DUTIL_PRINTF=sp_log_printf
CPPFLAGS += -Wno-deprecated
CPPFLAGS += $(SYSTEMC_CXX_FLAGS)
CPPFLAGS += $(OPT)
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
#CPPFLAGS += -W -Wall -Wno-char-subscripts -Wno-unused-parameter -Wno-unused-variable -Wno-uninitialized -Werror
endif
LDFLAGS += $(SYSTEMC_CXX_FLAGS)
+27 -2
View File
@@ -54,6 +54,7 @@ our $Raise_Weight_Max = 50;
'VCONST'=> {weight=>1&&20, width=>0, sc=>1, terminal=>1, v=>'%v', },
'VIDNEW'=> {weight=>1&&10, width=>0, sc=>1, terminal=>0, v=>'%i', },
'VIDOLD'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', },
'VIDSAME'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', },
'VRANGE'=> {weight=>1&&30, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2:%3]', },
'VBITSEL'=> {weight=>1&&10, width=>1, signed=>0,sc=>0, terminal=>0, v=>'%i[%2]', },
'VBITSELP'=> {weight=>1&&10, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2+:%3]', },
@@ -119,7 +120,8 @@ my %ops2 =
'VCONST'=> {pl=>'', rnd=>'rnd_const(%tr);'},
'VIDNEW'=> {pl=>'%tv=$Vars{%i}{val};',
rnd=>'%i=next_id(%tw); $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg); id_commit(%tr,"%i");1;',},
'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=old_id(%tr);', ok_id_width=>1,},
'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_old(%tr);', ok_id_width=>1,},
'VIDSAME'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_same(%tr);', ok_id_width=>1,},
'VRANGE'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1; %2r=val_leaf($msb); %3r=val_leaf($lsb); $Vars{%i}=gen_leaf(width=>($msb+1));'},
'VBITSEL'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%2v);', rnd=>'%i=next_id(%tw); my $wid=min(128,rnd_width()|3); %2r=gen_leaf(width=>(log2($wid)-1),signed=>0); $Vars{%i}=gen_leaf(width=>$wid);'},
'VBITSELP'=> {pl=>'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0)); $Vars{%i}=gen_leaf(width=>$wid);'},
@@ -421,7 +423,7 @@ sub id_commit {
};
}
sub old_id {
sub id_old {
my $treeref = shift;
my $width = $treeref->{width};
my $signed = $treeref->{signed};
@@ -433,6 +435,29 @@ sub old_id {
return $id;
}
sub id_same {
my $treeref = shift;
my $width = $treeref->{width};
my $signed = $treeref->{signed};
my @possible;
foreach my $id (keys %VarsBlock) {
next if !$VarsBlock{$id}{used};
my $varref = $Vars{$id};
next if $varref->{signed} != $signed;
next if $varref->{width} != $width;
push @possible, $id;
}
my $n = $#possible + 1;
if ($n<1) { # Nothing, grab another!
return id_old($treeref,$width,$signed);
}
my $idn = rnd($n);
my $id = $possible[$idn];
$VarsBlock{$id}{used} = 1;
return $id;
}
sub write_output_v {
my $filename = shift;