mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 08:33:21 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2dcd4d171b | ||
|
|
e7f4d18c3d | ||
|
|
1611362c22 | ||
|
|
2327698160 | ||
|
|
71c1f00ec2 | ||
|
|
6574a126ef | ||
|
|
1e68086355 | ||
|
|
326cc8fd67 | ||
|
|
4afcb421bd | ||
|
|
8d21917035 | ||
|
|
4ca7f8834c | ||
|
|
b43299c8da | ||
|
|
b763809f5e | ||
|
|
2cb97f7475 | ||
|
|
6283df7491 | ||
|
|
acc4490370 | ||
|
|
f85c1a995a | ||
|
|
809e5fda8a | ||
|
|
dce245da5a | ||
|
|
d261c4cd27 | ||
|
|
c33299d542 | ||
|
|
ebdf8a5f3c | ||
|
|
c8852d183f | ||
|
|
9f161b20ef | ||
|
|
40f9d64973 | ||
|
|
4a2e68a0fd | ||
|
|
bcd90d3401 | ||
|
|
114af7d33f | ||
|
|
7b83d2de49 | ||
|
|
850de5913d | ||
|
|
bb9ee46f40 | ||
|
|
e94fc1305b | ||
|
|
3e4e8feb29 | ||
|
|
fedf347b1a | ||
|
|
285277a50b | ||
|
|
323c96f42f | ||
|
|
7dee344ea9 | ||
|
|
65bce588e4 | ||
|
|
233ff1b744 | ||
|
|
0837e39787 | ||
|
|
86db565a21 | ||
|
|
d6ac5e5001 | ||
|
|
e6443f1981 | ||
|
|
d13e6c73db | ||
|
|
79ca7f3cb5 | ||
|
|
cfd07ccd34 | ||
|
|
48047d523a | ||
|
|
eeb8fc2626 | ||
|
|
3d1baf3f2f | ||
|
|
4e382d6765 | ||
|
|
582963375d | ||
|
|
56c7c1bcc8 | ||
|
|
f88e57ddb8 | ||
|
|
9d98e012e4 | ||
|
|
d305a774f0 | ||
|
|
16b0c8d353 | ||
|
|
55da4fdbf6 | ||
|
|
ed2fbd8f25 | ||
|
|
42199bc8e5 | ||
|
|
7c5318768c | ||
|
|
aba25aab19 | ||
|
|
f99bd33f91 | ||
|
|
a6a6ce83f0 | ||
|
|
f4908a9758 | ||
|
|
5e4ca4b76a | ||
|
|
1e938d0e90 | ||
|
|
f3704f4c05 | ||
|
|
8800efe953 | ||
|
|
a320c4584e | ||
|
|
3841850168 | ||
|
|
beb3885840 | ||
|
|
06967c0c46 | ||
|
|
9a382c572c | ||
|
|
44b6c371db | ||
|
|
00970be996 | ||
|
|
aca4ab015f | ||
|
|
68b63d5783 | ||
|
|
4b499f2bb1 | ||
|
|
ed17581f92 | ||
|
|
a46c4ec912 | ||
|
|
930cbeec17 | ||
|
|
10689ffaba | ||
|
|
29b0ea0af9 | ||
|
|
57d00946be | ||
|
|
ef51de72c9 | ||
|
|
c807bf1e0e | ||
|
|
2525b3fb05 | ||
|
|
9163ce0f6e | ||
|
|
d776638f53 | ||
|
|
83fff41312 | ||
|
|
dd7d9bc95b | ||
|
|
f8eabbc100 | ||
|
|
7ed18ac62d | ||
|
|
3ac707c645 | ||
|
|
8e9a1e0bf3 | ||
|
|
bc31b5d27a | ||
|
|
936738b750 | ||
|
|
7c3048ab9c | ||
|
|
64719f3ace | ||
|
|
a11a5f04d5 | ||
|
|
eb5c035dde | ||
|
|
c3887efbf3 | ||
|
|
495585830d | ||
|
|
6715cb9880 | ||
|
|
41b167d23c | ||
|
|
7ea8b54210 | ||
|
|
bcea39a858 | ||
|
|
fb560abac4 | ||
|
|
ba93a08b40 | ||
|
|
2be6b3481c | ||
|
|
6ef44a6fbb | ||
|
|
2afe40a0b5 | ||
|
|
e57d004718 | ||
|
|
d780d0aabb | ||
|
|
0f9e3f0767 | ||
|
|
381972c923 | ||
|
|
845d7ad718 | ||
|
|
f1b6c0c559 | ||
|
|
e39eddf3fe | ||
|
|
72218fb475 | ||
|
|
9a3e497c22 | ||
|
|
85d510cd48 | ||
|
|
786c65ea5f | ||
|
|
10e6f61125 | ||
|
|
cdd06e7236 | ||
|
|
48603c0ee2 | ||
|
|
63f30492be | ||
|
|
0e8772290d | ||
|
|
6cfc5798b0 | ||
|
|
6be275f5d4 | ||
|
|
716f237c4c | ||
|
|
2a192be4f5 | ||
|
|
2679185a09 | ||
|
|
b85e7ab0b1 | ||
|
|
29c9804843 | ||
|
|
56d8ddbaaf | ||
|
|
8b324249b1 | ||
|
|
59cc61529b | ||
|
|
3912e5ef0b | ||
|
|
e40fbf1470 | ||
|
|
56a03e1a10 | ||
|
|
5d5952d354 | ||
|
|
53fda88d4c | ||
|
|
c4f306c145 | ||
|
|
e01d7fcefc | ||
|
|
aec04b07e0 | ||
|
|
b1872a8e21 | ||
|
|
634816d378 | ||
|
|
2fd5a6d47f | ||
|
|
8dca56521b | ||
|
|
a41aefe77d | ||
|
|
46dbc7157d | ||
|
|
59261113d8 | ||
|
|
fc2834cf04 | ||
|
|
a15633053b | ||
|
|
60a06eef19 | ||
|
|
7fd6ddc25b | ||
|
|
c49e0ac5c8 | ||
|
|
a51e95d052 | ||
|
|
4df9d70e4a | ||
|
|
78d490d5e4 | ||
|
|
2f6002b197 | ||
|
|
abcb95b8a1 | ||
|
|
bf435cae7c | ||
|
|
4b38acd540 | ||
|
|
f71749c3c4 | ||
|
|
cbc90e7ffb | ||
|
|
62866dc8be | ||
|
|
11e702c430 | ||
|
|
3e6e6ec0a5 | ||
|
|
898c08c8e0 | ||
|
|
88fba101a3 | ||
|
|
b0f431e1a2 | ||
|
|
42a7aca504 | ||
|
|
c017f2e7c4 | ||
|
|
d17bcd8afe | ||
|
|
874673f64f | ||
|
|
e052d73321 | ||
|
|
58efab5cdf | ||
|
|
4360fe492e | ||
|
|
295faf726b | ||
|
|
2da9d46ca6 | ||
|
|
e4f1e5f4c3 | ||
|
|
c695af31b8 | ||
|
|
24753c8c6a | ||
|
|
6196cf09ff | ||
|
|
28eb5b9bc4 | ||
|
|
bb20331f9e | ||
|
|
d2bce042a5 | ||
|
|
5d57263a15 | ||
|
|
bded8755a1 | ||
|
|
2e9ade61b2 | ||
|
|
89e03a86b7 | ||
|
|
48e88e4e74 | ||
|
|
d182ecb2d3 | ||
|
|
27e4503dc6 | ||
|
|
72b596efb3 | ||
|
|
0d1de96dbc | ||
|
|
788f69a8c9 | ||
|
|
08b63b4f01 | ||
|
|
ba07dc1804 | ||
|
|
d46074e0ad | ||
|
|
d651063749 | ||
|
|
f60f8396bb | ||
|
|
919fdd70b8 | ||
|
|
ab2702070b | ||
|
|
057e1a1aff | ||
|
|
a2af4e1284 | ||
|
|
97adede70b | ||
|
|
b6447a9032 | ||
|
|
e40b5819bd | ||
|
|
16926edf18 | ||
|
|
8203c79f76 | ||
|
|
43e1b27d16 | ||
|
|
d1cb3b0d15 | ||
|
|
266b3b8678 | ||
|
|
a2629c4929 | ||
|
|
c1fc629c54 | ||
|
|
0d12fe43a0 | ||
|
|
6aec0ce702 | ||
|
|
32c30c34e9 | ||
|
|
6b7b2612a9 | ||
|
|
0b9c6ed178 | ||
|
|
d903855aa3 | ||
|
|
89234bcd42 | ||
|
|
85ba590fa9 | ||
|
|
2950f77dbc | ||
|
|
a94f5ba200 | ||
|
|
0c4e40102f | ||
|
|
27e8126b18 | ||
|
|
bf860b21d7 | ||
|
|
a03a540156 | ||
|
|
eb63c8dcb8 | ||
|
|
cdcb94751e | ||
|
|
cd5d8cceb8 | ||
|
|
8fbc87be46 | ||
|
|
06fba42858 | ||
|
|
0f8a1e3901 | ||
|
|
729dfdfed7 | ||
|
|
1b8051dfe5 | ||
|
|
be6454193b | ||
|
|
f3347be629 | ||
|
|
dbce06500d | ||
|
|
7a81dd3378 | ||
|
|
57dd9c9e01 | ||
|
|
ef4e52a60e | ||
|
|
e7cbefa316 | ||
|
|
b4f805b4e9 | ||
|
|
9b0d26aedd | ||
|
|
f6758c397d | ||
|
|
ef3ed6e338 | ||
|
|
45aa8742d8 | ||
|
|
ebe8f554c6 | ||
|
|
45b0e63be2 | ||
|
|
934dc842e0 | ||
|
|
deda877355 | ||
|
|
2dba8404eb | ||
|
|
f581b4e92c | ||
|
|
02c74b5bee | ||
|
|
df69439b9c | ||
|
|
eb4a686b14 | ||
|
|
3386466e7a | ||
|
|
6a2aa7e4f0 | ||
|
|
735871d501 | ||
|
|
097f3590ae | ||
|
|
17bf13fcb6 | ||
|
|
2dc7b7ad78 | ||
|
|
a3c1724d17 | ||
|
|
5a9309de78 | ||
|
|
a40fae04ce | ||
|
|
f8cb6979d7 | ||
|
|
fc70ae180e | ||
|
|
66b5fa821c | ||
|
|
2f2f416bea | ||
|
|
1da07a3b86 | ||
|
|
ad0fcb745e | ||
|
|
5a502d451d | ||
|
|
955824e634 | ||
|
|
3b62f3c9c0 | ||
|
|
d2a27a84cf | ||
|
|
c7d8eb126f | ||
|
|
d608fd77b9 | ||
|
|
af5aa38bc3 | ||
|
|
2f2f367c0b | ||
|
|
d7a2362a76 | ||
|
|
e479c8a553 | ||
|
|
62f707f501 | ||
|
|
19d62b7a68 | ||
|
|
103bda04d9 | ||
|
|
8e6846d9da | ||
|
|
fd38216eda | ||
|
|
ae27b8944e | ||
|
|
bb6b825836 | ||
|
|
3fc55bba8e | ||
|
|
92819f5082 | ||
|
|
736b9074c8 | ||
|
|
376147911f | ||
|
|
4281690021 | ||
|
|
65714165f9 | ||
|
|
82d917c2c5 | ||
|
|
8487d67f00 | ||
|
|
67d1dad77c | ||
|
|
3b39c3391d | ||
|
|
8a55c6fd9f | ||
|
|
68567e763c | ||
|
|
bc2d3a13f4 | ||
|
|
e0bca07e06 | ||
|
|
377f194837 | ||
|
|
de9989d5a2 | ||
|
|
50db34457c | ||
|
|
b1ce6bd5cc | ||
|
|
81915540de | ||
|
|
0d65f08b1d | ||
|
|
ffbd1fd474 | ||
|
|
700c1f836d | ||
|
|
db2c6820ee | ||
|
|
3236607be4 | ||
|
|
3edbeb8902 | ||
|
|
f59467b897 | ||
|
|
6bc81d3d26 | ||
|
|
4c26792c9b | ||
|
|
9a133ced2d | ||
|
|
18bebaf5c3 | ||
|
|
f7efae93d5 | ||
|
|
7b4d2118ea |
+4
-2
@@ -6,16 +6,18 @@
|
||||
*.info
|
||||
*.log
|
||||
*.1
|
||||
.*.swp
|
||||
*.tmp
|
||||
*.tex
|
||||
/Makefile
|
||||
README
|
||||
autom4te.cache
|
||||
config.cache
|
||||
config.status
|
||||
configure
|
||||
dddrun*
|
||||
gdbrun*
|
||||
verilator.txt
|
||||
internals.txt
|
||||
verilator.pdf
|
||||
verilator.txt
|
||||
verilator_bin*
|
||||
autom4te.cache
|
||||
|
||||
@@ -3,6 +3,194 @@ 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.810 2011/01/03
|
||||
|
||||
** Add limited support for VPI access to public signals, see docs.
|
||||
|
||||
*** Add -F option to read relative option files, bug297. [Neil Hamilton]
|
||||
|
||||
*** Support ++,--,+= etc as standalone statements. [Alex Solomatnikov]
|
||||
|
||||
**** When running with VERILATOR_ROOT, optionally find binaries under bin.
|
||||
|
||||
**** Suppress WIDTH warnings when adding/subtracting 1'b1.
|
||||
|
||||
** Add -Wall, -Wwarn-style, -Wno-style to enable code style warnings
|
||||
that have been added to this release, and disabled by default:
|
||||
|
||||
*** With --Wall, add BLKSEQ warning on blocking assignments in seq blocks.
|
||||
|
||||
*** With --Wall, add DECLFILENAME warning on modules not matching filename.
|
||||
|
||||
*** With --Wall, add DEFPARAM warning on deprecated defparam statements.
|
||||
|
||||
*** With --Wall, add IFDEPTH warning on deep if statements.
|
||||
|
||||
*** With --Wall, add INCABSPATH warning on `include with absolute paths.
|
||||
|
||||
*** With --Wall, add SYNCASYNCNET warning on mixed sync/async reset nets.
|
||||
|
||||
*** With --Wall, add UNDRIVEN warning on undriven nets.
|
||||
|
||||
*** With --Wall, add UNUSED warning on unused nets.
|
||||
|
||||
*** The VARHIDDEN warning is now disabled by default, use -Wall to enable.
|
||||
|
||||
* Verilator 3.805 2010/11/02
|
||||
|
||||
**** Add warning when directory contains spaces, msg378. [Salman Sheikh]
|
||||
|
||||
**** Fix wrong filename on include file errors, bug289. [Brad Parker]
|
||||
|
||||
**** Fix segfault on SystemVerilog "output wire foo=0", bug291. [Joshua Wise]
|
||||
|
||||
**** Fix DPI export name not found, msg369. [Terry Chen]
|
||||
|
||||
* Verilator 3.804 2010/09/20
|
||||
|
||||
*** Support tracing/coverage of underscore signals, bug280. [by Jason McMullan]
|
||||
|
||||
**** Fix preprocessor `` of existing base define, bug283. [Usha Priyadharshini]
|
||||
|
||||
**** Increase define recursions before error. [Paul Liu]
|
||||
|
||||
**** On core dump, print debug suggestions.
|
||||
|
||||
* Verilator 3.803 2010/07/10
|
||||
|
||||
*** Fix preprocessor preservation of newlines across macro substitutions.
|
||||
|
||||
**** Fix preprocessor stringification of nested macros.
|
||||
|
||||
**** Fix some constant parameter functions causing crash, bug253. [Nick Bowler]
|
||||
|
||||
**** Fix do {...} while() not requiring final semicolon.
|
||||
|
||||
* Verilator 3.802 2010/05/01
|
||||
|
||||
*** Support runtime access to public signal names.
|
||||
|
||||
*** Add /*verilator public_flat_rw*/ for timing-specific public access.
|
||||
|
||||
*** Fix word size to match uint64_t on -m64 systems, bug238. [Joe Eiler]
|
||||
|
||||
**** Improve error handling on slices of arrays, bug226. [by Byron Bradley]
|
||||
|
||||
**** Report errors when extra underscores used in meta-comments.
|
||||
|
||||
**** Fix bit reductions on multi-packed dimensions, bug227. [by Byron Bradley]
|
||||
|
||||
**** Fix removing $fscanf if assigned to unused var, bug248. [Ashutosh Das]
|
||||
|
||||
**** Fix "make install" with configure outside srcdir. [Stefan Wallentowitz]
|
||||
|
||||
**** Fix loop unroller out of memory; change --unroll-stmts. [Ashutosh Das]
|
||||
|
||||
**** Fix trace files with empty modules crashing some viewers.
|
||||
|
||||
**** Fix parsing single files > 2GB. [Jeffrey Short]
|
||||
|
||||
**** Fix installing data files as non-executable, bug168. [by Ahmed El-Mahmoudy]
|
||||
|
||||
* Verilator 3.801 2010/03/17
|
||||
|
||||
*** Support "break", "continue", "return".
|
||||
|
||||
*** Support "`default_nettype none|wire". [Dominic Plunkett]
|
||||
|
||||
**** Skip SystemC tests if not installed. [Iztok Jeras]
|
||||
|
||||
**** Fix clock-gates with non-AND complex logic, bug220. [Ashutosh Das]
|
||||
|
||||
**** Fix flushing VCD buffers on $stop. [Ashutosh Das]
|
||||
|
||||
**** Fix Mac OS-X compile issues, bug217. [Joshua Wise, Trevor Williams]
|
||||
|
||||
**** Fix make uninstall, bug216. [Iztok Jeras]
|
||||
|
||||
**** Fix parametrized defines with empty arguments.
|
||||
|
||||
* Verilator 3.800 2010/02/07
|
||||
|
||||
Application visible changes:
|
||||
|
||||
** SystemPerl is no longer required for tracing.
|
||||
Applications must use VerilatedVcdC class in place of SpTraceVcdC.
|
||||
|
||||
** SystemVerilog 1800-2009 is now the default language.
|
||||
Thus "global" etc are now keywords. See the --language option.
|
||||
|
||||
New features:
|
||||
|
||||
** Support SystemVerilog types "byte", "chandle", "int", "longint",
|
||||
"shortint", "time", "var" and "void" in variables and functions.
|
||||
|
||||
** Support "program", "package", "import" and $unit.
|
||||
|
||||
** Support typedef and enum. [by Donal Casey]
|
||||
|
||||
** Support direct programming interface (DPI) "import" and "export".
|
||||
Includes an extension to map user $system PLI calls to the DPI.
|
||||
|
||||
*** Support assignments of multidimensional slices, bug170. [by Byron Bradley]
|
||||
|
||||
*** Support multidimensional inputs/outputs, bug171. [by Byron Bradley]
|
||||
|
||||
*** Support "reg [1:0][1:0][1:0]" and "reg x [3][2]", bug176. [Byron Bradley]
|
||||
|
||||
*** Support declarations in loop initializers, bug172. [by Byron Bradley]
|
||||
|
||||
*** Support $test$plusargs and $value$plusargs, but see the docs!
|
||||
|
||||
*** Support $sformat and $swrite.
|
||||
|
||||
*** Support 1800-2009 define defaults and `undefineall.
|
||||
|
||||
*** Add -CFLAGS, -LDFLAGS, <file>.a, <file>.o, and <file>.so options.
|
||||
|
||||
*** Speed compiles by avoiding including the STL iostream header.
|
||||
Application programs may need to include it themselves to avoid errors.
|
||||
|
||||
*** Add experimental clock domain crossing checks.
|
||||
|
||||
*** Add experimental --pipe-filter to filter all Verilog input.
|
||||
|
||||
*** Add experimental config files to filter warnings outside of the source.
|
||||
|
||||
*** Add VARHIDDEN warning when signal name hides module name.
|
||||
|
||||
**** Support optional cell parenthesis, bug179. [by Byron Bradley]
|
||||
|
||||
**** Support for loop i++, ++i, i--, --i, bug175. [by Byron Bradley]
|
||||
|
||||
**** Support 1800-2009 /*comments*/ in define values.
|
||||
|
||||
**** Add Makefile VM_GLOBAL_FAST, listing objects needed to link executables.
|
||||
|
||||
**** Add --bbox-unsup option to black-box unsupported UDP tables.
|
||||
|
||||
**** Add -Wno-MODDUP option to allow duplicate modules.
|
||||
|
||||
Bug fixes:
|
||||
|
||||
**** Fix implicit variable issues, bug196, bug201. [Byron Bradley]
|
||||
|
||||
**** Fix 'for' variable typing, bug205. [by Byron Bradley]
|
||||
|
||||
**** Fix tracing with --pins-bv 1, bug195. [Michael S]
|
||||
|
||||
**** Fix MSVC++ 2008 compile issues, bug209. [Amir Gonnen]
|
||||
|
||||
**** Fix MinGW compilation, bug184, bug214. [by Shankar Giri, Amir Gonnen]
|
||||
|
||||
**** Fix Cygwin 1.7.x compiler error with uint32_t, bug204. [Ivan Djordjevic]
|
||||
|
||||
**** Fix `define argument mis-replacing system task of same name, bug191.
|
||||
|
||||
**** Fix Verilator core dump on wide integer divides, bug178. [Byron Bradley]
|
||||
|
||||
**** Fix lint_off/lint_on meta comments on same line as warning.
|
||||
|
||||
* Verilator 3.720 2009/10/26
|
||||
|
||||
** Support little endian bit vectors ("reg [0:2] x;").
|
||||
@@ -1504,7 +1692,7 @@ of input ports exists for tracing.
|
||||
|
||||
This uses outline mode in Emacs. See C-h m [M-x describe-mode].
|
||||
|
||||
Copyright 2001-2009 by Wilson Snyder. This program is free software; you
|
||||
Copyright 2001-2011 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
+12
-6
@@ -4,10 +4,10 @@
|
||||
\.svn/
|
||||
\.(bak|old)/
|
||||
\.(bak|old)$
|
||||
\bMakefile$
|
||||
\.tar\.
|
||||
.*\.tgz
|
||||
.*\.log
|
||||
\..*\.swp
|
||||
.*\.tmp
|
||||
.*\.tex
|
||||
.*\.key
|
||||
@@ -18,11 +18,17 @@
|
||||
/INCA_libs/
|
||||
/cov_work/
|
||||
/logs/
|
||||
Makefile
|
||||
src/Makefile_obj
|
||||
include/verilated.mk
|
||||
config.cache
|
||||
config.status
|
||||
^Makefile$
|
||||
src/Makefile$
|
||||
src/Makefile_obj$
|
||||
include/verilated.mk$
|
||||
config.cache$
|
||||
config.status$
|
||||
verilator_bin.*
|
||||
.vcsmx_rebuild$
|
||||
autom4te\.cache/
|
||||
nodist/
|
||||
/simv$
|
||||
/simv.daidir/
|
||||
/vc_hdrs.h$
|
||||
/csrc/
|
||||
|
||||
+125
-61
@@ -9,7 +9,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -58,7 +58,7 @@ INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = texi2dvi
|
||||
POD2TEXT = pod2text
|
||||
PERL = @PERL@
|
||||
|
||||
# Destination prefix for RPMs
|
||||
@@ -97,7 +97,7 @@ SHELL = /bin/sh
|
||||
|
||||
SUBDIRS = src test_verilated test_c test_sc test_sp test_regress test_vcs
|
||||
|
||||
INFOS = README verilator.txt verilator.html verilator.1 verilator.pdf
|
||||
INFOS = README internals.txt verilator.txt verilator.html verilator.1 verilator.pdf
|
||||
|
||||
# Files that can be generated, but should be up to date for a distribution.
|
||||
DISTDEP = info Makefile
|
||||
@@ -106,25 +106,28 @@ DISTBIN = $(wildcard bin/verilator-*)
|
||||
|
||||
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
*.in *.ac \
|
||||
Changes README TODO \
|
||||
Changes TODO \
|
||||
MANIFEST.SKIP \
|
||||
bin/* \
|
||||
install-sh configure mkinstalldirs *.texi \
|
||||
include/verilated*.[chv]* \
|
||||
install-sh configure mkinstalldirs *.pod \
|
||||
include/*.[chv]* \
|
||||
include/*.in \
|
||||
include/.*ignore \
|
||||
include/vltstd/*.[chv]* \
|
||||
.*attributes */.*attributes */*/.*attributes \
|
||||
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
|
||||
src/*.pl src/*.pod \
|
||||
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
|
||||
test_*/*.pl test_*/*.v test_*/*.vc test_*/vlint \
|
||||
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \
|
||||
test_verilated/vgen*.pl \
|
||||
test_regress/t/tsub/*.v* \
|
||||
test_regress/t/*.cpp \
|
||||
test_regress/t/*.h \
|
||||
test_regress/t/*.dat \
|
||||
test_regress/t/*.mem \
|
||||
test_regress/t/*.out \
|
||||
test_regress/t/*.pl \
|
||||
test_regress/t/*.pf \
|
||||
test_regress/t/*.v* \
|
||||
verilator.* \
|
||||
|
||||
@@ -132,10 +135,9 @@ INST_PROJ_FILES = \
|
||||
bin/verilator \
|
||||
bin/verilator_includer \
|
||||
bin/verilator_profcfunc \
|
||||
include/verilated.[chv]* \
|
||||
include/verilated.mk \
|
||||
include/verilatedos.[chv]* \
|
||||
include/verilatedsc.[chv]* \
|
||||
include/*.[chv]* \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
INST_PROJ_BIN_FILES = \
|
||||
verilator_bin \
|
||||
@@ -143,18 +145,19 @@ INST_PROJ_BIN_FILES = \
|
||||
|
||||
DISTFILES := $(DISTFILES_INC)
|
||||
|
||||
VL_INST_MAN_FILES = verilator.1
|
||||
|
||||
ifeq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE_JOBS :=
|
||||
else
|
||||
ifeq ($(OBJCACHE_JOBS),)
|
||||
ifneq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||
endif
|
||||
endif
|
||||
|
||||
default: all
|
||||
all: all_nomsg msg_test
|
||||
all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
|
||||
|
||||
.PHONY:verilator_exe
|
||||
.PHONY:verilator_bin
|
||||
.PHONY:verilator_bin_dbg
|
||||
verilator_exe verilator_bin verilator_bin_dbg:
|
||||
@echo ------------------------------------------------------------
|
||||
@echo "making verilator in src" ; \
|
||||
@@ -204,7 +207,7 @@ verilator.1: bin/verilator
|
||||
pod2man $< $@
|
||||
|
||||
verilator.txt: bin/verilator
|
||||
pod2text $< $@
|
||||
$(POD2TEXT) $< $@
|
||||
|
||||
verilator.html: bin/verilator
|
||||
pod2html $< >$@
|
||||
@@ -225,49 +228,95 @@ verilator.pdf: bin/verilator $(DISTCONFIG)
|
||||
pdflatex verilator.tex
|
||||
-rm -f verilator.toc verilator.aux verilator.idx verilator.out
|
||||
|
||||
INSTALL: install.texi
|
||||
$(MAKEINFO) -I$(srcdir) $(srcdir)/install.texi --output=$@ \
|
||||
--no-headers --no-validate
|
||||
README: readme.pod
|
||||
-rm -f $@
|
||||
$(POD2TEXT) --loose $< > $@
|
||||
|
||||
README: readme.texi
|
||||
$(MAKEINFO) -I$(srcdir) $(srcdir)/readme.texi --output=$@ \
|
||||
--no-headers --no-validate
|
||||
internals.txt: internals.pod
|
||||
-rm -f $@
|
||||
$(POD2TEXT) --loose $< > $@
|
||||
|
||||
# See uninstall also
|
||||
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
||||
verilator_includer verilator_profcfunc
|
||||
# Some scripts go into both the search path and pkgdatadir,
|
||||
# so they can be found by the user, and under $VERILATOR_ROOT.
|
||||
|
||||
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||
VL_INST_MAN_FILES = verilator.1
|
||||
|
||||
VL_INST_INC_BLDDIR_FILES = \
|
||||
include/verilated.mk \
|
||||
|
||||
# Files under srcdir, instead of build time
|
||||
VL_INST_INC_SRCDIR_FILES = \
|
||||
include/*.[chv]* \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
VL_INST_DATA_SRCDIR_FILES = \
|
||||
test_v/*.[chv]* \
|
||||
test_c/*.[chv]* test_c/Makefile test_c/Makefile_obj \
|
||||
test_sc/*.[chv]* test_sc/Makefile test_sc/Makefile_obj \
|
||||
test_sp/*.[chv]* test_sp/Makefile test_sp/Makefile_obj \
|
||||
|
||||
installbin:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
||||
( cd bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||
( cd bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
|
||||
( $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin )
|
||||
( $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg )
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
|
||||
( cd bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
|
||||
|
||||
installman:
|
||||
installman: $(VL_INST_MAN_FILES)
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(mandir)/man1
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
||||
done
|
||||
|
||||
installdata:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r include $(DESTDIR)$(pkgdatadir)
|
||||
cp -r test_c $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r test_sc $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r test_sp $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r test_v $(DESTDIR)$(pkgdatadir)/examples
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||
for p in $(VL_INST_INC_BLDDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_INC_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
|
||||
done
|
||||
|
||||
# We don't trust rm -rf, so rmdir instead as it will fail if user put in other files
|
||||
uninstall:
|
||||
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir)/bin && rm -f $(VL_INST_BIN_FILES)
|
||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_BLDDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_SRCDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_SRCDIR_FILES)
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/bin
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||
|
||||
VL_INST_DATA_FILES = verilator.1
|
||||
install: all_nomsg installbin installman installdata install-msg
|
||||
|
||||
install-here: installman ftp
|
||||
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
DIRPROJECT := $(shell project_dir --project)
|
||||
VERILATOR_CAD_DIR = $(CAD_DIR)/verilator/$(DISTNAMEREV)/$(DIRPROJECT_ARCH)
|
||||
INST_PROJ_CVS = cp_if_cvs_diff
|
||||
|
||||
install-project: dist
|
||||
@@ -275,7 +324,7 @@ install-project: dist
|
||||
strip verilator_bin*
|
||||
$(MAKE) install-project-quick
|
||||
for p in verilator.1 ; do \
|
||||
$(INSTALL_PROGRAM) -m 0666 $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||
done
|
||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
|
||||
rm $(DISTNAME).tgz
|
||||
@@ -292,6 +341,34 @@ endif
|
||||
for p in $(INST_PROJ_BIN_FILES) ; do \
|
||||
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p-$(DIRPROJECT_ARCH); \
|
||||
done
|
||||
|
||||
install-cadtools: dist
|
||||
@echo "Install-project to $(CAD_DIR)"
|
||||
strip verilator_bin*
|
||||
$(MAKE) install-cadtools-quick
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
|
||||
for p in verilator.1 ; do \
|
||||
$(INSTALL_DATA) $$p $(VERILATOR_CAD_DIR)/man/man1/$$p; \
|
||||
done
|
||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(VERILATOR_CAD_DIR)/verilator.tgz
|
||||
rm $(DISTNAME).tgz
|
||||
|
||||
install-cadtools-quick:
|
||||
ifeq ($(CFG_WITH_DEFENV),yes)
|
||||
@echo "%Error: Reconfigure with './configure --disable-defenv' to avoid hardcoded paths."
|
||||
false
|
||||
endif
|
||||
@echo "Install-cadtools-quick (no strip) to $(VERILATOR_CAD_DIR)"
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/include/vltstd
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/bin
|
||||
for p in $(INST_PROJ_FILES) ; do \
|
||||
$(INST_PROJ_CVS) $$p $(VERILATOR_CAD_DIR)/$$p; \
|
||||
done
|
||||
for p in $(INST_PROJ_BIN_FILES) ; do \
|
||||
$(INST_PROJ_CVS) $$p $(VERILATOR_CAD_DIR)/$$p; \
|
||||
done
|
||||
|
||||
# VERILATOR_AUTHOR_SITE
|
||||
endif
|
||||
|
||||
ftp: info
|
||||
@@ -299,33 +376,19 @@ ftp: info
|
||||
install-msg:
|
||||
@echo "Installed!"
|
||||
@echo
|
||||
@echo "Add to your startup file (for bash or csh, as appropriate):"
|
||||
@echo " export VERILATOR_ROOT="`pwd`
|
||||
@echo " setenv VERILATOR_ROOT "`pwd` " ; export VERILATOR_ROOT "
|
||||
@echo
|
||||
@echo "See 'verilator.txt' for documentation."
|
||||
@echo "Fod documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see http://www.veripool.org/verilator"
|
||||
@echo
|
||||
|
||||
uninstall:
|
||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
||||
-rm -f $(DESTDIR)$(pkgdatadir)
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||
|
||||
# autoheader might not change config_build.h.in, so touch a stamp file.
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in ${srcdir}/*/*/*.in \
|
||||
*.in */*.in */*.in
|
||||
|
||||
${srcdir}/config_build.h.in: stamp-h.in
|
||||
${srcdir}/stamp-h.in: configure.ac $(wildcard $(IN_WILD))
|
||||
# autoheader might not change config_build.h.in, so touch it
|
||||
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
|
||||
cd ${srcdir} && autoheader
|
||||
echo timestamp > ${srcdir}/stamp-h.in
|
||||
config_build.h: stamp-h
|
||||
stamp-h: config_build.h.in config.status
|
||||
./config.status
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
src/Makefile: src/Makefile.in config.status
|
||||
touch $@
|
||||
Makefile: Makefile.in config.status $(IN_WILD)
|
||||
./config.status
|
||||
src/Makefile: src/Makefile.in Makefile
|
||||
config.status: configure
|
||||
./config.status --recheck
|
||||
configure: configure.ac
|
||||
@@ -334,7 +397,7 @@ configure: configure.ac
|
||||
maintainer-clean::
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "rebuilding the deleted files requires makeinfo."
|
||||
rm -f *.info* $(INFOS) faq.html verilator.html configure
|
||||
rm -f *.info* $(INFOS) configure
|
||||
|
||||
clean mostlyclean distclean maintainer-clean maintainer-copy::
|
||||
for dir in $(SUBDIRS); do \
|
||||
@@ -354,7 +417,7 @@ distclean maintainer-clean::
|
||||
rm -f include/verilated.mk
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/[a-z]*.in \
|
||||
${srcdir}/[a-z]*.in ${srcdir}/*.texi
|
||||
${srcdir}/[a-z]*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
@@ -370,11 +433,12 @@ dist-file-list:
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
DISTCONFIG = src/config_build.h.in
|
||||
DISTCONFIG = ${srcdir}/src/config_build.h.in
|
||||
|
||||
DISTTITLE := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e 's/v/V/' -e q $(DISTCONFIG))
|
||||
DISTNAME := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e q $(DISTCONFIG))
|
||||
DISTDATEPRE := $(shell sed -e '/DTVERSION/!d' -e 's/.*\([1-2][0-9][0-9][0-9].[0-9]*[0-9].[0-9]*[0-9]\).*/\1/' -e q $(DISTCONFIG))
|
||||
DISTNAMEREV := $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q src/config_rev.h)
|
||||
|
||||
DISTTAGNAME := $(subst .,_,$(subst -,_,$(DISTNAME)))
|
||||
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
||||
|
||||
@@ -1,154 +1,139 @@
|
||||
// DESCRIPTION: Verilator: List of To Do issues.
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
|
||||
Features:
|
||||
Finish 3.400 new ordering fixes
|
||||
Latch optimizations {Need here}
|
||||
Task I/Os connecting to non-simple variables.
|
||||
Fix nested casez statements expanding into to huge C++. [JeanPaul Vanitegem]
|
||||
Fix FileLine memory inefficiency
|
||||
Fix ordering of each bit separately in a signal (mips)
|
||||
Language support:
|
||||
* Fix ordering of each bit separately in a signal (mips)
|
||||
assign b[3:0] = b[7:4]; assign b[7:4] = in;
|
||||
Support gate primitives/ cell libraries from xilinx, etc
|
||||
Assign dont_care value to an 1'bzzz assignment
|
||||
Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
||||
Support generated clocks (correctness)
|
||||
?gcov coverage
|
||||
Selectable SystemC types based on widths (see notes below)
|
||||
Compile time
|
||||
Inline first level trace routines
|
||||
Coverage
|
||||
Points should be per-scope like everything else rather then per-module
|
||||
Expression coverage (see notes)
|
||||
Constant functions for widths, etc, IE "input [log2(PARAM):0] xx;"
|
||||
More Verilog 2001 Support
|
||||
(* *) Attributes (just ignore -- preprocessor?)
|
||||
Real numbers (NEVER)
|
||||
Recursive functions (NEVER)
|
||||
Verilog configuration files (NEVER)
|
||||
DPI to define C/C++ calls from Verilog
|
||||
* Support UDP gate primitives/ cell libraries
|
||||
(have code for combos - problem is sequential udps)
|
||||
* Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
||||
* Support generated clocks (correctness)
|
||||
* Real numbers
|
||||
* Recursive functions
|
||||
* Verilog configuration files
|
||||
* Structs/unions (have starting point)
|
||||
* DPI to define C/C++ calls from Verilog
|
||||
* Expression coverage (see notes)
|
||||
* Better tristate support
|
||||
|
||||
Long-term Features
|
||||
Assertions
|
||||
VHDL parser [Philips]
|
||||
Tristate support
|
||||
SystemPerl integration
|
||||
Multithreaded execution
|
||||
Front end parser integration into Verilog-Perl like Netlist
|
||||
* Assertions
|
||||
* Tristate support
|
||||
* Multithreaded execution
|
||||
|
||||
Configure/Make/Install
|
||||
* Full MSVC++ compilation (does scons support this?) (4.000?)
|
||||
* Distribute with flex/bison already expanded?
|
||||
Flex library not needed. Probably too difficult to be worth it.
|
||||
* Integrate SystemPerl coverage
|
||||
(Note in /usr/include there are no upper cased include files.)
|
||||
Coverage.pm -- Need all functionality, but in C?
|
||||
Coverage/Item.pm -- Need all functionality, but in C?
|
||||
Coverage/ItemKey.pm -- Need all functionality, but in C?
|
||||
sp_preproc -- Some steps in here need to be moved to generated C
|
||||
src/Sp.cpp -- n/a
|
||||
src/SpCommon.h -- mostly overlaps verilatedos.h
|
||||
src/SpCoverage.cpp/h -- All needed
|
||||
src/SpFunctor.cpp/h -- No longer used
|
||||
src/SpTraceVcd.cpp/h -- MOVED
|
||||
src/SpTraceVcdC.cpp/h -- MOVED
|
||||
src/sp_log.cpp/h -- Not needed
|
||||
src/systemperl.h -- some stuff may be cut
|
||||
vcoverage -- Need all functionality, but in C?
|
||||
|
||||
Testing:
|
||||
Capture all inputs into global "rerun it" file
|
||||
Code to make wrapper that sets signals, so can do comparison checks
|
||||
New random program generator
|
||||
Better graph viewer with search and zoom
|
||||
Port and test against opencores.org code
|
||||
* Move test_c/sp/v/verilated into test_regress format (4.000?)
|
||||
* Capture all inputs into global "rerun it" file
|
||||
* Code to make wrapper that sets signals, so can do comparison checks
|
||||
* New random program generator
|
||||
* Better graph viewer with search and zoom
|
||||
* Port and test against opencores.org code
|
||||
|
||||
Usability:
|
||||
Better reporting of unopt problems, including what lines of code
|
||||
Report more errors (all of them?) before exiting [Eugene Weber]
|
||||
* Detect and pre-remove most UNOPTFLATs (4.000)
|
||||
* Better reporting of unopt problems, including what lines of code
|
||||
* Report more errors (all of them?) before exiting [Eugene Weber]
|
||||
* Auto-create scons config files
|
||||
* Print version/etc message at runtime. (4.000?)
|
||||
Include number of lines of code, percent comments, code complexity measurement
|
||||
<-80chars------------------------------------------------------------------->
|
||||
Verilator 3.600 - fast, free, open-sourced. Copyright 2001-2011.
|
||||
Verilated #### modules, #### instances, ##### sigs,
|
||||
#### non-comment lines, ##### ops, ### KB model size
|
||||
* Default the --l2name to remove extra "v" level of hierarchy (flag to make "top")
|
||||
|
||||
Internal Code:
|
||||
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||
and removing it will speed up and simplify all the other code.
|
||||
V3Graph should be templated container type, taking in Vertex + Edge types
|
||||
* Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||
and removing it will speed up and simplify all the other code.
|
||||
* V3Graph should be templated container type, taking in Vertex + Edge types
|
||||
* Rename V3PreLex etc to match VerilogPerl filenames
|
||||
* Instead of string, have an VEncodedString/VIdString which contains __DOT__ish
|
||||
things, to reduce bugs. Also add _20 trailing space to \ encoded names. (4.000)
|
||||
|
||||
Runtime:
|
||||
* New evalulation loop ~/src/verilator/notes/event_loop.txt (4.000?)
|
||||
* Remove all private internal functions from top level wrapper header, move
|
||||
to new level (4.000?)
|
||||
* Completely standalone simulation (4.000)
|
||||
main() records arguments for $test$plusvars
|
||||
instantiates top,
|
||||
does tracing (support $dump?)
|
||||
calls top->simulateForever()
|
||||
exits
|
||||
|
||||
Performance:
|
||||
Constant propagation
|
||||
* Latch optimizations
|
||||
* Constant propagation
|
||||
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
||||
Extra shift (perhaps due to clean): if (1 & CAST (VARREF >> #))
|
||||
Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
||||
* Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
||||
Could propagate the AND into pos/negedges and let domaining optimize.
|
||||
Negedge reset
|
||||
* Negedge reset
|
||||
Switch to remove negedges that don't matter
|
||||
Can't remove async resets from control flops (like in syncronizers)
|
||||
If all references to array have a constant index, blow up into separate signals-per-index
|
||||
Multithreaded execution
|
||||
Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
||||
Move _last sets and all other combo logic inside master
|
||||
* If all references to array have a constant index, blow up into separate signals-per-index
|
||||
* Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
||||
* Move _last sets and all other combo logic inside master
|
||||
if() that triggers on all possible sense items
|
||||
Rewrite and combine V3Life, V3Subst
|
||||
* Rewrite and combine V3Life, V3Subst
|
||||
If block temp only ever set in one place to constant, propagate it
|
||||
Used in t_mem for array delayed assignments
|
||||
Replace variables if set later in same cfunc branch
|
||||
See for example duplicate sets of _narrow in cycle 90/91 of t_select_plusloop
|
||||
Same assignment on both if branches
|
||||
* Same assignment on both if branches
|
||||
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
||||
Careful though, as b could appear in the statement or multiple times in statement
|
||||
(Could just require exatly two 'b's in statement)
|
||||
Simplify XOR/XNOR/AND/OR bit selection trees
|
||||
* Simplify XOR/XNOR/AND/OR bit selection trees
|
||||
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
||||
Combine variables into wider elements
|
||||
* Combine variables into wider elements
|
||||
Parallel statements on different bits should become single signal
|
||||
Variables that are always consumed in "parallel" can be joined
|
||||
Duplicate assignments in gate optimization
|
||||
* Duplicate assignments in gate optimization
|
||||
Common to have many separate posedge blocks, each with identical
|
||||
reset_r <= rst_in
|
||||
*If signal is used only once (not counting trace), always gate substitute
|
||||
* If signal is used only once (not counting trace), always gate substitute
|
||||
Don't merge if any combining would form circ logic (out goes back to in)
|
||||
Multiple assignments each bit can become single assign with concat
|
||||
* Multiple assignments each bit can become single assign with concat
|
||||
Make sure a SEL of a CONCAT can get the single bit back.
|
||||
Usually blocks/values
|
||||
* Usually blocks/values
|
||||
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
||||
Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||
Allow Split of case statements without a $display/$stop
|
||||
I-cache packing improvements (what/how?)
|
||||
Data cache organization (order of vars in class)
|
||||
* Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||
* Allow Split of case statements without a $display/$stop
|
||||
* I-cache packing improvements (what/how?)
|
||||
* Data cache organization (order of vars in class)
|
||||
First have clocks,
|
||||
then bools instead of uint32_t's
|
||||
then based on what sense list they come from, all outputs, then all inputs
|
||||
finally have any signals part of a "usually" block, or constant.
|
||||
Rather then tracking widths, have a MSB...LSB of this expression
|
||||
* Rather then tracking widths, have a MSB...LSB of this expression
|
||||
(or better, a bitmask of bits relevant in this expression)
|
||||
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)
|
||||
|
||||
All of the temp vars that get set, exp pre_ vars and never feedback
|
||||
(not flops) don't need to be stored in the structs, but instead can
|
||||
be per-invocation, and even better register-colored-like to reuse
|
||||
the space. This will greatly reduce the data footprint.
|
||||
|
||||
|
||||
//**********************************************************************
|
||||
//* Detailed notes on 'todo' features
|
||||
|
||||
Selectable SystemC types based on widths (see notes below)
|
||||
Statements:
|
||||
verilator sc_type uint32_t {override specific I/O signals}
|
||||
verilator sc_typedef width 1 bool
|
||||
verilator sc_typedef width 2-32 uint32_t
|
||||
verilator sc_typedef width 33-64 uint64_t
|
||||
verilator sc_typedef width 65+ sc_bv<width> //<< programmable width
|
||||
Replace `systemc_clock, --pins64
|
||||
Have accessor function with type overloading to get or set the pin value.
|
||||
(Get rid of getdatap mess?)
|
||||
|
||||
//**********************************************************************
|
||||
//* Eventual tristate bus Stuff allowed (old verilator)
|
||||
|
||||
1) Tristate assignments must be continuous assignments
|
||||
The RHS of a tristate assignment can be the following
|
||||
a) a node (tristate or non-tristate)
|
||||
b) a constant (must be all or no z's)
|
||||
x'b0, x'bz, x{x'bz}, x{x'b0} -> are allowed
|
||||
c) a conditional whose possible values are (a) or (b)
|
||||
|
||||
2) One can lose that fact that a node is a tristate node. This happens
|
||||
if a tristate node is assigned to a 'standard' node, or is used on
|
||||
RHS of a conditional. The following infer tristate signals:
|
||||
a) inout <SIGNAL>
|
||||
b) tri <SIGNAL>
|
||||
c) assigning to 'Z' (maybe through a conditional)
|
||||
Note: tristate-ness of an output port determined only by
|
||||
statements in the module (not the instances it calls)
|
||||
|
||||
4) Tristate variables can't be multidimensional arrays
|
||||
5) Only check tristate contention between modules (not within!)
|
||||
6) Only simple compares with 'Z' are allowed (===)
|
||||
|
||||
* 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)
|
||||
|
||||
+901
-291
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,7 @@ sub diff_dir {
|
||||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{b} = $fn;
|
||||
}
|
||||
my $any;
|
||||
foreach my $base (sort (keys %files)) {
|
||||
my $a = $files{$base}{a};
|
||||
my $b = $files{$base}{b};
|
||||
@@ -69,7 +70,9 @@ sub diff_dir {
|
||||
print "="x70,"\n";
|
||||
print "= $a <-> $b\n";
|
||||
diff_file($a,$b);
|
||||
$any = 1;
|
||||
}
|
||||
$any or warn "%Warning: No .tree files found\n";
|
||||
}
|
||||
|
||||
sub diff_file {
|
||||
@@ -174,7 +177,7 @@ Do not show differences in line numbering.
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/verilator>.
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. This package is free software; you can
|
||||
Copyright 2005-2011 by Wilson Snyder. This package is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@ eval 'exec perl -wS $0 ${1+"$@"}'
|
||||
if 0;
|
||||
# DESCRIPTION: Print include statements for each ARGV
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This package is free software; you can
|
||||
# Copyright 2003-2011 by Wilson Snyder. This package is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
######################################################################
|
||||
|
||||
require 5.005;
|
||||
use warnings;
|
||||
print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
|
||||
foreach my $param (@ARGV) {
|
||||
print "#include \"$param\"\n"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ Displays this message and program version and exits.
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/>.
|
||||
|
||||
Copyright 2007-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2007-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+1
-2
@@ -1,6 +1,6 @@
|
||||
dnl DESCRIPTION: Process this file with autoconf to produce a configure script.
|
||||
dnl
|
||||
dnl Copyright 2003-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
dnl Copyright 2003-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
dnl redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
dnl General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
@@ -15,7 +15,6 @@ AC_ARG_ENABLE(defenv,
|
||||
AC_SUBST(CFG_WITH_DEFENV)
|
||||
|
||||
dnl Compiler flags
|
||||
CXX=g++
|
||||
CFLAGS=-I${includedir}
|
||||
CPPFLAGS=-I${includedir}
|
||||
CXXFLAGS=-I${includedir}
|
||||
|
||||
+354
-78
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -23,19 +23,30 @@
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#include "verilated.h"
|
||||
#define _VERILATED_CPP_
|
||||
#include "verilated_imp.h"
|
||||
#include <cctype>
|
||||
#include <vector>
|
||||
|
||||
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
|
||||
|
||||
//===========================================================================
|
||||
// Global variables
|
||||
|
||||
// Slow path variables
|
||||
int Verilated::s_randReset = 0;
|
||||
int Verilated::s_debug = 1;
|
||||
VerilatedVoidCb Verilated::s_flushCb = NULL;
|
||||
|
||||
// Keep below together in one cache line
|
||||
int Verilated::s_debug = 0;
|
||||
bool Verilated::s_calcUnusedSigs = false;
|
||||
bool Verilated::s_gotFinish = false;
|
||||
bool Verilated::s_assertOn = true;
|
||||
VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL;
|
||||
VL_THREAD const char* Verilated::t_dpiFilename = "";
|
||||
VL_THREAD int Verilated::t_dpiLineno = 0;
|
||||
|
||||
VerilatedImp VerilatedImp::s_s;
|
||||
|
||||
//===========================================================================
|
||||
// User definable functions
|
||||
@@ -46,6 +57,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) {
|
||||
VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum);
|
||||
if (Verilated::gotFinish()) {
|
||||
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
||||
Verilated::flushCall();
|
||||
exit(0);
|
||||
}
|
||||
Verilated::gotFinish(true);
|
||||
@@ -55,6 +67,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) {
|
||||
#ifndef VL_USER_STOP // Define this to override this function
|
||||
void vl_stop (const char* filename, int linenum, const char* hier) {
|
||||
Verilated::gotFinish(true);
|
||||
Verilated::flushCall();
|
||||
vl_fatal (filename,linenum,hier,"Verilog $stop");
|
||||
}
|
||||
#endif
|
||||
@@ -64,6 +77,7 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
|
||||
if (0 && hier) {}
|
||||
Verilated::gotFinish(true);
|
||||
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
|
||||
Verilated::flushCall();
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
@@ -136,6 +150,15 @@ WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
|
||||
return outwp;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Debug
|
||||
|
||||
void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) {
|
||||
VL_PRINTF(" Data: w%d: ", lbits);
|
||||
for (int i=VL_WORDS_I(lbits)-1; i>=0; i--) { VL_PRINTF("%08x ",iwp[i]); }
|
||||
VL_PRINTF("\n");
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Slow math
|
||||
|
||||
@@ -172,8 +195,8 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
|
||||
}
|
||||
|
||||
// +1 word as we may shift during normalization
|
||||
uint32_t un[VL_MULS_MAX_WORDS+1]; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
uint32_t vn[VL_MULS_MAX_WORDS+1]; // v normalized
|
||||
vluint32_t un[VL_MULS_MAX_WORDS+1]; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
vluint32_t vn[VL_MULS_MAX_WORDS+1]; // v normalized
|
||||
|
||||
// Zero for ease of debugging and to save having to zero for shifts
|
||||
for (int i=0; i<words; i++) { un[i]=vn[i]=0; }
|
||||
@@ -181,7 +204,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
|
||||
// Algorithm requires divisor MSB to be set
|
||||
// Copy and shift to normalize divisor so MSB of vn[vw-1] is set
|
||||
int s = 31-VL_BITBIT_I(vmsbp1-1); // shift amount (0...31)
|
||||
uint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
|
||||
vluint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
|
||||
for (int i = vw-1; i>0; i--) {
|
||||
vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i-1] >> (32-s)));
|
||||
}
|
||||
@@ -292,6 +315,11 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
case '%':
|
||||
output += '%';
|
||||
break;
|
||||
case 'N': { // "C" string with name of module, add . if needed
|
||||
const char* cstrp = va_arg(ap, const char*);
|
||||
if (VL_LIKELY(*cstrp)) { output += cstrp; output += '.'; }
|
||||
break;
|
||||
}
|
||||
case 'S': { // "C" string
|
||||
const char* cstrp = va_arg(ap, const char*);
|
||||
output += cstrp;
|
||||
@@ -328,14 +356,14 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
}
|
||||
break;
|
||||
case 'd': { // Signed decimal
|
||||
int digits=sprintf(tmp,"%lld",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
|
||||
int digits=sprintf(tmp,"%" VL_PRI64 "d",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
||||
output += tmp;
|
||||
break;
|
||||
}
|
||||
case 'u': { // Unsigned decimal
|
||||
int digits=sprintf(tmp,"%llu",ld);
|
||||
int digits=sprintf(tmp,"%" VL_PRI64 "u",ld);
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
||||
output += tmp;
|
||||
@@ -344,13 +372,13 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
case 't': { // Time
|
||||
int digits;
|
||||
if (VL_TIME_MULTIPLIER==1) {
|
||||
digits=sprintf(tmp,"%llu",ld);
|
||||
digits=sprintf(tmp,"%" VL_PRI64 "u",ld);
|
||||
} else if (VL_TIME_MULTIPLIER==1000) {
|
||||
digits=sprintf(tmp,"%llu.%03llu",
|
||||
digits=sprintf(tmp,"%" VL_PRI64 "u.%03" VL_PRI64 "u",
|
||||
(QData)(ld/VL_TIME_MULTIPLIER),
|
||||
(QData)(ld%VL_TIME_MULTIPLIER));
|
||||
} else {
|
||||
vl_fatal(__FILE__,__LINE__,"","%%Error: Unsupported VL_TIME_MULTIPLIER");
|
||||
vl_fatal(__FILE__,__LINE__,"","Unsupported VL_TIME_MULTIPLIER");
|
||||
}
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
||||
@@ -382,7 +410,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
string msg = string("%%Error: Unknown _vl_vsformat code: ")+pos[0]+"\n";
|
||||
string msg = string("Unknown _vl_vsformat code: ")+pos[0];
|
||||
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
||||
break;
|
||||
} // switch
|
||||
@@ -393,7 +421,8 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
}
|
||||
|
||||
static inline bool _vl_vsss_eof(FILE* fp, int& floc) {
|
||||
return fp ? feof(fp) : (floc<0);
|
||||
if (fp) return feof(fp) ? 1 : 0; // 1:0 to prevent MSVC++ warning
|
||||
else return (floc<0);
|
||||
}
|
||||
static inline void _vl_vsss_advance(FILE* fp, int& floc) {
|
||||
if (fp) fgetc(fp);
|
||||
@@ -441,6 +470,32 @@ static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
|
||||
VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1);
|
||||
}
|
||||
}
|
||||
static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, int posstart, int posend) {
|
||||
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits.
|
||||
int lsb = 0;
|
||||
for (int i=0, pos=posend-1; i<obits && pos>=posstart; pos--) {
|
||||
switch (tolower (strp[pos])) {
|
||||
case 'x': case 'z': case '?': //FALLTHRU
|
||||
case '0': lsb += baseLog2; break;
|
||||
case '1': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 1); lsb+=baseLog2; break;
|
||||
case '2': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 2); lsb+=baseLog2; break;
|
||||
case '3': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 3); lsb+=baseLog2; break;
|
||||
case '4': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 4); lsb+=baseLog2; break;
|
||||
case '5': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 5); lsb+=baseLog2; break;
|
||||
case '6': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 6); lsb+=baseLog2; break;
|
||||
case '7': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 7); lsb+=baseLog2; break;
|
||||
case '8': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 8); lsb+=baseLog2; break;
|
||||
case '9': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 9); lsb+=baseLog2; break;
|
||||
case 'a': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 10); lsb+=baseLog2; break;
|
||||
case 'b': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 11); lsb+=baseLog2; break;
|
||||
case 'c': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 12); lsb+=baseLog2; break;
|
||||
case 'd': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 13); lsb+=baseLog2; break;
|
||||
case 'e': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 14); lsb+=baseLog2; break;
|
||||
case 'f': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 15); lsb+=baseLog2; break;
|
||||
case '_': break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
int fbits, WDataInP fromp, // Else if a sscanf
|
||||
@@ -480,7 +535,6 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
// Deal with all read-and-scan somethings
|
||||
// Note LSBs are preserved if there's an overflow
|
||||
const int obits = va_arg(ap, int);
|
||||
int lsb = 0;
|
||||
WData qowp[2];
|
||||
WDataOutP owp = qowp;
|
||||
if (obits > VL_QUADSIZE) {
|
||||
@@ -499,7 +553,8 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, NULL);
|
||||
if (!tmp[0]) goto done;
|
||||
int pos = strlen(tmp)-1;
|
||||
int pos = ((int)strlen(tmp))-1;
|
||||
int lsb = 0;
|
||||
for (int i=0; i<obits && pos>=0; pos--) {
|
||||
_vl_vsss_setbit(owp,obits,lsb, 8, tmp[pos]); lsb+=8;
|
||||
}
|
||||
@@ -507,90 +562,46 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
}
|
||||
case 'd': { // Signed decimal
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_");
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
vlsint64_t ld;
|
||||
sscanf(tmp,"%lld",&ld);
|
||||
sscanf(tmp,"%" VL_PRI64 "d",&ld);
|
||||
VL_SET_WQ(owp,ld);
|
||||
break;
|
||||
}
|
||||
case 't': // FALLTHRU // Time
|
||||
case 'u': { // Unsigned decimal
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_");
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
QData ld;
|
||||
sscanf(tmp,"%llu",&ld);
|
||||
sscanf(tmp,"%" VL_PRI64 "u",&ld);
|
||||
VL_SET_WQ(owp,ld);
|
||||
break;
|
||||
}
|
||||
case 'b': {
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "01xz?_");
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "01xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
int pos = strlen(tmp)-1;
|
||||
for (int i=0; i<obits && pos>=0; pos--) {
|
||||
switch(tmp[pos]) {
|
||||
case 'x': case 'z': case '?': //FALLTHRU
|
||||
case '0': lsb++; break;
|
||||
case '1': _vl_vsss_setbit(owp,obits,lsb, 1, 1); lsb++; break;
|
||||
case '_': break;
|
||||
}
|
||||
}
|
||||
_vl_vsss_based(owp,obits, 1, tmp, 0, (int)strlen(tmp));
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "01234567xz?_");
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "01234567xXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
int pos = strlen(tmp)-1;
|
||||
for (int i=0; i<obits && pos>=0; pos--) {
|
||||
switch(tmp[pos]) {
|
||||
case 'x': case 'z': case '?': //FALLTHRU
|
||||
case '0': lsb+=3; break;
|
||||
case '1': _vl_vsss_setbit(owp,obits,lsb, 3, 1); lsb+=3; break;
|
||||
case '2': _vl_vsss_setbit(owp,obits,lsb, 3, 2); lsb+=3; break;
|
||||
case '3': _vl_vsss_setbit(owp,obits,lsb, 3, 3); lsb+=3; break;
|
||||
case '4': _vl_vsss_setbit(owp,obits,lsb, 3, 4); lsb+=3; break;
|
||||
case '5': _vl_vsss_setbit(owp,obits,lsb, 3, 5); lsb+=3; break;
|
||||
case '6': _vl_vsss_setbit(owp,obits,lsb, 3, 6); lsb+=3; break;
|
||||
case '7': _vl_vsss_setbit(owp,obits,lsb, 3, 7); lsb+=3; break;
|
||||
case '_': break;
|
||||
}
|
||||
}
|
||||
_vl_vsss_based(owp,obits, 3, tmp, 0, (int)strlen(tmp));
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefxz?_");
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefABCDEFxXzZ?_");
|
||||
if (!tmp[0]) goto done;
|
||||
int pos = strlen(tmp)-1;
|
||||
for (int i=0; i<obits && pos>=0; pos--) {
|
||||
switch(tmp[pos]) {
|
||||
case 'x': case 'z': case '?': //FALLTHRU
|
||||
case '0': lsb+=4; break;
|
||||
case '1': _vl_vsss_setbit(owp,obits,lsb, 4, 1); lsb+=4; break;
|
||||
case '2': _vl_vsss_setbit(owp,obits,lsb, 4, 2); lsb+=4; break;
|
||||
case '3': _vl_vsss_setbit(owp,obits,lsb, 4, 3); lsb+=4; break;
|
||||
case '4': _vl_vsss_setbit(owp,obits,lsb, 4, 4); lsb+=4; break;
|
||||
case '5': _vl_vsss_setbit(owp,obits,lsb, 4, 5); lsb+=4; break;
|
||||
case '6': _vl_vsss_setbit(owp,obits,lsb, 4, 6); lsb+=4; break;
|
||||
case '7': _vl_vsss_setbit(owp,obits,lsb, 4, 7); lsb+=4; break;
|
||||
case '8': _vl_vsss_setbit(owp,obits,lsb, 4, 8); lsb+=4; break;
|
||||
case '9': _vl_vsss_setbit(owp,obits,lsb, 4, 9); lsb+=4; break;
|
||||
case 'a': _vl_vsss_setbit(owp,obits,lsb, 4, 10); lsb+=4; break;
|
||||
case 'b': _vl_vsss_setbit(owp,obits,lsb, 4, 11); lsb+=4; break;
|
||||
case 'c': _vl_vsss_setbit(owp,obits,lsb, 4, 12); lsb+=4; break;
|
||||
case 'd': _vl_vsss_setbit(owp,obits,lsb, 4, 13); lsb+=4; break;
|
||||
case 'e': _vl_vsss_setbit(owp,obits,lsb, 4, 14); lsb+=4; break;
|
||||
case 'f': _vl_vsss_setbit(owp,obits,lsb, 4, 15); lsb+=4; break;
|
||||
case '_': break;
|
||||
}
|
||||
}
|
||||
_vl_vsss_based(owp,obits, 4, tmp, 0, (int)strlen(tmp));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
string msg = string("%%Error: Unknown _vl_vsscanf code: ")+pos[0]+"\n";
|
||||
string msg = string("Unknown _vl_vsscanf code: ")+pos[0];
|
||||
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
||||
break;
|
||||
} // switch
|
||||
@@ -618,6 +629,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
// File I/O
|
||||
|
||||
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
|
||||
// See also VL_DATA_TO_STRING_NW
|
||||
int lsb=obits-1;
|
||||
bool start=true;
|
||||
char* destp = destoutp;
|
||||
@@ -683,6 +695,26 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
||||
return VL_CVT_FP_Q(fopen(filenamez,modez));
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
string output;
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, destp, (int)output.length(), output.c_str());
|
||||
}
|
||||
|
||||
string VL_SFORMATF_NX(const char* formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
string output;
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void VL_WRITEF(const char* formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
@@ -755,7 +787,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
||||
FILE* fp = fopen(ofilenamez, "r");
|
||||
if (!fp) {
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||
vl_fatal (ofilenamez, 0, "", "$readmem file not found");
|
||||
return;
|
||||
@@ -774,7 +806,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
// with changing buffer sizes dynamically, etc.
|
||||
while (1) {
|
||||
int c = fgetc(fp);
|
||||
if (c==EOF) break;
|
||||
if (VL_UNLIKELY(c==EOF)) break;
|
||||
//printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n", linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc);
|
||||
if (c=='\n') { linenum++; ignore_to_eol=false; if (innum) reading_addr=false; innum=false; }
|
||||
else if (c=='\t' || c==' ' || c=='\r' || c=='\f') { if (innum) reading_addr=false; innum=false; }
|
||||
@@ -801,7 +833,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
} else {
|
||||
needinc = true;
|
||||
//printf(" Value width=%d @%x = %c\n", width, addr, c);
|
||||
if (addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb)) {
|
||||
if (VL_UNLIKELY(addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb))) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmem file address beyond bounds of array");
|
||||
} else {
|
||||
int entry = addr - array_lsb;
|
||||
@@ -826,10 +858,10 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
} else {
|
||||
WDataOutP datap = &((WDataOutP)(memp))[ entry*VL_WORDS_I(width) ];
|
||||
if (!innum) { VL_ZERO_RESET_W(width, datap); }
|
||||
_VL_SHIFTL_INPLACE_W(width, datap, shift);
|
||||
_VL_SHIFTL_INPLACE_W(width, datap, (IData)shift);
|
||||
datap[0] |= value;
|
||||
}
|
||||
if (value>=(1<<shift)) {
|
||||
if (VL_UNLIKELY(value>=(1<<shift))) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmemb (binary) file contains hex characters");
|
||||
}
|
||||
}
|
||||
@@ -846,11 +878,86 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
|
||||
// Final checks
|
||||
fclose(fp);
|
||||
if (end != (IData)(~ VL_ULL(0)) && addr != (end+1)) {
|
||||
if (VL_UNLIKELY(end != VL_UL(0xffffffff) && addr != (end+1))) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmem file ended before specified ending-address");
|
||||
}
|
||||
}
|
||||
|
||||
IData VL_TESTPLUSARGS_I(const char* formatp) {
|
||||
string match = VerilatedImp::argPlusMatch(formatp);
|
||||
if (match == "") return 0;
|
||||
else return 1;
|
||||
}
|
||||
|
||||
IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp) {
|
||||
string match = VerilatedImp::argPlusMatch(prefixp);
|
||||
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
|
||||
if (match == "") return 0;
|
||||
VL_ZERO_RESET_W(rbits, rwp);
|
||||
switch (tolower(fmt)) {
|
||||
case '%':
|
||||
break;
|
||||
case 'd':
|
||||
vlsint64_t ld;
|
||||
sscanf(dp,"%" VL_PRI64 "d",&ld);
|
||||
VL_SET_WQ(rwp,ld);
|
||||
break;
|
||||
case 'b':
|
||||
_vl_vsss_based(rwp,rbits, 1, dp, 0, (int)strlen(dp));
|
||||
break;
|
||||
case 'o':
|
||||
_vl_vsss_based(rwp,rbits, 3, dp, 0, (int)strlen(dp));
|
||||
break;
|
||||
case 'h': //FALLTHRU
|
||||
case 'x':
|
||||
_vl_vsss_based(rwp,rbits, 4, dp, 0, (int)strlen(dp));
|
||||
break;
|
||||
case 's':
|
||||
for (int i=0, lsb=0, pos=((int)strlen(dp))-1; i<rbits && pos>=0; pos--) {
|
||||
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8;
|
||||
}
|
||||
break;
|
||||
default: // Compile time should have found all errors before this
|
||||
vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error");
|
||||
break;
|
||||
}
|
||||
_VL_CLEAN_INPLACE_W(rbits,rwp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* vl_mc_scan_plusargs(const char* prefixp) {
|
||||
string match = VerilatedImp::argPlusMatch(prefixp);
|
||||
static VL_THREAD char outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||
if (match == "") return NULL;
|
||||
strncpy(outstr, match.c_str()+strlen(prefixp)+1, // +1 to skip the "+"
|
||||
VL_VALUE_STRING_MAX_WIDTH);
|
||||
outstr[VL_VALUE_STRING_MAX_WIDTH-1] = '\0';
|
||||
return outstr;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Heavy functions
|
||||
|
||||
string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) {
|
||||
// See also _VL_VINT_TO_STRING
|
||||
char destout[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
int obits = lwords * VL_WORDSIZE;
|
||||
int lsb=obits-1;
|
||||
bool start=true;
|
||||
char* destp = destout;
|
||||
int len = 0;
|
||||
for (; lsb>=0; lsb--) {
|
||||
lsb = (lsb / 8) * 8; // Next digit
|
||||
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
|
||||
if (!start || charval) {
|
||||
*destp++ = (charval==0)?' ':charval;
|
||||
len++;
|
||||
start = false; // Drop leading 0s
|
||||
}
|
||||
}
|
||||
return string(destout, len);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Verilated:: Methods
|
||||
|
||||
@@ -858,18 +965,44 @@ const char* Verilated::catName(const char* n1, const char* n2) {
|
||||
// Returns new'ed data
|
||||
// Used by symbol table creation to make module names
|
||||
static char* strp = NULL;
|
||||
static int len = -1;
|
||||
int newlen = strlen(n1)+strlen(n2)+2;
|
||||
static size_t len = 0;
|
||||
size_t newlen = strlen(n1)+strlen(n2)+2;
|
||||
if (newlen > len) {
|
||||
if (strp) delete [] strp;
|
||||
strp = new char[newlen];
|
||||
len = newlen;
|
||||
}
|
||||
strcpy(strp,n1);
|
||||
if (*n1) strcat(strp,".");
|
||||
strcat(strp,n2);
|
||||
return strp;
|
||||
}
|
||||
|
||||
void Verilated::flushCb(VerilatedVoidCb cb) {
|
||||
if (s_flushCb == cb) {} // Ok - don't duplicate
|
||||
else if (!s_flushCb) { s_flushCb=cb; }
|
||||
else {
|
||||
// Someday we may allow multiple callbacks ala atexit(), but until then
|
||||
vl_fatal("unknown",0,"", "Verilated::flushCb called twice with different callbacks");
|
||||
}
|
||||
}
|
||||
|
||||
void Verilated::commandArgs(int argc, const char** argv) {
|
||||
VerilatedImp::commandArgs(argc,argv);
|
||||
}
|
||||
|
||||
void Verilated::scopesDump() {
|
||||
VerilatedImp::scopesDump();
|
||||
}
|
||||
|
||||
const VerilatedScope* Verilated::scopeFind(const char* namep) {
|
||||
return VerilatedImp::scopeFind(namep);
|
||||
}
|
||||
|
||||
int Verilated::exportFuncNum(const char* namep) {
|
||||
return VerilatedImp::exportFind(namep);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// VerilatedModule:: Methods
|
||||
|
||||
@@ -881,4 +1014,147 @@ VerilatedModule::~VerilatedModule() {
|
||||
if (m_namep) free((void*)m_namep); m_namep=NULL;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// VerilatedVar:: Methods
|
||||
|
||||
vluint32_t VerilatedVar::entSize() const {
|
||||
vluint32_t size = 1;
|
||||
switch (vltype()) {
|
||||
case VLVT_PTR: size=sizeof(void*); break;
|
||||
case VLVT_UINT8: size=sizeof(CData); break;
|
||||
case VLVT_UINT16: size=sizeof(SData); break;
|
||||
case VLVT_UINT32: size=sizeof(IData); break;
|
||||
case VLVT_UINT64: size=sizeof(QData); break;
|
||||
case VLVT_WDATA: size=VL_WORDS_I(range().bits())*sizeof(IData); break;
|
||||
default: size=0; break;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// VerilatedScope:: Methods
|
||||
|
||||
VerilatedScope::VerilatedScope() {
|
||||
m_callbacksp = NULL;
|
||||
m_namep = NULL;
|
||||
m_funcnumMax = 0;
|
||||
m_varsp = NULL;
|
||||
}
|
||||
|
||||
VerilatedScope::~VerilatedScope() {
|
||||
VerilatedImp::scopeErase(this);
|
||||
if (m_namep) { delete [] m_namep; m_namep = NULL; }
|
||||
if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; }
|
||||
if (m_varsp) { delete m_varsp; m_varsp = NULL; }
|
||||
m_funcnumMax = 0; // Force callback table to empty
|
||||
}
|
||||
|
||||
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp) {
|
||||
// Slowpath - called once/scope at construction
|
||||
// We don't want the space and reference-count access overhead of strings.
|
||||
m_symsp = symsp;
|
||||
char* namep = new char[strlen(prefixp)+strlen(suffixp)+2];
|
||||
strcpy(namep, prefixp);
|
||||
if (*prefixp && *suffixp) strcat(namep,".");
|
||||
strcat(namep, suffixp);
|
||||
m_namep = namep;
|
||||
VerilatedImp::scopeInsert(this);
|
||||
}
|
||||
|
||||
void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) {
|
||||
// Slowpath - called once/scope*export at construction
|
||||
// Insert a exported function into scope table
|
||||
int funcnum = VerilatedImp::exportInsert(namep);
|
||||
if (!finalize) {
|
||||
// Need two passes so we know array size to create
|
||||
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
||||
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; }
|
||||
} else {
|
||||
if (VL_UNLIKELY(funcnum >= m_funcnumMax)) {
|
||||
vl_fatal(__FILE__,__LINE__,"","Internal: Bad funcnum vs. pre-finalize maximum");
|
||||
}
|
||||
if (VL_UNLIKELY(!m_callbacksp)) { // First allocation
|
||||
m_callbacksp = new void* [m_funcnumMax];
|
||||
memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*));
|
||||
}
|
||||
m_callbacksp[funcnum] = cb;
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...) {
|
||||
// Grab dimensions
|
||||
// In the future we may just create a large table at emit time and statically construct from that.
|
||||
if (!finalize) return;
|
||||
|
||||
if (!m_varsp) m_varsp = new VerilatedVarNameMap();
|
||||
VerilatedVar var (namep, datap, vltype, (VerilatedVarFlags)vlflags, dims);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap,dims);
|
||||
for (int i=0; i<dims; ++i) {
|
||||
int msb = va_arg(ap,int);
|
||||
int lsb = va_arg(ap,int);
|
||||
if (i==0) {
|
||||
var.m_range.m_lhs = msb;
|
||||
var.m_range.m_rhs = lsb;
|
||||
} else if (i==1) {
|
||||
var.m_array.m_lhs = msb;
|
||||
var.m_array.m_rhs = lsb;
|
||||
} else {
|
||||
// We could have a linked list of ranges, but really this whole thing needs
|
||||
// to be generalized to support structs and unions, etc.
|
||||
vl_fatal(__FILE__,__LINE__,"",(string("Unsupported multi-dimensional public varInsert: ")+namep).c_str());
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
m_varsp->insert(make_pair(namep,var));
|
||||
}
|
||||
|
||||
VerilatedVar* VerilatedScope::varFind(const char* namep) const {
|
||||
if (VL_LIKELY(m_varsp)) {
|
||||
VerilatedVarNameMap::iterator it = m_varsp->find(namep);
|
||||
if (VL_LIKELY(it != m_varsp->end())) {
|
||||
return &(it->second);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFindNullError(int funcnum) const {
|
||||
// Slowpath - Called only when find has failed
|
||||
string msg = (string("Testbench C called '")
|
||||
+VerilatedImp::exportName(funcnum)
|
||||
+"' but scope wasn't set, perhaps due to dpi import call without 'context'");
|
||||
vl_fatal("unknown",0,"", msg.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFindError(int funcnum) const {
|
||||
// Slowpath - Called only when find has failed
|
||||
string msg = (string("Testbench C called '")
|
||||
+VerilatedImp::exportName(funcnum)
|
||||
+"' but this DPI export function exists only in other scopes, not scope '"
|
||||
+name()+"'");
|
||||
vl_fatal("unknown",0,"", msg.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void VerilatedScope::scopeDump() const {
|
||||
VL_PRINTF(" SCOPE %p: %s\n", this, name());
|
||||
for (int i=0; i<m_funcnumMax; i++) {
|
||||
if (m_callbacksp && m_callbacksp[i]) {
|
||||
VL_PRINTF(" DPI-EXPORT %p: %s\n",
|
||||
m_callbacksp[i], VerilatedImp::exportName(i));
|
||||
}
|
||||
}
|
||||
if (varsp()) {
|
||||
for (VerilatedVarNameMap::const_iterator it = varsp()->begin();
|
||||
it != varsp()->end(); ++it) {
|
||||
VL_PRINTF(" VAR %p: %s\n", &(it->second), it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
+197
-46
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -35,23 +35,63 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
// <iostream> avoided to reduce compile time
|
||||
// <string> avoided and instead in verilated_heavy.h to reduce compile time
|
||||
using namespace std;
|
||||
|
||||
//=============================================================================
|
||||
// Switches
|
||||
|
||||
#if VM_TRACE // Verilator tracing requested
|
||||
# define WAVES 1 // Set backward compatibility flag as in systemperl.h
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Basic types
|
||||
|
||||
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
|
||||
// P // Packed data of bit type (C/S/I/Q/W)
|
||||
typedef vluint8_t CData; ///< Verilated pack data, 1-8 bits
|
||||
typedef vluint16_t SData; ///< Verilated pack data, 9-16 bits
|
||||
typedef vluint32_t IData; ///< Verilated pack data, 17-32 bits
|
||||
typedef vluint64_t QData; ///< Verilated pack data, 33-64 bits
|
||||
typedef vluint32_t WData; ///< Verilated pack data, >64 bits, as an array
|
||||
// float F // No typedef needed; Verilator uses float
|
||||
// double D // No typedef needed; Verilator uses double
|
||||
// string N // No typedef needed; Verilator uses string
|
||||
|
||||
typedef const WData* WDataInP; ///< Array input to a function
|
||||
typedef WData* WDataOutP; ///< Array output from a function
|
||||
|
||||
typedef void (*VerilatedVoidCb)(void);
|
||||
|
||||
class SpTraceVcd;
|
||||
class SpTraceVcdCFile;
|
||||
class VerilatedVar;
|
||||
class VerilatedVarNameMap;
|
||||
class VerilatedVcd;
|
||||
class VerilatedVcdC;
|
||||
|
||||
enum VerilatedVarType {
|
||||
VLVT_UNKNOWN=0,
|
||||
VLVT_PTR, // Pointer to something
|
||||
VLVT_UINT8, // AKA CData
|
||||
VLVT_UINT16, // AKA SData
|
||||
VLVT_UINT32, // AKA IData
|
||||
VLVT_UINT64, // AKA QData
|
||||
VLVT_WDATA, // AKA WData
|
||||
VLVT_STRING // C++ string
|
||||
};
|
||||
|
||||
enum VerilatedVarFlags {
|
||||
VLVD_IN=1, // == vpiInput
|
||||
VLVD_OUT=2, // == vpiOutput
|
||||
VLVD_INOUT=3, // == vpiInOut
|
||||
VLVD_NODIR=5, // == vpiNoDirection
|
||||
VLVF_MASK_DIR=7, // Bit mask for above directions
|
||||
// Flags
|
||||
VLVF_PUB_RD=(1<<8), // Public readable
|
||||
VLVF_PUB_RW=(1<<9) // Public writable
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
/// Base class for all Verilated module classes
|
||||
@@ -122,20 +162,79 @@ public:
|
||||
#ifndef VL_PRINTF
|
||||
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired
|
||||
#endif
|
||||
#ifndef VL_VPRINTF
|
||||
# define VL_VPRINTF vprintf ///< Print ala vprintf; may redefine if desired
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator symbol table base class
|
||||
|
||||
class VerilatedSyms {
|
||||
// VerilatedSyms base class exists just so symbol tables have a common pointer type
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator global static information class
|
||||
|
||||
class VerilatedScope {
|
||||
// Fastpath:
|
||||
VerilatedSyms* m_symsp; ///< Symbol table
|
||||
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
||||
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
||||
// 4 bytes padding (on -m64), for rent.
|
||||
VerilatedVarNameMap* m_varsp; ///< Variable map
|
||||
const char* m_namep; ///< Scope name (Slowpath)
|
||||
|
||||
public: // But internals only - called from VerilatedModule's
|
||||
VerilatedScope();
|
||||
~VerilatedScope();
|
||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
|
||||
void exportInsert(int finalize, const char* namep, void* cb);
|
||||
void varInsert(int finalize, const char* namep, void* datap,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...);
|
||||
// ACCESSORS
|
||||
const char* name() const { return m_namep; }
|
||||
inline VerilatedSyms* symsp() const { return m_symsp; }
|
||||
VerilatedVar* varFind(const char* namep) const;
|
||||
VerilatedVarNameMap* varsp() const { return m_varsp; }
|
||||
void* exportFindError(int funcnum) const;
|
||||
void* exportFindNullError(int funcnum) const;
|
||||
void scopeDump() const;
|
||||
inline void* exportFind(int funcnum) const {
|
||||
if (VL_UNLIKELY(!this)) return exportFindNullError(funcnum);
|
||||
if (VL_LIKELY(funcnum < m_funcnumMax)) {
|
||||
// m_callbacksp must be declared, as Max'es are > 0
|
||||
return m_callbacksp[funcnum];
|
||||
} else {
|
||||
return exportFindError(funcnum);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator global static information class
|
||||
|
||||
struct Verilated {
|
||||
// Extern Vars
|
||||
// Below two are used as bool, but having as uint32_t avoids conversion time
|
||||
// MEMBERS
|
||||
private:
|
||||
// Slow path variables
|
||||
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
||||
|
||||
// Fast path
|
||||
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||
static bool s_gotFinish; ///< A $finish statement executed
|
||||
static bool s_assertOn; ///< Assertions are enabled
|
||||
|
||||
static VL_THREAD const VerilatedScope* t_dpiScopep; ///< DPI context scope
|
||||
static VL_THREAD const char* t_dpiFilename; ///< DPI context filename
|
||||
static VL_THREAD int t_dpiLineno; ///< DPI context line number
|
||||
|
||||
public:
|
||||
|
||||
// METHODS - User called
|
||||
|
||||
/// Select initial value of otherwise uninitialized signals.
|
||||
////
|
||||
/// 0 = Set to zeros
|
||||
@@ -151,8 +250,6 @@ public:
|
||||
#else
|
||||
static inline int debug() { return 0; } ///< Constant 0 debug, so C++'s optimizer rips up
|
||||
#endif
|
||||
/// Internal: Create a new module name by concatenating two strings
|
||||
static const char* catName(const char* n1, const char* n2); // Returns new'ed data
|
||||
/// Enable calculation of unused signals
|
||||
static void calcUnusedSigs(bool flag) { s_calcUnusedSigs=flag; }
|
||||
static bool calcUnusedSigs() { return s_calcUnusedSigs; } ///< Return calcUnusedSigs value
|
||||
@@ -166,6 +263,34 @@ public:
|
||||
/// Enable/disable assertions
|
||||
static void assertOn(bool flag) { s_assertOn=flag; }
|
||||
static bool assertOn() { return s_assertOn; }
|
||||
/// Flush callback for VCD waves
|
||||
static void flushCb(VerilatedVoidCb cb);
|
||||
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
|
||||
|
||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
||||
static void commandArgs(int argc, const char** argv);
|
||||
static void commandArgs(int argc, char** argv) { commandArgs(argc,(const char**)argv); }
|
||||
|
||||
/// For debugging, print text list of all scope names with
|
||||
/// dpiImport/Export context. This function may change in future
|
||||
/// releases - contact the authors before production use.
|
||||
static void scopesDump();
|
||||
|
||||
// METHODS - INTERNAL USE ONLY
|
||||
// Internal: Create a new module name by concatenating two strings
|
||||
static const char* catName(const char* n1, const char* n2); // Returns new'ed data
|
||||
// Internal: Find scope
|
||||
static const VerilatedScope* scopeFind(const char* namep);
|
||||
// Internal: Get and set DPI context
|
||||
static const VerilatedScope* dpiScope() { return t_dpiScopep; }
|
||||
static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; }
|
||||
static void dpiContext(const VerilatedScope* scopep, const char* filenamep, int lineno) {
|
||||
t_dpiScopep=scopep; t_dpiFilename=filenamep; t_dpiLineno=lineno; }
|
||||
static void dpiClearContext() { t_dpiScopep = NULL; }
|
||||
static bool dpiInContext() { return t_dpiScopep != NULL; }
|
||||
static const char* dpiFilenamep() { return t_dpiFilename; }
|
||||
static int dpiLineno() { return t_dpiLineno; }
|
||||
static int exportFuncNum(const char* namep);
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
@@ -196,7 +321,7 @@ extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a
|
||||
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
|
||||
|
||||
/// File I/O
|
||||
extern IData VL_FGETS_IXQ(int sbits, void* strgp, QData fpq);
|
||||
extern IData VL_FGETS_IXQ(int obits, void* destp, QData fpq);
|
||||
|
||||
extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
|
||||
extern QData VL_FOPEN_QI(QData ofilename, IData mode);
|
||||
@@ -218,6 +343,12 @@ extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
|
||||
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
|
||||
extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
|
||||
|
||||
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
|
||||
|
||||
extern IData VL_TESTPLUSARGS_I(const char* formatp);
|
||||
extern IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp);
|
||||
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
|
||||
@@ -228,16 +359,20 @@ extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
|
||||
#define VL_BITISSETLIMIT_W(data,width,bit) (((bit)<(width)) && data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
|
||||
/// Create two 32-bit words from quadword
|
||||
#define VL_SET_WQ(owp,data) { owp[0]=(data); owp[1]=((data)>>VL_WORDSIZE); }
|
||||
#define VL_SET_WI(owp,data) { owp[0]=(data); owp[1]=0; }
|
||||
#define VL_SET_WQ(owp,data) { owp[0]=(IData)(data); owp[1]=(IData)((data)>>VL_WORDSIZE); }
|
||||
#define VL_SET_WI(owp,data) { owp[0]=(IData)(data); owp[1]=0; }
|
||||
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
|
||||
#define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) )
|
||||
|
||||
// Use a union to avoid cast-to-different-size warnings
|
||||
/// Return FILE* from QData
|
||||
static inline FILE* VL_CVT_Q_FP(QData lhs) { union { FILE* fp; QData q; } u; u.q=lhs; return u.fp; }
|
||||
/// Return void* from QData
|
||||
static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
|
||||
/// Return QData from FILE*
|
||||
static inline QData VL_CVT_FP_Q(FILE* fp) { union { FILE* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
|
||||
/// Return QData from void*
|
||||
static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
|
||||
|
||||
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
|
||||
// (Requires clean input)
|
||||
@@ -251,26 +386,25 @@ static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) { return (-((lhs)&(VL
|
||||
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) { return (-((lhs)&(VL_ULL(1)<<(lbits-1)))); }
|
||||
|
||||
// Debugging prints
|
||||
static inline void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) {
|
||||
printf(" Data: w%d: ", lbits);
|
||||
for (int i=VL_WORDS_I(lbits)-1; i>=0; i--) { printf("%08x ",iwp[i]); }
|
||||
printf("\n");
|
||||
}
|
||||
void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp);
|
||||
|
||||
//=========================================================================
|
||||
// Pli macros
|
||||
|
||||
#ifndef VL_TIME_PRECISION
|
||||
# define VL_TIME_PRECISION -12 ///< Timescale units only for for VPI return - picoseconds
|
||||
#endif
|
||||
#ifndef VL_TIME_MULTIPLIER
|
||||
# define VL_TIME_MULTIPLIER 1
|
||||
#endif
|
||||
|
||||
/// Return current simulation time
|
||||
#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION>20011000)
|
||||
# define VL_TIME_I(ign) ((IData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_Q(ign) ((QData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_I() ((IData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_Q() ((QData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
#else
|
||||
# define VL_TIME_I(ign) ((IData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_Q(ign) ((QData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_I() ((IData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_Q() ((QData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
extern double sc_time_stamp();
|
||||
#endif
|
||||
|
||||
@@ -537,7 +671,7 @@ static inline IData VL_REDXOR_64(QData r) {
|
||||
return __builtin_parityll(r);
|
||||
#else
|
||||
r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); r=(r^(r>>8)); r=(r^(r>>16)); r=(r^(r>>32));
|
||||
return r;
|
||||
return (IData)r;
|
||||
#endif
|
||||
}
|
||||
static inline IData VL_REDXOR_W(int words, WDataInP lwp) {
|
||||
@@ -556,7 +690,7 @@ static inline IData VL_COUNTONES_I(IData lhs) {
|
||||
return r;
|
||||
}
|
||||
static inline IData VL_COUNTONES_Q(QData lhs) {
|
||||
return VL_COUNTONES_I(lhs) + VL_COUNTONES_I(lhs>>32);
|
||||
return VL_COUNTONES_I((IData)lhs) + VL_COUNTONES_I((IData)(lhs>>32));
|
||||
}
|
||||
static inline IData VL_COUNTONES_W(int words, WDataInP lwp) {
|
||||
IData r = 0;
|
||||
@@ -602,14 +736,14 @@ static inline IData VL_ONEHOT0_W(int words, WDataInP lwp) {
|
||||
|
||||
static inline IData VL_CLOG2_I(IData lhs) {
|
||||
// There are faster algorithms, or fls GCC4 builtins, but rarely used
|
||||
if (!lhs) return 0;
|
||||
if (VL_UNLIKELY(!lhs)) return 0;
|
||||
lhs--;
|
||||
int shifts=0;
|
||||
for (; lhs!=0; shifts++) lhs = lhs >> 1;
|
||||
return shifts;
|
||||
}
|
||||
static inline IData VL_CLOG2_Q(QData lhs) {
|
||||
if (!lhs) return 0;
|
||||
if (VL_UNLIKELY(!lhs)) return 0;
|
||||
lhs--;
|
||||
int shifts=0;
|
||||
for (; lhs!=0; shifts++) lhs = lhs >> VL_ULL(1);
|
||||
@@ -803,7 +937,7 @@ static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP
|
||||
static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
|
||||
QData carry = 0;
|
||||
for (int i=0; i<words; i++) {
|
||||
carry = carry + (QData)(lwp[i]) + (QData)(~rwp[i]);
|
||||
carry = carry + (QData)(lwp[i]) + (QData)(IData)(~rwp[i]);
|
||||
if (i==0) carry++; // Negation of temp2
|
||||
owp[i] = (carry & VL_ULL(0xffffffff));
|
||||
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
||||
@@ -811,19 +945,16 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP
|
||||
return(owp);
|
||||
}
|
||||
|
||||
// Optimization bug in GCC 2.96 and presumably all-pre GCC 3 versions need this workaround
|
||||
#if 1 //defined(__GNUC__) && __GNUC__ < 3
|
||||
// Optimization bug in GCC 2.96 and presumably all-pre GCC 3 versions need this workaround,
|
||||
// we can't just
|
||||
//# define VL_UNARYMIN_I(data) (-(data))
|
||||
static inline IData VL_UNARYMIN_I(IData data) { return -data; }
|
||||
static inline QData VL_UNARYMIN_Q(QData data) { return -data; }
|
||||
#else
|
||||
# define VL_UNARYMIN_I(IData data) (-(data))
|
||||
# define VL_UNARYMIN_Q(QData data) (-(data))
|
||||
#endif
|
||||
|
||||
static inline WDataOutP VL_UNARYMIN_W(int words, WDataOutP owp,WDataInP lwp){
|
||||
QData carry = 0;
|
||||
for (int i=0; i<words; i++) {
|
||||
carry = carry + (QData)(~lwp[i]);
|
||||
carry = carry + (QData)(IData)(~lwp[i]);
|
||||
if (i==0) carry++; // Negation of temp2
|
||||
owp[i] = (carry & VL_ULL(0xffffffff));
|
||||
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
||||
@@ -881,7 +1012,7 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
|
||||
if ((lneg ^ rneg) & 1) { // Negate output (not using UNARYMIN, as owp==lwp)
|
||||
QData carry = 0;
|
||||
for (int i=0; i<words; i++) {
|
||||
carry = carry + (QData)(~owp[i]);
|
||||
carry = carry + (QData)(IData)(~owp[i]);
|
||||
if (i==0) carry++; // Negation of temp2
|
||||
owp[i] = (carry & VL_ULL(0xffffffff));
|
||||
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff);
|
||||
@@ -893,25 +1024,25 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
|
||||
}
|
||||
|
||||
static inline IData VL_DIVS_III(int lbits, IData lhs,IData rhs) {
|
||||
if (rhs==0) return 0;
|
||||
if (VL_UNLIKELY(rhs==0)) return 0;
|
||||
vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
|
||||
vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
|
||||
return lhs_signed / rhs_signed;
|
||||
}
|
||||
static inline QData VL_DIVS_QQQ(int lbits, QData lhs,QData rhs) {
|
||||
if (rhs==0) return 0;
|
||||
if (VL_UNLIKELY(rhs==0)) return 0;
|
||||
vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed / rhs_signed;
|
||||
}
|
||||
static inline IData VL_MODDIVS_III(int lbits, IData lhs,IData rhs) {
|
||||
if (rhs==0) return 0;
|
||||
if (VL_UNLIKELY(rhs==0)) return 0;
|
||||
vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
|
||||
vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
|
||||
return lhs_signed % rhs_signed;
|
||||
}
|
||||
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs,QData rhs) {
|
||||
if (rhs==0) return 0;
|
||||
if (VL_UNLIKELY(rhs==0)) return 0;
|
||||
vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
|
||||
vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
|
||||
return lhs_signed % rhs_signed;
|
||||
@@ -957,7 +1088,7 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDa
|
||||
}
|
||||
|
||||
static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
|
||||
if (lhs==0) return 0;
|
||||
if (VL_UNLIKELY(lhs==0)) return 0;
|
||||
IData power = lhs;
|
||||
IData out = 1;
|
||||
for (int i=0; i<rbits; i++) {
|
||||
@@ -970,7 +1101,7 @@ static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
|
||||
#define VL_POW_QQI(obits,lbits,rbits,lhs,rhs) VL_POW_QQQ(obits,lbits,rbits,lhs,rhs)
|
||||
|
||||
static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) {
|
||||
if (lhs==0) return 0;
|
||||
if (VL_UNLIKELY(lhs==0)) return 0;
|
||||
QData power = lhs;
|
||||
QData out = VL_ULL(1);
|
||||
for (int i=0; i<rbits; i++) {
|
||||
@@ -1300,7 +1431,7 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int,int,WDataOutP owp,WDataInP
|
||||
|
||||
static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData rd) {
|
||||
int word = VL_BITWORD_I(rd);
|
||||
if ((int)rd>lbits) {
|
||||
if (VL_UNLIKELY((int)rd>lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
// We return all 1's as that's more likely to find bugs (?) than 0's.
|
||||
} else {
|
||||
@@ -1316,7 +1447,7 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData
|
||||
|
||||
static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) {
|
||||
int msb = lsb+width-1;
|
||||
if (msb>lbits) {
|
||||
if (VL_UNLIKELY(msb>lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
} else if (VL_BITWORD_I(msb)==VL_BITWORD_I((int)lsb)) {
|
||||
return (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb));
|
||||
@@ -1330,7 +1461,7 @@ static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData ls
|
||||
|
||||
static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) {
|
||||
int msb = lsb+width-1;
|
||||
if (msb>lbits) {
|
||||
if (VL_UNLIKELY(msb>lbits)) {
|
||||
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
|
||||
} else if (VL_BITWORD_I(msb)==VL_BITWORD_I((int)lsb)) {
|
||||
return (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb));
|
||||
@@ -1352,7 +1483,7 @@ static inline QData VL_SEL_QWII(int, int lbits, int, int, WDataInP lwp, IData ls
|
||||
static inline WDataOutP VL_SEL_WWII(int obits,int lbits,int,int,WDataOutP owp,WDataInP lwp, IData lsb, IData width) {
|
||||
int msb = lsb+width-1;
|
||||
int word_shift = VL_BITWORD_I(lsb);
|
||||
if (msb>lbits) { // Outside bounds,
|
||||
if (VL_UNLIKELY(msb>lbits)) { // Outside bounds,
|
||||
for (int i=0; i<VL_WORDS_I(obits)-1; i++) owp[i] = ~0;
|
||||
owp[VL_WORDS_I(obits)-1] = VL_MASK_I(obits);
|
||||
} else if (VL_BITBIT_I(lsb)==0) {
|
||||
@@ -1420,6 +1551,26 @@ static inline WDataOutP VL_COND_WIWW(int obits, int, int, int,
|
||||
return(owp);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// System Functions
|
||||
|
||||
inline IData VL_VALUEPLUSARGS_IQ(int rbits, const char* prefixp, char fmt, QData& ldr) {
|
||||
WData wd[2]; IData v=VL_VALUEPLUSARGS_IW(rbits,prefixp,fmt,wd); if (v) ldr=VL_SET_QW(wd);
|
||||
return v;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, CData& ldr) {
|
||||
QData qd; IData v=VL_VALUEPLUSARGS_IQ(rbits,prefixp,fmt,qd); if (v) ldr=(CData)qd;
|
||||
return v;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, SData& ldr) {
|
||||
QData qd; IData v=VL_VALUEPLUSARGS_IQ(rbits,prefixp,fmt,qd); if (v) ldr=(SData)qd;
|
||||
return v;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_II(int rbits, const char* prefixp, char fmt, IData& ldr) {
|
||||
QData qd; IData v=VL_VALUEPLUSARGS_IQ(rbits,prefixp,fmt,qd); if (v) ldr=(IData)qd;
|
||||
return v;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Constification
|
||||
|
||||
|
||||
+21
-10
@@ -2,7 +2,7 @@
|
||||
######################################################################
|
||||
# DESCRIPTION: Makefile commands for all verilated target files
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
# Copyright 2003-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
######################################################################
|
||||
@@ -19,6 +19,13 @@ RANLIB = ranlib
|
||||
SP_PREPROC = sp_preproc
|
||||
SP_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
|
||||
|
||||
######################################################################
|
||||
# Make checks
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# C Preprocessor flags
|
||||
|
||||
@@ -26,6 +33,7 @@ SP_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
|
||||
VK_CPPFLAGS_ALWAYS += \
|
||||
-MMD \
|
||||
-I$(VERILATOR_ROOT)/include \
|
||||
-I$(VERILATOR_ROOT)/include/vltstd \
|
||||
-DVL_PRINTF=printf \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
@@ -44,6 +52,7 @@ CPPFLAGS += -I. $(VK_CPPFLAGS_ALWAYS) $(VK_CPPFLAGS_WALL)
|
||||
|
||||
VPATH += ..
|
||||
VPATH += $(VERILATOR_ROOT)/include
|
||||
VPATH += $(VERILATOR_ROOT)/include/vltstd
|
||||
|
||||
#OPT = -ggdb -DPRINTINITSTR -DDETECTCHANGE
|
||||
#OPT = -ggdb -DPRINTINITSTR
|
||||
@@ -56,6 +65,12 @@ LDFLAGS += $(M32)
|
||||
# These aren't ever set by Verilator, so users are free to override them.
|
||||
CPPFLAGS += $(USER_CPPFLAGS)
|
||||
LDFLAGS += $(USER_LDFLAGS)
|
||||
LDLIBS += $(USER_LDLIBS)
|
||||
|
||||
# Add flags from -CFLAGS and -LDFLAGS on Verilator command line
|
||||
CPPFLAGS += $(VM_USER_CFLAGS)
|
||||
LDFLAGS += $(VM_USER_LDFLAGS)
|
||||
LDLIBS += $(VM_USER_LDLIBS)
|
||||
|
||||
# See the benchmarking section of bin/verilator.
|
||||
# Support class optimizations. This includes the tracing and symbol table.
|
||||
@@ -109,10 +124,6 @@ endif
|
||||
|
||||
ifeq ($(VM_SC),1)
|
||||
LIBS += -lm -lstdc++
|
||||
ifeq ($(VM_TRACE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
@@ -120,10 +131,6 @@ endif
|
||||
|
||||
ifeq ($(VM_PCLI),1)
|
||||
LIBS += -lm -lstdc++
|
||||
ifeq ($(VM_TRACE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
@@ -136,6 +143,8 @@ VK_SUPPORT_CPP = $(addsuffix .cpp, $(VM_SUPPORT))
|
||||
|
||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
||||
|
||||
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
|
||||
|
||||
ifneq ($(VM_PARALLEL_BUILDS),1)
|
||||
# Fast building, all .cpp's in one fell swoop
|
||||
# This saves about 5 sec per module, but can be slower if only a little changes
|
||||
@@ -171,13 +180,15 @@ $(VM_PREFIX)__ALLcls.o: $(VM_PREFIX)__ALLcls.cpp
|
||||
######################################################################
|
||||
### Debugging
|
||||
|
||||
debug::
|
||||
debug-make::
|
||||
@echo
|
||||
@echo VM_PREFIX: $(VM_PREFIX)
|
||||
@echo VM_CLASSES_FAST: $(VM_CLASSES_FAST)
|
||||
@echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW)
|
||||
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
|
||||
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
|
||||
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
|
||||
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: DPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the DPI.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#define _VERILATED_DPI_CPP_
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_imp.h"
|
||||
|
||||
// On MSVC++ we need svdpi.h to declare exports, not imports
|
||||
#define DPI_PROTOTYPES
|
||||
#define XXTERN DPI_EXTERN DPI_DLLESPEC
|
||||
#define EETERN DPI_EXTERN DPI_DLLESPEC
|
||||
|
||||
#include "vltstd/svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
// Not supported yet
|
||||
#define _VL_SVDPI_UNIMP() \
|
||||
vl_fatal(__FILE__,__LINE__,"",(string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str())
|
||||
|
||||
// Function requires a "context" in the import declaration
|
||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||
VL_PRINTF("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
// DPI ROUTINES
|
||||
|
||||
const char* svDpiVersion() {
|
||||
return "1800-2005";
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Bit-select utility functions.
|
||||
|
||||
svBit svGetBitselBit(const svBitVecVal* s, int i) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svLogic svGetBitselLogic(const svLogicVecVal* s, int i) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void svPutBitselBit(svBitVecVal* d, int i, svBit s) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitselLogic(svLogicVecVal* d, int i, svLogic s) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
void svGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
void svPutPartselBit(svBitVecVal* d, const svBitVecVal s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutPartselLogic(svLogicVecVal* d, const svLogicVecVal s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Open array querying functions
|
||||
|
||||
int svLeft(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svRight(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svLow(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svHigh(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svIncrement(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svLength(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svDimensions(const svOpenArrayHandle h) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void *svGetArrayPtr(const svOpenArrayHandle) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
int svSizeOfArray(const svOpenArrayHandle) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr1(const svOpenArrayHandle, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr2(const svOpenArrayHandle, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr3(const svOpenArrayHandle, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// s=source, d=destination
|
||||
// From user space into simulator storage
|
||||
|
||||
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// From simulator storage into user space
|
||||
|
||||
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Functions for working with DPI context
|
||||
|
||||
svScope svGetScope() {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return NULL; }
|
||||
return (svScope)Verilated::dpiScope();
|
||||
}
|
||||
|
||||
svScope svSetScope(const svScope scope) {
|
||||
const VerilatedScope* prevScopep = Verilated::dpiScope();
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
Verilated::dpiScope(vscopep);
|
||||
return (svScope)prevScopep;
|
||||
}
|
||||
|
||||
const char* svGetNameFromScope(const svScope scope) {
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
return vscopep->name();
|
||||
}
|
||||
|
||||
svScope svGetScopeFromName(const char* scopeName) {
|
||||
return (svScope)VerilatedImp::scopeFind(scopeName);
|
||||
}
|
||||
|
||||
int svPutUserData(const svScope scope, void *userKey, void* userData) {
|
||||
VerilatedImp::userInsert(scope,userKey,userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* svGetUserData(const svScope scope, void* userKey) {
|
||||
return VerilatedImp::userFind(scope,userKey);
|
||||
}
|
||||
|
||||
int svGetCallerInfo(const char** fileNamepp, int *lineNumberp) {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return false; }
|
||||
if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep(); // thread local
|
||||
if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno(); // thread local
|
||||
return true;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Disables
|
||||
|
||||
int svIsDisabledState() {
|
||||
return 0; // Disables not implemented
|
||||
}
|
||||
|
||||
void svAckDisabledState() {
|
||||
// Disables not implemented
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: String include for all Verilated C files
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates. It is used when strings or other
|
||||
/// heavyweight types are required; these contents are not part of
|
||||
/// verilated.h to save compile time when such types aren't used.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATED_HEAVY_H_
|
||||
#define _VERILATED_HEAVY_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//======================================================================
|
||||
// Conversion functions
|
||||
|
||||
extern string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
|
||||
inline string VL_CVT_PACK_STR_NQ(QData lhs) {
|
||||
IData lw[2]; VL_SET_WQ(lw, lhs);
|
||||
return VL_CVT_PACK_STR_NW(2, lw);
|
||||
}
|
||||
inline string VL_CVT_PACK_STR_NI(IData lhs) {
|
||||
IData lw[1]; lw[0] = lhs;
|
||||
return VL_CVT_PACK_STR_NW(1, lw);
|
||||
}
|
||||
|
||||
extern string VL_SFORMATF_NX(const char* formatp, ...);
|
||||
|
||||
#endif // Guard
|
||||
@@ -0,0 +1,189 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Implementation Header, only for verilated.cpp internals.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
|
||||
#ifndef _VERILATED_IMP_H_
|
||||
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
||||
|
||||
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_)
|
||||
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
||||
#endif
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_heavy.h"
|
||||
#include "verilated_syms.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class VerilatedScope;
|
||||
|
||||
//======================================================================
|
||||
// Types
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
|
||||
// TYPES
|
||||
typedef vector<string> ArgVec;
|
||||
typedef map<pair<const void*,void*>,void*> UserMap;
|
||||
typedef map<const char*, const VerilatedScope*, VerilatedCStrCmp> ScopeNameMap;
|
||||
typedef map<const char*, int, VerilatedCStrCmp> ExportNameMap;
|
||||
|
||||
// MEMBERS
|
||||
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
ArgVec m_argVec; ///< Argument list
|
||||
bool m_argVecLoaded; ///< Ever loaded argument list
|
||||
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
|
||||
ScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
|
||||
// Slow - somewhat static:
|
||||
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
|
||||
int m_exportNext; ///< Next export funcnum
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {}
|
||||
~VerilatedImp() {}
|
||||
|
||||
// METHODS - arguments
|
||||
static void commandArgs(int argc, const char** argv) {
|
||||
s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; i++) s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
static string argPlusMatch(const char* prefixp) {
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
vl_fatal("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0]=='+') {
|
||||
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// METHODS - user scope tracking
|
||||
// We implement this as a single large map instead of one map per scope
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) {
|
||||
UserMap::iterator it=s_s.m_userMap.find(make_pair(scopep,userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, make_pair(make_pair(scopep,userKey),userData));
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) {
|
||||
UserMap::iterator it=s_s.m_userMap.find(make_pair(scopep,userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope at construction
|
||||
ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, make_pair(scopep->name(),scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) {
|
||||
ScopeNameMap::iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope at destruction
|
||||
userEraseScope(scopep);
|
||||
ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
}
|
||||
|
||||
static void scopesDump() {
|
||||
VL_PRINTF("scopesDump:\n");
|
||||
for (ScopeNameMap::iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF("\n");
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - export names
|
||||
|
||||
// Each function prototype is converted to a function number which we
|
||||
// then use to index a 2D table also indexed by scope number, because we
|
||||
// can't know at Verilation time what scopes will exist in other modules
|
||||
// in the design that also happen to have our same callback function.
|
||||
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) {
|
||||
// Slow ok - called once/function at creation
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, make_pair(namep, s_s.m_exportNext++));
|
||||
return s_s.m_exportNext++;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) {
|
||||
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
string msg = (string("%Error: Testbench C called ")+namep
|
||||
+" but no such DPI export function name exists in ANY model");
|
||||
vl_fatal("unknown",0,"", msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
static const char* exportName(int funcnum) {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
for (ExportNameMap::iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
// what other models are using the assigned funcnum's.
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2009-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -24,8 +24,8 @@
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATEDSC_H_
|
||||
#define _VERILATEDSC_H_ 1 ///< Header Guard
|
||||
#ifndef _VERILATED_SC_H_
|
||||
#define _VERILATED_SC_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "systemc.h"
|
||||
@@ -39,9 +39,9 @@
|
||||
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
|
||||
class VlScBvExposer : public sc_bv_base {
|
||||
public:
|
||||
static uint32_t* sp_datap(const sc_bv_base& base) {
|
||||
static vluint32_t* sp_datap(const sc_bv_base& base) {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp(); }
|
||||
uint32_t* sp_datatp() const { return (uint32_t*)(m_data); }
|
||||
vluint32_t* sp_datatp() const { return (vluint32_t*)(m_data); }
|
||||
// Above reads this protected element in sc_bv_base:
|
||||
// sc_digit* m_data; // data array
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Include to allow symbol inspection
|
||||
///
|
||||
/// This file is for inclusion by files that need to inspect
|
||||
/// the symbol table. It is not included in verilated.h
|
||||
/// as it requires some heavyweight C++ classes.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATED_SYMS_H_
|
||||
#define _VERILATED_SYMS_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated_heavy.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
//======================================================================
|
||||
// Types
|
||||
|
||||
struct VerilatedCStrCmp {
|
||||
/// Ordering maps keyed by const char*'s
|
||||
bool operator() (const char *a, const char *b) const {
|
||||
return std::strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator range
|
||||
|
||||
class VerilatedRange {
|
||||
int m_lhs;
|
||||
int m_rhs;
|
||||
protected:
|
||||
friend class VerilatedVar;
|
||||
friend class VerilatedScope;
|
||||
VerilatedRange() : m_lhs(0), m_rhs(0) {}
|
||||
void sets(int lhs, int rhs) { m_lhs=lhs; m_rhs=rhs; }
|
||||
public:
|
||||
~VerilatedRange() {}
|
||||
int lhs() const { return m_lhs; }
|
||||
int rhs() const { return m_rhs; }
|
||||
int bits() const { return (VL_LIKELY(m_lhs>=m_rhs)?(m_lhs-m_rhs+1):(m_rhs-m_lhs+1)); }
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator variable
|
||||
|
||||
class VerilatedVar {
|
||||
void* m_datap; // Location of data
|
||||
VerilatedVarType m_vltype; // Data type
|
||||
VerilatedVarFlags m_vlflags; // Direction
|
||||
VerilatedRange m_range; // First range
|
||||
VerilatedRange m_array; // Array
|
||||
int m_dims; // Dimensions
|
||||
const char* m_namep; // Name - slowpath
|
||||
protected:
|
||||
friend class VerilatedScope;
|
||||
VerilatedVar(const char* namep, void* datap,
|
||||
VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims)
|
||||
: m_datap(datap), m_vltype(vltype), m_vlflags(vlflags), m_dims(dims), m_namep(namep) {}
|
||||
public:
|
||||
~VerilatedVar() {}
|
||||
void* datap() const { return m_datap; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
VerilatedVarFlags vldir() const { return (VerilatedVarFlags)((int)m_vlflags & VLVF_MASK_DIR); }
|
||||
vluint32_t entSize() const;
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
const VerilatedRange& range() const { return m_range; }
|
||||
const VerilatedRange& array() const { return m_array; }
|
||||
const char* name() const { return m_namep; }
|
||||
int dims() const { return m_dims; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
/// Types
|
||||
|
||||
struct VerilatedVarNameMap : public map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||
VerilatedVarNameMap() {}
|
||||
~VerilatedVarNameMap() {}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
@@ -0,0 +1,697 @@
|
||||
// -*- SystemC -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2011 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief C++ Tracing in VCD Format
|
||||
///
|
||||
/// AUTHOR: Wilson Snyder
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// SPDIFF_ON
|
||||
|
||||
#ifndef O_LARGEFILE // For example on WIN32
|
||||
# define O_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef O_NONBLOCK
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Global
|
||||
|
||||
vector<VerilatedVcd*> VerilatedVcd::s_vcdVecp; ///< List of all created traces
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdCallInfo
|
||||
/// Internal callback routines for each module being traced.
|
||||
////
|
||||
/// Each SystemPerl module that wishes to be traced registers a set of
|
||||
/// callbacks stored in this class. When the trace file is being
|
||||
/// constructed, this class provides the callback routines to be executed.
|
||||
|
||||
class VerilatedVcdCallInfo {
|
||||
protected:
|
||||
friend class VerilatedVcd;
|
||||
VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function
|
||||
VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function
|
||||
VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
|
||||
void* m_userthis; ///< Fake "this" for caller
|
||||
vluint32_t m_code; ///< Starting code number
|
||||
// CREATORS
|
||||
VerilatedVcdCallInfo (VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb,
|
||||
VerilatedVcdCallback_t changecb,
|
||||
void* ut, vluint32_t code)
|
||||
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {};
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Opening/Closing
|
||||
|
||||
void VerilatedVcd::open (const char* filename) {
|
||||
if (isOpen()) return;
|
||||
|
||||
// Set member variables
|
||||
m_filename = filename;
|
||||
s_vcdVecp.push_back(this);
|
||||
|
||||
// SPDIFF_OFF
|
||||
// Set callback so an early exit will flush us
|
||||
Verilated::flushCb(&flush_all);
|
||||
|
||||
// SPDIFF_ON
|
||||
openNext (m_rolloverMB!=0);
|
||||
if (!isOpen()) return;
|
||||
|
||||
dumpHeader();
|
||||
|
||||
// Allocate space now we know the number of codes
|
||||
if (!m_sigs_oldvalp) {
|
||||
m_sigs_oldvalp = new vluint32_t [m_nextCode+10];
|
||||
}
|
||||
|
||||
if (m_rolloverMB) {
|
||||
openNext(true);
|
||||
if (!isOpen()) return;
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::openNext (bool incFilename) {
|
||||
// Open next filename in concat sequence, mangle filename if
|
||||
// incFilename is true.
|
||||
closePrev(); // Close existing
|
||||
if (incFilename) {
|
||||
// Find _0000.{ext} in filename
|
||||
string name = m_filename;
|
||||
size_t pos=name.rfind(".");
|
||||
if (pos>8 && 0==strncmp("_cat",name.c_str()+pos-8,4)
|
||||
&& isdigit(name.c_str()[pos-4])
|
||||
&& isdigit(name.c_str()[pos-3])
|
||||
&& isdigit(name.c_str()[pos-2])
|
||||
&& isdigit(name.c_str()[pos-1])) {
|
||||
// Increment code.
|
||||
if ((++(name[pos-1])) > '9') {
|
||||
name[pos-1] = '0';
|
||||
if ((++(name[pos-2])) > '9') {
|
||||
name[pos-2] = '0';
|
||||
if ((++(name[pos-3])) > '9') {
|
||||
name[pos-3] = '0';
|
||||
if ((++(name[pos-4])) > '9') {
|
||||
name[pos-4] = '0';
|
||||
}}}}
|
||||
} else {
|
||||
// Append _cat0000
|
||||
name.insert(pos,"_cat0000");
|
||||
}
|
||||
m_filename = name;
|
||||
}
|
||||
if (m_filename[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
} else {
|
||||
m_fd = ::open (m_filename.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
m_fullDump = true; // First dump must be full
|
||||
m_wroteBytes = 0;
|
||||
}
|
||||
|
||||
void VerilatedVcd::makeNameMap() {
|
||||
// Take signal information from each module and build m_namemapp
|
||||
m_namemapp = new NameMap;
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
cip->m_code = nextCode();
|
||||
(cip->m_initcb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
|
||||
// Though not speced, it's illegal to generate a vcd with signals
|
||||
// not under any module - it crashes at least two viewers.
|
||||
// If no scope was specified, prefix everything with a "top"
|
||||
// This comes from user instantiations with no name - IE Vtop("").
|
||||
bool nullScope = false;
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const char* hiername = (*it).first.c_str();
|
||||
if (hiername[0] == '\t') nullScope=true;
|
||||
}
|
||||
if (nullScope) {
|
||||
NameMap* newmapp = new NameMap;
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const string& hiername = it->first;
|
||||
const string& decl = it->second;
|
||||
string newname = string("top");
|
||||
if (hiername[0] != '\t') newname += ' ';
|
||||
newname += hiername;
|
||||
newmapp->insert(make_pair(newname,decl));
|
||||
}
|
||||
delete m_namemapp; m_namemapp=NULL;
|
||||
m_namemapp = newmapp;
|
||||
}
|
||||
}
|
||||
|
||||
VerilatedVcd::~VerilatedVcd() {
|
||||
close();
|
||||
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
|
||||
if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; }
|
||||
// Remove from list of traces
|
||||
vector<VerilatedVcd*>::iterator pos = find(s_vcdVecp.begin(), s_vcdVecp.end(), this);
|
||||
if (pos != s_vcdVecp.end()) { s_vcdVecp.erase(pos); }
|
||||
}
|
||||
|
||||
void VerilatedVcd::closePrev () {
|
||||
if (!isOpen()) return;
|
||||
|
||||
bufferFlush();
|
||||
m_isOpen = false;
|
||||
::close(m_fd);
|
||||
}
|
||||
|
||||
void VerilatedVcd::closeErr () {
|
||||
// Close due to an error. We might abort before even getting here,
|
||||
// depending on the definition of vl_fatal.
|
||||
if (!isOpen()) return;
|
||||
|
||||
// No buffer flush, just fclose
|
||||
m_isOpen = false;
|
||||
::close(m_fd); // May get error, just ignore it
|
||||
}
|
||||
|
||||
void VerilatedVcd::close() {
|
||||
if (!isOpen()) return;
|
||||
if (m_evcd) {
|
||||
printStr("$vcdclose ");
|
||||
printTime(m_timeLastDump);
|
||||
printStr(" $end\n");
|
||||
}
|
||||
closePrev();
|
||||
}
|
||||
|
||||
void VerilatedVcd::printStr (const char* str) {
|
||||
// Not fast...
|
||||
while (*str) {
|
||||
*m_writep++ = *str++;
|
||||
bufferCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::printQuad (vluint64_t n) {
|
||||
char buf [100];
|
||||
sprintf(buf,"%" VL_PRI64 "u", n);
|
||||
printStr(buf);
|
||||
}
|
||||
|
||||
void VerilatedVcd::printTime (vluint64_t timeui) {
|
||||
// VCD file format specification does not allow non-integers for timestamps
|
||||
// Dinotrace doesn't mind, but Cadence vvision seems to choke
|
||||
if (VL_UNLIKELY(timeui < m_timeLastDump)) {
|
||||
timeui = m_timeLastDump;
|
||||
static bool backTime = false;
|
||||
if (!backTime) {
|
||||
backTime = true;
|
||||
VL_PRINTF("VCD time is moving backwards, wave file may be incorrect.\n");
|
||||
}
|
||||
}
|
||||
m_timeLastDump = timeui;
|
||||
printQuad(timeui);
|
||||
}
|
||||
|
||||
void VerilatedVcd::bufferFlush () {
|
||||
// We add output data to m_writep.
|
||||
// When it gets nearly full we dump it using this routine which calls write()
|
||||
// This is much faster than using buffered I/O
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
char* wp = m_wrBufp;
|
||||
while (1) {
|
||||
ssize_t remaining = (m_writep - wp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t got = write (m_fd, wp, remaining);
|
||||
if (got>0) {
|
||||
wp += got;
|
||||
m_wroteBytes += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
string msg = (string)"VerilatedVcd::bufferFlush: "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
closeErr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset buffer
|
||||
m_writep = m_wrBufp;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Simple methods
|
||||
|
||||
void VerilatedVcd::set_time_unit (const char* unitp) {
|
||||
string unitstr (unitp);
|
||||
//cout<<" set_time_unit ("<<unitp<<") == "<<timescaleToDouble(unitp)<<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
m_timeUnit = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
void VerilatedVcd::set_time_resolution (const char* unitp) {
|
||||
string unitstr (unitp);
|
||||
//cout<<"set_time_resolution ("<<unitp<<") == "<<timescaleToDouble(unitp)<<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
m_timeRes = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
double VerilatedVcd::timescaleToDouble (const char* unitp) {
|
||||
char* endp;
|
||||
double value = strtod(unitp, &endp);
|
||||
if (!value) value=1; // On error so we allow just "ns" to return 1e-9.
|
||||
unitp=endp;
|
||||
while (*unitp && isspace(*unitp)) unitp++;
|
||||
switch (*unitp) {
|
||||
case 's': value *= 1e1; break;
|
||||
case 'm': value *= 1e-3; break;
|
||||
case 'u': value *= 1e-6; break;
|
||||
case 'n': value *= 1e-9; break;
|
||||
case 'p': value *= 1e-12; break;
|
||||
case 'f': value *= 1e-15; break;
|
||||
case 'a': value *= 1e-18; break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
string VerilatedVcd::doubleToTimescale (double value) {
|
||||
const char* suffixp = "s";
|
||||
if (value>=1e0) { suffixp="s"; value *= 1e0; }
|
||||
else if (value>=1e-3 ) { suffixp="ms"; value *= 1e3; }
|
||||
else if (value>=1e-6 ) { suffixp="us"; value *= 1e6; }
|
||||
else if (value>=1e-9 ) { suffixp="ns"; value *= 1e9; }
|
||||
else if (value>=1e-12) { suffixp="ps"; value *= 1e12; }
|
||||
else if (value>=1e-15) { suffixp="fs"; value *= 1e15; }
|
||||
else if (value>=1e-18) { suffixp="as"; value *= 1e18; }
|
||||
char valuestr[100]; sprintf(valuestr,"%d%s",(int)(value), suffixp);
|
||||
return valuestr; // Gets converted to string, so no ref to stack
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Definitions
|
||||
|
||||
void VerilatedVcd::printIndent (int level_change) {
|
||||
if (level_change<0) m_modDepth += level_change;
|
||||
assert(m_modDepth>=0);
|
||||
for (int i=0; i<m_modDepth; i++) printStr(" ");
|
||||
if (level_change>0) m_modDepth += level_change;
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpHeader () {
|
||||
printStr("$version Generated by VerilatedVcd $end\n");
|
||||
time_t time_str = time(NULL);
|
||||
printStr("$date "); printStr(ctime(&time_str)); printStr(" $end\n");
|
||||
|
||||
printStr("$timescale ");
|
||||
printStr(doubleToTimescale(m_timeRes).c_str());
|
||||
printStr(" $end\n");
|
||||
|
||||
makeNameMap();
|
||||
|
||||
// Signal header
|
||||
assert (m_modDepth==0);
|
||||
printIndent(1);
|
||||
printStr("\n");
|
||||
|
||||
// We detect the spaces in module names to determine hierarchy. This
|
||||
// allows signals to be declared without fixed ordering, which is
|
||||
// required as Verilog signals might be separately declared from
|
||||
// "SP_TRACE" signals.
|
||||
|
||||
// Print the signal names
|
||||
const char* lastName = "";
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const char* hiername = (*it).first.c_str();
|
||||
const char* decl = (*it).second.c_str();
|
||||
|
||||
// Determine difference between the old and new names
|
||||
const char* lp = lastName;
|
||||
const char* np = hiername;
|
||||
lastName = hiername;
|
||||
|
||||
// Skip common prefix, it must break at a space or tab
|
||||
for (; *np && (*np == *lp); np++, lp++) {}
|
||||
while (np!=hiername && *np && *np!=' ' && *np!='\t') { np--; lp--; }
|
||||
//printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np);
|
||||
|
||||
// Any extra spaces in last name are scope ups we need to do
|
||||
bool first = true;
|
||||
for (; *lp; lp++) {
|
||||
if (*lp==' ' || (first && *lp!='\t')) {
|
||||
printIndent(-1);
|
||||
printStr("$upscope $end\n");
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Any new spaces are scope downs we need to do
|
||||
while (*np) {
|
||||
if (*np==' ') np++;
|
||||
if (*np=='\t') break; // tab means signal name starts
|
||||
printIndent(1);
|
||||
printStr("$scope module ");
|
||||
for (; *np && *np!=' ' && *np!='\t'; np++) {
|
||||
if (*np=='[') printStr("(");
|
||||
else if (*np==']') printStr(")");
|
||||
else *m_writep++=*np;
|
||||
}
|
||||
printStr(" $end\n");
|
||||
}
|
||||
|
||||
printIndent(0);
|
||||
printStr(decl);
|
||||
}
|
||||
|
||||
while (m_modDepth>1) {
|
||||
printIndent(-1);
|
||||
printStr("$upscope $end\n");
|
||||
}
|
||||
|
||||
printIndent(-1);
|
||||
printStr("$enddefinitions $end\n\n\n");
|
||||
assert (m_modDepth==0);
|
||||
|
||||
// Reclaim storage
|
||||
delete m_namemapp;
|
||||
}
|
||||
|
||||
void VerilatedVcd::module (string name) {
|
||||
m_modName = name;
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
if (!code) { vl_fatal(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
|
||||
|
||||
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
|
||||
int codesNeeded = 1+int(bits/32);
|
||||
if (tri) codesNeeded *= 2; // Space in change array for __en signals
|
||||
|
||||
// Make sure array is large enough
|
||||
m_nextCode = max(nextCode(), code+codesNeeded);
|
||||
if (m_sigs.capacity() <= m_nextCode) {
|
||||
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
|
||||
}
|
||||
|
||||
// Save declaration info
|
||||
VerilatedVcdSig sig = VerilatedVcdSig(code, bits);
|
||||
m_sigs.push_back(sig);
|
||||
|
||||
// Split name into basename
|
||||
// Spaces and tabs aren't legal in VCD signal names, so:
|
||||
// Space separates each level of scope
|
||||
// Tab separates final scope from signal name
|
||||
// Tab sorts before spaces, so signals nicely will print before scopes
|
||||
// Note the hiername may be nothing, if so we'll add "\t{name}"
|
||||
string nameasstr = name;
|
||||
if (m_modName!="") { nameasstr = m_modName+m_scopeEscape+nameasstr; } // Optional ->module prefix
|
||||
string hiername;
|
||||
string basename;
|
||||
for (const char* cp=nameasstr.c_str(); *cp; cp++) {
|
||||
if (isScopeEscape(*cp)) {
|
||||
// Ahh, we've just read a scope, not a basename
|
||||
if (hiername!="") hiername += " ";
|
||||
hiername += basename;
|
||||
basename = "";
|
||||
} else {
|
||||
basename += *cp;
|
||||
}
|
||||
}
|
||||
hiername += "\t"+basename;
|
||||
|
||||
// Print reference
|
||||
string decl = "$var ";
|
||||
if (m_evcd) decl += "port"; else decl += wirep; // usually "wire"
|
||||
char buf [1000];
|
||||
sprintf(buf, " %2d ", bits);
|
||||
decl += buf;
|
||||
if (m_evcd) {
|
||||
sprintf(buf, "<%d", code);
|
||||
decl += buf;
|
||||
} else {
|
||||
decl += stringCode(code);
|
||||
}
|
||||
decl += " ";
|
||||
decl += basename;
|
||||
if (arraynum>=0) {
|
||||
sprintf(buf, "(%d)", arraynum);
|
||||
decl += buf;
|
||||
hiername += buf;
|
||||
}
|
||||
if (bussed) {
|
||||
sprintf(buf, " [%d:%d]", msb, lsb);
|
||||
decl += buf;
|
||||
}
|
||||
decl += " $end\n";
|
||||
m_namemapp->insert(make_pair(hiername,decl));
|
||||
}
|
||||
|
||||
void VerilatedVcd::declBit (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "wire", arraynum, false, false, 0, 0); }
|
||||
void VerilatedVcd::declBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, false, true, msb, lsb); }
|
||||
void VerilatedVcd::declQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, false, true, msb, lsb); }
|
||||
void VerilatedVcd::declArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, false, true, msb, lsb); }
|
||||
void VerilatedVcd::declTriBit (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "wire", arraynum, true, false, 0, 0); }
|
||||
void VerilatedVcd::declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, true, true, msb, lsb); }
|
||||
void VerilatedVcd::declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, true, true, msb, lsb); }
|
||||
void VerilatedVcd::declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, true, true, msb, lsb); }
|
||||
void VerilatedVcd::declFloat (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "real", arraynum, false, false, 31, 0); }
|
||||
void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "real", arraynum, false, false, 63, 0); }
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
|
||||
(*((double*)&m_sigs_oldvalp[code])) = newval;
|
||||
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
|
||||
sprintf(m_writep, "r%.16g", newval);
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
|
||||
(*((float*)&m_sigs_oldvalp[code])) = newval;
|
||||
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
|
||||
sprintf(m_writep, "r%.16g", (double)newval);
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks
|
||||
|
||||
void VerilatedVcd::addCallback (
|
||||
VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb,
|
||||
void* userthis)
|
||||
{
|
||||
if (VL_UNLIKELY(isOpen())) {
|
||||
string msg = (string)"Internal: "+__FILE__+"::"+__FUNCTION__+" called with already open file";
|
||||
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
||||
}
|
||||
VerilatedVcdCallInfo* vci = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, nextCode());
|
||||
m_callbacks.push_back(vci);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Dumping
|
||||
|
||||
void VerilatedVcd::dumpFull (vluint64_t timeui) {
|
||||
dumpPrep (timeui);
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
(cip->m_fullcb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
dumpDone ();
|
||||
}
|
||||
|
||||
void VerilatedVcd::dump (vluint64_t timeui) {
|
||||
if (!isOpen()) return;
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No need for more full dumps
|
||||
dumpFull(timeui);
|
||||
return;
|
||||
}
|
||||
if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > this->m_rolloverMB)) {
|
||||
openNext(true);
|
||||
if (!isOpen()) return;
|
||||
}
|
||||
dumpPrep (timeui);
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
(cip->m_changecb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
dumpDone();
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpPrep (vluint64_t timeui) {
|
||||
printStr("#");
|
||||
printTime(timeui);
|
||||
printStr("\n");
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpDone () {
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Static members
|
||||
|
||||
void VerilatedVcd::flush_all() {
|
||||
for (vluint32_t ent = 0; ent< s_vcdVecp.size(); ent++) {
|
||||
VerilatedVcd* vcdp = s_vcdVecp[ent];
|
||||
vcdp->flush();
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
#ifdef VERILATED_VCD_TEST
|
||||
vluint32_t v1, v2, s1, s2[3];
|
||||
vluint32_t tri96[3];
|
||||
vluint32_t tri96__tri[3];
|
||||
vluint8_t ch;
|
||||
vluint64_t timestamp = 1;
|
||||
double doub = 0;
|
||||
|
||||
void vcdInit (VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
||||
vcdp->scopeEscape('.');
|
||||
vcdp->module ("top");
|
||||
vcdp->declBus (0x2, "v1",-1,5,1);
|
||||
vcdp->declBus (0x3, "v2",-1,6,0);
|
||||
vcdp->module ("top.sub1");
|
||||
vcdp->declBit (0x4, "s1",-1);
|
||||
vcdp->declBit (0x5, "ch",-1);
|
||||
vcdp->module ("top.sub2");
|
||||
vcdp->declArray (0x6, "s2",-1, 40,3);
|
||||
// Note need to add 3 for next code.
|
||||
vcdp->module ("top2");
|
||||
vcdp->declBus (0x2, "t2v1",-1,4,1);
|
||||
vcdp->declTriBit (0x10, "io1", -1);
|
||||
vcdp->declTriBus (0x12, "io5", -1,4,0);
|
||||
vcdp->declTriArray (0x16, "io96",-1,95,0);
|
||||
// Note need to add 6 for next code.
|
||||
vcdp->declDouble (0x1c, "doub",-1);
|
||||
// Note need to add 2 for next code.
|
||||
}
|
||||
|
||||
void vcdFull (VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
||||
vcdp->fullBus (0x2, v1,5);
|
||||
vcdp->fullBus (0x3, v2,7);
|
||||
vcdp->fullBit (0x4, s1);
|
||||
vcdp->fullBus (0x5, ch,2);
|
||||
vcdp->fullArray(0x6, &s2[0], 38);
|
||||
vcdp->fullTriBit (0x10, tri96[0]&1, tri96__tri[0]&1);
|
||||
vcdp->fullTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5);
|
||||
vcdp->fullTriArray (0x16, tri96, tri96__tri, 96);
|
||||
vcdp->fullDouble(0x1c, doub);
|
||||
}
|
||||
|
||||
void vcdChange (VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
||||
vcdp->chgBus (0x2, v1,5);
|
||||
vcdp->chgBus (0x3, v2,7);
|
||||
vcdp->chgBit (0x4, s1);
|
||||
vcdp->chgBus (0x5, ch,2);
|
||||
vcdp->chgArray(0x6, &s2[0], 38);
|
||||
vcdp->chgTriBit (0x10, tri96[0]&1, tri96__tri[0]&1);
|
||||
vcdp->chgTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5);
|
||||
vcdp->chgTriArray (0x16, tri96, tri96__tri, 96);
|
||||
vcdp->chgDouble (0x1c, doub);
|
||||
}
|
||||
|
||||
main() {
|
||||
cout<<"test: O_LARGEFILE="<<O_LARGEFILE<<endl;
|
||||
|
||||
v1 = v2 = s1 = 0;
|
||||
s2[0] = s2[1] = s2[2] = 0;
|
||||
tri96[2] = tri96[1] = tri96[0] = 0;
|
||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0;
|
||||
ch = 0;
|
||||
doub = 0;
|
||||
{
|
||||
VerilatedVcdC* vcdp = new VerilatedVcdC;
|
||||
vcdp->spTrace()->addCallback (&vcdInit, &vcdFull, &vcdChange, 0);
|
||||
vcdp->open ("test.vcd");
|
||||
// Dumping
|
||||
vcdp->dump(timestamp++);
|
||||
v1 = 0xfff;
|
||||
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
|
||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
|
||||
doub = 1.5;
|
||||
vcdp->dump(timestamp++);
|
||||
v2 = 0x1;
|
||||
s2[1] = 2;
|
||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
|
||||
doub = -1.66e13;
|
||||
vcdp->dump(timestamp++);
|
||||
ch = 2;
|
||||
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
|
||||
doub = -3.33e-13;
|
||||
vcdp->dump(timestamp++);
|
||||
vcdp->dump(timestamp++);
|
||||
# ifdef VERILATED_VCD_TEST_64BIT
|
||||
vluint64_t bytesPerDump = 15ULL;
|
||||
for (vluint64_t i=0; i<((1ULL<<32) / bytesPerDump); i++) {
|
||||
v1 = i;
|
||||
vcdp->dump(timestamp++);
|
||||
}
|
||||
# endif
|
||||
vcdp->close();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//********************************************************************
|
||||
// Local Variables:
|
||||
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && g++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
|
||||
// End:
|
||||
@@ -0,0 +1,420 @@
|
||||
// -*- SystemC -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2011 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief C++ Tracing in VCD Format
|
||||
///
|
||||
/// AUTHOR: Wilson Snyder
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#ifndef _VERILATED_VCD_C_H_
|
||||
#define _VERILATED_VCD_C_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
class VerilatedVcd;
|
||||
class VerilatedVcdCallInfo;
|
||||
|
||||
// SPDIFF_ON
|
||||
//=============================================================================
|
||||
// VerilatedVcdSig
|
||||
/// Internal data on one signal being traced.
|
||||
|
||||
class VerilatedVcdSig {
|
||||
protected:
|
||||
friend class VerilatedVcd;
|
||||
vluint32_t m_code; ///< VCD file code number
|
||||
int m_bits; ///< Size of value in bits
|
||||
VerilatedVcdSig (vluint32_t code, int bits)
|
||||
: m_code(code), m_bits(bits) {}
|
||||
public:
|
||||
~VerilatedVcdSig() {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluint32_t code);
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcd
|
||||
/// Create a SystemPerl VCD dump
|
||||
|
||||
class VerilatedVcd {
|
||||
private:
|
||||
bool m_isOpen; ///< True indicates open file
|
||||
bool m_evcd; ///< True for evcd format
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
string m_filename; ///< Filename we're writing to (if open)
|
||||
vluint64_t m_rolloverMB; ///< MB of file size to rollover at
|
||||
char m_scopeEscape; ///< Character to separate scope components
|
||||
int m_modDepth; ///< Depth of module hierarchy
|
||||
bool m_fullDump; ///< True indicates dump ignoring if changed
|
||||
vluint32_t m_nextCode; ///< Next code number to assign
|
||||
string m_modName; ///< Module name being traced now
|
||||
double m_timeRes; ///< Time resolution (ns/ms etc)
|
||||
double m_timeUnit; ///< Time units (ns/ms etc)
|
||||
vluint64_t m_timeLastDump; ///< Last time we did a dump
|
||||
|
||||
char* m_wrBufp; ///< Output buffer
|
||||
char* m_writep; ///< Write pointer into output buffer
|
||||
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
||||
vector<VerilatedVcdSig> m_sigs; ///< Pointer to signal information
|
||||
vector<VerilatedVcdCallInfo*> m_callbacks; ///< Routines to perform dumping
|
||||
typedef map<string,string> NameMap;
|
||||
NameMap* m_namemapp; ///< List of names for the header
|
||||
static vector<VerilatedVcd*> s_vcdVecp; ///< List of all created traces
|
||||
|
||||
inline size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline size_t bufferInsertSize() { return 16*1024; }
|
||||
void bufferFlush();
|
||||
void bufferCheck() {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_writep > (m_wrBufp+(bufferSize()-bufferInsertSize())))) {
|
||||
bufferFlush();
|
||||
}
|
||||
}
|
||||
void closePrev();
|
||||
void closeErr();
|
||||
void openNext();
|
||||
void makeNameMap();
|
||||
void printIndent (int levelchange);
|
||||
void printStr (const char* str);
|
||||
void printQuad (vluint64_t n);
|
||||
void printTime (vluint64_t timeui);
|
||||
void declare (vluint32_t code, const char* name, const char* wirep,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb);
|
||||
|
||||
void dumpHeader();
|
||||
void dumpPrep (vluint64_t timeui);
|
||||
void dumpFull (vluint64_t timeui);
|
||||
void dumpDone ();
|
||||
inline void printCode (vluint32_t code) {
|
||||
if (code>=(94*94*94)) *m_writep++ = ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) *m_writep++ = ((char)((code/94/94)%94+33));
|
||||
if (code>=(94)) *m_writep++ = ((char)((code/94)%94+33));
|
||||
*m_writep++ = ((char)((code)%94+33));
|
||||
}
|
||||
string stringCode (vluint32_t code) {
|
||||
string out;
|
||||
if (code>=(94*94*94)) out += ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) out += ((char)((code/94/94)%94+33));
|
||||
if (code>=(94)) out += ((char)((code/94)%94+33));
|
||||
return out + ((char)((code)%94+33));
|
||||
}
|
||||
|
||||
protected:
|
||||
// METHODS
|
||||
void evcd(bool flag) { m_evcd = flag; }
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedVcd () : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
|
||||
m_wrBufp = new char [bufferSize()];
|
||||
m_writep = m_wrBufp;
|
||||
m_namemapp = NULL;
|
||||
m_timeRes = m_timeUnit = 1e-9;
|
||||
m_timeLastDump = 0;
|
||||
m_sigs_oldvalp = NULL;
|
||||
m_evcd = false;
|
||||
m_scopeEscape = '.'; // Backward compatibility
|
||||
m_wroteBytes = 0;
|
||||
}
|
||||
~VerilatedVcd();
|
||||
|
||||
// ACCESSORS
|
||||
/// Inside dumping routines, return next VCD signal code
|
||||
vluint32_t nextCode() const {return m_nextCode;}
|
||||
/// Set size in megabytes after which new file should be created
|
||||
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB=rolloverMB; };
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
/// Change character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||
/// Is this an escape?
|
||||
inline bool isScopeEscape(char c) { return isspace(c) || c==m_scopeEscape; }
|
||||
|
||||
// METHODS
|
||||
void open (const char* filename); ///< Open the file; call isOpen() to see if errors
|
||||
void openNext (bool incFilename); ///< Open next data-only file
|
||||
void flush() { bufferFlush(); } ///< Flush any remaining data
|
||||
static void flush_all(); ///< Flush any remaining data from all files
|
||||
void close (); ///< Close the file
|
||||
|
||||
void set_time_unit (const char* unit); ///< Set time units (s/ms, defaults to ns)
|
||||
void set_time_unit (const string& unit) { set_time_unit(unit.c_str()); }
|
||||
|
||||
void set_time_resolution (const char* unit); ///< Set time resolution (s/ms, defaults to ns)
|
||||
void set_time_resolution (const string& unit) { set_time_resolution(unit.c_str()); }
|
||||
|
||||
double timescaleToDouble (const char* unitp);
|
||||
string doubleToTimescale (double value);
|
||||
|
||||
/// Inside dumping routines, called each cycle to make the dump
|
||||
void dump (vluint64_t timeui);
|
||||
/// Call dump with a absolute unscaled time in seconds
|
||||
void dumpSeconds (double secs) { dump((vluint64_t)(secs * m_timeRes)); }
|
||||
|
||||
/// Inside dumping routines, declare callbacks for tracings
|
||||
void addCallback (VerilatedVcdCallback_t init, VerilatedVcdCallback_t full,
|
||||
VerilatedVcdCallback_t change,
|
||||
void* userthis);
|
||||
|
||||
/// Inside dumping routines, declare a module
|
||||
void module (const string name);
|
||||
/// Inside dumping routines, declare a signal
|
||||
void declBit (vluint32_t code, const char* name, int arraynum);
|
||||
void declBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declTriBit (vluint32_t code, const char* name, int arraynum);
|
||||
void declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declDouble (vluint32_t code, const char* name, int arraynum);
|
||||
void declFloat (vluint32_t code, const char* name, int arraynum);
|
||||
// ... other module_start for submodules (based on cell name)
|
||||
|
||||
/// Inside dumping routines, dump one signal
|
||||
void fullBit (vluint32_t code, const vluint32_t newval) {
|
||||
// Note the &1, so we don't require clean input -- makes more common no change case faster
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
*m_writep++=('0'+(char)(newval&1)); printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullBus (vluint32_t code, const vluint32_t newval, int bits) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++=((newval&(1L<<bit))?'1':'0');
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullQuad (vluint32_t code, const vluint64_t newval, int bits) {
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code])) = newval;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++=((newval&(1ULL<<bit))?'1':'0');
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullArray (vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
m_sigs_oldvalp[code+word] = newval[word];
|
||||
}
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++=((newval[(bit/32)]&(1L<<(bit&0x1f)))?'1':'0');
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriBit (vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
m_sigs_oldvalp[code+1] = newtri;
|
||||
*m_writep++ = "01zz"[m_sigs_oldvalp[code]
|
||||
| (m_sigs_oldvalp[code+1]<<1)];
|
||||
printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriBus (vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
m_sigs_oldvalp[code+1] = newtri;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit)&1)
|
||||
| (((newtri >> bit)&1)<<1)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code])) = newval;
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code+1])) = newtri;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit)&1ULL)
|
||||
| (((newtri >> bit)&1ULL)<<1ULL)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
m_sigs_oldvalp[code+word*2] = newvalp[word];
|
||||
m_sigs_oldvalp[code+word*2+1] = newtrip[word];
|
||||
}
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1;
|
||||
vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1;
|
||||
*m_writep++ = "01zz"[valbit | (tribit<<1)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullDouble (vluint32_t code, const double newval);
|
||||
void fullFloat (vluint32_t code, const float newval);
|
||||
|
||||
/// Inside dumping routines, dump one signal as unknowns
|
||||
/// Presently this code doesn't change the oldval vector.
|
||||
/// Thus this is for special standalone applications that after calling
|
||||
/// fullBitX, must when then value goes non-X call fullBit.
|
||||
inline void fullBitX (vluint32_t code) {
|
||||
*m_writep++='x'; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
inline void fullBusX (vluint32_t code, int bits) {
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++='x';
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
inline void fullQuadX (vluint32_t code, int bits) { fullBusX (code, bits); }
|
||||
inline void fullArrayX (vluint32_t code, int bits) { fullBusX (code, bits); }
|
||||
|
||||
/// Inside dumping routines, dump one signal if it has changed
|
||||
inline void chgBit (vluint32_t code, const vluint32_t newval) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
// Verilator 3.510 and newer provide clean input, so the below is only for back compatibility
|
||||
if (VL_UNLIKELY(diff & 1)) { // Change after clean?
|
||||
fullBit (code, newval);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgBus (vluint32_t code, const vluint32_t newval, int bits) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==32 || (diff & ((1U<<bits)-1) ))) {
|
||||
fullBus (code, newval, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgQuad (vluint32_t code, const vluint64_t newval, int bits) {
|
||||
vluint64_t diff = (*((vluint64_t*)&m_sigs_oldvalp[code])) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==64 || (diff & ((1ULL<<bits)-1) ))) {
|
||||
fullQuad(code, newval, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgArray (vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code+word] ^ newval[word])) {
|
||||
fullArray (code,newval,bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriBit (vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
||||
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
|
||||
| (m_sigs_oldvalp[code+1] ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
// Verilator 3.510 and newer provide clean input, so the below is only for back compatibility
|
||||
if (VL_UNLIKELY(diff & 1)) { // Change after clean?
|
||||
fullTriBit (code, newval, newtri);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriBus (vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
|
||||
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
|
||||
| (m_sigs_oldvalp[code+1] ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==32 || (diff & ((1U<<bits)-1) ))) {
|
||||
fullTriBus (code, newval, newtri, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
|
||||
vluint64_t diff = ( ((*((vluint64_t*)&m_sigs_oldvalp[code])) ^ newval)
|
||||
| ((*((vluint64_t*)&m_sigs_oldvalp[code+1])) ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==64 || (diff & ((1ULL<<bits)-1) ))) {
|
||||
fullTriQuad(code, newval, newtri, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
if (VL_UNLIKELY((m_sigs_oldvalp[code+word*2] ^ newvalp[word])
|
||||
| (m_sigs_oldvalp[code+word*2+1] ^ newtrip[word]))) {
|
||||
fullTriArray (code,newvalp,newtrip,bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgDouble (vluint32_t code, const double newval) {
|
||||
if (VL_UNLIKELY((*((double*)&m_sigs_oldvalp[code])) != newval)) {
|
||||
fullDouble (code, newval);
|
||||
}
|
||||
}
|
||||
inline void chgFloat (vluint32_t code, const float newval) {
|
||||
if (VL_UNLIKELY((*((float*)&m_sigs_oldvalp[code])) != newval)) {
|
||||
fullFloat (code, newval);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdC
|
||||
/// Create a VCD dump file in C standalone (no SystemC) simulations.
|
||||
|
||||
class VerilatedVcdC {
|
||||
VerilatedVcd m_sptrace; ///< SystemPerl trace file being created
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedVcdC() {}
|
||||
~VerilatedVcdC() {}
|
||||
// ACCESSORS
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_sptrace.isOpen(); }
|
||||
// METHODS
|
||||
/// Open a new VCD file
|
||||
void open (const char* filename) { m_sptrace.open(filename); }
|
||||
/// Continue a VCD dump by rotating to a new file name
|
||||
void openNext (bool incFilename=true) { m_sptrace.openNext(incFilename); }
|
||||
/// Set size in megabytes after which new file should be created
|
||||
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); };
|
||||
/// Close dump
|
||||
void close() { m_sptrace.close(); }
|
||||
/// Flush dump
|
||||
void flush() { m_sptrace.flush(); }
|
||||
/// Write one cycle of dump data
|
||||
void dump (vluint64_t timeui) { m_sptrace.dump(timeui); }
|
||||
/// Write one cycle of dump data - backward compatible and to reduce
|
||||
/// conversion warnings. It's better to use a vluint64_t time instead.
|
||||
void dump (double timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (vluint32_t timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (int timestamp) { dump((vluint64_t)timestamp); }
|
||||
/// Internal class access
|
||||
inline VerilatedVcd* spTrace () { return &m_sptrace; };
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
@@ -0,0 +1,159 @@
|
||||
// -*- SystemC -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2011 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief SystemPerl Tracing in VCD Format
|
||||
///
|
||||
/// AUTHOR: Wilson Snyder
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_vcd_sc.h"
|
||||
|
||||
// SPDIFF_ON
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
//--------------------------------------------------
|
||||
#if (SYSTEMC_VERSION>=20050714)
|
||||
// SystemC 2.1.v1
|
||||
void VerilatedVcdSc::write_comment (const std::string &) {}
|
||||
void VerilatedVcdSc::trace (const unsigned int &, const std::string &, const char **) {}
|
||||
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const std::string& name ) {}
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const std::string& name, int width ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
|
||||
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_B( sc_dt::int64 )
|
||||
DECL_TRACE_METHOD_B( sc_dt::uint64 )
|
||||
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
#elif (SYSTEMC_VERSION>20011000)
|
||||
// SystemC 2.0.1
|
||||
void VerilatedVcdSc::write_comment (const sc_string &) {}
|
||||
void VerilatedVcdSc::trace (const unsigned int &, const sc_string &, const char **) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
#if (SYSTEMC_VERSION>20041000)
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
DECL_TRACE_METHOD_B( long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
#else
|
||||
// SystemC 1.2.1beta
|
||||
void VerilatedVcdSc::write_comment (const sc_string &) {}
|
||||
void VerilatedVcdSc::trace (const unsigned int &, const sc_string &, const char **) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( short unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( long unsigned int )
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short int )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long int )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_A( sc_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||
#endif
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
|
||||
//********************************************************************
|
||||
@@ -0,0 +1,213 @@
|
||||
// -*- SystemC -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2011 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief SystemPerl tracing in VCD format
|
||||
///
|
||||
/// AUTHOR: Wilson Snyder
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#ifndef _VERILATED_VCD_SC_H_
|
||||
#define _VERILATED_VCD_SC_H_ 1
|
||||
|
||||
#include "verilated_sc.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
|
||||
// SPDIFF_ON
|
||||
//=============================================================================
|
||||
// VerilatedVcdSc
|
||||
///
|
||||
/// This class is passed to the SystemC simulation kernel, just like a
|
||||
/// documented SystemC trace format.
|
||||
|
||||
class VerilatedVcdSc
|
||||
: sc_trace_file
|
||||
, public VerilatedVcdC
|
||||
{
|
||||
public:
|
||||
VerilatedVcdSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
# if (SYSTEMC_VERSION>=20060505)
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an annoying "to turn off" message.
|
||||
sc_time t1sec(1,SC_SEC);
|
||||
if (t1sec.to_default_time_units()!=0) {
|
||||
sc_time tunits(1.0/t1sec.to_default_time_units(),SC_SEC);
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
# elif (SYSTEMC_VERSION>20011000)
|
||||
// To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string
|
||||
// we allow both flavors with overloaded set_time_* functions.
|
||||
spTrace()->set_time_unit(sc_get_default_time_unit().to_string());
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
# endif
|
||||
}
|
||||
|
||||
virtual ~VerilatedVcdSc() {}
|
||||
/// Called by SystemC simulate()
|
||||
virtual void cycle (bool delta_cycle) {
|
||||
# if (SYSTEMC_VERSION>20011000)
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
# else
|
||||
// VCD files must have integer timestamps, so we write all times in increments of time_resolution
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
# endif
|
||||
}
|
||||
|
||||
private:
|
||||
/// Fake outs for linker
|
||||
|
||||
#ifdef NC_SYSTEMC
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
virtual void set_time_unit( int exponent10_seconds ) {} // deprecated
|
||||
virtual void set_time_unit( double v, sc_time_unit tu ) {}
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
# if (SYSTEMC_VERSION>=20050714)
|
||||
// SystemC 2.1.v1
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
virtual void trace( const tp& object, const std::string& name );
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace( const tp& object, const std::string& name, int width );
|
||||
|
||||
virtual void write_comment (const std::string &);
|
||||
virtual void trace (const unsigned int &, const std::string &, const char **);
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
|
||||
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_B( sc_dt::int64 )
|
||||
DECL_TRACE_METHOD_B( sc_dt::uint64 )
|
||||
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
# elif (SYSTEMC_VERSION>20011000)
|
||||
// SystemC 2.0.1
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
virtual void trace( const tp& object, const sc_string& name );
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace( const tp& object, const sc_string& name, int width );
|
||||
|
||||
virtual void write_comment (const sc_string &);
|
||||
virtual void trace (const unsigned int &, const sc_string &, const char **);
|
||||
virtual void delta_cycles (bool) {}
|
||||
virtual void space( int n ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
#if (SYSTEMC_VERSION>20041000)
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
DECL_TRACE_METHOD_B( long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
# else
|
||||
// SystemC 1.2.1beta
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
virtual void trace( const tp& object, const sc_string& name );
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace( const tp& object, const sc_string& name, int width );
|
||||
|
||||
virtual void write_comment (const sc_string &);
|
||||
virtual void trace (const unsigned int &, const sc_string &, const char **);
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( short unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( long unsigned int )
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short int )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long int )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_A( sc_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||
# endif
|
||||
|
||||
# undef DECL_TRACE_METHOD_A
|
||||
# undef DECL_TRACE_METHOD_B
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
@@ -0,0 +1,33 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: VPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the VPI.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#include "verilated_vpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
VerilatedVpi VerilatedVpi::s_s; // Singleton
|
||||
vluint8_t* VerilatedVpio::s_freeHead = NULL;
|
||||
|
||||
//======================================================================
|
||||
@@ -0,0 +1,835 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: VPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the VPI.
|
||||
///
|
||||
/// "//-" indicates features that are as yet unimplemented.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#ifndef CHPI_VERILATED_VPI_H
|
||||
#define CHPI_VERILATED_VPI_H 1
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_syms.h"
|
||||
|
||||
//======================================================================
|
||||
// From IEEE 1800-2009 annex K
|
||||
|
||||
#include "vltstd/vpi_user.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
// Not supported yet
|
||||
#define _VL_VPI_UNIMP() \
|
||||
vl_fatal(__FILE__,__LINE__,"",Verilated::catName("Unsupported VPI function: ",VL_FUNC))
|
||||
|
||||
//======================================================================
|
||||
// Implementation
|
||||
|
||||
#include <set>
|
||||
|
||||
#define VL_DEBUG_IF_PLI VL_DEBUG_IF
|
||||
|
||||
// Base VPI handled object
|
||||
class VerilatedVpio {
|
||||
// MEM MANGLEMENT
|
||||
static vluint8_t* s_freeHead;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedVpio() {}
|
||||
virtual ~VerilatedVpio() {}
|
||||
inline static void* operator new(size_t size) {
|
||||
// We new and delete tons of vpi structures, so keep them around
|
||||
// To simplify our free list, we use a size large enough for all derived types
|
||||
// We reserve word zero for the next pointer, as that's safer in case a
|
||||
// dangling reference to the original remains around.
|
||||
static size_t chunk = 96;
|
||||
if (VL_UNLIKELY(size>chunk)) vl_fatal(__FILE__,__LINE__,"", "increase chunk");
|
||||
if (VL_LIKELY(s_freeHead)) {
|
||||
vluint8_t* newp = s_freeHead;
|
||||
s_freeHead = *((vluint8_t**)newp);
|
||||
return newp+8;
|
||||
} else {
|
||||
// +8: 8 bytes for next
|
||||
vluint8_t* newp = (vluint8_t*)(::operator new(chunk+8));
|
||||
return newp+8;
|
||||
}
|
||||
}
|
||||
inline static void operator delete(void* obj, size_t size) {
|
||||
vluint8_t* oldp = ((vluint8_t*)obj)-8;
|
||||
*((void**)oldp) = s_freeHead;
|
||||
s_freeHead = oldp;
|
||||
}
|
||||
// MEMBERS
|
||||
static inline VerilatedVpio* castp(vpiHandle h) { return dynamic_cast<VerilatedVpio*>((VerilatedVpio*)h); }
|
||||
inline vpiHandle castVpiHandle() { return (vpiHandle)(this); }
|
||||
// ACCESSORS
|
||||
virtual const char* name() { return "<null>"; }
|
||||
virtual const char* fullname() { return "<null>"; }
|
||||
virtual const char* defname() { return "<null>"; }
|
||||
virtual vpiHandle dovpi_scan() { return 0; }
|
||||
};
|
||||
|
||||
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *);
|
||||
|
||||
class VerilatedVpioCb : public VerilatedVpio {
|
||||
t_cb_data m_cbData;
|
||||
QData m_time;
|
||||
public:
|
||||
VerilatedVpioCb(const t_cb_data* cbDatap, QData time) : m_cbData(*cbDatap), m_time(time) {}
|
||||
virtual ~VerilatedVpioCb() {}
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
|
||||
vluint32_t reason() const { return m_cbData.reason; }
|
||||
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
|
||||
t_cb_data* cb_datap() { return &(m_cbData); }
|
||||
QData time() const { return m_time; }
|
||||
};
|
||||
|
||||
class VerilatedVpioConst : public VerilatedVpio {
|
||||
vlsint32_t m_num;
|
||||
public:
|
||||
VerilatedVpioConst(vlsint32_t num) : m_num(num) {}
|
||||
virtual ~VerilatedVpioConst() {}
|
||||
static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
|
||||
vlsint32_t num() const { return m_num; }
|
||||
};
|
||||
|
||||
class VerilatedVpioRange : public VerilatedVpio {
|
||||
vlsint32_t m_lhs; // Ranges can be signed
|
||||
vlsint32_t m_rhs;
|
||||
bool m_iteration;
|
||||
public:
|
||||
VerilatedVpioRange(vlsint32_t lhs, vlsint32_t rhs) : m_lhs(lhs), m_rhs(rhs), m_iteration(0) {}
|
||||
virtual ~VerilatedVpioRange() {}
|
||||
static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
|
||||
vlsint32_t lhs() const { return m_lhs; }
|
||||
vlsint32_t rhs() const { return m_rhs; }
|
||||
int iteration() const { return m_iteration; }
|
||||
void iterationInc() { ++m_iteration; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (!iteration()) {
|
||||
VerilatedVpioRange* nextp = new VerilatedVpioRange(*this);
|
||||
nextp->iterationInc();
|
||||
return ((nextp)->castVpiHandle());
|
||||
} else {
|
||||
return 0; // End of list - only one deep
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioScope : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
public:
|
||||
VerilatedVpioScope(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep) {}
|
||||
virtual ~VerilatedVpioScope() {}
|
||||
static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
virtual const char* name() { return m_scopep->name(); }
|
||||
virtual const char* fullname() { return m_scopep->name(); }
|
||||
};
|
||||
|
||||
class VerilatedVpioVar : public VerilatedVpio {
|
||||
const VerilatedVar* m_varp;
|
||||
const VerilatedScope* m_scopep;
|
||||
vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange
|
||||
vluint32_t m_mask; // memoized variable mask
|
||||
vluint32_t m_entSize; // memoized variable size
|
||||
protected:
|
||||
void* m_varDatap; // varp()->datap() adjusted for array entries
|
||||
vlsint32_t m_index;
|
||||
public:
|
||||
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
|
||||
: m_varp(varp), m_scopep(scopep), m_index(0) {
|
||||
m_prevDatap = NULL;
|
||||
m_mask = VL_MASK_I(varp->range().bits());
|
||||
m_entSize = varp->entSize();
|
||||
m_varDatap = varp->datap();
|
||||
}
|
||||
virtual ~VerilatedVpioVar() {
|
||||
if (m_prevDatap) { delete [] m_prevDatap; m_prevDatap = NULL; }
|
||||
}
|
||||
static inline VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVar*>((VerilatedVpio*)h); }
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
vluint32_t mask() const { return m_mask; }
|
||||
vluint32_t entSize() const { return m_entSize; }
|
||||
virtual const char* name() { return m_varp->name(); }
|
||||
virtual const char* fullname() {
|
||||
static VL_THREAD string out;
|
||||
out = string(m_scopep->name())+"."+name();
|
||||
return out.c_str();
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
void* varDatap() const { return m_varDatap; }
|
||||
void createPrevDatap() {
|
||||
if (VL_UNLIKELY(!m_prevDatap)) {
|
||||
m_prevDatap = new vluint8_t [entSize()];
|
||||
memcpy(prevDatap(), varp()->datap(), entSize());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioVarIndex : public VerilatedVpioVar {
|
||||
public:
|
||||
VerilatedVpioVarIndex(const VerilatedVar* varp, const VerilatedScope* scopep,
|
||||
vlsint32_t index, int offset)
|
||||
: VerilatedVpioVar(varp, scopep) {
|
||||
m_index = index;
|
||||
m_varDatap = ((vluint8_t*)varp->datap()) + entSize()*offset;
|
||||
}
|
||||
virtual ~VerilatedVpioVarIndex() {}
|
||||
static inline VerilatedVpioVarIndex* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIndex*>((VerilatedVpio*)h); }
|
||||
virtual const char* fullname() {
|
||||
static VL_THREAD string out;
|
||||
char num[20]; sprintf(num,"%d",m_index);
|
||||
out = string(scopep()->name())+"."+name()+"["+num+"]";
|
||||
return out.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioVarIter : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
VerilatedVarNameMap::iterator m_it;
|
||||
bool m_started;
|
||||
public:
|
||||
VerilatedVpioVarIter(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep), m_started(false) { }
|
||||
virtual ~VerilatedVpioVarIter() {}
|
||||
static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (VL_LIKELY(m_scopep->varsp())) {
|
||||
if (VL_UNLIKELY(!m_started)) { m_it = m_scopep->varsp()->begin(); m_started=true; }
|
||||
else if (VL_UNLIKELY(m_it == m_scopep->varsp()->end())) return 0;
|
||||
else ++m_it;
|
||||
if (m_it == m_scopep->varsp()->end()) return 0;
|
||||
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))
|
||||
->castVpiHandle());
|
||||
} else {
|
||||
return 0; // End of list - only one deep
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
struct VerilatedVpiTimedCbsCmp {
|
||||
/// Ordering sets keyed by time, then callback descriptor
|
||||
bool operator() (const pair<QData,VerilatedVpioCb*>& a,
|
||||
const pair<QData,VerilatedVpioCb*>& b) const {
|
||||
if (a.first < b.first) return 1;
|
||||
if (a.first > b.first) return 0;
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpi {
|
||||
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason
|
||||
typedef set<VerilatedVpioCb*> VpioCbSet;
|
||||
typedef set<pair<QData,VerilatedVpioCb*>,VerilatedVpiTimedCbsCmp > VpioTimedCbs;
|
||||
|
||||
VpioCbSet m_cbObjSets[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
|
||||
VpioTimedCbs m_timedCbs; // Time based callbacks
|
||||
|
||||
static VerilatedVpi s_s; // Singleton
|
||||
|
||||
public:
|
||||
VerilatedVpi() {}
|
||||
~VerilatedVpi() {}
|
||||
static void cbReasonAdd(VerilatedVpioCb* vop) {
|
||||
if (vop->reason() == cbValueChange) {
|
||||
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
|
||||
varop->createPrevDatap();
|
||||
}
|
||||
}
|
||||
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) vl_fatal(__FILE__,__LINE__,"", "vpi bb reason too large");
|
||||
s_s.m_cbObjSets[vop->reason()].insert(vop);
|
||||
}
|
||||
static void cbTimedAdd(VerilatedVpioCb* vop) {
|
||||
s_s.m_timedCbs.insert(make_pair(vop->time(), vop));
|
||||
}
|
||||
static void cbReasonRemove(VerilatedVpioCb* cbp) {
|
||||
VpioCbSet& cbObjSet = s_s.m_cbObjSets[cbp->reason()];
|
||||
VpioCbSet::iterator it=cbObjSet.find(cbp);
|
||||
if (VL_LIKELY(it != cbObjSet.end())) {
|
||||
cbObjSet.erase(it);
|
||||
}
|
||||
}
|
||||
static void cbTimedRemove(VerilatedVpioCb* cbp) {
|
||||
VpioTimedCbs::iterator it=s_s.m_timedCbs.find(make_pair(cbp->time(),cbp));
|
||||
if (VL_LIKELY(it != s_s.m_timedCbs.end())) {
|
||||
s_s.m_timedCbs.erase(it);
|
||||
}
|
||||
}
|
||||
static void callTimedCbs() {
|
||||
QData time = VL_TIME_Q();
|
||||
for (VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); it!=s_s.m_timedCbs.end(); ) {
|
||||
if (VL_UNLIKELY(it->first <= time)) {
|
||||
VerilatedVpioCb* vop = it->second;
|
||||
++it; // iterator may be deleted by callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: timed_callback %p\n",vop););
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
else { ++it; }
|
||||
}
|
||||
}
|
||||
static QData cbNextDeadline() {
|
||||
VpioTimedCbs::iterator it=s_s.m_timedCbs.begin();
|
||||
if (VL_LIKELY(it!=s_s.m_timedCbs.end())) {
|
||||
return it->first;
|
||||
} else {
|
||||
return ~VL_ULL(0); // maxquad
|
||||
}
|
||||
}
|
||||
static void callCbs(vluint32_t reason) {
|
||||
VpioCbSet& cbObjSet = s_s.m_cbObjSets[reason];
|
||||
for (VpioCbSet::iterator it=cbObjSet.begin(); it!=cbObjSet.end();) {
|
||||
VerilatedVpioCb* vop = *it;
|
||||
++it; // iterator may be deleted by callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: reason_callback %d %p\n",reason,vop););
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
static void callValueCbs() {
|
||||
VpioCbSet& cbObjSet = s_s.m_cbObjSets[cbValueChange];
|
||||
for (VpioCbSet::iterator it=cbObjSet.begin(); it!=cbObjSet.end();) {
|
||||
VerilatedVpioCb* vop = *it;
|
||||
++it; // iterator may be deleted by callback
|
||||
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
|
||||
void* newDatap = varop->varDatap();
|
||||
void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_test %s v[0]=%d/%d %p %p\n",
|
||||
varop->fullname(), *((CData*)newDatap), *((CData*)prevDatap),
|
||||
newDatap, prevDatap););
|
||||
if (memcmp(prevDatap, newDatap, varop->entSize())) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n",
|
||||
vop,varop->fullname(), *((CData*)newDatap)););
|
||||
memcpy(prevDatap, newDatap, varop->entSize());
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// callback related
|
||||
|
||||
vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
||||
if (VL_UNLIKELY(!cb_data_p)) return NULL;
|
||||
switch (cb_data_p->reason) {
|
||||
case cbAfterDelay: {
|
||||
QData time = 0;
|
||||
if (cb_data_p->time) time = _VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
|
||||
VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, VL_TIME_Q()+time);
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_register_cb %d %p delay=%" VL_PRI64 "d\n",cb_data_p->reason,vop,time););
|
||||
VerilatedVpi::cbTimedAdd(vop);
|
||||
return vop->castVpiHandle();
|
||||
}
|
||||
case cbReadWriteSynch: // FALLTHRU // Supported via vlt_main.cpp
|
||||
case cbReadOnlySynch: // FALLTHRU // Supported via vlt_main.cpp
|
||||
case cbNextSimTime: // FALLTHRU // Supported via vlt_main.cpp
|
||||
case cbStartOfSimulation: // FALLTHRU // Supported via vlt_main.cpp
|
||||
case cbEndOfSimulation: // FALLTHRU // Supported via vlt_main.cpp
|
||||
case cbValueChange: // FALLTHRU // Supported via vlt_main.cpp
|
||||
case cbEnterInteractive: // FALLTHRU // NOP, but need to return handle, so make object
|
||||
case cbExitInteractive: // FALLTHRU // NOP, but need to return handle, so make object
|
||||
case cbInteractiveScopeChange: { // FALLTHRU // NOP, but need to return handle, so make object
|
||||
VerilatedVpioCb* vop = new VerilatedVpioCb(cb_data_p, 0);
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_register_cb %d %p\n",cb_data_p->reason,vop););
|
||||
VerilatedVpi::cbReasonAdd(vop);
|
||||
return vop->castVpiHandle();
|
||||
}
|
||||
default:
|
||||
_VL_VPI_UNIMP(); return NULL;
|
||||
};
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_remove_cb(vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_remove_cb %p\n",object););
|
||||
VerilatedVpioCb* vop = VerilatedVpioCb::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (vop->cb_datap()->reason == cbAfterDelay) {
|
||||
VerilatedVpi::cbTimedRemove(vop);
|
||||
} else {
|
||||
VerilatedVpi::cbReasonRemove(vop);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-void vpi_get_cb_info(vpiHandle object, p_cb_data cb_data_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-vpiHandle vpi_register_systf(p_vpi_systf_data systf_data_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-void vpi_get_systf_info(vpiHandle object, p_vpi_systf_data systf_data_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
// for obtaining handles
|
||||
|
||||
vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||
if (VL_UNLIKELY(!namep)) return NULL;
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle_by_name %s %p\n",namep,scope););
|
||||
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
|
||||
const VerilatedVar* varp;
|
||||
const VerilatedScope* scopep;
|
||||
string scopeAndName = namep;
|
||||
if (voScopep) {
|
||||
scopeAndName = string(voScopep->fullname()) + "." + namep;
|
||||
namep = (PLI_BYTE8*)scopeAndName.c_str();
|
||||
}
|
||||
{
|
||||
// This doesn't yet follow the hierarchy in the proper way
|
||||
scopep = Verilated::scopeFind(namep);
|
||||
if (scopep) { // Whole thing found as a scope
|
||||
return (new VerilatedVpioScope(scopep))->castVpiHandle();
|
||||
}
|
||||
const char* baseNamep = scopeAndName.c_str();
|
||||
string scopename;
|
||||
const char* dotp = strrchr(namep, '.');
|
||||
if (VL_LIKELY(dotp)) {
|
||||
baseNamep = dotp+1;
|
||||
scopename = string(namep,dotp-namep);
|
||||
}
|
||||
scopep = Verilated::scopeFind(scopename.c_str());
|
||||
if (!scopep) return NULL;
|
||||
varp = scopep->varFind(baseNamep);
|
||||
}
|
||||
if (!varp) return NULL;
|
||||
return (new VerilatedVpioVar(varp, scopep))->castVpiHandle();
|
||||
}
|
||||
|
||||
vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
||||
// Used to get array entries
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle_by_index %p %d\n",object, indx););
|
||||
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
|
||||
if (VL_LIKELY(varop)) {
|
||||
if (varop->varp()->dims()<2) return 0;
|
||||
if (VL_LIKELY(varop->varp()->array().lhs() >= varop->varp()->array().rhs())) {
|
||||
if (VL_UNLIKELY(indx > varop->varp()->array().lhs() || indx < varop->varp()->array().rhs())) return 0;
|
||||
return (new VerilatedVpioVarIndex(varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->array().rhs()))
|
||||
->castVpiHandle();
|
||||
} else {
|
||||
if (VL_UNLIKELY(indx < varop->varp()->array().lhs() || indx > varop->varp()->array().rhs())) return 0;
|
||||
return (new VerilatedVpioVarIndex(varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->array().lhs()))
|
||||
->castVpiHandle();
|
||||
}
|
||||
} else {
|
||||
_VL_VPI_UNIMP(); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// for traversing relationships
|
||||
|
||||
vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_handle %d %p\n",type,object););
|
||||
switch (type) {
|
||||
case vpiLeftRange: // FALLTHRU
|
||||
case vpiRightRange: {
|
||||
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||
vluint32_t num = ((type==vpiLeftRange)
|
||||
? vop->varp()->range().lhs()
|
||||
: vop->varp()->range().rhs());
|
||||
return (new VerilatedVpioConst(num))->castVpiHandle();
|
||||
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
|
||||
vluint32_t num = ((type==vpiLeftRange)
|
||||
? vop->lhs()
|
||||
: vop->rhs());
|
||||
return (new VerilatedVpioConst(num))->castVpiHandle();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
default:
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle refHandle1, vpiHandle refHandle2, ... ) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_iterate %d %p\n",type,object););
|
||||
switch (type) {
|
||||
case vpiMemoryWord: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (vop->varp()->dims() < 2) return 0;
|
||||
// Unsupported is multidim list
|
||||
return ((new VerilatedVpioRange(vop->varp()->array().lhs(),
|
||||
vop->varp()->array().rhs()))
|
||||
->castVpiHandle());
|
||||
}
|
||||
case vpiReg: {
|
||||
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
return ((new VerilatedVpioVarIter(vop->scopep()))
|
||||
->castVpiHandle());
|
||||
}
|
||||
case vpiIODecl: // Skipping - we'll put under reg
|
||||
case vpiNet: // Skipping - we'll put under reg
|
||||
return 0;
|
||||
default:
|
||||
_VL_VPI_UNIMP(); return 0;
|
||||
}
|
||||
}
|
||||
vpiHandle vpi_scan(vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_scan %p\n",object););
|
||||
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return NULL;
|
||||
return vop->dovpi_scan();
|
||||
}
|
||||
|
||||
// for processing properties
|
||||
|
||||
PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
|
||||
// Leave this in the header file - in many cases the compiler can constant propagate "object"
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get %d %p\n",property,object););
|
||||
switch (property) {
|
||||
case vpiTimePrecision: {
|
||||
return VL_TIME_PRECISION;
|
||||
}
|
||||
case vpiType: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
return ((vop->varp()->dims()>1) ? vpiMemory : vpiReg);
|
||||
}
|
||||
case vpiDirection: {
|
||||
// By forthought, the directions already are vpi enumerated
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
return vop->varp()->vldir();
|
||||
}
|
||||
case vpiVector: {
|
||||
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
if (vop->varp()->dims()==0) return 0;
|
||||
else return 1;
|
||||
}
|
||||
default:
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-PLI_INT64 vpi_get64(PLI_INT32 property, vpiHandle object) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
PLI_BYTE8 *vpi_get_str(PLI_INT32 property, vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_str %d %p\n",property,object););
|
||||
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return NULL;
|
||||
switch (property) {
|
||||
case vpiName: {
|
||||
return (PLI_BYTE8*)vop->name();
|
||||
}
|
||||
case vpiFullName: {
|
||||
return (PLI_BYTE8*)vop->fullname();
|
||||
}
|
||||
case vpiDefName: {
|
||||
return (PLI_BYTE8*)vop->defname();
|
||||
}
|
||||
default:
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// delay processing
|
||||
|
||||
//-void vpi_get_delays(vpiHandle object, p_vpi_delay delay_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-void vpi_put_delays(vpiHandle object, p_vpi_delay delay_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
// value processing
|
||||
|
||||
void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_get_value %p\n",object););
|
||||
if (VL_UNLIKELY(!value_p)) return;
|
||||
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||
// We presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||
if (value_p->format == vpiVectorVal) {
|
||||
// Vector pointer must come from our memory pool
|
||||
// It only needs to persist until the next vpi_get_value
|
||||
static VL_THREAD t_vpi_vecval out[VL_MULS_MAX_WORDS*2];
|
||||
value_p->value.vector = out;
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8:
|
||||
out[0].aval = *((CData*)(vop->varDatap()));
|
||||
out[0].bval = 0;
|
||||
return;
|
||||
case VLVT_UINT16:
|
||||
out[0].aval = *((SData*)(vop->varDatap()));
|
||||
out[0].bval = 0;
|
||||
return;
|
||||
case VLVT_UINT32:
|
||||
out[0].aval = *((IData*)(vop->varDatap()));
|
||||
out[0].bval = 0;
|
||||
return;
|
||||
case VLVT_WDATA: {
|
||||
int words = VL_WORDS_I(vop->varp()->range().bits());
|
||||
if (VL_UNLIKELY(words >= VL_MULS_MAX_WORDS)) {
|
||||
vl_fatal(__FILE__,__LINE__,"", "vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile");
|
||||
}
|
||||
WDataInP datap = ((IData*)(vop->varDatap()));
|
||||
for (int i=0; i<words; i++) {
|
||||
out[i].aval = datap[i];
|
||||
out[i].bval = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
case VLVT_UINT64: {
|
||||
QData data = *((QData*)(vop->varDatap()));
|
||||
out[1].aval = (IData)(data>>VL_ULL(32));
|
||||
out[1].bval = 0;
|
||||
out[0].aval = (IData)(data);
|
||||
out[0].bval = 0;
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
_VL_VPI_UNIMP();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8:
|
||||
value_p->value.integer = *((CData*)(vop->varDatap()));
|
||||
return;
|
||||
case VLVT_UINT16:
|
||||
value_p->value.integer = *((SData*)(vop->varDatap()));
|
||||
return;
|
||||
case VLVT_UINT32:
|
||||
value_p->value.integer = *((IData*)(vop->varDatap()));
|
||||
return;
|
||||
case VLVT_WDATA:
|
||||
case VLVT_UINT64:
|
||||
// Not legal
|
||||
value_p->value.integer = 0;
|
||||
default:
|
||||
_VL_VPI_UNIMP();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
|
||||
value_p->value.integer = vop->num();
|
||||
return;
|
||||
}
|
||||
_VL_VPI_UNIMP();
|
||||
}
|
||||
|
||||
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
||||
p_vpi_time time_p, PLI_INT32 flags) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_put_value %p %p\n",object, value_p););
|
||||
if (VL_UNLIKELY(!value_p)) return 0;
|
||||
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
||||
// We presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_put_value name=%s fmt=%d vali=%d\n",
|
||||
vop->fullname(), value_p->format, value_p->value.integer);
|
||||
VL_PRINTF("-vltVpi: varp=%p putatp=%p\n",
|
||||
vop->varp()->datap(), vop->varDatap()););
|
||||
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
|
||||
VL_PRINTF("%%Warning: Ignoring vpi_put_value to signal marked read-only, use public_flat_rw instead: %s\n",
|
||||
vop->fullname());
|
||||
return 0;
|
||||
}
|
||||
if (value_p->format == vpiVectorVal) {
|
||||
if (VL_UNLIKELY(!value_p->value.vector)) return NULL;
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8:
|
||||
*((CData*)(vop->varDatap())) = value_p->value.vector[0].aval;
|
||||
return object;
|
||||
case VLVT_UINT16:
|
||||
*((SData*)(vop->varDatap())) = value_p->value.vector[0].aval;
|
||||
return object;
|
||||
case VLVT_UINT32:
|
||||
*((IData*)(vop->varDatap())) = value_p->value.vector[0].aval;
|
||||
return object;
|
||||
case VLVT_WDATA: {
|
||||
int words = VL_WORDS_I(vop->varp()->range().bits());
|
||||
WDataOutP datap = ((IData*)(vop->varDatap()));
|
||||
for (int i=0; i<words; i++) {
|
||||
datap[i] = value_p->value.vector[i].aval;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
case VLVT_UINT64: {
|
||||
*((QData*)(vop->varDatap())) = _VL_SET_QII(
|
||||
value_p->value.vector[1].aval,
|
||||
value_p->value.vector[0].aval);
|
||||
return object;
|
||||
}
|
||||
default: {
|
||||
_VL_VPI_UNIMP();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8:
|
||||
*((CData*)(vop->varDatap())) = vop->mask() & value_p->value.integer;
|
||||
return object;
|
||||
case VLVT_UINT16:
|
||||
*((SData*)(vop->varDatap())) = vop->mask() & value_p->value.integer;
|
||||
return object;
|
||||
case VLVT_UINT32:
|
||||
*((IData*)(vop->varDatap())) = vop->mask() & value_p->value.integer;
|
||||
return object;
|
||||
case VLVT_WDATA: // FALLTHRU
|
||||
case VLVT_UINT64: // FALLTHRU
|
||||
default:
|
||||
_VL_VPI_UNIMP();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
_VL_VPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
//-void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
|
||||
//- PLI_INT32 *index_p, PLI_UINT32 num) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
|
||||
//- PLI_INT32 *index_p, PLI_UINT32 num) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
|
||||
// time processing
|
||||
|
||||
//-void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
|
||||
//- _VL_VPI_UNIMP();
|
||||
//-}
|
||||
|
||||
// I/O routines
|
||||
|
||||
//-PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *fileName) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 cd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *format, ...) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
int chars = vpi_vprintf(formatp, ap);
|
||||
va_end(ap);
|
||||
return chars;
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) {
|
||||
return VL_VPRINTF(formatp, ap);
|
||||
}
|
||||
|
||||
//-PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_flush(void) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
// utility routines
|
||||
|
||||
//-PLI_INT32 vpi_compare_objects(vpiHandle object1, vpiHandle object2) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
PLI_INT32 vpi_free_object(vpiHandle object) {
|
||||
return vpi_release_handle(object); // Deprecated
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_release_handle (vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_release_handle %p\n",object););
|
||||
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return 0;
|
||||
vpi_remove_cb(object); // May not be a callback, but that's ok
|
||||
delete vop;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
// routines added with 1364-2001
|
||||
|
||||
//-PLI_INT32 vpi_get_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_put_data(PLI_INT32 id, PLI_BYTE8 *dataLoc, PLI_INT32 numOfBytes) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-void *vpi_get_userdata(vpiHandle obj) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_put_userdata(vpiHandle obj, void *userdata) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: vpi_control %d\n",operation););
|
||||
switch (operation) {
|
||||
case vpiFinish: {
|
||||
vl_finish(__FILE__,__LINE__,"*VPI*");
|
||||
return 1;
|
||||
}
|
||||
case vpiStop: {
|
||||
vl_stop(__FILE__,__LINE__,"*VPI*");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
_VL_VPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
//-vpiHandle vpi_handle_by_multi_index(vpiHandle obj, PLI_INT32 num_index, PLI_INT32 *index_array) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // Guard
|
||||
+93
-16
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -34,19 +34,38 @@
|
||||
// Compiler pragma abstraction
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, fmtArgNum, fmtArgNum+1)))
|
||||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
||||
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
||||
# ifdef _WIN32
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) // GCC with MS runtime will fool the print arg checker
|
||||
# else
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, fmtArgNum, fmtArgNum+1)))
|
||||
# endif
|
||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||
# define VL_FUNC __func__
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
||||
#elif defined(_MSC_VER)
|
||||
# define VL_ATTR_ALIGNED(alignment)
|
||||
# define VL_ATTR_ALWINLINE
|
||||
# define VL_ATTR_NORETURN
|
||||
# define VL_ATTR_PRINTF(fmtArgNum)
|
||||
# define VL_ATTR_UNUSED
|
||||
# define VL_FUNC __FUNCTION__
|
||||
# define VL_LIKELY(x) (!!(x))
|
||||
# define VL_UNLIKELY(x) (!!(x))
|
||||
# define VL_PREFETCH_RD(p)
|
||||
# define VL_PREFETCH_RW(p)
|
||||
#else
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
@@ -72,40 +91,98 @@
|
||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||
#define VL_UL(c) ((IData)(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
||||
//=========================================================================
|
||||
// Warning disabled
|
||||
|
||||
#ifndef VL_WARNINGS
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(disable:4099) // C4099: type name first seen using 'class' now seen using 'struct' (V3AstNode)
|
||||
# pragma warning(disable:4100) // C4100: unreferenced formal parameter (L4)
|
||||
# pragma warning(disable:4127) // C4127: conditional expression is constant (L4)
|
||||
# pragma warning(disable:4146) // C4146: unary minus operator applied to unsigned type, result still unsigned
|
||||
# pragma warning(disable:4189) // C4189: local variable is initialized but not referenced (L4)
|
||||
# pragma warning(disable:4244) // C4244: conversion from 'uint64_t' to 'uint_32_t', possible loss of data
|
||||
# pragma warning(disable:4245) // C4245: conversion from 'int' to 'unsigned', signed/unsigned mismatch
|
||||
# pragma warning(disable:4996) // C4996: sscanf/fopen/etc may be unsafe
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Basic integer types
|
||||
|
||||
#ifdef VL_UINTS_DEFINED
|
||||
#elif defined(__CYGWIN__)
|
||||
|
||||
# include <stdint.h>
|
||||
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
|
||||
# ifdef __uint32_t_defined // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
||||
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||
# else // Older Cygwin has long==uint32_t
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||
# endif
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
# else
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
|
||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||
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 int 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
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
|
||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
|
||||
# ifndef _SSIZE_T_DEFINED
|
||||
# ifdef _WIN64
|
||||
typedef signed __int64 ssize_t; ///< signed size_t; returned from read()
|
||||
# else
|
||||
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#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
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
# else
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Printing printf/scanf formats
|
||||
// Alas cinttypes isn't that standard yet
|
||||
|
||||
#ifdef _WIN32
|
||||
# define VL_PRI64 "I64"
|
||||
#else // Linux or compliant Unix flavors
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
# define VL_PRI64 "l"
|
||||
# else
|
||||
# define VL_PRI64 "ll"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -0,0 +1,489 @@
|
||||
/* -*- C -*-
|
||||
*
|
||||
* svdpi.h
|
||||
*
|
||||
* SystemVerilog Direct Programming Interface (DPI).
|
||||
*
|
||||
* This file contains the constant definitions, structure definitions,
|
||||
* and routine declarations used by SystemVerilog DPI.
|
||||
*
|
||||
* This file is from the SystemVerilog IEEE 1800-2009 Annex I.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SVDPI
|
||||
#define INCLUDED_SVDPI
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Define size-critical types on all OS platforms. */
|
||||
#if defined (_MSC_VER)
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef signed __int8 int8_t;
|
||||
#elif defined(__MINGW32__)
|
||||
#include <stdint.h>
|
||||
#elif defined(__linux)
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
/* Use to export a symbol from application */
|
||||
#if defined (_MSC_VER)
|
||||
#define DPI_DLLISPEC __declspec(dllimport)
|
||||
#else
|
||||
#define DPI_DLLISPEC
|
||||
#endif
|
||||
|
||||
/* Use to import a symbol into application */
|
||||
#if defined (_MSC_VER)
|
||||
#define DPI_DLLESPEC __declspec(dllexport)
|
||||
#else
|
||||
#define DPI_DLLESPEC
|
||||
#endif
|
||||
|
||||
/* Use to mark a function as external */
|
||||
#ifndef DPI_EXTERN
|
||||
#define DPI_EXTERN
|
||||
#endif
|
||||
|
||||
#ifndef DPI_PROTOTYPES
|
||||
#define DPI_PROTOTYPES
|
||||
/* object is defined imported by the application */
|
||||
#define XXTERN DPI_EXTERN DPI_DLLISPEC
|
||||
/* object is exported by the application */
|
||||
#define EETERN DPI_EXTERN DPI_DLLESPEC
|
||||
#endif
|
||||
|
||||
/* canonical representation */
|
||||
#define sv_0 0
|
||||
#define sv_1 1
|
||||
#define sv_z 2
|
||||
#define sv_x 3
|
||||
|
||||
/* common type for 'bit' and 'logic' scalars. */
|
||||
typedef uint8_t svScalar;
|
||||
typedef svScalar svBit; /* scalar */
|
||||
typedef svScalar svLogic; /* scalar */
|
||||
|
||||
/*
|
||||
* DPI representation of packed arrays.
|
||||
* 2-state and 4-state vectors, exactly the same as PLI's avalue/bvalue.
|
||||
*/
|
||||
#ifndef VPI_VECVAL
|
||||
#define VPI_VECVAL
|
||||
typedef struct t_vpi_vecval {
|
||||
uint32_t aval;
|
||||
uint32_t bval;
|
||||
} s_vpi_vecval, *p_vpi_vecval;
|
||||
#endif
|
||||
|
||||
/* (a chunk of) packed logic array */
|
||||
typedef s_vpi_vecval svLogicVecVal;
|
||||
|
||||
/* (a chunk of) packed bit array */
|
||||
typedef uint32_t svBitVecVal;
|
||||
|
||||
/* Number of chunks required to represent the given width packed array */
|
||||
#define SV_PACKED_DATA_NELEMS(WIDTH) (((WIDTH) + 31) >> 5)
|
||||
|
||||
/*
|
||||
* Because the contents of the unused bits is undetermined,
|
||||
* the following macros can be handy.
|
||||
*/
|
||||
#define SV_MASK(N) (~(-1 << (N)))
|
||||
|
||||
#define SV_GET_UNSIGNED_BITS(VALUE, N) \
|
||||
((N) == 32 ? (VALUE) : ((VALUE) & SV_MASK(N)))
|
||||
|
||||
#define SV_GET_SIGNED_BITS(VALUE, N) \
|
||||
((N) == 32 ? (VALUE) : \
|
||||
(((VALUE) & (1 << (N))) ? ((VALUE) | ~SV_MASK(N)) : ((VALUE) & SV_MASK(N))))
|
||||
|
||||
/*
|
||||
* Implementation-dependent representation.
|
||||
*/
|
||||
/*
|
||||
* Return implementation version information string ("1800-2005" or "SV3.1a").
|
||||
*/
|
||||
XXTERN const char* svDpiVersion();
|
||||
|
||||
/* a handle to a scope (an instance of a module or interface) */
|
||||
XXTERN typedef void* svScope;
|
||||
|
||||
/* a handle to a generic object (actually, unsized array) */
|
||||
XXTERN typedef void* svOpenArrayHandle;
|
||||
|
||||
/*
|
||||
* Bit-select utility functions.
|
||||
*
|
||||
* Packed arrays are assumed to be indexed n-1:0,
|
||||
* where 0 is the index of LSB
|
||||
*/
|
||||
|
||||
/* s=source, i=bit-index */
|
||||
XXTERN svBit svGetBitselBit(const svBitVecVal* s, int i);
|
||||
XXTERN svLogic svGetBitselLogic(const svLogicVecVal* s, int i);
|
||||
|
||||
/* d=destination, i=bit-index, s=scalar */
|
||||
XXTERN void svPutBitselBit(svBitVecVal* d, int i, svBit s);
|
||||
XXTERN void svPutBitselLogic(svLogicVecVal* d, int i, svLogic s);
|
||||
|
||||
/*
|
||||
* Part-select utility functions.
|
||||
*
|
||||
* A narrow (<=32 bits) part-select is extracted from the
|
||||
* source representation and written into the destination word.
|
||||
*
|
||||
* Normalized ranges and indexing [n-1:0] are used for both arrays.
|
||||
*
|
||||
* s=source, d=destination, i=starting bit index, w=width
|
||||
* like for variable part-selects; limitations: w <= 32
|
||||
*/
|
||||
XXTERN void svGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i, int w);
|
||||
XXTERN void svGetPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w);
|
||||
|
||||
XXTERN void svPutPartselBit(svBitVecVal* d, const svBitVecVal s, int i, int w);
|
||||
XXTERN void svPutPartselLogic(svLogicVecVal* d, const svLogicVecVal s, int i, int w);
|
||||
|
||||
/*
|
||||
* Open array querying functions
|
||||
* These functions are modeled upon the SystemVerilog array
|
||||
* querying functions and use the same semantics.
|
||||
*
|
||||
* If the dimension is 0, then the query refers to the
|
||||
* packed part of an array (which is one-dimensional).
|
||||
* Dimensions > 0 refer to the unpacked part of an array.
|
||||
*/
|
||||
/* h= handle to open array, d=dimension */
|
||||
XXTERN int svLeft(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svRight(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svLow(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svHigh(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svIncrement(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svSize(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svDimensions(const svOpenArrayHandle h);
|
||||
|
||||
/*
|
||||
* Pointer to the actual representation of the whole array of any type
|
||||
* NULL if not in C layout
|
||||
*/
|
||||
XXTERN void *svGetArrayPtr(const svOpenArrayHandle);
|
||||
|
||||
/* total size in bytes or 0 if not in C layout */
|
||||
XXTERN int svSizeOfArray(const svOpenArrayHandle);
|
||||
|
||||
/*
|
||||
* Return a pointer to an element of the array
|
||||
* or NULL if index outside the range or null pointer
|
||||
*/
|
||||
XXTERN void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...);
|
||||
|
||||
/* specialized versions for 1-, 2- and 3-dimensional arrays: */
|
||||
XXTERN void *svGetArrElemPtr1(const svOpenArrayHandle, int indx1);
|
||||
XXTERN void *svGetArrElemPtr2(const svOpenArrayHandle, int indx1, int indx2);
|
||||
XXTERN void *svGetArrElemPtr3(const svOpenArrayHandle, int indx1, int indx2,
|
||||
int indx3);
|
||||
|
||||
/*
|
||||
* Functions for copying between simulator storage and user space.
|
||||
* These functions copy the whole packed array in either direction.
|
||||
* The user is responsible for allocating an array to hold the
|
||||
* canonical representation.
|
||||
*/
|
||||
|
||||
/* s=source, d=destination */
|
||||
/* From user space into simulator storage */
|
||||
XXTERN void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1);
|
||||
XXTERN void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
XXTERN void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1);
|
||||
XXTERN void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/* From simulator storage into user space */
|
||||
XXTERN void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
...);
|
||||
XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1);
|
||||
XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2, int indx3);
|
||||
XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1);
|
||||
XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2, int indx3);
|
||||
|
||||
/* Functions for working with DPI context */
|
||||
|
||||
/*
|
||||
* Retrieve the active instance scope currently associated with the executing
|
||||
* imported function. Unless a prior call to svSetScope has occurred, this
|
||||
* is the scope of the function's declaration site, not call site.
|
||||
* Returns NULL if called from C code that is *not* an imported function.
|
||||
*/
|
||||
XXTERN svScope svGetScope();
|
||||
|
||||
/*
|
||||
* Set context for subsequent export function execution.
|
||||
* This function must be called before calling an export function, unless
|
||||
* the export function is called while executing an import function. In that
|
||||
* case the export function shall inherit the scope of the surrounding import
|
||||
* function. This is known as the "default scope".
|
||||
* The return is the previous active scope (per svGetScope)
|
||||
*/
|
||||
XXTERN svScope svSetScope(const svScope scope);
|
||||
|
||||
/* Gets the fully qualified name of a scope handle */
|
||||
XXTERN const char* svGetNameFromScope(const svScope);
|
||||
|
||||
/*
|
||||
* Retrieve svScope to instance scope of an arbitrary function declaration.
|
||||
* (can be either module, program, interface, or generate scope)
|
||||
* The return value shall be NULL for unrecognized scope names.
|
||||
*/
|
||||
XXTERN svScope svGetScopeFromName(const char* scopeName);
|
||||
|
||||
/*
|
||||
* Store an arbitrary user data pointer for later retrieval by svGetUserData()
|
||||
* The userKey is generated by the user. It must be guaranteed by the user to
|
||||
* be unique from all other userKey's for all unique data storage requirements
|
||||
* It is recommended that the address of static functions or variables in the
|
||||
* user's C code be used as the userKey.
|
||||
* It is illegal to pass in NULL values for either the scope or userData
|
||||
* arguments. It is also an error to call svPutUserData() with an invalid
|
||||
* svScope. This function returns -1 for all error cases, 0 upon success. It is
|
||||
* suggested that userData values of 0 (NULL) not be used as otherwise it can
|
||||
* be impossible to discern error status returns when calling svGetUserData()
|
||||
*/
|
||||
XXTERN int svPutUserData(const svScope scope, void *userKey, void* userData);
|
||||
|
||||
/*
|
||||
* Retrieve an arbitrary user data pointer that was previously
|
||||
* stored by a call to svPutUserData(). See the comment above
|
||||
* svPutUserData() for an explanation of userKey, as well as
|
||||
* restrictions on NULL and illegal svScope and userKey values.
|
||||
* This function returns NULL for all error cases, 0 upon success.
|
||||
* This function also returns NULL in the event that a prior call
|
||||
* to svPutUserData() was never made.
|
||||
*/
|
||||
XXTERN void* svGetUserData(const svScope scope, void* userKey);
|
||||
|
||||
/*
|
||||
* Returns the file and line number in the SV code from which the import call
|
||||
* was made. If this information available, returns TRUE and updates fileName
|
||||
* and lineNumber to the appropriate values. Behavior is unpredictable if
|
||||
* fileName or lineNumber are not appropriate pointers. If this information is
|
||||
* not available return FALSE and contents of fileName and lineNumber not
|
||||
* modified. Whether this information is available or not is implementation-
|
||||
* specific. Note that the string provided (if any) is owned by the SV
|
||||
* implementation and is valid only until the next call to any SV function.
|
||||
* Applications must not modify this string or free it
|
||||
*/
|
||||
XXTERN int svGetCallerInfo(const char** fileName, int *lineNumber);
|
||||
|
||||
/*
|
||||
* Returns 1 if the current execution thread is in the disabled state.
|
||||
* Disable protocol must be adhered to if in the disabled state.
|
||||
*/
|
||||
XXTERN int svIsDisabledState();
|
||||
|
||||
/*
|
||||
* Imported functions call this API function during disable processing to
|
||||
* acknowledge that they are correctly participating in the DPI disable protocol.
|
||||
* This function must be called before returning from an imported function that is
|
||||
* in the disabled state.
|
||||
*/
|
||||
XXTERN void svAckDisabledState();
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
* DEPRECATED PORTION OF FILE STARTS FROM HERE.
|
||||
* IEEE-1800-compliant tools may not provide
|
||||
* support for the following functionality.
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* Canonical representation of packed arrays
|
||||
* 2-state and 4-state vectors, modeled upon PLI's avalue/bvalue
|
||||
*/
|
||||
#define SV_CANONICAL_SIZE(WIDTH) (((WIDTH)+31)>>5)
|
||||
typedef unsigned int svBitVec32;/* (a chunk of) packed bit array */
|
||||
typedef struct { unsigned int c; unsigned int d;}
|
||||
svLogicVec32; /* (a chunk of) packed logic array */
|
||||
|
||||
/* reference to a standalone packed array */
|
||||
typedef void* svBitPackedArrRef;
|
||||
typedef void* svLogicPackedArrRef;
|
||||
|
||||
/*
|
||||
* total size in bytes of the simulator's representation of a packed array
|
||||
* width in bits
|
||||
*/
|
||||
XXTERN int svSizeOfBitPackedArr(int width);
|
||||
XXTERN int svSizeOfLogicPackedArr(int width);
|
||||
|
||||
/* Translation between the actual representation and the canonical representation */
|
||||
|
||||
/* s=source, d=destination, w=width */
|
||||
/* actual <-- canonical */
|
||||
XXTERN void svPutBitVec32(svBitPackedArrRef d, const svBitVec32* s, int w);
|
||||
XXTERN void svPutLogicVec32(svLogicPackedArrRef d, const svLogicVec32* s, int w);
|
||||
|
||||
/* canonical <-- actual */
|
||||
XXTERN void svGetBitVec32(svBitVec32* d, const svBitPackedArrRef s, int w);
|
||||
XXTERN void svGetLogicVec32(svLogicVec32* d, const svLogicPackedArrRef s, int w);
|
||||
|
||||
/*
|
||||
* Bit-select functions
|
||||
* Packed arrays are assumed to be indexed n-1:0,
|
||||
* where 0 is the index of LSB
|
||||
*/
|
||||
|
||||
/* s=source, i=bit-index */
|
||||
XXTERN svBit svGetSelectBit(const svBitPackedArrRef s, int i);
|
||||
XXTERN svLogic svGetSelectLogic(const svLogicPackedArrRef s, int i);
|
||||
|
||||
/* d=destination, i=bit-index, s=scalar */
|
||||
XXTERN void svPutSelectBit(svBitPackedArrRef d, int i, svBit s);
|
||||
XXTERN void svPutSelectLogic(svLogicPackedArrRef d, int i, svLogic s);
|
||||
|
||||
/*
|
||||
* functions for part-select
|
||||
*
|
||||
* a narrow (<=32 bits) part-select is copied between
|
||||
* the implementation representation and a single chunk of
|
||||
* canonical representation
|
||||
* Normalized ranges and indexing [n-1:0] are used for both arrays:
|
||||
* the array in the implementation representation and the canonical array.
|
||||
*
|
||||
* s=source, d=destination, i=starting bit index, w=width
|
||||
* like for variable part-selects; limitations: w <= 32
|
||||
*/
|
||||
|
||||
/* canonical <-- actual */
|
||||
XXTERN void svGetPartSelectBit(svBitVec32* d, const svBitPackedArrRef s,
|
||||
int i, int w);
|
||||
XXTERN svBitVec32 svGetBits(const svBitPackedArrRef s, int i, int w);
|
||||
XXTERN svBitVec32 svGet32Bits(const svBitPackedArrRef s, int i); /* 32-bits */
|
||||
|
||||
XXTERN uint64_t svGet64Bits(const svBitPackedArrRef s, int i);
|
||||
|
||||
/* 64-bits */
|
||||
XXTERN void svGetPartSelectLogic(svLogicVec32* d, const svLogicPackedArrRef s,
|
||||
int i, int w);
|
||||
/* actual <-- canonical */
|
||||
XXTERN void svPutPartSelectBit(svBitPackedArrRef d, const svBitVec32 s,
|
||||
int i, int w);
|
||||
XXTERN void svPutPartSelectLogic(svLogicPackedArrRef d, const svLogicVec32 s,
|
||||
int i, int w);
|
||||
|
||||
/*
|
||||
* Functions for open array translation between simulator and canonical
|
||||
* representations. These functions copy the whole packed array in either
|
||||
* direction. The user is responsible for allocating an array in the
|
||||
* canonical representation.
|
||||
*/
|
||||
|
||||
/* s=source, d=destination */
|
||||
/* actual <-- canonical */
|
||||
XXTERN void svPutBitArrElemVec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1Vec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1);
|
||||
XXTERN void svPutBitArrElem2Vec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutBitArrElem3Vec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svPutLogicArrElemVec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutLogicArrElem1Vec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1);
|
||||
XXTERN void svPutLogicArrElem2Vec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutLogicArrElem3Vec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/* canonical <-- actual */
|
||||
XXTERN void svGetBitArrElemVec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetBitArrElem1Vec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetBitArrElem2Vec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetBitArrElem3Vec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svGetLogicArrElemVec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetLogicArrElem1Vec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetLogicArrElem2Vec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetLogicArrElem3Vec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
* DEPRECATED PORTION OF FILE ENDS HERE.
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
#undef DPI_EXTERN
|
||||
|
||||
#ifdef DPI_PROTOTYPES
|
||||
#undef DPI_PROTOTYPES
|
||||
#undef XXTERN
|
||||
#undef EETERN
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
+259
@@ -0,0 +1,259 @@
|
||||
# DESCRIPTION: DOCUMENT source run through perl to produce internals.txt file
|
||||
# Use 'make internals.txt' to produce the output file
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Verilator Internals
|
||||
|
||||
=head1 INTRODUCTION
|
||||
|
||||
This file discusses internal and programming details for Verilator. It's
|
||||
the first for reference for developers and debugging problems.
|
||||
|
||||
See also the Verilator internals presentation at http://www.veripool.org.
|
||||
|
||||
=head1 ADDING A NEW FEATURE
|
||||
|
||||
Generally what would you do to add a new feature?
|
||||
|
||||
=over 4
|
||||
|
||||
File a bug (if there isn't already) so others know what you're working on.
|
||||
|
||||
Make a testcase in the test_regress/t/t_EXAMPLE format, see TESTING Below.
|
||||
|
||||
If grammar changes are needed, look at the git version of VerilogPerl's
|
||||
src/VParseGrammar.y, as this grammar supports the full SystemVerilog
|
||||
language and has a lot of back-and-forth with Verilator's grammar. Copy
|
||||
the appropriate rules to src/verilog.y and modify the productions.
|
||||
|
||||
If a new Ast type is needed, add it to V3AstNodes.h.
|
||||
|
||||
Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
|
||||
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
|
||||
file which you can examine to see if the parsing worked. See also the
|
||||
sections below on debugging.
|
||||
|
||||
Modify the later visitor functions to process the new feature as needed.
|
||||
|
||||
=back
|
||||
|
||||
=head1 CODE FLOWS
|
||||
|
||||
=head2 Verilator Flow
|
||||
|
||||
The main flow of Verilator can be followed by reading the Verilator.cpp
|
||||
process() function:
|
||||
|
||||
First, the files specified on the command line are read. Reading involves
|
||||
preprocessing, then lexical analysis with Flex and parsing with Bison.
|
||||
This produces an abstract syntax tree (AST) representation of the design,
|
||||
which is what is visible in the .tree files described below.
|
||||
|
||||
Cells are then linked, which will read and parse additional files as above.
|
||||
|
||||
Functions, variable and other references are linked to their definitions.
|
||||
|
||||
Parameters are resolved and the design is elaborated.
|
||||
|
||||
Verilator then performs many additional edits and optimizations on the
|
||||
hierarchical design. This includes coverage, assertions, X elimination,
|
||||
inlining, constant propagation, and dead code elimination.
|
||||
|
||||
References in the design are then psudo-flattened. Each module's variables
|
||||
and functions get "Scope" references. A scope reference is an occurrence of
|
||||
that un-flattened variable in the flattened hierarchy. A module that occurs
|
||||
only once in the hierarchy will have a single scope and single VarScope for
|
||||
each variable. A module that occurs twice will have a scope for each
|
||||
occurrence, and two VarScopes for each variable. This allows optimizations
|
||||
to proceed across the flattened design, while still preserving the
|
||||
hierarchy.
|
||||
|
||||
Additional edits and optimizations proceed on the psudo-flat design. These
|
||||
include module references, function inlining, loop unrolling, variable
|
||||
lifetime analysis, lookup table creation, always splitting, and logic gate
|
||||
simplifications (pushing inverters, etc).
|
||||
|
||||
Verilator orders the code. Best case, this results in a single "eval"
|
||||
function which has all always statements flowing from top to bottom with no
|
||||
loops.
|
||||
|
||||
Verilator mostly removes the flattening, so that code may be shared between
|
||||
multiple invocations of the same module. It localizes variables, combines
|
||||
identical functions, expands macros to C primitives, adds branch prediction
|
||||
hints, and performs additional constant propagation.
|
||||
|
||||
Verilator finally writes the C++ modules.
|
||||
|
||||
=head2 Verilated Flow
|
||||
|
||||
The evaluation loop outputted by Verilator is designed to allow a single
|
||||
function to perform evaluation under most situations.
|
||||
|
||||
On the first evaluation, the Verilated code calls initial blocks, and then
|
||||
"settles" the modules, by evaluating functions (from always statements)
|
||||
until all signals are stable.
|
||||
|
||||
On other evaluations, the Verilated code detects what input signals have
|
||||
changes. If any are clocks, it calls the appropriate sequential functions
|
||||
(from always @ posedge statements). Interspersed with sequential functions
|
||||
it calls combo functions (from always @*). After this is complete, it
|
||||
detects any changes due to combo loops or internally generated clocks, and
|
||||
if one is found must reevaluate the model again.
|
||||
|
||||
For SystemC code, the eval() function is wrapped in a SystemC SC_METHOD,
|
||||
sensitive to all inputs. (Ideally it would only be sensitive to clocks and
|
||||
combo inputs, but tracing requires all signals to cause evaluation, and the
|
||||
performance difference is small.)
|
||||
|
||||
If tracing is enabled, a callback examines all variables in the design for
|
||||
changes, and writes the trace for each change. To accelerate this process
|
||||
the evaluation process records a bitmask of variables that might have
|
||||
changed; if clear, checking those signals for changes may be skipped.
|
||||
|
||||
=head1 CODING CONVENTIONS
|
||||
|
||||
=head2 Indentation style
|
||||
|
||||
To match the indentation of Verilator C++ sources, use 4 spaces per level,
|
||||
and leave tabs at 8 columns, so every other indent level is a tab stop.
|
||||
|
||||
In Emacs, use in your ~/.emacs
|
||||
|
||||
(add-hook 'c-mode-common-hook '(lambda ()
|
||||
(c-set-style "cc-mode"))))
|
||||
|
||||
This sets indentation to the cc-mode defaults. (Verilator predates a
|
||||
CC-mode change of several years ago which overrides the defaults with GNU
|
||||
style indentation; the c-set-style undoes that.)
|
||||
|
||||
=head2 Visitor Functions
|
||||
|
||||
There's three ways data is passed between visitor functions.
|
||||
|
||||
1. A visitor-class member variable. This is generally for passing "parent"
|
||||
information down to children. m_modp is a common example. It's set to
|
||||
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
||||
the children are iterated, then it's cleared. Children under an AstModule
|
||||
will see it set, while nodes elsewhere will see it clear. If there can be
|
||||
nested items (for example an AstFor under an AstFor) the variable needs to
|
||||
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
||||
will loose the upper for's setting.
|
||||
|
||||
2. User() attributes. Each node has 5 ->user() number or ->userp() pointer
|
||||
utility values (a common technique lifted from graph traversal packages).
|
||||
A visitor first clears the one it wants to use by calling
|
||||
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
||||
data it wants. Readers just call nodep->user(), but may need to cast
|
||||
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
||||
top of each visitor are comments describing how the user() stuff applies to
|
||||
that visitor class. For example:
|
||||
|
||||
// NODE STATE
|
||||
// Cleared entire netlist
|
||||
// AstModule::user1p() // bool. True to inline this module
|
||||
|
||||
This says that at the AstNetlist user1ClearTree() is called. Each
|
||||
AstModule's is user1() is used to indicate if we're going to inline it.
|
||||
|
||||
These comments are important to make sure a user#() on a given AstNode type
|
||||
is never being used for two different purposes.
|
||||
|
||||
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
||||
ok to call fairly often. For example, it's commonly called on every
|
||||
module.
|
||||
|
||||
3. Parameters can be passed between the visitors in close to the "normal"
|
||||
function caller to callee way. This is the second "vup" parameter that is
|
||||
ignored on most of the visitor functions. V3Width does this, but it proved
|
||||
more messy than the above and is deprecated. (V3Width was nearly the first
|
||||
module written. Someday this scheme may be removed, as it slows the
|
||||
program down to have to pass vup everywhere.)
|
||||
|
||||
=head1 TESTING
|
||||
|
||||
To write a test see notes in the forum and in the verilator.txt manual.
|
||||
|
||||
Note you can run the regression tests in parallel; see the
|
||||
test_regress/driver.pl script -j flag.
|
||||
|
||||
=head1 DEBUGGING
|
||||
|
||||
=head2 --debug
|
||||
|
||||
When you run with --debug there are two primary output file types placed into
|
||||
the obj_dir, .tree and .dot files.
|
||||
|
||||
=head2 .dot output
|
||||
|
||||
Dot files are dumps of internal graphs in Graphviz
|
||||
L<http://www.graphviz.org/> dot format. When a dot file is dumped,
|
||||
Verilator will also print a line on stdout that can be used to format the
|
||||
output, for example:
|
||||
|
||||
dot -Tps -o ~/a.ps obj_dir/Vtop_foo.dot
|
||||
|
||||
You can then print a.ps. You may prefer gif format, which doesn't get
|
||||
scaled so can be more useful with large graphs.
|
||||
|
||||
For dynamic graph viewing consider ZGRViewer
|
||||
L<http://zvtm.sourceforge.net/zgrviewer.html>. If you know of better
|
||||
viewers let us know; ZGRViewer isn't great for large graphs.
|
||||
|
||||
=head2 .tree output
|
||||
|
||||
Tree files are dumps of the AST Tree and are produced between every major
|
||||
algorithmic stage. An example:
|
||||
|
||||
NETLIST 0x90fb00 <e1> {0} w0
|
||||
1: MODULE 0x912b20 <e8822> {8} w0 top L2 [P]
|
||||
*1:2: VAR 0x91a780 <e74#> {22} w70 out_wide [O] WIRE
|
||||
1:2:1: BASICDTYPE 0x91a3c0 <e73> {22} w70 [logic]
|
||||
|
||||
=over 4
|
||||
|
||||
"1:2:" indicates the hierarchy the VAR is op2p under the MODULE.
|
||||
|
||||
"VAR" is the AstNodeType.
|
||||
|
||||
"0x91a780" is the address of this node.
|
||||
|
||||
"<e74>" means the 74th edit to the netlist was the last modification to
|
||||
this node. A trailing # indicates this node changed since the last tree
|
||||
dump was made. You can gdb break on this edit; see below.
|
||||
|
||||
"{22}" indicates this node is related to line 22 in the source.
|
||||
|
||||
"w70" indicates the width is 70 bits. sw70 would be signed 70 bits.
|
||||
|
||||
"out_wide" is the name of the node, in this case the name of the variable.
|
||||
|
||||
"[O]" are flags which vary with the type of node, in this case it means the
|
||||
variable is an output.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Debugging with GDB
|
||||
|
||||
The test_regress/driver.pl script accepts --debug --gdb to start Verilator
|
||||
under gdb. You can also use --debug --gdbbt to just backtrace and then
|
||||
exit gdb.
|
||||
|
||||
To break at a specific edit number which changed a node (presumably to find
|
||||
what made a <e####> line in the tree dumps):
|
||||
|
||||
watch AstNode::s_editCntGbl==####
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/>.
|
||||
|
||||
Copyright 2008-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
# Copyright 2007-2011 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -81,5 +81,5 @@ sub prep {
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "./bisondiff --unsup $WUP/Verilog/Parser/VParseBison.y ../src/verilog.y"
|
||||
# compile-command: "./bisondiff --unsup $VP/Parser/VParseBison.y ../src/verilog.y"
|
||||
# End:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
# Copyright 2007-2011 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2005-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2005-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+6
-3
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
# Copyright 2007-2011 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -48,7 +48,10 @@ sub prep {
|
||||
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
# Productions
|
||||
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||
#$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||
$line =~ s/StashPrefix;//g;
|
||||
$line =~ s/VALTEXT;//g;
|
||||
$line =~ s/CALLBACK\([^)]*\);//g;
|
||||
push @lines, $line;
|
||||
}
|
||||
|
||||
@@ -57,5 +60,5 @@ sub prep {
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "./flexdiff $WUP/Verilog/Parser/VParseLex.l ../src/verilog.l"
|
||||
# compile-command: "./flexdiff $VP/Parser/VParseLex.l ../src/verilog.l"
|
||||
# End:
|
||||
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
use Getopt::Long;
|
||||
use Cwd;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug);
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config ("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
||||
}
|
||||
|
||||
test();
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub test {
|
||||
-r "nodist/install_test" or die "%Error: Run from the top of the verilator kit,";
|
||||
|
||||
cleanenv();
|
||||
$ENV{VERILATOR_NO_OPT_BUILD} = 1; # Don't build optimized executables; just slows this down
|
||||
run("make distclean") if -r "Makefile";
|
||||
|
||||
# Try building from a scratch area
|
||||
my $srcdir = getcwd();
|
||||
my $blddir = $srcdir."/test_regress/obj_dir/install_test_bld";
|
||||
my $prefix = $srcdir."/test_regress/obj_dir/install_test_prefix";
|
||||
my $testdir = $srcdir."/test_regress/obj_dir/install_test_test";
|
||||
if (1) {
|
||||
run("/bin/rm -rf $blddir");
|
||||
run("/bin/mkdir -p $blddir");
|
||||
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
||||
run("cd $blddir && make -j");
|
||||
}
|
||||
|
||||
# Install it under the prefix
|
||||
if (1) {
|
||||
run("/bin/rm -rf $prefix");
|
||||
run("/bin/mkdir -p $prefix");
|
||||
run("cd $blddir && make install");
|
||||
}
|
||||
|
||||
# Run a test using just the path
|
||||
if (1) {
|
||||
run("/bin/rm -rf $testdir");
|
||||
run("/bin/mkdir -p $testdir");
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
IO::File->new(">$testdir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); end endmodule'."\n");
|
||||
run("cd $testdir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v");
|
||||
run("cd $testdir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||
#Need .c file, and --exe for this to work
|
||||
#run("cd $testdir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
}
|
||||
}
|
||||
|
||||
sub cleanenv {
|
||||
foreach my $var (keys %ENV) {
|
||||
if ($var eq "VERILATOR_ROOT") {
|
||||
print "unset $var # Was '$ENV{$var}'\n";
|
||||
delete $ENV{$var}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub run {
|
||||
# Run a system command, check errors
|
||||
my $command = shift;
|
||||
print "\t$command\n";
|
||||
system "$command";
|
||||
my $status = $?;
|
||||
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
install_test - Build and install Verilator several ways
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
install_test
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
install_test performs several make-and-install iterations to verify the
|
||||
kit. It isn't part of the normal "make test" due to the number of builds
|
||||
required.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2009-2011 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "cd .. ; nodist/install_test "
|
||||
### End:
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
require 5.006_001;
|
||||
use strict;
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','axiom-athdl');
|
||||
exec('atsim',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
invoke_atsim - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_atsim {ncv arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2011 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "./invoke_atsim -help"
|
||||
### End:
|
||||
+3
-3
@@ -10,7 +10,7 @@ use strict;
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','cadence_verif');
|
||||
module('add','cadence-ius');
|
||||
exec('iccr',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
@@ -18,7 +18,7 @@ exec('iccr',@ARGV);
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "/sicortex/$ENV{DIRPROJECT_ARCH}/lib/Modules/default/init/perl";
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ invoke_iccr - Invoke tool under "modules" command
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
Copyright 2007-2011 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
@@ -10,7 +10,7 @@ use strict;
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','cadence_verif');
|
||||
module('add','cadence-ius');
|
||||
exec('ncverilog',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
@@ -18,7 +18,7 @@ exec('ncverilog',@ARGV);
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "/sicortex/$ENV{DIRPROJECT_ARCH}/lib/Modules/default/init/perl";
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ invoke_ncverilog - Invoke tool under "modules" command
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. This package is free software; you
|
||||
Copyright 2005-2011 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
require 5.006_001;
|
||||
use strict;
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','synopsys-vcs');
|
||||
exec('vcs',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
invoke_vcs - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_vcs {ncv arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2011 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "./invoke_vcs -help"
|
||||
### End:
|
||||
@@ -1,4 +1,4 @@
|
||||
export GLIBCPP_FORCE_NEW=1
|
||||
compile with -DVL_LEAK_CHECKS
|
||||
valgrind --tool=memcheck --leak-check=yes /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg -MMD --bin /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg --cc -f /home/wsnyder/src/verilator/v4/verilator/test_c/../test_v/input.vc top.v --no-skip-identical 2>&1 | tee ~/d/aa
|
||||
valgrind --tool=memcheck --leak-check=yes /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg -MMD --bin /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg --cc /home/wsnyder/src/verilator/v4/verilator/test_regress/t/t_case_huge.v --no-skip-identical -I/home/wsnyder/src/verilator/v4/verilator/test_regress/t 2>&1 | tee ~/d/aa
|
||||
valgrind --tool=memcheck --leak-check=yes $VERILATOR_ROOT/verilator_bin_dbg -MMD --bin $VERILATOR_ROOT/verilator_bin_dbg --cc -f $VERILATOR_ROOT/test_c/../test_v/input.vc top.v --no-skip-identical 2>&1 | tee ~/d/aa
|
||||
valgrind --tool=memcheck --leak-check=yes $VERILATOR_ROOT/verilator_bin_dbg -MMD --bin $VERILATOR_ROOT/verilator_bin_dbg --cc $VERILATOR_ROOT/test_regress/t/t_case_huge.v --no-skip-identical -I$VERILATOR_ROOT/test_regress/t 2>&1 | tee ~/d/aa
|
||||
|
||||
Executable
+141
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2010-2011 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
######################################################################
|
||||
|
||||
# DESCRIPTION: Diff Verilator includes against SystemPerl include files
|
||||
|
||||
use Getopt::Long;
|
||||
use IO::File;
|
||||
use strict;
|
||||
|
||||
our $Debug;
|
||||
our $Bad;
|
||||
|
||||
if (! GetOptions (
|
||||
#"help" => \&usage,
|
||||
"debug" => sub { $Debug = 1; },
|
||||
)) {
|
||||
die "usage();"
|
||||
}
|
||||
|
||||
diff("$ARGV[0]/include/verilated_vcd_c.h", "$ARGV[1]/src/SpTraceVcdC.h");
|
||||
diff("$ARGV[0]/include/verilated_vcd_sc.h", "$ARGV[1]/src/SpTraceVcd.h");
|
||||
diff("$ARGV[0]/include/verilated_vcd_c.cpp", "$ARGV[1]/src/SpTraceVcdC.cpp");
|
||||
diff("$ARGV[0]/include/verilated_vcd_sc.cpp", "$ARGV[1]/src/SpTraceVcd.cpp");
|
||||
|
||||
exit(10) if $Bad;
|
||||
|
||||
sub diff {
|
||||
my $a=shift;
|
||||
my $b=shift;
|
||||
|
||||
my $ta = "/tmp/spdiff.$$.a";
|
||||
my $tb = "/tmp/spdiff.$$.b";
|
||||
|
||||
prep($a,$ta);
|
||||
prep($b,$tb);
|
||||
|
||||
system("diff -u -w $ta $tb");
|
||||
}
|
||||
|
||||
sub prep {
|
||||
my $filename = shift;
|
||||
my $wfilename = shift;
|
||||
|
||||
my $sp;
|
||||
if ($filename =~ m!src/Sp!) {
|
||||
$sp = "Sp";
|
||||
} elsif ($filename =~ m!include/verilated!) {
|
||||
} else {
|
||||
die "%Error: Not sure if Sp/Verilated: $filename,\n";
|
||||
}
|
||||
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename";
|
||||
my $fho = IO::File->new(">$wfilename") or die "%Error: $! writing $wfilename";
|
||||
|
||||
my @wf;
|
||||
my $off;
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
if ($line =~ m!// *SPDIFF_OFF!) {
|
||||
$off = 1;
|
||||
next;
|
||||
} elsif ($line =~ m!// *SPDIFF_ON!) {
|
||||
$off = 0;
|
||||
next;
|
||||
}
|
||||
next if $off;
|
||||
|
||||
next if $line =~ /compile-command:/;
|
||||
$line =~ s/SP_ABORT.*// if $sp;
|
||||
$line =~ s/SP_NOTICE.*// if $sp;
|
||||
$line =~ s/vl_fatal.*// if !$sp;
|
||||
$line =~ s/VL_PRINT.*// if !$sp;
|
||||
$line =~ s/Copyright \d+-\d+/Copyright #-#/g;
|
||||
|
||||
push @wf, $line;
|
||||
|
||||
my $check = $line;
|
||||
$check =~ s/\bspace//i;
|
||||
$check =~ s/\bsplit//i;
|
||||
$check =~ s/"SP_TRACE"//;
|
||||
|
||||
if ($sp && $check =~ /Verilat/i
|
||||
&& $check !~ /and newer/) {
|
||||
warn "%Warning: $filename:$.: Verilator text in Sp version: $line";
|
||||
$Bad = 1;
|
||||
} elsif (!$sp && $check =~ /\b(Sp|SP)/
|
||||
) {
|
||||
warn "%Warning: $filename:$.: Sp text in Verilator version: $line";
|
||||
$Bad = 1;
|
||||
} elsif (!$sp && $check =~ /\<uint[0-9]+_t/) {
|
||||
warn "%Warning: $filename:$.: uint in Verilator version: $line";
|
||||
$Bad = 1;
|
||||
}
|
||||
}
|
||||
!$off or die "%Error: $filename: SPDIFF_OFF block never terminated\n";
|
||||
|
||||
my $wholefile = join('',@wf);
|
||||
|
||||
if ($sp) {
|
||||
$wholefile =~ s/SPTRACEVCDC_VERSION/VERILATED_VCD_VERSION/g;
|
||||
$wholefile =~ s/SPTRACEVCDC_/VERILATED_VCD_C_/g;
|
||||
$wholefile =~ s/SPTRACEVCD_TEST/VERILATED_VCD_TEST/g;
|
||||
$wholefile =~ s/SPTRACEVCD_/VERILATED_VCD_SC_/g;
|
||||
|
||||
#
|
||||
$wholefile =~ s/\bSpTraceFile\b/VerilatedVcdSc/g;
|
||||
$wholefile =~ s/\bSpTraceFileC\b/VerilatedVcdC/g;
|
||||
$wholefile =~ s/\bSpTraceVcd\b/VerilatedVcd/g;
|
||||
$wholefile =~ s/\bSpTraceVcdCFile\b/VerilatedVcdC/g;
|
||||
#
|
||||
$wholefile =~ s/\bSpTraceCallInfo\b/VerilatedVcdCallInfo/g;
|
||||
$wholefile =~ s/\bSpTraceCallback_t/VerilatedVcdCallback_t/g;
|
||||
$wholefile =~ s/\bSpTraceVcd_/VerilatedVcd_/g;
|
||||
$wholefile =~ s/\bSpTraceVcdSig\b/VerilatedVcdSig/g;
|
||||
$wholefile =~ s/\bSpScBvExposer/VlScBvExposer/g;
|
||||
#
|
||||
$wholefile =~ s/\b(uint[0-9]+_t)/vl$1/g;
|
||||
$wholefile =~ s/%ll/%" VL_PRI64 "/g;
|
||||
$wholefile =~ s/\(long long unsigned\)n/ n/g; # printQuad
|
||||
#
|
||||
$wholefile =~ s/\bSP_SC_BV/VL_SC_BV/g;
|
||||
$wholefile =~ s/\bSP_UNLIKELY/VL_UNLIKELY/g;
|
||||
}
|
||||
|
||||
$fho->print($wholefile);
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "./spdiff $SYP $V4"
|
||||
# End:
|
||||
@@ -331,7 +331,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2005-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
# DESCRIPTION: DOCUMENT source run through perl to produce README file
|
||||
# Use 'make README' to produce the output file
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
This is the Verilator Package README file.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
This package is Copyright 2003-2011 by Wilson Snyder. (Report bugs to
|
||||
L<http://www.veripool.org/>.)
|
||||
|
||||
Verilator is free software; you can redistribute it and/or modify it under
|
||||
the terms of either the GNU Lesser General Public License Version 3 or the
|
||||
Perl Artistic License Version 2.0. (See the documentation for more
|
||||
details.)
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Verilator converts synthesizable (not behavioral) Verilog code into C++ or
|
||||
SystemC code. It is not a complete simulator, just a translator.
|
||||
|
||||
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
||||
reads the specified Verilog code, lints it, and optionally adds coverage
|
||||
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
|
||||
it outputs .sp files for the SystemPerl preprocessor available at
|
||||
http://www.veripool.org.
|
||||
|
||||
The resulting files are then compiled with C++. The user writes a little
|
||||
C++ wrapper file, which instantiates the top level module. This is
|
||||
compiled in C++, and linked with the Verilated files.
|
||||
|
||||
The resulting executable will perform the actual simulation.
|
||||
|
||||
=head1 SUPPORTED SYSTEMS
|
||||
|
||||
Verilator is developed and has primary testing on:
|
||||
|
||||
SuSE 11.1 AMD64 i686-linux-2.6.27, GCC 4.3.2
|
||||
|
||||
Versions have also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It
|
||||
should run with minor porting on any Linix-ish platform. Verilator also
|
||||
works on Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin).
|
||||
Verilated output (not Verilator itself) compiles under MSVC++ 2008.
|
||||
|
||||
=head1 INSTALLATION
|
||||
|
||||
For more details see
|
||||
L<http://www.veripool.org/projects/verilator/wiki/Installing>.
|
||||
|
||||
If you will be modifying Verilator, you should use the "git" method as it
|
||||
will let you track changes.
|
||||
|
||||
=over 4
|
||||
|
||||
=item
|
||||
|
||||
The latest version is available at L<http://www.veripool.org/verilator>.
|
||||
|
||||
Download the latest package from that site, and decompress.
|
||||
|
||||
tar xvzf verilator_version.tgz
|
||||
|
||||
=item
|
||||
|
||||
If you will be using SystemC (vs straight C++ output), download SystemC
|
||||
2.0.1 from L<http://www.systemc.org>. Follow their installation
|
||||
instructions. You will need to set the SYSTEMC environment variable to
|
||||
point to this download. Also, setenv SYSTEMC_ARCH to the architecture name
|
||||
you used with SystemC, generally 'linux' or 'cygwin'.
|
||||
|
||||
Verilator assumes you did a make in the SystemC kit directory and SYSTEMC
|
||||
points to that directory. There must be appropriate files in
|
||||
C<$SYSTEMC/include> and C<$SYSTEMC/lib-linux> for SystemC compilation to
|
||||
work.
|
||||
|
||||
=item
|
||||
|
||||
If you will be using SystemPerl or coverage, download and install
|
||||
System-Perl, L<http://www.veripool.org/systemperl>. Note you'll need to
|
||||
set a C<SYSTEMPERL> environment variable to point to the downloaded kit.
|
||||
Optionally also set C<SYSTEMPERL_INCLUDE> to point to the installed
|
||||
headers.
|
||||
|
||||
=item
|
||||
|
||||
C<cd> to the Verilator directory containing this README.
|
||||
|
||||
=item
|
||||
|
||||
You now have to decide how you're going to eventually install the kit.
|
||||
|
||||
Note Verilator builds the current value of VERILATOR_ROOT, SYSTEMC,
|
||||
SYSTEMC_ARCH, SYSTEMPERL, and SYSTEMPERL_INCLUDE as defaults into the
|
||||
executable, so try to have them correct before configuring.
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
Our personal favorite is to always run Verilator from the kit directory.
|
||||
This allows the easiest experimentation and upgrading. It's also how most
|
||||
EDA tools operate; to run any of them you point to the tarball.
|
||||
|
||||
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
||||
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
||||
./configure
|
||||
|
||||
=item 2.
|
||||
|
||||
To install globally onto a "cad" disk with multiple versions of every tool,
|
||||
and add it to path using Modules/modulecmd:
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
# For the tarball, use the version number instead of git describe
|
||||
./configure --prefix /CAD_DISK/verilator/`git describe | sed "s/verilator_//"`
|
||||
|
||||
After installing you'll want a module file like the following:
|
||||
|
||||
set install_root /CAD_DISK/verilator/{version-number-used-above}
|
||||
setenv VERILATOR_ROOT $install_root
|
||||
prepend-path PATH $install_root/bin
|
||||
prepend-path MANPATH $install_root/man
|
||||
|
||||
=item 3.
|
||||
|
||||
The next option is to install it globally, using the normal system paths:
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure
|
||||
|
||||
=item 4.
|
||||
|
||||
Alternatively you can configure a prefix that install will populate, as
|
||||
most GNU tools support:
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure --prefix /opt/verilator-VERSION
|
||||
|
||||
=back
|
||||
|
||||
=item
|
||||
|
||||
Type C<make> to compile Verilator.
|
||||
|
||||
Type C<make test_c> to check the compilation.
|
||||
|
||||
Type C<make test> for a more complete test. You may get a error about the
|
||||
Bit::Vector Perl package. You will need to install it and SystemPerl if
|
||||
you want all tests to pass.
|
||||
|
||||
You may get a error about a typedef conflict for uint32_t. Edit
|
||||
verilated.h to change the typedef to work, probably to @samp{typedef
|
||||
unsigned long uint32_t;}.
|
||||
|
||||
=item
|
||||
|
||||
If you used the VERILATOR_ROOT scheme you're done. Programs should set the
|
||||
environment variable VERILATOR_ROOT to point to this distribution, then
|
||||
execute $VERILATOR_ROOT/bin/verilator, which will find the path to all
|
||||
needed files.
|
||||
|
||||
If you used the prefix scheme, now do a C<make install>. To run verilator,
|
||||
have the verilator binary directory in your PATH (this should already be
|
||||
true if using the default configure), and make sure VERILATOR_ROOT is not
|
||||
set.
|
||||
|
||||
=back
|
||||
|
||||
=head1 USAGE DOCUMENTATION
|
||||
|
||||
Detailed documentation and the man page can be seen by running:
|
||||
|
||||
bin/verilator --help
|
||||
|
||||
or reading verilator.txt in the same directory as this README.
|
||||
|
||||
=head1 DIRECTORY STRUCTURE
|
||||
|
||||
The directories in the kit after de-taring are as follows:
|
||||
|
||||
bin/verilator => Compiler Wrapper invoked to Verilate code
|
||||
include/ => Files that should be in your -I compiler path
|
||||
include/verilated*.cpp => Global routines to link into your simulator
|
||||
include/verilated.h => Global headers
|
||||
include/verilated.v => Stub defines for linting
|
||||
include/verilated.mk => Common makefile
|
||||
src/ => Translator source code
|
||||
test_v => Example Verilog code for other test dirs
|
||||
test_c => Example Verilog->C++ conversion
|
||||
test_sc => Example Verilog->SystemC conversion
|
||||
test_sp => Example Verilog->SystemPerl conversion
|
||||
test_vcs => Example Verilog->VCS conversion (test the test)
|
||||
test_verilated => Internal tests
|
||||
test_regress => Internal tests
|
||||
|
||||
=head1 LIMITATIONS
|
||||
|
||||
See verilator.txt (or execute C<bin/verilator --help>) for limitations.
|
||||
+1
-1
@@ -26,7 +26,7 @@ This is the Verilator Package.
|
||||
@node Copyright, Description, Top, Top
|
||||
@section Copyright
|
||||
|
||||
This package is Copyright 2003-2009 by Wilson Snyder @email{wsnyder@@wsnyder.org}.
|
||||
This package is Copyright 2003-2011 by Wilson Snyder @email{wsnyder@@wsnyder.org}.
|
||||
|
||||
Verilator is free software; you can redistribute it and/or modify it
|
||||
under the terms of either the GNU Lesser General Public License
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Verilator Source Code Notes
|
||||
|
||||
=head1 INTRODUCTION
|
||||
|
||||
See also the Verilator internals presentation at http://www.veripool.org.
|
||||
|
||||
=head1 VISITOR FUNCTIONS
|
||||
|
||||
=head2 Passing Variables
|
||||
|
||||
There's three ways data is passed between visitor functions.
|
||||
|
||||
1. A visitor-class member variable. This is generally for passing "parent"
|
||||
information down to children. m_modp is a common example. It's set to
|
||||
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
||||
the children are iterated, then it's cleared. Children under an AstModule
|
||||
will see it set, while nodes elsewhere will see it clear. If there can be
|
||||
nested items (for example an AstFor under an AstFor) the variable needs to
|
||||
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
||||
will loose the upper for's setting.
|
||||
|
||||
2. User() attributes. Each node has 4 ->user() number or ->userp() pointer
|
||||
utility values (a common technique lifted from graph traversal packages).
|
||||
A visitor first clears the one it wants to use by calling
|
||||
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
||||
data it wants. Readers just call nodep->user(), but may need to cast
|
||||
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
||||
top of each visitor are comments describing how the user() stuff applies to
|
||||
that visitor class. For example:
|
||||
|
||||
// NODE STATE
|
||||
// Cleared entire netlist
|
||||
// AstModule::user1p() // bool. True to inline this module
|
||||
|
||||
This says that at the AstNetlist user1ClearTree() is called. Each
|
||||
AstModule's is user1() is used to indicate if we're going to inline it.
|
||||
|
||||
These comments are important to make sure a user#() on a given AstNode type
|
||||
is never being used for two different purposes.
|
||||
|
||||
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
||||
ok to call fairly often. For example, it's commonly called on every
|
||||
module.
|
||||
|
||||
3. Parameters can be passed between the visitors in close to the "normal"
|
||||
function caller to callee way. This is the second "vup" parameter that is
|
||||
ignored on most of the visitor functions. V3Width does this, but it proved
|
||||
more messy than the above and is deprecated. (V3Width was nearly the first
|
||||
module written. Someday this scheme may be removed, as it slows the
|
||||
program down to have to pass vup everywhere.)
|
||||
|
||||
=head1 DEBUGGING WITH GDB
|
||||
|
||||
The test_regress/driver.pl script accepts --gdb to start Verilator under
|
||||
gdb.
|
||||
|
||||
To break at a specific edit number which changed a node (presumably to find
|
||||
what made a <e####> line in the tree dumps):
|
||||
|
||||
watch AstNode::s_editCntGbl==####
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2008-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
+13
-9
@@ -7,7 +7,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -40,11 +40,14 @@ export OBJCACHE_HOSTS := $(shell rschedule --no-allow-reserved --similar hostnam
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE :=
|
||||
else
|
||||
ifeq ($(OBJCACHE_JOBS),)
|
||||
ifneq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||
export OBJCACHE := @objcache --read --write
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
UNDER_GIT = $(wildcard ../.git/logs/HEAD)
|
||||
@@ -61,17 +64,18 @@ obj_dbg:
|
||||
opt: ../verilator_bin
|
||||
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
|
||||
../verilator_bin: ../verilator_bin_dbg
|
||||
cp -p $< $@
|
||||
@-cp -p $<.exe $@.exe
|
||||
-rm -rf $@ $@.exe
|
||||
-cp -p $< $@
|
||||
-cp -p $<.exe $@.exe
|
||||
else
|
||||
../verilator_bin: obj_opt prefiles
|
||||
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) -j 1 TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) $(OBJCACHE_JOBS) TGT=../$@ -f ../Makefile_obj
|
||||
endif
|
||||
|
||||
dbg: ../verilator_bin_dbg
|
||||
../verilator_bin_dbg: obj_dbg prefiles
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
|
||||
cd obj_dbg && $(MAKE) -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
|
||||
cd obj_dbg && $(MAKE) $(OBJCACHE_JOBS) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
|
||||
|
||||
prefiles::
|
||||
|
||||
+40
-15
@@ -7,7 +7,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -21,8 +21,22 @@
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = ..
|
||||
incdir = ../../include
|
||||
# Unfortunately configure uses relative paths, and this makefile is called
|
||||
# from a level lower, so we need to move up if it's relative, not if absolute.
|
||||
config_srcdir = @srcdir@
|
||||
ifeq ($(config_srcdir),.)
|
||||
srcdir = ..
|
||||
else # Run an experiment
|
||||
ifeq ($(shell -e $(config_srcdir)/../Makefile_obj.in),)
|
||||
srcdir = $(config_srcdir)
|
||||
else
|
||||
srcdir = $(config_srcdir)/..
|
||||
endif
|
||||
endif
|
||||
|
||||
incdir = $(srcdir)/../include
|
||||
# Bldsrc may differ from srcdir if configure wan't run from the kit top
|
||||
bldsrc = ..
|
||||
|
||||
# Programs
|
||||
CC = @CC@
|
||||
@@ -49,7 +63,7 @@ LDFLAGS += @LDFLAGS@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
VPATH += . $(srcdir)
|
||||
VPATH += . $(bldsrc) $(srcdir)
|
||||
TGT = ../../verilator_bin
|
||||
|
||||
#################
|
||||
@@ -68,10 +82,11 @@ endif
|
||||
#LIBS += -ldl
|
||||
#CCMALLOC = /usr/local/lib/ccmalloc-gcc.o -lccmalloc -ldl
|
||||
|
||||
LIBS = -lm -lfl
|
||||
# -lfl not needed as Flex invoked with %nowrap option
|
||||
LIBS = -lm
|
||||
|
||||
CPPFLAGSNOWALL += -MMD
|
||||
CPPFLAGSNOWALL += -I. -I$(srcdir) -I$(incdir)
|
||||
CPPFLAGSNOWALL += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir)
|
||||
CPPFLAGSNOWALL += -DYYDEBUG # Required to get nice error messages
|
||||
#CPPFLAGSNOWALL += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGSNOWALL += $(COPT)
|
||||
@@ -106,6 +121,7 @@ HEADERS = $(wildcard V*.h v*.h)
|
||||
|
||||
ASTGEN = $(srcdir)/astgen
|
||||
BISONPRE = $(srcdir)/bisonpre
|
||||
FLEXFIX = $(srcdir)/flexfix
|
||||
|
||||
######################################################################
|
||||
#### Top level
|
||||
@@ -141,11 +157,13 @@ RAW_OBJS = \
|
||||
V3Broken.o \
|
||||
V3Case.o \
|
||||
V3Cast.o \
|
||||
V3Cdc.o \
|
||||
V3Changed.o \
|
||||
V3Clean.o \
|
||||
V3ClkGater.o \
|
||||
V3Clock.o \
|
||||
V3Combine.o \
|
||||
V3Config.o \
|
||||
V3Const__gen.o \
|
||||
V3Coverage.o \
|
||||
V3CoverageJoin.o \
|
||||
@@ -177,8 +195,9 @@ RAW_OBJS = \
|
||||
V3Link.o \
|
||||
V3LinkCells.o \
|
||||
V3LinkDot.o \
|
||||
V3LinkLevel.o \
|
||||
V3LinkJump.o \
|
||||
V3LinkLValue.o \
|
||||
V3LinkLevel.o \
|
||||
V3LinkParse.o \
|
||||
V3LinkResolve.o \
|
||||
V3Localize.o \
|
||||
@@ -191,6 +210,7 @@ RAW_OBJS = \
|
||||
V3Premit.o \
|
||||
V3Scope.o \
|
||||
V3Signed.o \
|
||||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3Stats.o \
|
||||
@@ -201,6 +221,7 @@ RAW_OBJS = \
|
||||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
V3Tristate.o \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3Width.o \
|
||||
@@ -208,9 +229,10 @@ RAW_OBJS = \
|
||||
|
||||
# Non-concatable
|
||||
OBJS += \
|
||||
V3Parse.o \
|
||||
V3ParseImp.o \
|
||||
V3ParseGrammar.o \
|
||||
V3ParseLex.o \
|
||||
V3PreProc.o \
|
||||
V3Read.o \
|
||||
|
||||
#### Linking
|
||||
|
||||
@@ -245,10 +267,13 @@ V3Number_test: V3Number_test.o
|
||||
%.o: %.c
|
||||
$(OBJCACHE) ${CC} ${CPPFLAGS} -c $<
|
||||
|
||||
V3Read.o: V3Read.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
|
||||
V3Parse.o: V3Parse.cpp V3ParseBison.c
|
||||
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
|
||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
|
||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||
@@ -273,15 +298,15 @@ V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
||||
${LEX} --version
|
||||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp
|
||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
|
||||
$(PERL) $(FLEXFIX) V3Lexer <$< >$@
|
||||
|
||||
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
||||
${LEX} --version
|
||||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp
|
||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX)
|
||||
$(PERL) $(FLEXFIX) V3PreLex <$< >$@
|
||||
|
||||
######################################################################
|
||||
######################################################################
|
||||
|
||||
+82
-41
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -160,26 +160,58 @@ public:
|
||||
|
||||
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
||||
private:
|
||||
bool m_combo; // Combo logic
|
||||
AstNode* m_alwaysp; // Always we're under
|
||||
AstNode* m_assignp; // In assign
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignDly* nodep, AstNUser*) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
nodep->v3warn(COMBDLY,"Delayed assignments (<=) in non-clocked (non flop or latch) blocks should be non-delayed assignments (=).");
|
||||
AstNode* newp = new AstAssign (nodep->fileline(),
|
||||
nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
if (m_combo) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
nodep->v3warn(COMBDLY,"Delayed assignments (<=) in non-clocked (non flop or latch) block; suggest blocking assignments (=).");
|
||||
AstNode* newp = new AstAssign (nodep->fileline(),
|
||||
nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssign* nodep, AstNUser*) {
|
||||
if (!m_combo) {
|
||||
AstNode* las = m_assignp;
|
||||
m_assignp = nodep;
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
m_assignp = las;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
AstVar* varp=nodep->varp();
|
||||
if (!m_combo
|
||||
&& m_assignp
|
||||
&& !varp->isUsedLoopIdx() // Ignore loop indicies
|
||||
&& !varp->isTemp()
|
||||
) {
|
||||
// Allow turning off warnings on the always, or the variable also
|
||||
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||
&& !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||
&& !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||
) {
|
||||
m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
|
||||
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
|
||||
nodep->v3warn(BLKSEQ,"Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ActiveDlyVisitor(AstNode* nodep) {
|
||||
ActiveDlyVisitor(AstNode* nodep, bool combo) {
|
||||
m_alwaysp = nodep;
|
||||
m_combo = combo;
|
||||
m_assignp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~ActiveDlyVisitor() {}
|
||||
@@ -197,7 +229,6 @@ private:
|
||||
// STATE
|
||||
ActiveNamer m_namer; // Tracking of active names
|
||||
AstCFunc* m_scopeFinalp; // Final function for this scope
|
||||
AstAlways* m_alwaysp; // Under always
|
||||
bool m_itemCombo; // Found a SenItem combo
|
||||
bool m_itemSequent; // Found a SenItem sequential
|
||||
|
||||
@@ -251,7 +282,7 @@ private:
|
||||
if (!m_scopeFinalp) {
|
||||
m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final", m_namer.scopep());
|
||||
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
m_scopeFinalp->dontCombine(true);
|
||||
m_scopeFinalp->formCallTree(true);
|
||||
m_scopeFinalp->slow(true);
|
||||
@@ -264,32 +295,22 @@ private:
|
||||
}
|
||||
|
||||
// METHODS
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
return;
|
||||
}
|
||||
if (nodep->sensesp()
|
||||
&& nodep->sensesp()->sensesp()
|
||||
&& nodep->sensesp()->sensesp()->castSenItem()
|
||||
&& nodep->sensesp()->sensesp()->castSenItem()->isNever()) {
|
||||
if (oldsensesp
|
||||
&& oldsensesp->sensesp()
|
||||
&& oldsensesp->sensesp()->castSenItem()
|
||||
&& oldsensesp->sensesp()->castSenItem()->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
if (nodep->sensesp()->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
||||
if (oldsensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Read sensitivitues
|
||||
m_alwaysp = nodep;
|
||||
m_itemCombo = false;
|
||||
m_itemSequent = false;
|
||||
nodep->sensesp()->iterateAndNext(*this);
|
||||
m_alwaysp = NULL;
|
||||
oldsensesp->iterateAndNext(*this);
|
||||
bool combo = m_itemCombo;
|
||||
bool sequent = m_itemSequent;
|
||||
|
||||
@@ -311,15 +332,15 @@ private:
|
||||
// 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
|
||||
if (combo) oldsensesp->addSensesp
|
||||
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
|
||||
#endif
|
||||
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp());
|
||||
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
|
||||
}
|
||||
|
||||
// Delete sensitivity list
|
||||
if (AstNode* oldsense = nodep->sensesp()) {
|
||||
oldsense->unlinkFrBackWithNext()->deleteTree(); oldsense=NULL;
|
||||
if (oldsensesp) {
|
||||
oldsensesp->unlinkFrBackWithNext()->deleteTree(); oldsensesp=NULL;
|
||||
}
|
||||
|
||||
// Move node to new active
|
||||
@@ -328,20 +349,41 @@ private:
|
||||
|
||||
// Warn and/or convert any delayed assignments
|
||||
if (combo && !sequent) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep);
|
||||
ActiveDlyVisitor dlyvisitor (nodep, true);
|
||||
}
|
||||
else if (!combo && sequent) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, false);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
return;
|
||||
}
|
||||
visitAlways(nodep, nodep->sensesp());
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALWPub "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||
visitAlways(nodep, nodep->sensesp());
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep, AstNUser*) {
|
||||
AstSenItem* subitemp = nodep->sensesp();
|
||||
if (subitemp->edgeType() != AstEdgeType::ANYEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::POSEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::NEGEDGE) {
|
||||
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::ET_POSEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::ET_NEGEDGE) {
|
||||
nodep->v3fatalSrc("Strange activity type under SenGate");
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
if (nodep->edgeType() == AstEdgeType::ANYEDGE) {
|
||||
if (nodep->edgeType() == AstEdgeType::ET_ANYEDGE) {
|
||||
m_itemCombo = true;
|
||||
// Delete the sensitivity
|
||||
// We'll add it as a generic COMBO SenItem in a moment.
|
||||
@@ -366,7 +408,6 @@ public:
|
||||
// CONSTUCTORS
|
||||
ActiveVisitor(AstNetlist* nodep) {
|
||||
m_scopeFinalp = NULL;
|
||||
m_alwaysp = NULL;
|
||||
m_itemCombo = false;
|
||||
m_itemSequent = false;
|
||||
nodep->accept(*this);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+5
-2
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -72,7 +72,7 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
m_topscopep = NULL;
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
// Create required actives and add to module
|
||||
// We can start ordering at a module, or a scope
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
@@ -133,6 +133,9 @@ private:
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("Node should have been deleted");
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+25
-27
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Last module
|
||||
AstNodeModule* m_modp; // Last module
|
||||
AstBegin* m_beginp; // Last begin
|
||||
V3Double0 m_statAsCover; // Statistic tracking
|
||||
V3Double0 m_statAsPsl; // Statistic tracking
|
||||
@@ -60,15 +60,13 @@ private:
|
||||
+"\\n");
|
||||
}
|
||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||
nodep->displayType(AstDisplayType::WRITE);
|
||||
nodep->text(assertDisplayMessage(nodep, prefix, nodep->text()));
|
||||
AstNode* timesp = nodep->exprsp(); if (timesp) timesp->unlinkFrBack();
|
||||
nodep->displayType(AstDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
AstNode* timesp = nodep->fmtp()->exprsp(); if (timesp) timesp->unlinkFrBack();
|
||||
timesp = timesp->addNext(new AstTime(nodep->fileline()));
|
||||
nodep->exprsp(timesp);
|
||||
if (!nodep->scopeNamep()
|
||||
&& (nodep->name().find("%m") != string::npos
|
||||
|| nodep->name().find("%M") != string::npos)) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
nodep->fmtp()->exprsp(timesp);
|
||||
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
|
||||
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +78,7 @@ private:
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.assertOn()
|
||||
? (AstNode*)(new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1))
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 0)))),
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
|
||||
nodep, NULL);
|
||||
}
|
||||
|
||||
@@ -91,13 +89,13 @@ private:
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.coverage()
|
||||
? (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 1)))
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 0)))),
|
||||
? (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicTrue()))
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
|
||||
nodep, NULL);
|
||||
}
|
||||
|
||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::ERROR, message, NULL, NULL);
|
||||
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||
AstNode* bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop (nodep->fileline()));
|
||||
@@ -136,7 +134,7 @@ private:
|
||||
if (stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
|
||||
bodysp = ifp;
|
||||
if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||
if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
//
|
||||
AstNode* newp = new AstAlways (nodep->fileline(),
|
||||
sentreep,
|
||||
@@ -168,7 +166,7 @@ private:
|
||||
|
||||
AstIf* ifp = new AstIf (nodep->fileline(), propp, passsp, failsp);
|
||||
AstNode* newp = ifp;
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
//
|
||||
// Install it
|
||||
nodep->replaceWith(newp);
|
||||
@@ -179,13 +177,12 @@ private:
|
||||
// VISITORS //========== Case assertions
|
||||
virtual void visit(AstCase* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true);
|
||||
if (!nodep->user1Inc()) {
|
||||
bool has_default=false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
if (itemp->isDefault()) has_default=true;
|
||||
}
|
||||
if (nodep->fullPragma()) {
|
||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||
// Simply need to add a default if there isn't one already
|
||||
m_statAsFull++;
|
||||
if (!has_default) {
|
||||
@@ -193,7 +190,7 @@ private:
|
||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||
}
|
||||
}
|
||||
if (nodep->parallelPragma()) {
|
||||
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
// Need to check that one, and only one of the case items match at any moment
|
||||
// If there's a default, we allow none to match, else exactly one must match
|
||||
m_statAsFull++;
|
||||
@@ -210,14 +207,15 @@ private:
|
||||
else propp = onep;
|
||||
}
|
||||
}
|
||||
AstNode* ohot = (has_default
|
||||
bool allow_none = has_default || nodep->unique0Pragma();
|
||||
AstNode* ohot = (allow_none
|
||||
? (new AstOneHot0(nodep->fileline(), propp))->castNode()
|
||||
: (new AstOneHot (nodep->fileline(), propp))->castNode());
|
||||
AstIf* ifp = new AstIf (nodep->fileline(),
|
||||
new AstLogNot (nodep->fileline(), ohot),
|
||||
newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"),
|
||||
NULL);
|
||||
ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
nodep->addNotParallelp(ifp);
|
||||
}
|
||||
}
|
||||
@@ -228,12 +226,12 @@ private:
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Replace the special types with standard text
|
||||
if (nodep->displayType()==AstDisplayType::INFO) {
|
||||
if (nodep->displayType()==AstDisplayType::DT_INFO) {
|
||||
replaceDisplay(nodep, "-Info");
|
||||
} else if (nodep->displayType()==AstDisplayType::WARNING) {
|
||||
} else if (nodep->displayType()==AstDisplayType::DT_WARNING) {
|
||||
replaceDisplay(nodep, "%%Warning");
|
||||
} else if (nodep->displayType()==AstDisplayType::ERROR
|
||||
|| nodep->displayType()==AstDisplayType::FATAL) {
|
||||
} else if (nodep->displayType()==AstDisplayType::DT_ERROR
|
||||
|| nodep->displayType()==AstDisplayType::DT_FATAL) {
|
||||
replaceDisplay(nodep, "%%Error");
|
||||
}
|
||||
}
|
||||
@@ -257,7 +255,7 @@ private:
|
||||
m_statAsSV++;
|
||||
}
|
||||
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
//
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -112,7 +112,7 @@ private:
|
||||
virtual void visit(AstPslClocked* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_senip) {
|
||||
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion\n");
|
||||
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
||||
}
|
||||
// Block is the new expression to evaluate
|
||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
nodep->replaceWith(blockp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Reset defaults
|
||||
m_seniDefaultp = NULL;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+26
-17
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -44,11 +44,13 @@ uint32_t AstUser1InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser2InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser3InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser4InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser5InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
|
||||
bool AstUser1InUse::s_userBusy=false;
|
||||
bool AstUser2InUse::s_userBusy=false;
|
||||
bool AstUser3InUse::s_userBusy=false;
|
||||
bool AstUser4InUse::s_userBusy=false;
|
||||
bool AstUser5InUse::s_userBusy=false;
|
||||
|
||||
//######################################################################
|
||||
// V3AstType
|
||||
@@ -83,6 +85,8 @@ void AstNode::init() {
|
||||
m_user3Cnt = 0;
|
||||
m_user4p = NULL;
|
||||
m_user4Cnt = 0;
|
||||
m_user5p = NULL;
|
||||
m_user5Cnt = 0;
|
||||
}
|
||||
|
||||
string AstNode::encodeName(const string& namein) {
|
||||
@@ -140,7 +144,7 @@ string AstNode::dedotName(const string& namein) {
|
||||
}
|
||||
|
||||
string AstNode::vcdName(const string& namein) {
|
||||
// VCD tracing expects space to separate hiearchy
|
||||
// VCD tracing expects space to separate hierarchy
|
||||
// Dots are reserved for dots the user put in the name
|
||||
string pretty = namein;
|
||||
string::size_type pos;
|
||||
@@ -693,14 +697,17 @@ AstNode::~AstNode() {
|
||||
|
||||
void AstNode::deleteTreeIter() {
|
||||
if (!this) return;
|
||||
// MUST be depth first!
|
||||
this->m_op1p->deleteTreeIter();
|
||||
this->m_op2p->deleteTreeIter();
|
||||
this->m_op3p->deleteTreeIter();
|
||||
this->m_op4p->deleteTreeIter();
|
||||
this->m_nextp->deleteTreeIter();
|
||||
this->m_backp = NULL;
|
||||
deleteNode();
|
||||
for (AstNode* nodep=this, *nnextp; nodep; nodep=nnextp) {
|
||||
nnextp = nodep->m_nextp;
|
||||
// MUST be depth first!
|
||||
nodep->m_op1p->deleteTreeIter();
|
||||
nodep->m_op2p->deleteTreeIter();
|
||||
nodep->m_op3p->deleteTreeIter();
|
||||
nodep->m_op4p->deleteTreeIter();
|
||||
nodep->m_nextp = NULL;
|
||||
nodep->m_backp = NULL;
|
||||
nodep->deleteNode();
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::deleteTree() {
|
||||
@@ -806,7 +813,7 @@ void AstNode::iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup) {
|
||||
AstNode* AstNode::acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup) {
|
||||
// Some visitors perform tree edits (such as V3Const), and may even
|
||||
// replace/delete the exact nodep that the visitor is called with. If
|
||||
// this happens, the parent will loose the handle to the node that was
|
||||
// this happens, the parent will lose the handle to the node that was
|
||||
// processed.
|
||||
// To solve this, this function returns the pointer to the replacement node,
|
||||
// which in many cases is just the same node that was passed in.
|
||||
@@ -843,12 +850,13 @@ AstNode* AstNode::acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup) {
|
||||
|
||||
void AstNode::cloneRelinkTree() {
|
||||
if (!this) return;
|
||||
this->cloneRelink();
|
||||
m_op1p->cloneRelinkTree();
|
||||
m_op2p->cloneRelinkTree();
|
||||
m_op3p->cloneRelinkTree();
|
||||
m_op4p->cloneRelinkTree();
|
||||
m_nextp->cloneRelinkTree(); // Tail recursion
|
||||
for (AstNode* nodep=this; nodep; nodep=nodep->m_nextp) {
|
||||
nodep->cloneRelink();
|
||||
nodep->m_op1p->cloneRelinkTree();
|
||||
nodep->m_op2p->cloneRelinkTree();
|
||||
nodep->m_op3p->cloneRelinkTree();
|
||||
nodep->m_op4p->cloneRelinkTree();
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
@@ -950,6 +958,7 @@ void AstNode::dumpPtrs(ostream& os) {
|
||||
if (user2p()) os<<" user2p="<<(void*)user2p();
|
||||
if (user3p()) os<<" user3p="<<(void*)user3p();
|
||||
if (user4p()) os<<" user4p="<<(void*)user4p();
|
||||
if (user5p()) os<<" user5p="<<(void*)user5p();
|
||||
if (m_iterpp) {
|
||||
os<<" iterpp="<<(void*)m_iterpp;
|
||||
os<<"*="<<(void*)*m_iterpp;
|
||||
|
||||
+311
-84
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -32,6 +32,9 @@
|
||||
// Things like:
|
||||
// class V3AstNode;
|
||||
|
||||
// Hint class so we can choose constructors
|
||||
class AstLogicPacked {};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstType {
|
||||
@@ -78,7 +81,7 @@ public:
|
||||
class AstCFuncType {
|
||||
public:
|
||||
enum en {
|
||||
NORMAL,
|
||||
FT_NORMAL,
|
||||
TRACE_INIT,
|
||||
TRACE_INIT_SUB,
|
||||
TRACE_FULL,
|
||||
@@ -107,19 +110,19 @@ public:
|
||||
// REMEMBER to edit the strings below too
|
||||
enum en {
|
||||
// These must be in general -> most specific order, as we sort by it in V3Const::visit AstSenTre
|
||||
ILLEGAL,
|
||||
ET_ILLEGAL,
|
||||
// Involving a variable
|
||||
ANYEDGE, // Default for sensitivities; rip them out
|
||||
BOTHEDGE, // POSEDGE | NEGEDGE
|
||||
POSEDGE,
|
||||
NEGEDGE,
|
||||
HIGHEDGE, // Is high now (latches)
|
||||
LOWEDGE, // Is low now (latches)
|
||||
ET_ANYEDGE, // Default for sensitivities; rip them out
|
||||
ET_BOTHEDGE, // POSEDGE | NEGEDGE
|
||||
ET_POSEDGE,
|
||||
ET_NEGEDGE,
|
||||
ET_HIGHEDGE, // Is high now (latches)
|
||||
ET_LOWEDGE, // Is low now (latches)
|
||||
// Not involving anything
|
||||
COMBO, // Sensitive to all combo inputs to this block
|
||||
INITIAL, // User initial statements
|
||||
SETTLE, // Like combo but for initial wire resolutions after initial statement
|
||||
NEVER // Never occurs (optimized away)
|
||||
ET_COMBO, // Sensitive to all combo inputs to this block
|
||||
ET_INITIAL, // User initial statements
|
||||
ET_SETTLE, // Like combo but for initial wire resolutions after initial statement
|
||||
ET_NEVER // Never occurs (optimized away)
|
||||
};
|
||||
enum en m_e;
|
||||
bool clockedStmt() const {
|
||||
@@ -131,15 +134,15 @@ public:
|
||||
}
|
||||
AstEdgeType invert() const {
|
||||
switch (m_e) {
|
||||
case ANYEDGE: return ANYEDGE;
|
||||
case BOTHEDGE: return BOTHEDGE;
|
||||
case POSEDGE: return NEGEDGE;
|
||||
case NEGEDGE: return POSEDGE;
|
||||
case HIGHEDGE: return LOWEDGE;
|
||||
case LOWEDGE: return HIGHEDGE;
|
||||
case ET_ANYEDGE: return ET_ANYEDGE;
|
||||
case ET_BOTHEDGE: return ET_BOTHEDGE;
|
||||
case ET_POSEDGE: return ET_NEGEDGE;
|
||||
case ET_NEGEDGE: return ET_POSEDGE;
|
||||
case ET_HIGHEDGE: return ET_LOWEDGE;
|
||||
case ET_LOWEDGE: return ET_HIGHEDGE;
|
||||
default: UASSERT_STATIC(0,"Inverting bad edgeType()");
|
||||
};
|
||||
return AstEdgeType::ILLEGAL;
|
||||
return AstEdgeType::ET_ILLEGAL;
|
||||
}
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
@@ -150,7 +153,7 @@ public:
|
||||
};
|
||||
const char* verilogKwd() const {
|
||||
static const char* names[] = {
|
||||
"%E-edge", "[any]", "[both]", "posedge", "negedge", "[high]","[low]",
|
||||
"%E-edge", "[any]", "edge", "posedge", "negedge", "[high]","[low]",
|
||||
"*","[initial]","[settle]","[never]"
|
||||
};
|
||||
return names[m_e];
|
||||
@@ -169,21 +172,25 @@ public:
|
||||
class AstAttrType {
|
||||
public:
|
||||
enum en {
|
||||
BITS, // V3Const converts to constant
|
||||
EXPR_BITS, // V3Const converts to constant
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked
|
||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_ISOLATE_ASSIGNMENTS // V3LinkParse moves to AstVar::attrIsolateAssign
|
||||
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
|
||||
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"BITS", "VAR_BASE",
|
||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
||||
"VAR_ISOLATE_ASSIGNMENTS"
|
||||
"EXPR_BITS", "VAR_BASE",
|
||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
@@ -198,6 +205,94 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstBasicDTypeKwd {
|
||||
public:
|
||||
enum en {
|
||||
BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT,
|
||||
REAL, REALTIME, SHORTINT, SHORTREAL, TIME,
|
||||
// Closer to a class type, but limited usage
|
||||
STRING,
|
||||
// Internal types for mid-steps
|
||||
SCOPEPTR, CHARPTR,
|
||||
// Internal types, eliminated after parsing
|
||||
LOGIC_IMPLICIT
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"bit", "byte", "chandle", "int", "integer", "logic", "longint",
|
||||
"real", "realtime", "shortint", "shortreal", "time",
|
||||
"string",
|
||||
"VerilatedScope*", "char*",
|
||||
"LOGIC_IMPLICIT"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
const char* dpiType() const {
|
||||
static const char* names[] = {
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "double", "short int", "float", "long long",
|
||||
"const char*",
|
||||
"dpiScope", "const char*",
|
||||
""
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
inline AstBasicDTypeKwd () {}
|
||||
inline AstBasicDTypeKwd (en _e) : m_e(_e) {}
|
||||
explicit inline AstBasicDTypeKwd (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
int width() const {
|
||||
switch (m_e) {
|
||||
case BIT: return 1;
|
||||
case BYTE: return 8;
|
||||
case CHANDLE: return 64;
|
||||
case INT: return 32;
|
||||
case INTEGER: return 32;
|
||||
case LOGIC: return 1;
|
||||
case LONGINT: return 64;
|
||||
case SHORTINT: return 16;
|
||||
case TIME: return 64;
|
||||
case STRING: return 64; // Just the pointer, for today
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
bool isSigned() const {
|
||||
return m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER;
|
||||
}
|
||||
bool isFourstate() const {
|
||||
return m_e==INTEGER || m_e==LOGIC || m_e==LOGIC_IMPLICIT;
|
||||
}
|
||||
bool isZeroInit() const { // Otherwise initializes to X
|
||||
return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT
|
||||
|| m_e==STRING);
|
||||
}
|
||||
bool isSloppy() const { // Don't be as anal about width warnings
|
||||
return !(m_e==LOGIC || m_e==BIT);
|
||||
}
|
||||
bool isBitLogic() const { // Don't be as anal about width warnings
|
||||
return (m_e==LOGIC || m_e==BIT);
|
||||
}
|
||||
bool isDpiUnsupported() const {
|
||||
return (m_e==LOGIC || m_e==TIME || m_e==REALTIME);
|
||||
}
|
||||
bool isOpaque() const { // IE not a simple number we can bit optimize
|
||||
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR);
|
||||
}
|
||||
};
|
||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator== (AstBasicDTypeKwd::en lhs, AstBasicDTypeKwd rhs) { return (lhs == rhs.m_e); }
|
||||
|
||||
//######################################################################
|
||||
|
||||
enum AstSignedState {
|
||||
// This can't be in the fancy class as the lexer union will get upset
|
||||
signedst_NOP=0, signedst_SIGNED=1, signedst_UNSIGNED=2
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstVarType {
|
||||
public:
|
||||
enum en {
|
||||
@@ -205,15 +300,14 @@ public:
|
||||
GPARAM,
|
||||
LPARAM,
|
||||
GENVAR,
|
||||
INTEGER,
|
||||
VAR, // Reg, integer, logic, etc
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
INOUT,
|
||||
SUPPLY0,
|
||||
SUPPLY1,
|
||||
WIRE,
|
||||
IMPLICIT,
|
||||
REG,
|
||||
IMPLICITWIRE,
|
||||
TRIWIRE,
|
||||
PORT, // Temp type used in parser only
|
||||
BLOCKTEMP,
|
||||
@@ -229,8 +323,8 @@ public:
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"?","GPARAM","LPARAM","GENVAR",
|
||||
"INTEGER","INPUT","OUTPUT","INOUT",
|
||||
"SUPPLY0","SUPPLY1","WIRE","IMPLICIT","REG","TRIWIRE","PORT",
|
||||
"VAR","INPUT","OUTPUT","INOUT",
|
||||
"SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE","TRIWIRE","PORT",
|
||||
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
@@ -244,20 +338,20 @@ public:
|
||||
class AstBranchPred {
|
||||
public:
|
||||
enum en {
|
||||
UNKNOWN=0,
|
||||
LIKELY,
|
||||
UNLIKELY,
|
||||
BP_UNKNOWN=0,
|
||||
BP_LIKELY,
|
||||
BP_UNLIKELY,
|
||||
_ENUM_END
|
||||
};
|
||||
enum en m_e;
|
||||
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
||||
inline AstBranchPred () : m_e(UNKNOWN) {}
|
||||
inline AstBranchPred () : m_e(BP_UNKNOWN) {}
|
||||
inline AstBranchPred (en _e) : m_e(_e) {}
|
||||
explicit inline AstBranchPred (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
AstBranchPred invert() const {
|
||||
if (m_e==UNLIKELY) return LIKELY;
|
||||
else if (m_e==LIKELY) return UNLIKELY;
|
||||
if (m_e==BP_UNLIKELY) return BP_LIKELY;
|
||||
else if (m_e==BP_LIKELY) return BP_UNLIKELY;
|
||||
else return m_e;
|
||||
}
|
||||
const char* ascii() const {
|
||||
@@ -275,9 +369,9 @@ public:
|
||||
class AstCaseType {
|
||||
public:
|
||||
enum en {
|
||||
CASE,
|
||||
CASEX,
|
||||
CASEZ
|
||||
CT_CASE,
|
||||
CT_CASEX,
|
||||
CT_CASEZ
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstCaseType () {}
|
||||
@@ -294,20 +388,20 @@ public:
|
||||
class AstDisplayType {
|
||||
public:
|
||||
enum en {
|
||||
DISPLAY,
|
||||
WRITE,
|
||||
INFO,
|
||||
ERROR,
|
||||
WARNING,
|
||||
FATAL
|
||||
DT_DISPLAY,
|
||||
DT_WRITE,
|
||||
DT_INFO,
|
||||
DT_ERROR,
|
||||
DT_WARNING,
|
||||
DT_FATAL
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstDisplayType () {}
|
||||
inline AstDisplayType (en _e) : m_e(_e) {}
|
||||
explicit inline AstDisplayType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
bool addNewline() const { return m_e!=WRITE; }
|
||||
bool needScopeTracking() const { return m_e!=DISPLAY && m_e!=WRITE; }
|
||||
bool addNewline() const { return m_e!=DT_WRITE; }
|
||||
bool needScopeTracking() const { return m_e!=DT_DISPLAY && m_e!=DT_WRITE; }
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"display","write","info","error","warning","fatal"};
|
||||
@@ -322,15 +416,14 @@ public:
|
||||
class AstParseRefExp {
|
||||
public:
|
||||
enum en {
|
||||
NONE, // Used in V3LinkParse only
|
||||
VAR_MEM,
|
||||
VAR_ANY,
|
||||
TASK,
|
||||
FUNC,
|
||||
_ENUM_END
|
||||
PX_NONE, // Used in V3LinkParse only
|
||||
PX_VAR_MEM,
|
||||
PX_VAR_ANY,
|
||||
PX_TASK,
|
||||
PX_FUNC
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstParseRefExp() : m_e(NONE) {}
|
||||
inline AstParseRefExp() : m_e(PX_NONE) {}
|
||||
inline AstParseRefExp (en _e) : m_e(_e) {}
|
||||
explicit inline AstParseRefExp (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -407,6 +500,9 @@ protected:
|
||||
++cntGblRef;
|
||||
UASSERT_STATIC(cntGblRef, "User*() overflowed!");
|
||||
}
|
||||
static void checkcnt(int id, uint32_t&, bool& userBusyRef) {
|
||||
UASSERT_STATIC(userBusyRef, "Check of User"+cvtToStr(id)+"() failed, not under AstUserInUse");
|
||||
}
|
||||
};
|
||||
|
||||
// For each user() declare the in use structure
|
||||
@@ -421,6 +517,7 @@ public:
|
||||
AstUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
~AstUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
class AstUser2InUse : AstUserInUseBase {
|
||||
protected:
|
||||
@@ -431,6 +528,7 @@ public:
|
||||
AstUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
~AstUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
class AstUser3InUse : AstUserInUseBase {
|
||||
protected:
|
||||
@@ -441,6 +539,7 @@ public:
|
||||
AstUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
~AstUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
class AstUser4InUse : AstUserInUseBase {
|
||||
protected:
|
||||
@@ -451,6 +550,18 @@ public:
|
||||
AstUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
~AstUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
class AstUser5InUse : AstUserInUseBase {
|
||||
protected:
|
||||
friend class AstNode;
|
||||
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
|
||||
static bool s_userBusy; // Count is in use
|
||||
public:
|
||||
AstUser5InUse() { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
~AstUser5InUse() { free (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -587,6 +698,8 @@ class AstNode {
|
||||
uint32_t m_user3Cnt; // Mark of when userp was set
|
||||
uint32_t m_user4Cnt; // Mark of when userp was set
|
||||
AstNUser* m_user4p; // Pointer to any information the user iteration routine wants
|
||||
AstNUser* m_user5p; // Pointer to any information the user iteration routine wants
|
||||
uint32_t m_user5Cnt; // Mark of when userp was set
|
||||
|
||||
// METHODS
|
||||
void op1p(AstNode* nodep) { m_op1p = nodep; if (nodep) nodep->m_backp = this; }
|
||||
@@ -651,6 +764,7 @@ public:
|
||||
AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); }
|
||||
AstNode* firstAbovep() const { return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } // Returns NULL when second or later in list
|
||||
bool brokeExists() const;
|
||||
bool brokeExistsAbove() const;
|
||||
|
||||
// CONSTRUCTORS
|
||||
virtual ~AstNode();
|
||||
@@ -662,6 +776,7 @@ public:
|
||||
// CONSTANT ACCESSORS
|
||||
static int instrCountBranch() { return 4; } ///< Instruction cycles to branch
|
||||
static int instrCountDiv() { return 10; } ///< Instruction cycles to divide
|
||||
static int instrCountDpi() { return 1000; } ///< Instruction cycles to call user function
|
||||
static int instrCountLd() { return 2; } ///< Instruction cycles to load memory
|
||||
static int instrCountMul() { return 3; } ///< Instruction cycles to multiply integers
|
||||
static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines
|
||||
@@ -682,6 +797,7 @@ public:
|
||||
string prettyName() const { return prettyName(name()); }
|
||||
string prettyTypeName() const; // "VARREF name" for error messages
|
||||
FileLine* fileline() const { return m_fileline; }
|
||||
void fileline(FileLine* fl) { m_fileline=fl; }
|
||||
int width() const { return m_width; }
|
||||
bool width1() const { return width()==1; }
|
||||
int widthWords() const { return VL_WORDS_I(width()); }
|
||||
@@ -706,6 +822,7 @@ public:
|
||||
void user1p(void* userp) { m_user1p=(AstNUser*)(userp); m_user1Cnt=AstUser1InUse::s_userCntGbl; }
|
||||
int user1() const { return user1p()->castInt(); }
|
||||
void user1(int val) { user1p(AstNUser::fromInt(val)); }
|
||||
int user1Inc() { int v=user1(); user1(v+1); return v; }
|
||||
static void user1ClearTree() { AstUser1InUse::clear(); } // Clear userp()'s across the entire tree
|
||||
|
||||
AstNUser* user2p() const {
|
||||
@@ -714,6 +831,7 @@ public:
|
||||
void user2p(void* userp) { m_user2p=(AstNUser*)(userp); m_user2Cnt=AstUser2InUse::s_userCntGbl; }
|
||||
int user2() const { return user2p()->castInt(); }
|
||||
void user2(int val) { user2p(AstNUser::fromInt(val)); }
|
||||
int user2Inc() { int v=user2(); user2(v+1); return v; }
|
||||
static void user2ClearTree() { AstUser2InUse::clear(); }
|
||||
|
||||
AstNUser* user3p() const {
|
||||
@@ -722,6 +840,7 @@ public:
|
||||
void user3p(void* userp) { m_user3p=(AstNUser*)(userp); m_user3Cnt=AstUser3InUse::s_userCntGbl; }
|
||||
int user3() const { return user3p()->castInt(); }
|
||||
void user3(int val) { user3p(AstNUser::fromInt(val)); }
|
||||
int user3Inc() { int v=user3(); user3(v+1); return v; }
|
||||
static void user3ClearTree() { AstUser3InUse::clear(); }
|
||||
|
||||
AstNUser* user4p() const {
|
||||
@@ -730,8 +849,18 @@ public:
|
||||
void user4p(void* userp) { m_user4p=(AstNUser*)(userp); m_user4Cnt=AstUser4InUse::s_userCntGbl; }
|
||||
int user4() const { return user4p()->castInt(); }
|
||||
void user4(int val) { user4p(AstNUser::fromInt(val)); }
|
||||
int user4Inc() { int v=user4(); user4(v+1); return v; }
|
||||
static void user4ClearTree() { AstUser4InUse::clear(); }
|
||||
|
||||
AstNUser* user5p() const {
|
||||
//UASSERT_STATIC(AstUser5InUse::s_userBusy, "user5p set w/o busy");
|
||||
return ((m_user5Cnt==AstUser5InUse::s_userCntGbl)?m_user5p:NULL); }
|
||||
void user5p(void* userp) { m_user5p=(AstNUser*)(userp); m_user5Cnt=AstUser5InUse::s_userCntGbl; }
|
||||
int user5() const { return user5p()->castInt(); }
|
||||
void user5(int val) { user5p(AstNUser::fromInt(val)); }
|
||||
int user5Inc() { int v=user5(); user5(v+1); return v; }
|
||||
static void user5ClearTree() { AstUser5InUse::clear(); }
|
||||
|
||||
vluint64_t editCount() const { return m_editCount; }
|
||||
void editCountInc() { m_editCount = ++s_editCntGbl; } // Preincrement, so can "watch AstNode::s_editCntGbl=##"
|
||||
static vluint64_t editCountLast() { return s_editCntLast; }
|
||||
@@ -750,6 +879,7 @@ public:
|
||||
AstNode* addNext(AstNode* newp); // Returns this, adds to end of list
|
||||
AstNode* addNextNull(AstNode* newp); // Returns this, adds to end of list, NULL is OK
|
||||
void addNextHere(AstNode* newp); // Adds after speced node
|
||||
void addPrev(AstNode* newp) { replaceWith(newp); newp->addNext(this); }
|
||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||
void v3errorEnd(ostringstream& str) const;
|
||||
@@ -823,6 +953,9 @@ struct AstNodeMath : public AstNode {
|
||||
virtual string emitC() = 0;
|
||||
virtual string emitSimpleOperator() { return ""; }
|
||||
virtual bool cleanOut() = 0; // True if output has extra upper bits zero
|
||||
// Someday we will generically support data types on every math node
|
||||
// Until then isOpaque indicates we shouldn't constant optimize this node type
|
||||
bool isOpaque() { return castCvtPackString()!=NULL; }
|
||||
};
|
||||
|
||||
struct AstNodeTermop : public AstNodeMath {
|
||||
@@ -924,7 +1057,7 @@ struct AstNodeCond : public AstNodeTriop {
|
||||
AstNode* condp() const { return op1p()->castNode(); } // op1 = Condition
|
||||
AstNode* expr1p() const { return op2p()->castNode(); } // op2 = If true...
|
||||
AstNode* expr2p() const { return op3p()->castNode(); } // op3 = If false...
|
||||
virtual string emitVerilog() { return "%k(%l %k? %r %k: %t)"; }
|
||||
virtual string emitVerilog() { return "%k(%l %f? %r %k: %t)"; }
|
||||
virtual string emitC() { return "VL_COND_%nq%lq%rq%tq(%nw,%lw,%rw,%tw, %P, %li, %ri, %ti)"; }
|
||||
virtual bool cleanOut() { return false; } // clean if e1 & e2 clean
|
||||
virtual bool cleanLhs() { return true; }
|
||||
@@ -981,6 +1114,7 @@ struct AstNodeAssign : public AstNodeStmt {
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
virtual string verilogKwd() const { return "="; }
|
||||
};
|
||||
|
||||
struct AstNodeFor : public AstNodeStmt {
|
||||
@@ -1054,17 +1188,18 @@ private:
|
||||
bool m_lvalue; // Left hand side assignment
|
||||
AstVar* m_varp; // [AfterLink] Pointer to variable itself
|
||||
AstVarScope* m_varScopep; // Varscope for hierarchy
|
||||
AstPackage* m_packagep; // Package hierarchy
|
||||
string m_name; // Name of variable
|
||||
string m_hiername; // Scope converted into name-> for emitting
|
||||
bool m_hierThis; // Hiername points to "this" function
|
||||
public:
|
||||
AstNodeVarRef(FileLine* fl, const string& name, bool lvalue)
|
||||
: AstNodeMath(fl), m_lvalue(lvalue), m_varp(NULL), m_varScopep(NULL),
|
||||
m_name(name), m_hierThis(false) {
|
||||
m_packagep(NULL), m_name(name), m_hierThis(false) {
|
||||
}
|
||||
AstNodeVarRef(FileLine* fl, const string& name, AstVar* varp, bool lvalue)
|
||||
: AstNodeMath(fl), m_lvalue(lvalue), m_varp(varp), m_varScopep(NULL),
|
||||
m_name(name), m_hierThis(false) {
|
||||
m_packagep(NULL), m_name(name), m_hierThis(false) {
|
||||
// May have varp==NULL
|
||||
if (m_varp) widthSignedFrom((AstNode*)m_varp);
|
||||
}
|
||||
@@ -1084,27 +1219,13 @@ public:
|
||||
void hiername(const string& hn) { m_hiername = hn; }
|
||||
bool hierThis() const { return m_hierThis; }
|
||||
void hierThis(bool flag) { m_hierThis = flag; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// See checkTreeIter also that asserts no children
|
||||
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
|
||||
};
|
||||
|
||||
class AstNodePli : public AstNodeStmt {
|
||||
string m_text;
|
||||
public:
|
||||
AstNodePli(FileLine* fl, const string& text, AstNode* exprsp)
|
||||
: AstNodeStmt(fl), m_text(text) {
|
||||
addNOp1p(exprsp); }
|
||||
ASTNODE_BASE_FUNCS(NodePli)
|
||||
virtual string name() const { return m_text; }
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text=text; }
|
||||
// op2p,op3p... used by AstDisplay
|
||||
};
|
||||
|
||||
struct AstNodeText : public AstNode {
|
||||
private:
|
||||
string m_text;
|
||||
@@ -1115,18 +1236,33 @@ public:
|
||||
m_text = textp; // Copy it
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeText)
|
||||
const string& text() const { return m_text; }
|
||||
virtual void dump(ostream& str=cout);
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castNodeText()->text(); }
|
||||
const string& text() const { return m_text; }
|
||||
};
|
||||
|
||||
struct AstNodeDType : public AstNode {
|
||||
// Data type
|
||||
AstNodeDType(FileLine* fl) : AstNode(fl) {}
|
||||
ASTNODE_BASE_FUNCS(NodeDType)
|
||||
// Accessors
|
||||
virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type
|
||||
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs to next non-typeref type
|
||||
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
};
|
||||
|
||||
struct AstNodeSel : public AstNodeBiop {
|
||||
// Single bit range extraction, perhaps with non-constant selection or array selection
|
||||
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
|
||||
:AstNodeBiop(fl, fromp, bitp) {}
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
AstNode* bitp() const { return op2p()->castNode(); } // op2 = Msb selection expression
|
||||
ASTNODE_BASE_FUNCS(NodeSel)
|
||||
AstNode* fromp() const { return op1p()->castNode(); } // op1 = Extracting what (NULL=TBD during parsing)
|
||||
void fromp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* bitp() const { return op2p()->castNode(); } // op2 = Msb selection expression
|
||||
void bitp(AstNode* nodep) { setOp2p(nodep); }
|
||||
int bitConst() const;
|
||||
};
|
||||
|
||||
@@ -1136,25 +1272,62 @@ struct AstNodeSel : public AstNodeBiop {
|
||||
struct AstNodeFTask : public AstNode {
|
||||
private:
|
||||
string m_name; // Name of task
|
||||
bool m_taskPublic; // Public task
|
||||
string m_cname; // Name of task if DPI import
|
||||
bool m_taskPublic:1; // Public task
|
||||
bool m_didSigning:1; // V3Signed completed; can skip iteration
|
||||
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
|
||||
bool m_prototype:1; // Just a prototype
|
||||
bool m_dpiExport:1; // DPI exported
|
||||
bool m_dpiImport:1; // DPI imported
|
||||
bool m_dpiContext:1; // DPI import context
|
||||
bool m_dpiTask:1; // DPI import task (vs. void function)
|
||||
bool m_pure:1; // DPI import pure
|
||||
public:
|
||||
// Node that simply puts name into the output stream
|
||||
AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp)
|
||||
: AstNode(fileline)
|
||||
, m_name(name), m_taskPublic(false) {
|
||||
, m_name(name), m_taskPublic(false), m_didSigning(false)
|
||||
, m_attrIsolateAssign(false), m_prototype(false)
|
||||
, m_dpiExport(false), m_dpiImport(false), m_dpiContext(false)
|
||||
, m_dpiTask(false), m_pure(false) {
|
||||
addNOp3p(stmtsp);
|
||||
cname(name); // Might be overridden by dpi import/export
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeFTask)
|
||||
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
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
AstNode* stmtsp() const { return op3p()->castNode(); } // op1 = List of statements
|
||||
void addStmtsp(AstNode* nodep) { addOp3p(nodep); }
|
||||
string cname() const { return m_cname; }
|
||||
void cname(const string& cname) { m_cname = cname; }
|
||||
// op1 = Output variable (functions only, NULL for tasks)
|
||||
AstNode* fvarp() const { return op1p()->castNode(); }
|
||||
void addFvarp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
bool isFunction() const { return fvarp()!=NULL; }
|
||||
// op3 = Statements/Ports/Vars
|
||||
AstNode* stmtsp() const { return op3p()->castNode(); } // op3 = List of statements
|
||||
void addStmtsp(AstNode* nodep) { addNOp3p(nodep); }
|
||||
// op4 = scope name
|
||||
AstScopeName* scopeNamep() const { return op4p()->castScopeName(); }
|
||||
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
|
||||
void taskPublic(bool flag) { m_taskPublic=flag; }
|
||||
bool taskPublic() const { return m_taskPublic; }
|
||||
void didSigning(bool flag) { m_didSigning=flag; }
|
||||
bool didSigning() const { return m_didSigning; }
|
||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||
void prototype(bool flag) { m_prototype = flag; }
|
||||
bool prototype() const { return m_prototype; }
|
||||
void dpiExport(bool flag) { m_dpiExport = flag; }
|
||||
bool dpiExport() const { return m_dpiExport; }
|
||||
void dpiImport(bool flag) { m_dpiImport = flag; }
|
||||
bool dpiImport() const { return m_dpiImport; }
|
||||
void dpiContext(bool flag) { m_dpiContext = flag; }
|
||||
bool dpiContext() const { return m_dpiContext; }
|
||||
void dpiTask(bool flag) { m_dpiTask = flag; }
|
||||
bool dpiTask() const { return m_dpiTask; }
|
||||
void pure(bool flag) { m_pure = flag; }
|
||||
bool pure() const { return m_pure; }
|
||||
};
|
||||
|
||||
struct AstNodeFTaskRef : public AstNode {
|
||||
@@ -1164,12 +1337,18 @@ private:
|
||||
string m_name; // Name of variable
|
||||
string m_dotted; // Dotted part of scope to task or ""
|
||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||
AstPackage* m_packagep; // Package hierarchy
|
||||
public:
|
||||
AstNodeFTaskRef(FileLine* fl, AstNode* namep, AstNode* pinsp)
|
||||
:AstNode(fl)
|
||||
, m_taskp(NULL) {
|
||||
, m_taskp(NULL), m_packagep(NULL) {
|
||||
setOp1p(namep); addNOp2p(pinsp);
|
||||
}
|
||||
AstNodeFTaskRef(FileLine* fl, const string& name, AstNode* pinsp)
|
||||
:AstNode(fl)
|
||||
, m_taskp(NULL), m_name(name), m_packagep(NULL) {
|
||||
addNOp2p(pinsp);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeFTaskRef)
|
||||
virtual bool broken() const { return m_taskp && !m_taskp->brokeExists(); }
|
||||
virtual void cloneRelink() { if (m_taskp && m_taskp->clonep()) {
|
||||
@@ -1185,11 +1364,59 @@ public:
|
||||
void taskp(AstNodeFTask* taskp) { m_taskp=taskp; }
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
void dotted(const string& name) { m_dotted = name; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
||||
// op1 = namep
|
||||
AstNode* namep() const { return op1p(); }
|
||||
// op2 = Pin interconnection list
|
||||
AstNode* pinsp() const { return op2p()->castNode(); }
|
||||
void addPinsp(AstNode* nodep) { addOp2p(nodep); }
|
||||
// op3 = scope tracking
|
||||
AstScopeName* scopeNamep() const { return op3p()->castScopeName(); }
|
||||
void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
|
||||
};
|
||||
|
||||
struct AstNodeModule : public AstNode {
|
||||
// A module, package, program or interface declaration;
|
||||
// something that can live directly under the TOP,
|
||||
// excluding $unit package stuff
|
||||
private:
|
||||
string m_name; // Name of the module
|
||||
string m_origName; // Name of the module, ignoring name() changes, for dot lookup
|
||||
bool m_modPublic:1; // Module has public references
|
||||
bool m_modTrace:1; // Tracing this module
|
||||
bool m_inLibrary:1; // From a library, no error if not used, never top level
|
||||
int m_level; // 1=top module, 2=cell off top module, ...
|
||||
int m_varNum; // Incrementing variable number
|
||||
public:
|
||||
AstNodeModule(FileLine* fl, const string& name)
|
||||
: AstNode (fl)
|
||||
,m_name(name), m_origName(name)
|
||||
,m_modPublic(false), m_modTrace(false), m_inLibrary(false)
|
||||
,m_level(0), m_varNum(0) { }
|
||||
ASTNODE_BASE_FUNCS(NodeModule)
|
||||
virtual void dump(ostream& str);
|
||||
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
|
||||
// METHODS
|
||||
void addInlinesp(AstNode* nodep) { addOp1p(nodep); }
|
||||
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
|
||||
void addActivep(AstNode* nodep) { addOp3p(nodep); }
|
||||
// ACCESSORS
|
||||
virtual void name(const string& name) { m_name = name; }
|
||||
string origName() const { return m_origName; }
|
||||
bool inLibrary() const { return m_inLibrary; }
|
||||
void inLibrary(bool flag) { m_inLibrary = flag; }
|
||||
void level(int level) { m_level = level; }
|
||||
int level() const { return m_level; }
|
||||
bool isTop() const { return level()==1; }
|
||||
int varNumGetInc() { return ++m_varNum; }
|
||||
void modPublic(bool flag) { m_modPublic = flag; }
|
||||
bool modPublic() const { return m_modPublic; }
|
||||
void modTrace(bool flag) { m_modTrace = flag; }
|
||||
bool modTrace() const { return m_modTrace; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+288
-45
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -47,6 +47,20 @@ int AstNodeSel::bitConst() const {
|
||||
AstConst* constp=bitp()->castConst(); return (constp?constp->toSInt():0);
|
||||
}
|
||||
|
||||
int AstBasicDType::widthAlignBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isQuad()) return 8;
|
||||
else return 4;
|
||||
}
|
||||
|
||||
int AstBasicDType::widthTotalBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isQuad()) return 8;
|
||||
else return widthWords()*(VL_WORDSIZE/8);
|
||||
}
|
||||
|
||||
bool AstVar::isSigPublic() const {
|
||||
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
|
||||
}
|
||||
@@ -72,20 +86,6 @@ void AstVar::combineType(AstVarType type) {
|
||||
m_tristate = true;
|
||||
}
|
||||
|
||||
int AstVar::widthAlignBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isSc() ? isScQuad() : isQuad()) return 8;
|
||||
else return 4;
|
||||
}
|
||||
|
||||
int AstVar::widthTotalBytes() const {
|
||||
if (width()<=8) return 1;
|
||||
else if (width()<=16) return 2;
|
||||
else if (isSc() ? isScQuad() : isQuad()) return 8;
|
||||
else return widthWords()*(VL_WORDSIZE/8);
|
||||
}
|
||||
|
||||
string AstVar::verilogKwd() const {
|
||||
if (isInout()) {
|
||||
return "inout";
|
||||
@@ -93,27 +93,135 @@ string AstVar::verilogKwd() const {
|
||||
return "input";
|
||||
} else if (isOutput()) {
|
||||
return "output";
|
||||
} else if (isInteger()) {
|
||||
return "integer";
|
||||
} else if (isTristate()) {
|
||||
return "tri";
|
||||
} else if (varType()==AstVarType::WIRE) {
|
||||
return "wire";
|
||||
} else {
|
||||
return "reg";
|
||||
return dtypep()->name();
|
||||
}
|
||||
}
|
||||
|
||||
string AstVar::cType() const {
|
||||
if (widthMin() == 1) {
|
||||
return "bool";
|
||||
string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
AstBasicDType* bdtypep = basicp();
|
||||
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
|
||||
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
||||
arg += "const char*";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||
arg += "const VerilatedScope*";
|
||||
} else if (strtype) {
|
||||
if (isInOnly()) arg += "const ";
|
||||
arg += "string";
|
||||
} else if (widthMin() <= 8) {
|
||||
arg += "CData";
|
||||
} else if (widthMin() <= 16) {
|
||||
arg += "SData";
|
||||
} else if (widthMin() <= VL_WORDSIZE) {
|
||||
return "uint32_t";
|
||||
arg += "IData";
|
||||
} else if (isQuad()) {
|
||||
arg += "QData";
|
||||
} else if (isWide()) {
|
||||
return "uint32_t"; // []'s added later
|
||||
} else {
|
||||
return "uint64_t";
|
||||
arg += "WData"; // []'s added later
|
||||
}
|
||||
if (isWide() && !strtype) {
|
||||
arg += " (& "+name();
|
||||
arg += ")["+cvtToStr(widthWords())+"]";
|
||||
} else {
|
||||
if (isOutput() || (strtype && isInput())) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::vlEnumType() const {
|
||||
string arg;
|
||||
AstBasicDType* bdtypep = basicp();
|
||||
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
|
||||
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
||||
return "VLVT_PTR";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||
return "VLVT_PTR";
|
||||
} else if (strtype) {
|
||||
arg += "VLVT_STRING";
|
||||
} else if (widthMin() <= 8) {
|
||||
arg += "VLVT_UINT8";
|
||||
} else if (widthMin() <= 16) {
|
||||
arg += "VLVT_UINT16";
|
||||
} else if (widthMin() <= VL_WORDSIZE) {
|
||||
arg += "VLVT_UINT32";
|
||||
} else if (isQuad()) {
|
||||
arg += "VLVT_UINT64";
|
||||
} else if (isWide()) {
|
||||
arg += "VLVT_WDATA";
|
||||
}
|
||||
// else return "VLVT_UNKNOWN"
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::vlEnumDir() const {
|
||||
if (isInout()) {
|
||||
return "VLVD_INOUT";
|
||||
} else if (isInOnly()) {
|
||||
return "VLVD_IN";
|
||||
} else if (isOutOnly()) {
|
||||
return "VLVD_OUT";
|
||||
} else {
|
||||
return "VLVD_NODIR";
|
||||
}
|
||||
}
|
||||
|
||||
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (isWide() && isInOnly()) arg += "const ";
|
||||
if (widthMin() == 1) {
|
||||
arg += "bool";
|
||||
} else if (widthMin() <= VL_WORDSIZE) {
|
||||
arg += "uint32_t";
|
||||
} else if (isWide()) {
|
||||
arg += "uint32_t"; // []'s added later
|
||||
} else {
|
||||
arg += "uint64_t";
|
||||
}
|
||||
if (isWide()) {
|
||||
if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
|
||||
arg += " (& "+name();
|
||||
arg += ")["+cvtToStr(widthWords())+"]";
|
||||
} else {
|
||||
if (isOutput() && !forReturn) arg += "&";
|
||||
if (named) arg += " "+name();
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (!basicp()) arg = "UNKNOWN";
|
||||
if (isWide()) v3error("Unsupported: DPI functions with vectored outputs > 32-bits");
|
||||
if (basicp()->isBitLogic()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
} else {
|
||||
if (forReturn) {
|
||||
arg = "svBitVecVal";
|
||||
} else if (isInOnly()) {
|
||||
arg = "const svBitVecVal*";
|
||||
} else {
|
||||
arg = "svBitVecVal*";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
arg = basicp()->keyword().dpiType();
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
}
|
||||
if (named) arg += " "+name();
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::scType() const {
|
||||
@@ -134,32 +242,84 @@ string AstVar::scType() const {
|
||||
}
|
||||
}
|
||||
|
||||
AstRange* AstVar::arrayp(int dimension) const {
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
if ((dimension--)==0) return arrayp;
|
||||
AstNodeDType* AstVar::dtypeDimensionp(int dimension) const {
|
||||
// dimension passed from AstArraySel::dimension
|
||||
// Dimension 0 means the VAR itself, 1 is the closest SEL to the AstVar,
|
||||
// which is the lowest in the dtype list.
|
||||
// ref order: a[1][2][3][4]
|
||||
// Created as: reg [4] a [1][2][3];
|
||||
// *or* reg a [1][2][3][4];
|
||||
// // The bit select is optional; used only if "leftover" []'s
|
||||
// SEL: SEL4(SEL3(SEL2(SEL1(VARREF0 a))))
|
||||
// DECL: VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (DT RANGE3))))
|
||||
// *or* VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (ARRAYSEL3 (DT))))
|
||||
// SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0
|
||||
int dim = 0;
|
||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
if ((dim++)==dimension) {
|
||||
return dtypep;
|
||||
}
|
||||
dtypep = adtypep->dtypep();
|
||||
continue;
|
||||
}
|
||||
else if (AstBasicDType* adtypep = dtypep->castBasicDType()) {
|
||||
// AstBasicDType - nothing below, return null
|
||||
if (adtypep->rangep()) {
|
||||
if ((dim++) == dimension) {
|
||||
return adtypep;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// Node no ->next in loop; use continue where necessary
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AstVar::arrayDimensions() const {
|
||||
int entries=0;
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
entries++;
|
||||
uint32_t AstVar::arrayElements() const {
|
||||
uint32_t entries=1;
|
||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
entries *= adtypep->elementsConst();
|
||||
dtypep = adtypep->dtypep();
|
||||
}
|
||||
else {
|
||||
// AstBasicDType - nothing below, 1
|
||||
break;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
uint32_t AstVar::arrayElements() const {
|
||||
uint32_t entries=1;
|
||||
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
entries *= arrayp->elementsConst();
|
||||
pair<uint32_t,uint32_t> AstVar::dimensions() const {
|
||||
// How many array dimensions (packed,unpacked) does this Var have?
|
||||
uint32_t packed = 0;
|
||||
uint32_t unpacked = 0;
|
||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
if (adtypep->isPacked()) packed += 1;
|
||||
else unpacked += 1;
|
||||
dtypep = adtypep->dtypep();
|
||||
}
|
||||
else {
|
||||
// AstBasicDType - nothing below, 1
|
||||
break;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
return make_pair(packed, unpacked);
|
||||
}
|
||||
|
||||
// Special operators
|
||||
int AstArraySel::dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
|
||||
// Only called after V3Param; so only ArraySel's need to be recursed
|
||||
int AstArraySel::dimension(AstNode* nodep) {
|
||||
// How many dimensions is this reference from the base variable?
|
||||
// nodep is typically the fromp() of a select; thus the first select
|
||||
// is selecting from the entire variable type - effectively dimension 0.
|
||||
// Dimension passed to AstVar::dtypeDimensionp; see comments there
|
||||
int dim = 0;
|
||||
while (nodep) {
|
||||
if (nodep->castNodeSel()) { dim++; nodep=nodep->castNodeSel()->fromp(); continue; }
|
||||
@@ -197,16 +357,46 @@ bool AstScope::broken() const {
|
||||
void AstScope::cloneRelink() {
|
||||
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep()->castScope();
|
||||
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep()->castCell();
|
||||
if (m_modp && ((AstNode*)m_modp)->clonep()) ((AstNode*)m_modp)->clonep()->castModule();
|
||||
if (m_modp && ((AstNode*)m_modp)->clonep()) ((AstNode*)m_modp)->clonep()->castNodeModule();
|
||||
}
|
||||
|
||||
string AstScope::nameDotless() const {
|
||||
string dotless = shortName();
|
||||
string out = shortName();
|
||||
string::size_type pos;
|
||||
while ((pos=dotless.find(".")) != string::npos) {
|
||||
dotless.replace(pos, 1, "__");
|
||||
while ((pos=out.find(".")) != string::npos) {
|
||||
out.replace(pos, 1, "__");
|
||||
}
|
||||
return dotless;
|
||||
return out;
|
||||
}
|
||||
|
||||
string AstScopeName::scopePrettyName() const {
|
||||
string out;
|
||||
for (AstText* textp=scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
out += textp->text();
|
||||
}
|
||||
// TOP will be replaced by top->name()
|
||||
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
||||
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
|
||||
if (out.substr(0,1) == ".") out.replace(0,1,"");
|
||||
return AstNode::prettyName(out);
|
||||
}
|
||||
|
||||
string AstScopeName::scopeSymName() const {
|
||||
string out;
|
||||
for (AstText* textp=scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
out += textp->text();
|
||||
}
|
||||
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
||||
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
|
||||
if (out.substr(0,1) == ".") out.replace(0,1,"");
|
||||
string::size_type pos;
|
||||
while ((pos=out.find(".")) != string::npos) {
|
||||
out.replace(pos, 1, "__");
|
||||
}
|
||||
while ((pos=out.find("__DOT__")) != string::npos) {
|
||||
out.replace(pos, 7, "__");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool AstSenTree::hasClocked() {
|
||||
@@ -315,10 +505,23 @@ void AstNode::dump(ostream& os) {
|
||||
if (name()!="") os<<" "<<AstNode::quoteName(name());
|
||||
}
|
||||
|
||||
void AstArrayDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (isPacked()) str<<" [PACKED]";
|
||||
}
|
||||
void AstArraySel::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
|
||||
}
|
||||
void AstAttrOf::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" ["<<attrType().ascii()<<"]";
|
||||
}
|
||||
void AstBasicDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" ["<<keyword().ascii()<<"]";
|
||||
if (implicit()) str<<" [IMPLICIT]";
|
||||
}
|
||||
void AstCast::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" sz"<<size();
|
||||
@@ -336,6 +539,18 @@ void AstDisplay::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
//str<<" "<<displayType().ascii();
|
||||
}
|
||||
void AstJumpGo::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" -> ";
|
||||
if (labelp()) { labelp()->dump(str); }
|
||||
else { str<<"%Error:UNLINKED"; }
|
||||
}
|
||||
void AstEnumItemRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" -> ";
|
||||
if (itemp()) { itemp()->dump(str); }
|
||||
else { str<<"UNLINKED"; }
|
||||
}
|
||||
void AstPin::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }
|
||||
@@ -346,6 +561,11 @@ void AstRange::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (littleEndian()) str<<" [LITTLE]";
|
||||
}
|
||||
void AstRefDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (defp()) { str<<" -> "; defp()->dump(str); }
|
||||
else { str<<" -> UNLINKED"; }
|
||||
}
|
||||
void AstVarXRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (lvalue()) str<<" [LV] => ";
|
||||
@@ -356,12 +576,16 @@ void AstVarXRef::dump(ostream& str) {
|
||||
else if (varp()) { varp()->dump(str); }
|
||||
else { str<<"UNLINKED"; }
|
||||
}
|
||||
void AstModule::dump(ostream& str) {
|
||||
void AstNodeModule::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" L"<<level();
|
||||
if (modPublic()) str<<" [P]";
|
||||
if (inLibrary()) str<<" [LIB]";
|
||||
}
|
||||
void AstPackageImport::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" -> "<<packagep();
|
||||
}
|
||||
void AstVarScope::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (isCircular()) str<<" [CIRC]";
|
||||
@@ -422,6 +646,10 @@ void AstNodeFTaskRef::dump(ostream& str) {
|
||||
void AstNodeFTask::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (taskPublic()) str<<" [PUBLIC]";
|
||||
if (prototype()) str<<" [PROTOTYPE]";
|
||||
if (dpiImport()) str<<" [DPII]";
|
||||
if (dpiExport()) str<<" [DPIX]";
|
||||
if ((dpiImport() || dpiExport()) && cname()!=name()) str<<" [c="<<cname()<<"]";
|
||||
}
|
||||
void AstBegin::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
@@ -448,6 +676,17 @@ void AstTraceInc::dump(ostream& str) {
|
||||
if (declp()) { declp()->dump(str); }
|
||||
else { str<<"%Error:UNLINKED"; }
|
||||
}
|
||||
void AstNodeText::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
string out = text();
|
||||
string::size_type pos;
|
||||
if ((pos = out.find("\n")) != string::npos) {
|
||||
out.erase(pos,out.length()-pos);
|
||||
out += "...";
|
||||
}
|
||||
str<<" \""<<out<<"\"";
|
||||
}
|
||||
|
||||
void AstCFile::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (source()) str<<" [SRC]";
|
||||
@@ -463,4 +702,8 @@ void AstCCall::dump(ostream& str) {
|
||||
void AstCFunc::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (slow()) str<<" [SLOW]";
|
||||
if (pure()) str<<" [PURE]";
|
||||
if (dpiImport()) str<<" [DPII]";
|
||||
if (dpiExport()) str<<" [DPIX]";
|
||||
if (dpiExportWrapper()) str<<" [DPIXWR]";
|
||||
}
|
||||
|
||||
+887
-233
File diff suppressed because it is too large
Load Diff
+21
-52
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -48,11 +48,12 @@
|
||||
class BeginVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_repeatNum; // Repeat counter
|
||||
int m_ifDepth; // Current if depth
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -62,7 +63,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
m_repeatNum = 0;
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -135,54 +136,6 @@ private:
|
||||
m_modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFor* nodep, AstNUser*) {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// FOR(init,cond,assign,body) -> init,WHILE(cond) { body, assign }
|
||||
AstNode* initsp = nodep->initsp(); if (initsp) initsp->unlinkFrBackWithNext();
|
||||
AstNode* condp = nodep->condp(); if (condp) condp->unlinkFrBackWithNext();
|
||||
AstNode* incsp = nodep->incsp(); if (incsp) incsp->unlinkFrBackWithNext();
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(incsp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
new AstRange(nodep->fileline(), countp->width()-1, 0));
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
countp);
|
||||
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* condp;
|
||||
if (countp->isSigned()) {
|
||||
condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
} else {
|
||||
condp = new AstGt (nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
}
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(decp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Inline
|
||||
@@ -190,7 +143,7 @@ private:
|
||||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_namedScope)));
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_namedScope));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -200,6 +153,21 @@ private:
|
||||
// any BEGINs, but V3Coverage adds them all under the module itself.
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
// VISITORS - LINT CHECK
|
||||
virtual void visit(AstIf* nodep, AstNUser*) { // Note not AstNodeIf; other types don't get covered
|
||||
// Check IFDEPTH warning - could be in other transform files if desire
|
||||
int prevIfDepth = m_ifDepth;
|
||||
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
|
||||
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
|
||||
m_ifDepth = -1;
|
||||
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
|
||||
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
|
||||
nodep->fileline()->warnOn(V3ErrorCode::IFDEPTH, false); // Warn only once
|
||||
m_ifDepth = -1;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
m_ifDepth = prevIfDepth;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
@@ -209,6 +177,7 @@ public:
|
||||
m_modp = NULL;
|
||||
m_ftaskp = NULL;
|
||||
m_repeatNum = 0;
|
||||
m_ifDepth = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~BeginVisitor() {}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -76,9 +76,9 @@ private:
|
||||
// Compute
|
||||
int likeness = ifLikely - ifUnlikely - (elseLikely - elseUnlikely);
|
||||
if (likeness>0) {
|
||||
nodep->branchPred(AstBranchPred::LIKELY);
|
||||
nodep->branchPred(AstBranchPred::BP_LIKELY);
|
||||
} else if (likeness<0) {
|
||||
nodep->branchPred(AstBranchPred::UNLIKELY);
|
||||
nodep->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
} // else leave unknown
|
||||
}
|
||||
m_likely = lastLikely;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+25
-1
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -52,6 +52,7 @@ private:
|
||||
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
|
||||
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
|
||||
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
|
||||
static const int FLAG_UNDER_NOW = 0x10; // Is in tree as parent of current node
|
||||
public:
|
||||
// METHODS
|
||||
static void deleted(const AstNode* nodep) {
|
||||
@@ -74,6 +75,15 @@ public:
|
||||
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
|
||||
}
|
||||
}
|
||||
static void setUnder(const AstNode* nodep, bool flag) {
|
||||
// Called by BrokenCheckVisitor when each node entered/exited
|
||||
if (!okIfLinkedTo(nodep)) return;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter!=s_nodes.end()) {
|
||||
iter->second &= ~FLAG_UNDER_NOW;
|
||||
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||
}
|
||||
}
|
||||
static void addInTree(AstNode* nodep, bool linkable) {
|
||||
#ifndef VL_LEAK_CHECKS
|
||||
if (!linkable) return; // save some time, else the map will get huge!
|
||||
@@ -111,6 +121,14 @@ public:
|
||||
if (!(iter->second & FLAG_LINKABLE)) return false;
|
||||
return true;
|
||||
}
|
||||
static bool okIfBelow(const AstNode* nodep) {
|
||||
// Must be linked to and below current node
|
||||
if (!okIfLinkedTo(nodep)) return false;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) return false;
|
||||
if (!(iter->second & FLAG_UNDER_NOW)) return false;
|
||||
return true;
|
||||
}
|
||||
static void prepForTree() {
|
||||
#ifndef VL_LEAK_CHECKS
|
||||
s_nodes.clear();
|
||||
@@ -152,6 +170,10 @@ bool AstNode::brokeExists() const {
|
||||
// Called by node->broken() routines to do table lookup
|
||||
return BrokenTable::okIfLinkedTo(this);
|
||||
}
|
||||
bool AstNode::brokeExistsAbove() const {
|
||||
// Called by node->broken() routines to do table lookup
|
||||
return BrokenTable::okIfBelow(this);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -180,6 +202,7 @@ public:
|
||||
class BrokenCheckVisitor : public AstNVisitor {
|
||||
private:
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
BrokenTable::setUnder(nodep,true);
|
||||
if (nodep->broken()) {
|
||||
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
|
||||
}
|
||||
@@ -192,6 +215,7 @@ private:
|
||||
}
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
BrokenTable::setUnder(nodep,false);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+10
-7
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -67,6 +67,9 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeCase* nodep, AstNUser*) {
|
||||
if (nodep->castCase() && nodep->castCase()->casex()) {
|
||||
nodep->v3warn(CASEX,"Suggest casez (with ?'s) in place of casex (with X's)");
|
||||
}
|
||||
// Detect multiple defaults
|
||||
bool hitDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
@@ -133,7 +136,7 @@ private:
|
||||
// Per-CASE
|
||||
int m_caseWidth; // Width of valueItems
|
||||
int m_caseItems; // Number of caseItem unique values
|
||||
int m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
AstNode* m_valueItem[1<<CASE_OVERLAP_WIDTH]; // For each possible value, the case branch we need
|
||||
|
||||
// METHODS
|
||||
@@ -308,7 +311,7 @@ private:
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
if (!itemp->condsp()) {
|
||||
// Default clause. Just make true, we'll optimize it away later
|
||||
itemp->condsp(new AstConst(itemp->fileline(), V3Number(itemp->fileline(), 1,1)));
|
||||
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
|
||||
hadDefault = true;
|
||||
} else {
|
||||
// Expressioned clause
|
||||
@@ -326,8 +329,8 @@ private:
|
||||
icondp->deleteTree(); icondp=NULL; iconstp=NULL;
|
||||
// For simplicity, make expression that is not equal, and let later
|
||||
// optimizations remove it
|
||||
and1p = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,0));
|
||||
and2p = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,1));
|
||||
and1p = new AstConst(itemp->fileline(), AstConst::LogicFalse());
|
||||
and2p = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
} else if (iconstp && iconstp->num().isFourState()
|
||||
&& (nodep->casex() || nodep->casez())) {
|
||||
V3Number nummask (itemp->fileline(), iconstp->width());
|
||||
@@ -361,7 +364,7 @@ private:
|
||||
// If there was no default, add a empty one, this greatly simplifies below code
|
||||
// and constant propagation will just eliminate it for us later.
|
||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), V3Number(nodep->fileline(),1,1)),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()),
|
||||
NULL));
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout," _comp_COND: ");
|
||||
@@ -398,7 +401,7 @@ private:
|
||||
AstNode* itemexprp = ifexprp; ifexprp=NULL;
|
||||
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
|
||||
itemexprp->deleteTree(); itemexprp=NULL;
|
||||
itemexprp = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,1));
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
|
||||
if (itemnextp) itemnextp->addElsesp(newp);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+738
@@ -0,0 +1,738 @@
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Clock Domain Crossing Lint
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Cdc's Transformations:
|
||||
//
|
||||
// Create V3Graph-ish graph
|
||||
// Find all negedge reset flops
|
||||
// Trace back to previous flop
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Cdc.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcBaseVisitor : public AstNVisitor {
|
||||
public:
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Graph support classes
|
||||
|
||||
class CdcEitherVertex : public V3GraphVertex {
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstSenTree* m_srcDomainp;
|
||||
AstSenTree* m_dstDomainp;
|
||||
bool m_srcDomainSet;
|
||||
bool m_dstDomainSet;
|
||||
bool m_asyncPath;
|
||||
public:
|
||||
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
|
||||
: V3GraphVertex(graphp), m_scopep(scopep), m_nodep(nodep)
|
||||
, m_srcDomainp(NULL), m_dstDomainp(NULL)
|
||||
, m_srcDomainSet(false), m_dstDomainSet(false)
|
||||
, m_asyncPath(false) {}
|
||||
virtual ~CdcEitherVertex() {}
|
||||
// Accessors
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
AstSenTree* srcDomainp() const { return m_srcDomainp; }
|
||||
void srcDomainp(AstSenTree* nodep) { m_srcDomainp = nodep; }
|
||||
bool srcDomainSet() const { return m_srcDomainSet; }
|
||||
void srcDomainSet(bool flag) { m_srcDomainSet = flag; }
|
||||
AstSenTree* dstDomainp() const { return m_dstDomainp; }
|
||||
void dstDomainp(AstSenTree* nodep) { m_dstDomainp = nodep; }
|
||||
bool dstDomainSet() const { return m_dstDomainSet; }
|
||||
void dstDomainSet(bool flag) { m_dstDomainSet = flag; }
|
||||
bool asyncPath() const { return m_asyncPath; }
|
||||
void asyncPath(bool flag) { m_asyncPath = flag; }
|
||||
};
|
||||
|
||||
class CdcVarVertex : public CdcEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
int m_cntAsyncRst;
|
||||
bool m_fromFlop;
|
||||
public:
|
||||
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: CdcEitherVertex(graphp, scopep, varScp), m_varScp(varScp), m_cntAsyncRst(0), m_fromFlop(false) {}
|
||||
virtual ~CdcVarVertex() {}
|
||||
// Accessors
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const { return (cvtToStr((void*)m_varScp)+" "+varScp()->name()); }
|
||||
virtual string dotColor() const { return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; }
|
||||
int cntAsyncRst() const { return m_cntAsyncRst; }
|
||||
void cntAsyncRst(int flag) { m_cntAsyncRst=flag; }
|
||||
bool fromFlop() const { return m_fromFlop; }
|
||||
void fromFlop(bool flag) { m_fromFlop = flag; }
|
||||
};
|
||||
|
||||
class CdcLogicVertex : public CdcEitherVertex {
|
||||
bool m_hazard;
|
||||
bool m_isFlop;
|
||||
public:
|
||||
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
|
||||
: CdcEitherVertex(graphp,scopep,nodep), m_hazard(false), m_isFlop(false)
|
||||
{ srcDomainp(sensenodep); dstDomainp(sensenodep); }
|
||||
virtual ~CdcLogicVertex() {}
|
||||
// Accessors
|
||||
virtual string name() const { return (cvtToStr((void*)nodep())+"@"+scopep()->prettyName()); }
|
||||
virtual string dotColor() const { return hazard() ? "black" : "yellow"; }
|
||||
bool hazard() const { return m_hazard; }
|
||||
void setHazard(AstNode* nodep) { m_hazard = true; nodep->user3(true); }
|
||||
void clearHazard() { m_hazard = false; }
|
||||
bool isFlop() const { return m_isFlop; }
|
||||
void isFlop(bool flag) { m_isFlop = flag; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcDumpVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// {statement}Node::user3p -> bool, indicating not hazard
|
||||
ofstream* m_ofp; // Output file
|
||||
string m_prefix;
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
*m_ofp<<m_prefix;
|
||||
if (nodep->user3()) *m_ofp<<" %%";
|
||||
else *m_ofp<<" ";
|
||||
*m_ofp<<nodep->prettyTypeName()<<" "<<endl;
|
||||
string lastPrefix = m_prefix;
|
||||
m_prefix = lastPrefix + "1:";
|
||||
nodep->op1p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix + "2:";
|
||||
nodep->op2p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix + "3:";
|
||||
nodep->op3p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix + "4:";
|
||||
nodep->op4p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CdcDumpVisitor(AstNode* nodep, ofstream* ofp, const string& prefix) {
|
||||
m_ofp = ofp;
|
||||
m_prefix = prefix;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CdcDumpVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcWidthVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
int m_maxLineno;
|
||||
size_t m_maxFilenameLen;
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Keeping line+filename lengths separate is much faster than calling ascii().length()
|
||||
if (nodep->fileline()->lineno() >= m_maxLineno) {
|
||||
m_maxLineno = nodep->fileline()->lineno()+1;
|
||||
}
|
||||
if (nodep->fileline()->filename().length() >= m_maxFilenameLen) {
|
||||
m_maxFilenameLen = nodep->fileline()->filename().length()+1;
|
||||
}
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CdcWidthVisitor(AstNode* nodep) {
|
||||
m_maxLineno = 0;
|
||||
m_maxFilenameLen = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CdcWidthVisitor() {}
|
||||
// ACCESSORS
|
||||
int maxWidth() {
|
||||
size_t width=1;
|
||||
width += m_maxFilenameLen;
|
||||
width += 1; // The :
|
||||
width += cvtToStr(m_maxLineno).length();
|
||||
width += 1; // Final :
|
||||
return (int)width;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
class CdcVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet
|
||||
// AstVarScope::user2 -> bool Used in sensitivity list
|
||||
// {statement}Node::user1p -> CdcLogicVertex* for this statement
|
||||
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
|
||||
AstScope* m_scopep; // Current scope being processed
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstSenTree* m_domainp; // Current sentree
|
||||
bool m_inDly; // In delayed assign
|
||||
int m_inSenItem; // Number of senitems
|
||||
string m_ofFilename; // Output filename
|
||||
ofstream* m_ofp; // Output file
|
||||
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth; // Characters in longest fileline
|
||||
|
||||
// METHODS
|
||||
void iterateNewStmt(AstNode* nodep) {
|
||||
if (m_scopep) {
|
||||
UINFO(4," STMT "<<nodep<<endl);
|
||||
m_logicVertexp = new CdcLogicVertex(&m_graph, m_scopep, nodep, m_domainp);
|
||||
if (m_domainp && m_domainp->hasClocked()) { // To/from a flop
|
||||
m_logicVertexp->isFlop(true);
|
||||
m_logicVertexp->srcDomainp(m_domainp);
|
||||
m_logicVertexp->srcDomainSet(true);
|
||||
m_logicVertexp->dstDomainp(m_domainp);
|
||||
m_logicVertexp->dstDomainSet(true);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
m_logicVertexp = NULL;
|
||||
|
||||
if (0 && debug()>=9) {
|
||||
UINFO(9, "Trace Logic:\n");
|
||||
nodep->dumpTree(cout, "-log1: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdcVarVertex* makeVarVertex(AstVarScope* varscp) {
|
||||
CdcVarVertex* vertexp = (CdcVarVertex*)(varscp->user1p());
|
||||
if (!vertexp) {
|
||||
UINFO(6,"New vertex "<<varscp<<endl);
|
||||
vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp);
|
||||
varscp->user1p(vertexp);
|
||||
if (varscp->varp()->isUsedClock()) {}
|
||||
if (varscp->varp()->isPrimaryIO()) {
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are now
|
||||
// This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
|
||||
if (varscp->varp()->isInput()) {
|
||||
new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1);
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_inSenItem) {
|
||||
varscp->user2(true); // It's like a clock...
|
||||
// TODO: In the future we could mark it here and do normal clock tree glitch checks also
|
||||
} else if (varscp->user2()) { // It was detected in a sensitivity list earlier
|
||||
// And now it's used as logic. So must be a reset.
|
||||
vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1);
|
||||
}
|
||||
return vertexp;
|
||||
}
|
||||
|
||||
void warnAndFile(AstNode* nodep, V3ErrorCode code, const string& msg) {
|
||||
static bool told_file = false;
|
||||
nodep->v3warnCode(code,msg);
|
||||
if (!told_file) {
|
||||
told_file = 1;
|
||||
cerr<<V3Error::msgPrefix()<<" See details in "<<m_ofFilename<<endl;
|
||||
}
|
||||
*m_ofp<<"%Warning-"<<code.ascii()<<": "<<nodep->fileline()<<" "<<msg<<endl;
|
||||
}
|
||||
|
||||
void setNodeHazard(AstNode* nodep) {
|
||||
// Need to not clear if warnings are off (rather than when report it)
|
||||
// as bypassing this warning may turn up another path that isn't warning off'ed.
|
||||
if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though)
|
||||
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
|
||||
UINFO(9,"Set hazard "<<nodep<<endl);
|
||||
m_logicVertexp->setHazard(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string spaces(int level) { string out; while (level--) out+=" "; return out; }
|
||||
|
||||
string pad(unsigned column, const string& in) {
|
||||
string out = in;
|
||||
while (out.length()<column) out += ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
void analyze() {
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
//if (debug()>6) m_graph.dump();
|
||||
if (debug()>6) m_graph.dumpDotFilePrefixed("cdc_pre");
|
||||
m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
|
||||
m_graph.dumpDotFilePrefixed("cdc_simp");
|
||||
//
|
||||
analyzeReset();
|
||||
}
|
||||
|
||||
int filelineWidth() {
|
||||
if (!m_filelineWidth) {
|
||||
CdcWidthVisitor visitor (v3Global.rootp());
|
||||
m_filelineWidth = visitor.maxWidth();
|
||||
}
|
||||
return m_filelineWidth;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// RESET REPORT
|
||||
|
||||
void analyzeReset() {
|
||||
// Find all async reset wires, and trace backwards
|
||||
// userClearVertices is very slow, so we use a generation count instead
|
||||
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (vvertexp->cntAsyncRst()) {
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
UINFO(9, " Trace One async: "<<vvertexp<<endl);
|
||||
// Twice, as we need to detect, then propagate
|
||||
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
|
||||
if (markp) { // Mark is non-NULL if something bad on this path
|
||||
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
traceAsyncRecurse(vvertexp, true);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
dumpAsync(vvertexp, markp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
|
||||
// Return vertex of any hazardous stuff attached, or NULL if OK
|
||||
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
CdcEitherVertex* mark_outp = NULL;
|
||||
UINFO(9," Trace: "<<vertexp<<endl);
|
||||
|
||||
// Clear out in prep for marking next path
|
||||
if (!mark) vertexp->asyncPath(false);
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Any logic considered bad, at the moment, anyhow
|
||||
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
|
||||
// And keep tracing back so the user can understand what's up
|
||||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
if (mark) vvertexp->asyncPath(true);
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryIn()) {
|
||||
// Show the source "input" statement if it exists
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Also ok if from flop, but partially trace the flop so more obvious to users
|
||||
if (vvertexp->fromFlop()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
|
||||
if (submarkp && !mark_outp) mark_outp = submarkp;
|
||||
}
|
||||
|
||||
if (mark) vertexp->asyncPath(true);
|
||||
return mark_outp;
|
||||
}
|
||||
|
||||
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
|
||||
AstNode* nodep = vertexp->varScp();
|
||||
*m_ofp<<"\n";
|
||||
*m_ofp<<"\n";
|
||||
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top();
|
||||
if (!eToVertexp) targetp = eToVertexp;
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (vvertexp->isFlop()) {
|
||||
targetp = eToVertexp;
|
||||
break;
|
||||
}
|
||||
} // else it might be random logic that's not relevant
|
||||
}
|
||||
warnAndFile(markp->nodep(),V3ErrorCode::CDCRSTLOGIC,"Logic in path that feeds async reset, via signal: "+nodep->prettyName());
|
||||
dumpAsyncRecurse(targetp, "", " ",0);
|
||||
}
|
||||
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep, int level) {
|
||||
// level=0 is special, indicates to dump destination flop
|
||||
// Return true if printed anything
|
||||
// If mark, also mark the output even if nothing hazardous below
|
||||
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
if (!vertexp->asyncPath() && level!=0) return false; // Not part of path
|
||||
|
||||
// Other logic in the path
|
||||
string cont = prefix+sep;
|
||||
string nextsep = " ";
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level+1)) {
|
||||
nextsep = " | ";
|
||||
}
|
||||
}
|
||||
|
||||
// Dump single variable/logic block
|
||||
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
|
||||
AstNode* nodep = vertexp->nodep();
|
||||
string front = pad(filelineWidth(),nodep->fileline()->ascii()+":")+" "+prefix+" +- ";
|
||||
if (nodep->castVarScope()) {
|
||||
*m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
|
||||
}
|
||||
else {
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" +- ", filelineWidth(),
|
||||
vertexp->srcDomainp(), true);
|
||||
if (debug()) {
|
||||
CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: ");
|
||||
}
|
||||
}
|
||||
|
||||
nextsep = " | ";
|
||||
if (level) *m_ofp<<V3OutFile::indentSpaces(filelineWidth())<<" "<<prefix<<nextsep<<"\n";
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Now that we've printed a path with this hazard, don't bother to print any more
|
||||
// Otherwise, we'd get a path for almost every destination flop
|
||||
vvertexp->clearHazard();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// EDGE REPORTS
|
||||
|
||||
void edgeReport() {
|
||||
// Make report of all signal names and what clock edges they have
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
|
||||
// Trace all sources and sinks
|
||||
for (int traceDests=0; traceDests<2; ++traceDests) {
|
||||
UINFO(9, " Trace Direction "<<(traceDests?"dst":"src")<<endl);
|
||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
UINFO(9, " Trace One edge: "<<vvertexp<<endl);
|
||||
edgeDomainRecurse(vvertexp, traceDests, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc_edges.txt";
|
||||
const auto_ptr<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
*ofp<<"Edge Report for "<<v3Global.opt.prefix()<<endl;
|
||||
|
||||
deque<string> report; // Sort output by name
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (1) { // varp->isPrimaryIO()
|
||||
const char* whatp = "wire";
|
||||
if (varp->isPrimaryIO()) whatp = (varp->isInout()?"inout":varp->isInput()?"input":"output");
|
||||
|
||||
ostringstream os;
|
||||
os.setf(ios::left);
|
||||
os<<" "<<setw(8)<<whatp;
|
||||
os<<" "<<setw(40)<<vvertexp->varScp()->prettyName();
|
||||
os<<" SRC=";
|
||||
if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
|
||||
os<<" DST=";
|
||||
if (vvertexp->dstDomainp()) V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
|
||||
os<<setw(0);
|
||||
os<<endl;
|
||||
report.push_back(os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
sort(report.begin(), report.end());
|
||||
for (deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
|
||||
*ofp << *it;
|
||||
}
|
||||
}
|
||||
|
||||
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
||||
// Scan back to inputs/outputs, flops, and compute clock domain information
|
||||
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
|
||||
if (vertexp->user()>=m_userGeneration) return; // Mid-Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
// Variables from flops already are domained
|
||||
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed
|
||||
|
||||
typedef set<AstSenTree*> SenSet;
|
||||
SenSet senouts; // List of all sensitivities for new signal
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (vvertexp) {} // Unused
|
||||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
// If primary I/O, give it domain of the input
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (varp->isPrimaryIO() && varp->isInput() && !traceDests) {
|
||||
senouts.insert(new AstSenTree(varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
}
|
||||
}
|
||||
|
||||
// Now combine domains of sources/dests
|
||||
if (traceDests) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top();
|
||||
edgeDomainRecurse(eToVertexp, traceDests, level+1);
|
||||
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
|
||||
}
|
||||
} else {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
edgeDomainRecurse(eFromVertexp, traceDests, level+1);
|
||||
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert list of senses into one sense node
|
||||
AstSenTree* senoutp = NULL;
|
||||
bool senedited = false;
|
||||
for (SenSet::iterator it=senouts.begin(); it!=senouts.end(); ++it) {
|
||||
if (!senoutp) senoutp = *it;
|
||||
else {
|
||||
if (!senedited) {
|
||||
senedited = true;
|
||||
senoutp = senoutp->cloneTree(true);
|
||||
}
|
||||
senoutp->addSensesp((*it)->sensesp()->cloneTree(true));
|
||||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
if (senedited) {
|
||||
senoutp = V3Const::constifyExpensiveEdit(senoutp)->castSenTree();
|
||||
}
|
||||
if (traceDests) {
|
||||
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->dstDomainp(senoutp);
|
||||
if (debug()>=9) {
|
||||
UINFO(9,spaces(level)+" Tracedst "<<vertexp);
|
||||
if (senoutp) V3EmitV::verilogForTree(senoutp, cout); cout<<endl;
|
||||
}
|
||||
} else {
|
||||
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->srcDomainp(senoutp);
|
||||
if (debug()>=9) {
|
||||
UINFO(9,spaces(level)+" Tracesrc "<<vertexp);
|
||||
if (senoutp) V3EmitV::verilogForTree(senoutp, cout); cout<<endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep, AstNUser*) {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4," BLOCK "<<nodep<<endl);
|
||||
AstNode::user2ClearTree();
|
||||
m_domainp = nodep->sensesp();
|
||||
if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
m_domainp = NULL;
|
||||
AstNode::user2ClearTree();
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
||||
if (m_scopep) {
|
||||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
CdcVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
// We use weight of one; if we ref the var more than once, when we simplify,
|
||||
// the weight will increase
|
||||
if (nodep->lvalue()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
if (m_inDly) {
|
||||
varvertexp->fromFlop(true);
|
||||
varvertexp->srcDomainp(m_domainp);
|
||||
varvertexp->srcDomainSet(true);
|
||||
}
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep, AstNUser*) {
|
||||
m_inDly = true;
|
||||
nodep->iterateChildren(*this);
|
||||
m_inDly = false;
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
// Note we look at only AstSenItems, not AstSenGate's
|
||||
// The gating term of a AstSenGate is normal logic
|
||||
m_inSenItem = true;
|
||||
nodep->iterateChildren(*this);
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
// CDC doesn't care about public variables
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep, AstNUser*) {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is delt with as logic
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
|
||||
// Math that shouldn't cause us to clear hazard
|
||||
virtual void visit(AstConst* nodep, AstNUser*) { }
|
||||
virtual void visit(AstReplicate* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstConcat* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNot* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
if (!nodep->lsbp()->castConst()) setNodeHazard(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNodeSel* nodep, AstNUser*) {
|
||||
if (!nodep->bitp()->castConst()) setNodeHazard(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// Ignores
|
||||
virtual void visit(AstInitial* nodep, AstNUser*) { }
|
||||
virtual void visit(AstTraceInc* nodep, AstNUser*) { }
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) { }
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {
|
||||
setNodeHazard(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CdcVisitor(AstNode* nodep) {
|
||||
m_logicVertexp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_modp = NULL;
|
||||
m_domainp = NULL;
|
||||
m_inDly = false;
|
||||
m_inSenItem = 0;
|
||||
m_userGeneration = 0;
|
||||
m_filelineWidth = 0;
|
||||
|
||||
// Make report of all signal names and what clock edges they have
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
|
||||
m_ofp = V3File::new_ofstream(filename);
|
||||
if (m_ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
m_ofFilename = filename;
|
||||
*m_ofp<<"CDC Report for "<<v3Global.opt.prefix()<<endl;
|
||||
*m_ofp<<"Each dump below traces logic from inputs/source flops to destination flop(s).\n";
|
||||
*m_ofp<<"First source logic is listed, then a variable that logic generates,\n";
|
||||
*m_ofp<<"repeating recursively forwards to the destination flop(s).\n";
|
||||
*m_ofp<<"%% Indicates the operator considered potentially hazardous.\n";
|
||||
|
||||
nodep->accept(*this);
|
||||
analyze();
|
||||
//edgeReport(); // Not useful at the moment
|
||||
|
||||
if (0) { *m_ofp<<"\nDBG-test-dumper\n"; V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ",40,NULL,true); *m_ofp<<endl; }
|
||||
}
|
||||
virtual ~CdcVisitor() {
|
||||
if (m_ofp) { delete m_ofp; m_ofp = NULL; }
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
void V3Cdc::cdcAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CdcVisitor visitor (nodep);
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity block domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3CDC_H_
|
||||
#define _V3CDC_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Cdc {
|
||||
public:
|
||||
static void cdcAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+6
-7
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstModule* m_topModp; // Top module
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp; // Change function we're building
|
||||
|
||||
@@ -72,7 +72,7 @@ private:
|
||||
#endif
|
||||
AstVar* varp = vscp->varp();
|
||||
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
|
||||
if (varp->arraysp()) {
|
||||
if (!varp->dtypeSkipRefp()->castBasicDType()) {
|
||||
vscp->v3error("Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
|
||||
} else {
|
||||
string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
|
||||
@@ -99,7 +99,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
if (nodep->isTop()) {
|
||||
m_topModp = nodep;
|
||||
@@ -115,7 +115,7 @@ private:
|
||||
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
|
||||
m_scopetopp = scopep;
|
||||
// Create change detection function
|
||||
m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "bool");
|
||||
m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "IData");
|
||||
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_chgFuncp->symProlog(true);
|
||||
m_chgFuncp->declPrivate(true);
|
||||
@@ -128,8 +128,7 @@ private:
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||
if (nodep->isCircular()) {
|
||||
UINFO(8," CIRC "<<nodep<<endl);
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true);
|
||||
if (!nodep->user1Inc()) {
|
||||
genChangeDet(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+11
-10
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -52,10 +52,10 @@ private:
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// TYPES
|
||||
enum CleanState { UNKNOWN, CLEAN, DIRTY };
|
||||
enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp;
|
||||
AstNodeModule* m_modp;
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
}
|
||||
void computeCppWidth (AstNode* nodep) {
|
||||
if (!nodep->user2()) {
|
||||
if (nodep->castVar()) { // Don't want to change variable widths!
|
||||
if (nodep->castVar() || nodep->castNodeDType()) { // Don't want to change variable widths!
|
||||
setCppWidth(nodep, nodep->width(), nodep->width()); // set widthMin anyways so can see it later
|
||||
} else {
|
||||
setCppWidth(nodep, cppWidth(nodep), nodep->widthMin());
|
||||
@@ -93,15 +93,15 @@ private:
|
||||
}
|
||||
bool isClean(AstNode* nodep) {
|
||||
CleanState clstate = getCleanState(nodep);
|
||||
if (clstate==CLEAN) return true;
|
||||
if (clstate==DIRTY) return false;
|
||||
nodep->v3fatalSrc("Unknown clean state on node.");
|
||||
if (clstate==CS_CLEAN) return true;
|
||||
if (clstate==CS_DIRTY) return false;
|
||||
nodep->v3fatalSrc("Unknown clean state on node: "+nodep->prettyTypeName());
|
||||
return false;
|
||||
}
|
||||
void setClean(AstNode* nodep, bool isClean) {
|
||||
computeCppWidth (nodep); // Just to be sure it's in widthMin
|
||||
bool wholeUint = ((nodep->widthMin() % VL_WORDSIZE) == 0); //32,64,...
|
||||
setCleanState(nodep, ((isClean||wholeUint) ? CLEAN:DIRTY));
|
||||
setCleanState(nodep, ((isClean||wholeUint) ? CS_CLEAN:CS_DIRTY));
|
||||
}
|
||||
|
||||
// Operate on nodes
|
||||
@@ -160,7 +160,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
@@ -240,9 +240,10 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
insureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstNodePli* nodep, AstNUser*) {
|
||||
virtual void visit(AstSFormatF* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->exprsp());
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+2
-3
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2008-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2008-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -704,8 +704,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
if (debug()>=9) cout<<endl<<endl<<endl;
|
||||
UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
|
||||
if (nodep->user4()) return;
|
||||
nodep->user4(1);
|
||||
if (nodep->user4Inc()) return;
|
||||
|
||||
clear();
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+14
-16
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstTopScope* m_topScopep; // Current top scope
|
||||
AstScope* m_scopep; // Current scope
|
||||
AstActive* m_activep; // Current block
|
||||
@@ -85,8 +85,7 @@ private:
|
||||
AstVar* varp = vscp->varp();
|
||||
if (varp->width()!=1) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
|
||||
string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName());
|
||||
AstVar* newvarp
|
||||
= new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, NULL, NULL); // No range; 1 bit.
|
||||
AstVar* newvarp = new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, AstLogicPacked(), 1);
|
||||
newvarp->width(1,1);
|
||||
m_modp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
|
||||
@@ -105,7 +104,7 @@ private:
|
||||
AstVarScope* getCreateLocalVar(FileLine* fl, const string& name, AstVar* examplep, int width) {
|
||||
AstVar* newvarp;
|
||||
if (width) {
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, new AstRange(fl, width-1, 0));
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, AstLogicPacked(), width);
|
||||
} else {
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, examplep); // No range; 1 bit.
|
||||
}
|
||||
@@ -124,7 +123,7 @@ private:
|
||||
// LOWEDGE: ~var
|
||||
AstNode* newp = NULL;
|
||||
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
||||
if (nodep->edgeType()==AstEdgeType::POSEDGE) {
|
||||
if (nodep->edgeType()==AstEdgeType::ET_POSEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
@@ -132,23 +131,23 @@ private:
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
lastVscp, false)));
|
||||
} else if (nodep->edgeType()==AstEdgeType::NEGEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_NEGEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
} else if (nodep->edgeType()==AstEdgeType::BOTHEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_BOTHEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstXor(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
} else if (nodep->edgeType()==AstEdgeType::HIGHEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_HIGHEDGE) {
|
||||
newp = new AstVarRef(nodep->fileline(),
|
||||
clkvscp, false);
|
||||
} else if (nodep->edgeType()==AstEdgeType::LOWEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_LOWEDGE) {
|
||||
newp = new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
clkvscp, false));
|
||||
@@ -233,10 +232,9 @@ private:
|
||||
funcp->slow(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->entryPoint(true);
|
||||
funcp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline(),
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
m_scopep->addActivep(funcp);
|
||||
m_finalFuncp = funcp;
|
||||
}
|
||||
@@ -259,7 +257,7 @@ private:
|
||||
m_topScopep=NULL;
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
//UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_stableNum = 0;
|
||||
@@ -508,7 +506,7 @@ private:
|
||||
ifstmtp->addNext(new AstIf(fl,
|
||||
new AstLt (fl, new AstConst(fl, 100),
|
||||
new AstVarRef(fl, countVarp, false)),
|
||||
(new AstDisplay (fl, AstDisplayType::DISPLAY,
|
||||
(new AstDisplay (fl, AstDisplayType::DT_DISPLAY,
|
||||
"%%Error: Verilated model didn't converge", NULL, NULL))
|
||||
->addNext(new AstStop (fl)),
|
||||
NULL));
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+8
-4
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -72,6 +72,10 @@ protected:
|
||||
//***** optimization levels
|
||||
bool emptyFunctionDeletion() { return true; }
|
||||
bool duplicateFunctionCombine() { return true; }
|
||||
// Note this is disabled, it still needed work
|
||||
// Also repair it for DPI functions; when make __common need to insure proper
|
||||
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
|
||||
// get split between functions causing the text to have a danginling reference.
|
||||
bool statementCombine() { return false && duplicateFunctionCombine(); }
|
||||
};
|
||||
|
||||
@@ -101,7 +105,7 @@ public:
|
||||
if (callp->funcp() != oldfuncp) callp->v3fatalSrc("Call list broken, points to call w/different func");
|
||||
if (newfuncp) {
|
||||
AstCCall* newp = new AstCCall(callp, newfuncp);
|
||||
newp->argTypes(callp->argTypes());
|
||||
// Special new AstCCall form above transfers children of callp to newfuncp
|
||||
callp->replaceWith(newp);
|
||||
addCall(newp); // Fix the table
|
||||
} else { // Just deleting empty function
|
||||
@@ -189,7 +193,7 @@ private:
|
||||
typedef enum {STATE_IDLE, STATE_HASH, STATE_DUP} CombineState;
|
||||
V3Double0 m_statCombs; // Statistic tracking
|
||||
CombineState m_state; // Major state
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
@@ -393,7 +397,7 @@ private:
|
||||
// Required so that a module instantiating another can benefit from collapsing.
|
||||
nodep->iterateChildrenBackwards(*this);
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_modNFuncs = 0;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Configuration Files
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Config.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3ConfigLine {
|
||||
public:
|
||||
int m_lineno; // Line number to make change at
|
||||
V3ErrorCode m_code; // Error code
|
||||
bool m_on; // True to enaable message
|
||||
V3ConfigLine(V3ErrorCode code, int lineno, bool on)
|
||||
: m_lineno(lineno), m_code(code), m_on(on) {}
|
||||
~V3ConfigLine() {}
|
||||
inline bool operator< (const V3ConfigLine& rh) const {
|
||||
if (m_lineno<rh.m_lineno) return true;
|
||||
if (m_lineno>rh.m_lineno) return false;
|
||||
if (m_code<rh.m_code) return true;
|
||||
if (m_code>rh.m_code) return false;
|
||||
// Always turn "on" before "off" so that overlapping lines will end up finally with the error "off"
|
||||
return (m_on>rh.m_on);
|
||||
}
|
||||
};
|
||||
ostream& operator<<(ostream& os, V3ConfigLine rhs) { return os<<rhs.m_lineno<<", "<<rhs.m_code<<", "<<rhs.m_on; }
|
||||
|
||||
class V3ConfigIgnores {
|
||||
typedef multiset<V3ConfigLine> IgnLines; // list of {line,code,on}
|
||||
typedef map<string,IgnLines> IgnFiles; // {filename} => list of {line,code,on}
|
||||
|
||||
// MEMBERS
|
||||
string m_lastFilename; // Last filename looked up
|
||||
int m_lastLineno; // Last linenumber looked up
|
||||
|
||||
IgnLines::const_iterator m_lastIt; // Point with next linenumber > current line number
|
||||
IgnLines::const_iterator m_lastEnd; // Point with end()
|
||||
|
||||
IgnFiles m_ignWilds; // Ignores for each wildcarded filename
|
||||
IgnFiles m_ignFiles; // Ignores for each non-wildcarded filename
|
||||
|
||||
static V3ConfigIgnores s_singleton; // Singleton (not via local static, as that's slow)
|
||||
|
||||
V3ConfigIgnores() { m_lastLineno = -1; }
|
||||
~V3ConfigIgnores() {}
|
||||
|
||||
// METHODS
|
||||
inline IgnLines* findWilds(const string& wildname) {
|
||||
IgnFiles::iterator it = m_ignWilds.find(wildname);
|
||||
if (it != m_ignWilds.end()) {
|
||||
return &(it->second);
|
||||
} else {
|
||||
m_ignWilds.insert(make_pair(wildname, IgnLines()));
|
||||
it = m_ignWilds.find(wildname);
|
||||
return &(it->second);
|
||||
}
|
||||
}
|
||||
inline void absBuild(const string& filename) {
|
||||
// Given a filename, find all wildcard matches against it and build
|
||||
// hash with the specific filename. This avoids having to wildmatch
|
||||
// more than once against any filename.
|
||||
IgnFiles::iterator it = m_ignFiles.find(filename);
|
||||
if (it == m_ignFiles.end()) {
|
||||
// Haven't seen this filename before
|
||||
m_ignFiles.insert(make_pair(filename, IgnLines()));
|
||||
it = m_ignFiles.find(filename);
|
||||
// Make new list for this file of all matches
|
||||
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
|
||||
if (V3Options::wildmatch(filename.c_str(), fnit->first.c_str())) {
|
||||
for (IgnLines::iterator lit = fnit->second.begin(); lit != fnit->second.end(); ++lit) {
|
||||
it->second.insert(*lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_lastIt = it->second.begin();
|
||||
m_lastEnd = it->second.end();
|
||||
}
|
||||
|
||||
public:
|
||||
inline static V3ConfigIgnores& singleton() { return s_singleton; }
|
||||
|
||||
void addIgnore(V3ErrorCode code, string wildname, int lineno, bool on) {
|
||||
// Insert
|
||||
IgnLines* linesp = findWilds(wildname);
|
||||
UINFO(9,"config addIgnore "<<wildname<<":"<<lineno<<", "<<code<<", "<<on<<endl);
|
||||
linesp->insert(V3ConfigLine(code, lineno, on));
|
||||
// Flush the match cache, due to a change in the rules.
|
||||
m_ignFiles.clear();
|
||||
m_lastFilename = " ";
|
||||
}
|
||||
inline void applyIgnores(FileLine* filelinep) {
|
||||
// HOT routine, called each parsed token line
|
||||
if (m_lastLineno != filelinep->lineno()
|
||||
|| m_lastFilename != filelinep->filename()) {
|
||||
//UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
|
||||
if (VL_UNLIKELY(m_lastFilename != filelinep->filename())) {
|
||||
absBuild(filelinep->filename());
|
||||
m_lastFilename = filelinep->filename();
|
||||
}
|
||||
// Process all on/offs for lines up to and including the current line
|
||||
int curlineno = filelinep->lineno();
|
||||
for (; m_lastIt != m_lastEnd; ++m_lastIt) {
|
||||
if (m_lastIt->m_lineno > curlineno) break;
|
||||
//UINFO(9," Hit "<<*m_lastIt<<endl);
|
||||
filelinep->warnOn(m_lastIt->m_code, m_lastIt->m_on);
|
||||
}
|
||||
if (0 && debug() >= 9) {
|
||||
for (IgnLines::const_iterator it=m_lastIt; it != m_lastEnd; ++it) {
|
||||
UINFO(9," NXT "<<*it<<endl);
|
||||
}
|
||||
}
|
||||
m_lastLineno = filelinep->lineno();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
V3ConfigIgnores V3ConfigIgnores::s_singleton;
|
||||
|
||||
//######################################################################
|
||||
// V3Config
|
||||
|
||||
void V3Config::addIgnore(V3ErrorCode code, string filename, int min, int max) {
|
||||
if (filename=="*") {
|
||||
FileLine::globalWarnOff(code,true);
|
||||
} else {
|
||||
V3ConfigIgnores::singleton().addIgnore(code, filename, min, false);
|
||||
if (max) V3ConfigIgnores::singleton().addIgnore(code, filename, max, true);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::applyIgnores(FileLine* filelinep) {
|
||||
V3ConfigIgnores::singleton().applyIgnores(filelinep);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Configuration Files
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3CONFIG_H_
|
||||
#define _V3CONFIG_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <string>
|
||||
#include "V3Error.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3Config {
|
||||
public:
|
||||
static void addIgnore(V3ErrorCode code, string filename, int min, int max);
|
||||
static void applyIgnores(FileLine* filelinep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+355
-237
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Read.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Signed.h"
|
||||
@@ -94,18 +93,20 @@ public:
|
||||
class ConstVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// ** only when m_warn/m_expensive is set. If state is needed other times,
|
||||
// ** only when m_warn/m_doExpensive is set. If state is needed other times,
|
||||
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
||||
// AstVar::user4p -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
||||
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
|
||||
|
||||
// STATE
|
||||
bool m_params; // If true, propogate parameterized and true numbers only
|
||||
bool m_required; // If true, must become a constant
|
||||
bool m_wremove; // Inside scope, no assignw removal
|
||||
bool m_warn; // Output warnings
|
||||
bool m_cpp; // C++ conversions only
|
||||
bool m_expensive; // Enable computationally expensive optimizations
|
||||
AstModule* m_modp; // Current module
|
||||
bool m_doExpensive; // Enable computationally expensive optimizations
|
||||
bool m_doNConst; // Enable non-constant-child simplifications
|
||||
bool m_doV; // Verilog, not C++ conversion
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNode* m_scopep; // Current scope
|
||||
|
||||
// METHODS
|
||||
@@ -289,7 +290,7 @@ private:
|
||||
// SEL(EXTEND(any,width,...),(width-1),0) -> ...
|
||||
// Since select's return unsigned, this is always an extend
|
||||
AstExtend* extendp = nodep->fromp()->castExtend();
|
||||
return (!m_cpp
|
||||
return (m_doV
|
||||
&& extendp
|
||||
&& nodep->lsbp()->castConst()
|
||||
&& nodep->widthp()->castConst()
|
||||
@@ -307,13 +308,15 @@ private:
|
||||
|
||||
// Extraction checks
|
||||
bool warnSelect(AstSel* nodep) {
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
|
||||
AstVar* varp = varrefp->varp();
|
||||
if (!varp->dtypep()) varp->v3fatalSrc("Data type lost");
|
||||
AstBasicDType* bdtypep = varp->basicp(); if (!bdtypep) varp->v3fatalSrc("Select of non-selectable type");
|
||||
if (m_warn
|
||||
&& nodep->lsbp()->castConst()
|
||||
&& nodep->widthp()->castConst()
|
||||
&& (!varp->rangep() || varp->msb())) { // else it's non-resolvable parameterized
|
||||
&& (!bdtypep->rangep() || bdtypep->msb())) { // else it's non-resolvable parameterized
|
||||
if (nodep->lsbp()->castConst()->num().isFourState()
|
||||
|| nodep->widthp()->castConst()->num().isFourState()) {
|
||||
nodep->v3error("Selection index is constantly unknown or tristated: "
|
||||
@@ -321,14 +324,14 @@ private:
|
||||
// Replacing nodep will make a mess above, so we replace the offender
|
||||
replaceZero(nodep->lsbp());
|
||||
}
|
||||
else if ((nodep->msbConst() > varp->msbMaxSelect())
|
||||
|| (nodep->lsbConst() > varp->msbMaxSelect())) {
|
||||
else if ((nodep->msbConst() > bdtypep->msbMaxSelect())
|
||||
|| (nodep->lsbConst() > bdtypep->msbMaxSelect())) {
|
||||
// See also warning in V3Width
|
||||
nodep->v3error("Selection index out of range: "
|
||||
<<nodep->msbConst()<<":"<<nodep->lsbConst()
|
||||
<<" outside "<<varp->msbMaxSelect()<<":0"
|
||||
<<(varp->lsb()>=0 ? ""
|
||||
:" (adjusted +"+cvtToStr(-varp->lsb())+" to account for negative lsb)"));
|
||||
<<" outside "<<bdtypep->msbMaxSelect()<<":0"
|
||||
<<(bdtypep->lsb()>=0 ? ""
|
||||
:" (adjusted +"+cvtToStr(-bdtypep->lsb())+" to account for negative lsb)"));
|
||||
// Don't replace with zero, we'll do it later
|
||||
}
|
||||
}
|
||||
@@ -393,13 +396,13 @@ private:
|
||||
void replaceNumSigned(AstNodeBiop* nodep, uint32_t val) {
|
||||
// We allow both sides to be constant, as one may have come from parameter propagation, etc.
|
||||
if (m_warn && !(nodep->lhsp()->castConst() && nodep->rhsp()->castConst())) {
|
||||
nodep->v3warn(UNSIGNED,"Comparison is constant due to unsigned arithmetic\n");
|
||||
nodep->v3warn(UNSIGNED,"Comparison is constant due to unsigned arithmetic");
|
||||
}
|
||||
replaceNum(nodep, val); nodep=NULL;
|
||||
}
|
||||
void replaceNumLimited(AstNodeBiop* nodep, uint32_t val) {
|
||||
// Avoids gcc warning about same
|
||||
if (m_warn) nodep->v3warn(CMPCONST,"Comparison is constant due to limited range\n");
|
||||
if (m_warn) nodep->v3warn(CMPCONST,"Comparison is constant due to limited range");
|
||||
replaceNum(nodep, val); nodep=NULL;
|
||||
}
|
||||
void replaceZero(AstNode* nodep) {
|
||||
@@ -431,6 +434,15 @@ private:
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
}
|
||||
|
||||
void replaceConstString (AstNode* oldp, const string& num) {
|
||||
// Replace oldp node with a constant set to specified value
|
||||
UASSERT (oldp, "Null old\n");
|
||||
AstNode* newp = new AstConstString(oldp->fileline(), num);
|
||||
if (debug()>5) oldp->dumpTree(cout," const_old: ");
|
||||
if (debug()>5) newp->dumpTree(cout," _new: ");
|
||||
oldp->replaceWith(newp);
|
||||
oldp->deleteTree(); oldp=NULL;
|
||||
}
|
||||
//----------------------------------------
|
||||
// Replacement functions.
|
||||
// These all take a node and replace it with something else
|
||||
@@ -713,7 +725,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (!m_cpp && nodep->lhsp()->castConcat()) {
|
||||
else if (m_doV && nodep->lhsp()->castConcat()) {
|
||||
bool need_temp = false;
|
||||
if (m_warn && !nodep->castAssignDly()) { // Is same var on LHS and RHS?
|
||||
// Note only do this (need user4) when m_warn, which is
|
||||
@@ -771,9 +783,9 @@ private:
|
||||
string name1 = ((string)"__Vconcswap"+cvtToStr(m_modp->varNumGetInc()));
|
||||
string name2 = ((string)"__Vconcswap"+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1,
|
||||
new AstRange(sel1p->fileline(), msb1-lsb1, 0));
|
||||
AstLogicPacked(), msb1-lsb1+1);
|
||||
AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2,
|
||||
new AstRange(sel2p->fileline(), msb2-lsb2, 0));
|
||||
AstLogicPacked(), msb2-lsb2+1);
|
||||
m_modp->addStmtp(temp1p);
|
||||
m_modp->addStmtp(temp2p);
|
||||
AstNodeAssign* asn1ap=nodep->cloneType
|
||||
@@ -844,10 +856,10 @@ private:
|
||||
// Run it - may be unoptimizable due to large for loop, etc
|
||||
simvis.mainParamEmulate(nodep);
|
||||
if (!simvis.optimizable()) {
|
||||
AstNode* errorp = simvis.whyNotNodep(); if (!errorp) errorp = nodep;
|
||||
AstNode* errorp = simvis.whyNotNodep(); if (!errorp) errorp = nodep;
|
||||
nodep->v3error("Expecting expression to be constant, but can't determine constant for "
|
||||
<<nodep->prettyTypeName()<<endl
|
||||
<<V3Error::msgPrefix()<<errorp->fileline()<<"... Location of non-constant "
|
||||
<<V3Error::msgPrefix(V3ErrorCode::EC_ERROR,false)<<errorp->fileline()<<"... Location of non-constant "
|
||||
<<errorp->prettyTypeName()<<": "<<simvis.whyNotMessage());
|
||||
replaceZero(nodep); nodep=NULL;
|
||||
} else {
|
||||
@@ -866,7 +878,7 @@ private:
|
||||
// Iterate modules backwards, in bottom-up order. That's faster
|
||||
nodep->iterateChildrenBackwards(*this);
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
@@ -1053,15 +1065,17 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||
bool did=false;
|
||||
if (!m_cpp && nodep->varp()->hasSimpleInit() && !nodep->backp()->castAttrOf()) {
|
||||
//if (debug()) nodep->varp()->initp()->dumpTree(cout," visitvaref: ");
|
||||
nodep->varp()->initp()->iterateAndNext(*this);
|
||||
if (operandConst(nodep->varp()->initp())
|
||||
if (m_doV && nodep->varp()->hasSimpleInit() && !nodep->backp()->castAttrOf()) {
|
||||
//if (debug()) nodep->varp()->valuep()->dumpTree(cout," visitvaref: ");
|
||||
nodep->varp()->valuep()->iterateAndNext(*this);
|
||||
if (operandConst(nodep->varp()->valuep())
|
||||
&& !nodep->lvalue()
|
||||
&& ((v3Global.opt.oConst() && !m_params // Can reduce constant wires into equations
|
||||
&& ((!m_params // Can reduce constant wires into equations
|
||||
&& m_doNConst
|
||||
&& v3Global.opt.oConst()
|
||||
&& !nodep->varp()->isSigPublic())
|
||||
|| nodep->varp()->isParam())) {
|
||||
AstConst* constp = nodep->varp()->initp()->castConst();
|
||||
AstConst* constp = nodep->varp()->valuep()->castConst();
|
||||
const V3Number& num = constp->num();
|
||||
//UINFO(2,"constVisit "<<(void*)constp<<" "<<num<<endl);
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
@@ -1072,9 +1086,31 @@ private:
|
||||
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->itemp()) nodep->v3fatalSrc("Not linked");
|
||||
bool did=false;
|
||||
if (nodep->itemp()->valuep()) {
|
||||
//if (debug()) nodep->varp()->valuep()->dumpTree(cout," visitvaref: ");
|
||||
nodep->itemp()->valuep()->iterateAndNext(*this);
|
||||
if (AstConst* valuep = nodep->itemp()->valuep()->castConst()) {
|
||||
const V3Number& num = valuep->num();
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
did=true;
|
||||
}
|
||||
}
|
||||
if (!did && m_required) {
|
||||
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->itemp()->prettyName());
|
||||
}
|
||||
}
|
||||
|
||||
// virtual void visit(AstCvtPackString* nodep, AstNUser*) {
|
||||
// Not constant propagated (for today) because AstMath::isOpaque is set
|
||||
// Someday if lower is constant, convert to quoted "string".
|
||||
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||
// Don't iterate children, don't want to loose VarRef.
|
||||
if (nodep->attrType()==AstAttrType::BITS) {
|
||||
// Don't iterate children, don't want to lose VarRef.
|
||||
if (nodep->attrType()==AstAttrType::EXPR_BITS) {
|
||||
if (!nodep->fromp() || !nodep->fromp()->widthMin()) nodep->v3fatalSrc("Unsized expression");
|
||||
V3Number num (nodep->fileline(), 32, nodep->fromp()->widthMin());
|
||||
replaceNum(nodep, num); nodep=NULL;
|
||||
@@ -1088,8 +1124,9 @@ private:
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->sensp()->castConst()
|
||||
|| (nodep->varrefp() && nodep->varrefp()->varp()->isParam())) {
|
||||
if (m_doNConst
|
||||
&& (nodep->sensp()->castConst()
|
||||
|| (nodep->varrefp() && nodep->varrefp()->varp()->isParam()))) {
|
||||
// Constants in sensitivity lists may be removed (we'll simplify later)
|
||||
if (nodep->isClocked()) { // A constant can never get a pos/negexge
|
||||
if (onlySenItemInSenTree(nodep)) {
|
||||
@@ -1102,7 +1139,7 @@ private:
|
||||
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
} else if (nodep->sensp()->castNot()) {
|
||||
} else if (m_doNConst && nodep->sensp()->castNot()) {
|
||||
// V3Gate may propagate NOTs into clocks... Just deal with it
|
||||
AstNode* sensp = nodep->sensp();
|
||||
AstNode* lastSensp = sensp;
|
||||
@@ -1149,8 +1186,6 @@ private:
|
||||
const AstSenItem* ritemp = rhsp->castSenItem();
|
||||
if (litemp && ritemp) {
|
||||
// Looks visually better if we keep sorted by name
|
||||
if (litemp->edgeType() < ritemp->edgeType()) return true;
|
||||
if (litemp->edgeType() > ritemp->edgeType()) return false;
|
||||
if (!litemp->varrefp() && ritemp->varrefp()) return true;
|
||||
if ( litemp->varrefp() && !ritemp->varrefp()) return false;
|
||||
if (litemp->varrefp() && ritemp->varrefp()) {
|
||||
@@ -1160,6 +1195,10 @@ private:
|
||||
if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) return true;
|
||||
if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) return false;
|
||||
}
|
||||
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent
|
||||
// note the SenTree optimizer requires this order (more general firsst, less general last)
|
||||
if (litemp->edgeType() < ritemp->edgeType()) return true;
|
||||
if (litemp->edgeType() > ritemp->edgeType()) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1167,7 +1206,7 @@ private:
|
||||
|
||||
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_expensive) {
|
||||
if (m_doExpensive) {
|
||||
//cout<<endl; nodep->dumpTree(cout,"ssin: ");
|
||||
// Optimize ideas for the future:
|
||||
// SENTREE(... SENGATE(x,a), SENGATE(SENITEM(x),b) ...) => SENGATE(x,OR(a,b))
|
||||
@@ -1244,16 +1283,16 @@ private:
|
||||
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameTree(ritemp->varrefp()))
|
||||
|| (!litemp->varrefp() && !ritemp->varrefp())) {
|
||||
// We've sorted in the order ANY, BOTH, POS, NEG, so we don't need to try opposite orders
|
||||
if (( litemp->edgeType()==AstEdgeType::ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
|
||||
|| (litemp->edgeType()==AstEdgeType::BOTHEDGE) // BOTH or {POS|NEG} -> BOTH
|
||||
|| (litemp->edgeType()==AstEdgeType::POSEDGE // POS or NEG -> BOTH
|
||||
&& ritemp->edgeType()==AstEdgeType::NEGEDGE)
|
||||
if (( litemp->edgeType()==AstEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
|
||||
|| (litemp->edgeType()==AstEdgeType::ET_BOTHEDGE) // BOTH or {POS|NEG} -> BOTH
|
||||
|| (litemp->edgeType()==AstEdgeType::ET_POSEDGE // POS or NEG -> BOTH
|
||||
&& ritemp->edgeType()==AstEdgeType::ET_NEGEDGE)
|
||||
|| (litemp->edgeType()==ritemp->edgeType()) // Identical edges
|
||||
) {
|
||||
// Fix edge of old node
|
||||
if (litemp->edgeType()==AstEdgeType::POSEDGE
|
||||
&& ritemp->edgeType()==AstEdgeType::NEGEDGE)
|
||||
litemp->edgeType(AstEdgeType::BOTHEDGE);
|
||||
if (litemp->edgeType()==AstEdgeType::ET_POSEDGE
|
||||
&& ritemp->edgeType()==AstEdgeType::ET_NEGEDGE)
|
||||
litemp->edgeType(AstEdgeType::ET_BOTHEDGE);
|
||||
// Remove redundant node
|
||||
ritemp->unlinkFrBack()->deleteTree(); ritemp=NULL; cmpp=NULL;
|
||||
// Try to collapse again
|
||||
@@ -1270,22 +1309,21 @@ private:
|
||||
// Zero elimination
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
replaceNodeAssign(nodep);
|
||||
if (m_doNConst && replaceNodeAssign(nodep)) return;
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
||||
// Don't perform any optimizations, keep the alias around
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (replaceNodeAssign(nodep)) return;
|
||||
if (m_doNConst && replaceNodeAssign(nodep)) return;
|
||||
AstNodeVarRef* varrefp = nodep->lhsp()->castVarRef(); // Not VarXRef, as different refs may set different values to each hierarchy
|
||||
if (m_wremove
|
||||
if (m_wremove && !m_params && m_doNConst
|
||||
&& m_modp && operandConst(nodep->rhsp())
|
||||
&& !nodep->rhsp()->castConst()->num().isFourState()
|
||||
&& varrefp // Don't do messes with BITREFs/ARRAYREFs
|
||||
&& !varrefp->varp()->initp() // Not already constified
|
||||
&& !varrefp->varScopep() // Not scoped (or each scope may have different initial value)
|
||||
&& !m_params) {
|
||||
&& !varrefp->varp()->valuep() // Not already constified
|
||||
&& !varrefp->varScopep()) { // Not scoped (or each scope may have different initial value)
|
||||
// ASSIGNW (VARREF, const) -> INITIAL ( ASSIGN (VARREF, const) )
|
||||
UINFO(4,"constAssignW "<<nodep<<endl);
|
||||
// Make a initial assignment
|
||||
@@ -1299,87 +1337,89 @@ private:
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
// Set the initial value right in the variable so we can constant propagate
|
||||
AstNode* initvaluep = exprp->cloneTree(false);
|
||||
varrefp->varp()->initp(initvaluep);
|
||||
varrefp->varp()->valuep(initvaluep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (AstConst* constp = nodep->condp()->castConst()) {
|
||||
AstNode* keepp = NULL;
|
||||
if (constp->isZero()) {
|
||||
UINFO(4,"IF(0,{any},{x}) => {x}: "<<nodep<<endl);
|
||||
keepp = nodep->elsesp();
|
||||
} else {
|
||||
UINFO(4,"IF(!0,{x},{any}) => {x}: "<<nodep<<endl);
|
||||
keepp = nodep->ifsp();
|
||||
if (m_doNConst) {
|
||||
if (AstConst* constp = nodep->condp()->castConst()) {
|
||||
AstNode* keepp = NULL;
|
||||
if (constp->isZero()) {
|
||||
UINFO(4,"IF(0,{any},{x}) => {x}: "<<nodep<<endl);
|
||||
keepp = nodep->elsesp();
|
||||
} else {
|
||||
UINFO(4,"IF(!0,{x},{any}) => {x}: "<<nodep<<endl);
|
||||
keepp = nodep->ifsp();
|
||||
}
|
||||
if (keepp) {
|
||||
keepp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(keepp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
if (keepp) {
|
||||
keepp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(keepp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) {
|
||||
// Empty block, remove it
|
||||
// Note if we support more C++ then there might be side effects in the condition itself
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (!afterComment(nodep->ifsp())) {
|
||||
UINFO(4,"IF({x}) NULL {...} => IF(NOT{x}}: "<<nodep<<endl);
|
||||
AstNode* condp = nodep->condp();
|
||||
AstNode* elsesp = nodep->elsesp();
|
||||
condp->unlinkFrBackWithNext();
|
||||
elsesp->unlinkFrBackWithNext();
|
||||
if (nodep->ifsp()) { nodep->ifsp()->unlinkFrBackWithNext()->deleteTree(); } // Must have been comment
|
||||
nodep->condp(new AstLogNot(condp->fileline(), condp)); // LogNot, as C++ optimization also possible
|
||||
nodep->addIfsp(elsesp);
|
||||
}
|
||||
else if (((nodep->condp()->castNot() && nodep->condp()->width()==1)
|
||||
|| (nodep->condp()->castLogNot()))
|
||||
&& nodep->ifsp() && nodep->elsesp()) {
|
||||
UINFO(4,"IF(NOT {x}) => IF(x) swapped if/else"<<nodep<<endl);
|
||||
AstNode* condp = nodep->condp()->castNot()->lhsp()->unlinkFrBackWithNext();
|
||||
AstNode* ifsp = nodep->ifsp()->unlinkFrBackWithNext();
|
||||
AstNode* elsesp = nodep->elsesp()->unlinkFrBackWithNext();
|
||||
AstIf* ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp);
|
||||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (ifSameAssign(nodep)) {
|
||||
UINFO(4,"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"<<endl);
|
||||
AstNodeAssign* ifp = nodep->ifsp()->castNodeAssign();
|
||||
AstNodeAssign* elsep = nodep->elsesp()->castNodeAssign();
|
||||
ifp->unlinkFrBack();
|
||||
AstNode* condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* truep = ifp->rhsp()->unlinkFrBack();
|
||||
AstNode* falsep = elsep->rhsp()->unlinkFrBack();
|
||||
ifp->rhsp(new AstCond(truep->fileline(),
|
||||
condp, truep, falsep));
|
||||
nodep->replaceWith(ifp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
|
||||
&& operandIfIf(nodep)) {
|
||||
UINFO(0,"IF({a}) IF({b}) => IF({a} && {b})"<<endl);
|
||||
AstNodeIf* lowerIfp = nodep->ifsp()->castNodeIf();
|
||||
AstNode* condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* lowerIfsp = lowerIfp->ifsp()->unlinkFrBackWithNext();
|
||||
AstNode* lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext();
|
||||
nodep->condp(new AstLogAnd(lowerIfp->fileline(),
|
||||
condp, lowerCondp));
|
||||
lowerIfp->replaceWith(lowerIfsp);
|
||||
lowerIfp->deleteTree(); lowerIfp=NULL;
|
||||
}
|
||||
else if (operandBoolShift(nodep->condp())) {
|
||||
replaceBoolShift(nodep->condp());
|
||||
}
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (!afterComment(nodep->ifsp()) && !afterComment(nodep->elsesp())) {
|
||||
// Empty block, remove it
|
||||
// Note if we support more C++ then there might be side effects in the condition itself
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (!afterComment(nodep->ifsp())) {
|
||||
UINFO(4,"IF({x}) NULL {...} => IF(NOT{x}}: "<<nodep<<endl);
|
||||
AstNode* condp = nodep->condp();
|
||||
AstNode* elsesp = nodep->elsesp();
|
||||
condp->unlinkFrBackWithNext();
|
||||
elsesp->unlinkFrBackWithNext();
|
||||
if (nodep->ifsp()) { nodep->ifsp()->unlinkFrBackWithNext()->deleteTree(); } // Must have been comment
|
||||
nodep->condp(new AstLogNot(condp->fileline(), condp)); // LogNot, as C++ optimization also possible
|
||||
nodep->addIfsp(elsesp);
|
||||
}
|
||||
else if (((nodep->condp()->castNot() && nodep->condp()->width()==1)
|
||||
|| (nodep->condp()->castLogNot()))
|
||||
&& nodep->ifsp() && nodep->elsesp()) {
|
||||
UINFO(4,"IF(NOT {x}) => IF(x) swapped if/else"<<nodep<<endl);
|
||||
AstNode* condp = nodep->condp()->castNot()->lhsp()->unlinkFrBackWithNext();
|
||||
AstNode* ifsp = nodep->ifsp()->unlinkFrBackWithNext();
|
||||
AstNode* elsesp = nodep->elsesp()->unlinkFrBackWithNext();
|
||||
AstIf* ifp = new AstIf(nodep->fileline(), condp, elsesp, ifsp);
|
||||
ifp->branchPred(nodep->branchPred().invert());
|
||||
nodep->replaceWith(ifp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (ifSameAssign(nodep)) {
|
||||
UINFO(4,"IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})"<<endl);
|
||||
AstNodeAssign* ifp = nodep->ifsp()->castNodeAssign();
|
||||
AstNodeAssign* elsep = nodep->elsesp()->castNodeAssign();
|
||||
ifp->unlinkFrBack();
|
||||
AstNode* condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* truep = ifp->rhsp()->unlinkFrBack();
|
||||
AstNode* falsep = elsep->rhsp()->unlinkFrBack();
|
||||
ifp->rhsp(new AstCond(truep->fileline(),
|
||||
condp, truep, falsep));
|
||||
nodep->replaceWith(ifp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (0 // Disabled, as vpm assertions are faster without due to short-circuiting
|
||||
&& operandIfIf(nodep)) {
|
||||
UINFO(0,"IF({a}) IF({b}) => IF({a} && {b})"<<endl);
|
||||
AstNodeIf* lowerIfp = nodep->ifsp()->castNodeIf();
|
||||
AstNode* condp = nodep->condp()->unlinkFrBack();
|
||||
AstNode* lowerIfsp = lowerIfp->ifsp()->unlinkFrBackWithNext();
|
||||
AstNode* lowerCondp = lowerIfp->condp()->unlinkFrBackWithNext();
|
||||
nodep->condp(new AstLogAnd(lowerIfp->fileline(),
|
||||
condp, lowerCondp));
|
||||
lowerIfp->replaceWith(lowerIfsp);
|
||||
lowerIfp->deleteTree(); lowerIfp=NULL;
|
||||
}
|
||||
else if (operandBoolShift(nodep->condp())) {
|
||||
replaceBoolShift(nodep->condp());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
virtual void visit(AstSFormatF* nodep, AstNUser*) {
|
||||
// Substitute constants into displays. The main point of this is to
|
||||
// simplify assertion methodologies which call functions with display's.
|
||||
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
|
||||
@@ -1388,7 +1428,7 @@ private:
|
||||
for (AstNode* argp = nodep->exprsp(); argp; argp=argp->nextp()) {
|
||||
if (argp->castConst()) { anyconst=true; break; }
|
||||
}
|
||||
if (anyconst) {
|
||||
if (m_doNConst && anyconst) {
|
||||
//UINFO(9," Display in "<<nodep->text()<<endl);
|
||||
string dispout = "";
|
||||
string fmt = "";
|
||||
@@ -1434,6 +1474,12 @@ private:
|
||||
nodep->text(dispout);
|
||||
//UINFO(9," Display out "<<nodep->text()<<endl);
|
||||
}
|
||||
if (!nodep->exprsp()
|
||||
&& nodep->name().find("%") == string::npos
|
||||
&& !nodep->hidden()) {
|
||||
// Just a simple constant string - the formatting is pointless
|
||||
replaceConstString(nodep, nodep->name()); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
||||
@@ -1445,13 +1491,16 @@ private:
|
||||
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->condp()->isZero()) {
|
||||
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
||||
nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (operandBoolShift(nodep->condp())) {
|
||||
replaceBoolShift(nodep->condp());
|
||||
if (m_doNConst) {
|
||||
if (nodep->condp()->isZero()) {
|
||||
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
||||
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (operandBoolShift(nodep->condp())) {
|
||||
replaceBoolShift(nodep->condp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1459,6 +1508,38 @@ private:
|
||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
||||
|
||||
// Ignored, can eliminate early
|
||||
virtual void visit(AstSysIgnore* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_doNConst) {
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----
|
||||
// Jump elimination
|
||||
|
||||
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_doExpensive) { nodep->labelp()->user4(true); }
|
||||
}
|
||||
|
||||
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||
// Because JumpLabels disable many optimizations,
|
||||
// remove JumpLabels that are not pointed to by any AstJumpGos
|
||||
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
|
||||
nodep->iterateChildren(*this);
|
||||
// AstJumpGo's below here that point to this node will set user4
|
||||
if (m_doExpensive && !nodep->user4()) {
|
||||
UINFO(4,"JUMPLABEL => unused "<<nodep<<endl);
|
||||
AstNode* underp = NULL;
|
||||
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (underp) nodep->replaceWith(underp);
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//-----
|
||||
// Below lines are magic expressions processed by astgen
|
||||
// "AstNODETYPE { # bracket not paren
|
||||
@@ -1480,78 +1561,81 @@ private:
|
||||
|
||||
// Lint Checks
|
||||
// v--- *1* These ops are always first, as we warn before replacing
|
||||
// v--- *V* This op is a verilog op, ignore when in m_cpp mode
|
||||
// v--- *V* This op is a verilog op, only in m_doV mode
|
||||
// v--- *C* This op works on all constant children, allowed in m_doConst mode
|
||||
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
|
||||
// Generic constants on both side. Do this first to avoid other replacements
|
||||
TREEOP("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOP("AstNodeUniop{$lhsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
|
||||
// Zero on one side or the other
|
||||
TREEOP("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP("AstAnd {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstLogAnd{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstLogOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP("AstDiv {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstDivS {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstMul {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstMulS {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstPow {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstPowS {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP("AstShiftL{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
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)");
|
||||
TREEOP("AstLogAnd{$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP("AstLogOr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstMul {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP("AstMulS {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP("AstOr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstShiftL{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstShiftR{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
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}");
|
||||
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstDiv {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstDivS {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstMul {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstMulS {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstPow {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstPowS {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstShiftL{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
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)");
|
||||
TREEOP ("AstLogAnd{$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogOr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstMul {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP ("AstMulS {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP ("AstOr {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftL{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstShiftR{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
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)");
|
||||
TREEOP("AstOr {$lhsp.isAllOnes, $rhsp}", "replaceWLhs(nodep)"); //->allOnes
|
||||
TREEOP("AstLogOr {$lhsp.isNeqZero, $rhsp}", "replaceNum(nodep,1)");
|
||||
TREEOP("AstAnd {$lhsp, $rhsp.isAllOnes}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstLogAnd{$lhsp, $rhsp.isNeqZero}", "replaceWLhs(nodep)");
|
||||
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)");
|
||||
TREEOP("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
|
||||
TREEOP("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
|
||||
TREEOP("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP("AstPowS {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP ("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstOr {$lhsp.isAllOnes, $rhsp}", "replaceWLhs(nodep)"); //->allOnes
|
||||
TREEOP ("AstLogOr {$lhsp.isNeqZero, $rhsp}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstAnd {$lhsp, $rhsp.isAllOnes}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp, $rhsp.isNeqZero}", "replaceWLhs(nodep)");
|
||||
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)");
|
||||
TREEOP ("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
|
||||
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
|
||||
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP ("AstPowS {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
// Trinary ops
|
||||
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
|
||||
TREEOP("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
|
||||
TREEOP("AstNodeCond{$condp.isNeqZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr1p)");
|
||||
TREEOP("AstNodeCond{$condp, operandsSame($expr1p,,$expr2p)}","replaceWChild(nodep,$expr1p)");
|
||||
TREEOP("AstCond{$condp->castNot(), $expr1p, $expr2p}", "AstCond{$condp->op1p(), $expr2p, $expr1p}");
|
||||
TREEOP("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isAllOnes, $expr2p}", "AstOr {$condp, $expr2p}"); // a?1:b == a|b
|
||||
TREEOP("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isZero}", "AstAnd{$condp, $expr1p}"); // a?b:0 == a&b
|
||||
TREEOP("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isAllOnes}", "AstOr {AstNot{$condp}, $expr1p}"); // a?b:1 == ~a|b
|
||||
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())");
|
||||
TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
|
||||
TREEOP ("AstNodeCond{$condp.isNeqZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr1p)");
|
||||
TREEOPC("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)");
|
||||
TREEOPC("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)");
|
||||
TREEOP ("AstNodeCond{$condp, operandsSame($expr1p,,$expr2p)}","replaceWChild(nodep,$expr1p)");
|
||||
TREEOP ("AstCond{$condp->castNot(), $expr1p, $expr2p}", "AstCond{$condp->op1p(), $expr2p, $expr1p}");
|
||||
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isAllOnes, $expr2p}", "AstOr {$condp, $expr2p}"); // a?1:b == a|b
|
||||
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isZero}", "AstAnd{$condp, $expr1p}"); // a?b:0 == a&b
|
||||
TREEOP ("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p, $expr2p.isAllOnes}", "AstOr {AstNot{$condp}, $expr1p}"); // a?b:1 == ~a|b
|
||||
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.castConst, $rhsp.castConst}", "swapSides(nodep)");
|
||||
TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsv(nodep)");
|
||||
TREEOP("AstNodeBiComAsv{operandAsvSame(nodep)}", "replaceAsv(nodep)");
|
||||
TREEOP("AstNodeBiComAsv{operandAsvLUp(nodep)}", "replaceAsvLUp(nodep)");
|
||||
TREEOP("AstNodeBiComAsv{operandAsvRUp(nodep)}", "replaceAsvRUp(nodep)");
|
||||
TREEOP ("AstNodeBiCom{!$lhsp.castConst, $rhsp.castConst}", "swapSides(nodep)");
|
||||
TREEOP ("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsv(nodep)");
|
||||
TREEOP ("AstNodeBiComAsv{operandAsvSame(nodep)}", "replaceAsv(nodep)");
|
||||
TREEOP ("AstNodeBiComAsv{operandAsvLUp(nodep)}", "replaceAsvLUp(nodep)");
|
||||
TREEOP ("AstNodeBiComAsv{operandAsvRUp(nodep)}", "replaceAsvRUp(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)");
|
||||
@@ -1603,30 +1687,30 @@ private:
|
||||
// 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("AstEqWild {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("AstNeqWild{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstLogOr {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
|
||||
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 ("AstEqWild {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 ("AstNeqWild{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
|
||||
@@ -1680,13 +1764,16 @@ private:
|
||||
TREEOPV("AstSel{operandSelExtend(nodep)}", "replaceWChild(nodep, nodep->fromp()->castExtend()->lhsp())");
|
||||
TREEOPV("AstSel{operandSelFull(nodep)}", "replaceWChild(nodep, nodep->fromp())");
|
||||
TREEOPV("AstSel{$fromp.castSel}", "replaceSelSel(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.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}}");
|
||||
// Strings
|
||||
TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, nodep->lhsp()->castConst()->num().toString())");
|
||||
|
||||
|
||||
// Possible futures:
|
||||
// (a?(b?y:x):y) -> (a&&!b)?x:y
|
||||
@@ -1712,15 +1799,37 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
// Processing Mode Enum
|
||||
enum ProcMode {
|
||||
PROC_PARAMS,
|
||||
PROC_LIVE,
|
||||
PROC_V_WARN,
|
||||
PROC_V_NOWARN,
|
||||
PROC_V_EXPENSIVE,
|
||||
PROC_CPP
|
||||
};
|
||||
|
||||
// CONSTUCTORS
|
||||
ConstVisitor(bool params, bool expensive, bool warn, bool cpp) {
|
||||
m_params = params; m_required = params;
|
||||
m_expensive = expensive;
|
||||
m_warn = warn;
|
||||
m_cpp = cpp;
|
||||
m_wremove = true;
|
||||
ConstVisitor(ProcMode pmode) {
|
||||
m_params = false;
|
||||
m_required = false;
|
||||
m_doExpensive = false;
|
||||
m_doNConst = false;
|
||||
m_doV = false;
|
||||
m_warn = false;
|
||||
m_wremove = true; // Overridden in visitors
|
||||
m_modp = NULL;
|
||||
m_scopep = NULL;
|
||||
//
|
||||
switch (pmode) {
|
||||
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; m_required = true; break;
|
||||
case PROC_LIVE: break;
|
||||
case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break;
|
||||
case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break;
|
||||
case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break;
|
||||
case PROC_CPP: m_doV = false; m_doNConst = true; break;
|
||||
default: v3fatalSrc("Bad case"); break;
|
||||
}
|
||||
}
|
||||
virtual ~ConstVisitor() {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
@@ -1737,12 +1846,12 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
|
||||
// Resize even if the node already has a width, because burried in the treee we may
|
||||
// have a node we just created with signing, etc, that isn't sized yet.
|
||||
nodep = V3Width::widthParamsEdit(nodep); // Make sure we've sized everything first
|
||||
ConstVisitor visitor (true,false,false,false);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_PARAMS);
|
||||
if (AstVar* varp=nodep->castVar()) {
|
||||
// If a var wants to be constified, it's really a param, and
|
||||
// we want the value to be constant. We aren't passed just the
|
||||
// init value because we need widthing above to handle the var's type.
|
||||
if (varp->initp()) visitor.mainAcceptEdit(varp->initp());
|
||||
if (varp->valuep()) visitor.mainAcceptEdit(varp->valuep());
|
||||
} else {
|
||||
nodep = visitor.mainAcceptEdit(nodep);
|
||||
}
|
||||
@@ -1751,34 +1860,43 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
|
||||
return nodep;
|
||||
}
|
||||
|
||||
void V3Const::constifyAll(AstNetlist* nodep) {
|
||||
// Only call from Verilator.cpp, as it uses user#'s
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (false,true,false,false);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
}
|
||||
|
||||
void V3Const::constifyAllLint(AstNetlist* nodep) {
|
||||
// Only call from Verilator.cpp, as it uses user#'s
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (false,false,true,false);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_WARN);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
}
|
||||
|
||||
void V3Const::constifyCpp(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (false,false,false,true);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_CPP);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
}
|
||||
|
||||
AstNode* V3Const::constifyEdit(AstNode* nodep) {
|
||||
ConstVisitor visitor (false,false,false,false);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_NOWARN);
|
||||
nodep = visitor.mainAcceptEdit(nodep);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
void V3Const::constifyAllLive(AstNetlist* nodep) {
|
||||
// Only call from Verilator.cpp, as it uses user#'s
|
||||
// This only pushes constants up, doesn't make any other edits
|
||||
// IE doesn't prune dead statements, as we need to do some usability checks after this
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_LIVE);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
}
|
||||
|
||||
void V3Const::constifyAll(AstNetlist* nodep) {
|
||||
// Only call from Verilator.cpp, as it uses user#'s
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_EXPENSIVE);
|
||||
(void)visitor.mainAcceptEdit(nodep);
|
||||
}
|
||||
|
||||
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {
|
||||
ConstVisitor visitor (false,true,false,false);
|
||||
ConstVisitor visitor (ConstVisitor::PROC_V_EXPENSIVE);
|
||||
nodep = visitor.mainAcceptEdit(nodep);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
+3
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
// Force this cell node's parameter list to become a constant
|
||||
// Return new node that may have replaced nodep
|
||||
static AstNode* constifyParamsEdit(AstNode* nodep);
|
||||
// Only do constant pushing, without removing dead logic
|
||||
static void constifyAllLive(AstNetlist* nodep);
|
||||
// Everything that's possible
|
||||
static void constifyAll(AstNetlist* nodep);
|
||||
// Also, warn
|
||||
|
||||
+71
-58
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -48,9 +48,22 @@ private:
|
||||
// TYPES
|
||||
typedef map<string,int> FileMap;
|
||||
|
||||
struct ToggleEnt {
|
||||
string m_comment; // Comment for coverage dump
|
||||
AstNode* m_varRefp; // How to get to this element
|
||||
AstNode* m_chgRefp; // How to get to this element
|
||||
ToggleEnt(const string& comment, AstNode* vp, AstNode* cp)
|
||||
: m_comment(comment), m_varRefp(vp), m_chgRefp(cp) {}
|
||||
~ToggleEnt() {}
|
||||
void cleanup() {
|
||||
m_varRefp->deleteTree(); m_varRefp=NULL;
|
||||
m_chgRefp->deleteTree(); m_chgRefp=NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// STATE
|
||||
bool m_checkBlock; // Should this block get covered?
|
||||
AstModule* m_modp; // Current module to add statement to
|
||||
AstNodeModule* m_modp; // Current module to add statement to
|
||||
bool m_inToggleOff; // In function/task etc
|
||||
FileMap m_fileps; // Column counts for each fileline
|
||||
string m_beginHier; // AstBegin hier name for user coverage points
|
||||
@@ -68,10 +81,12 @@ private:
|
||||
string prettyName = nodep->prettyName();
|
||||
if (!nodep->isToggleCoverable())
|
||||
return "Not relevant signal type";
|
||||
if (prettyName.c_str()[0] == '_')
|
||||
return "Leading underscore";
|
||||
if (prettyName.find("._") != string::npos)
|
||||
return "Inlined leading underscore";
|
||||
if (!v3Global.opt.coverageUnderscore()) {
|
||||
if (prettyName.c_str()[0] == '_')
|
||||
return "Leading underscore";
|
||||
if (prettyName.find("._") != string::npos)
|
||||
return "Inlined leading underscore";
|
||||
}
|
||||
if ((nodep->width()*nodep->arrayElements()) > 256) return "Wide bus/array > 256 bits";
|
||||
// We allow this, though tracing doesn't
|
||||
// if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
|
||||
@@ -108,7 +123,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS - BOTH
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
m_fileps.clear();
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -143,12 +158,6 @@ private:
|
||||
// Convert to "AstCoverInc(CoverInc...)"
|
||||
// We'll do this, and make the if(...) coverinc later.
|
||||
|
||||
// Compute size of the problem
|
||||
int dimensions = 0;
|
||||
for (AstRange* arrayp=nodep->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
|
||||
dimensions++;
|
||||
}
|
||||
|
||||
// Add signal to hold the old value
|
||||
string newvarname = (string)"__Vtogcov__"+nodep->shortName();
|
||||
AstVar* chgVarp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP, newvarname, nodep);
|
||||
@@ -157,61 +166,65 @@ private:
|
||||
// Create bucket for each dimension * bit.
|
||||
// This is necessarily an O(n^2) expansion, which is why
|
||||
// we limit coverage to signals with < 256 bits.
|
||||
vector<int> selects_docs; selects_docs.resize(dimensions);
|
||||
vector<int> selects_code; selects_code.resize(dimensions);
|
||||
toggleVarRecurse(nodep, chgVarp, nodep->arraysp(),
|
||||
0, selects_docs, selects_code );
|
||||
|
||||
ToggleEnt newvec (string(""),
|
||||
new AstVarRef(nodep->fileline(), nodep, false),
|
||||
new AstVarRef(nodep->fileline(), chgVarp, true));
|
||||
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec,
|
||||
nodep, chgVarp);
|
||||
newvec.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void toggleVarRecurse(AstVar* nodep, AstVar* chgVarp, AstRange* arrayp,
|
||||
int dimension, vector<int>& selects_docs, vector<int>& selects_code) {
|
||||
if (arrayp) {
|
||||
for (int index=arrayp->lsbConst(); index<=arrayp->msbConst()+1; index++) {
|
||||
// Handle the next dimension, if any
|
||||
selects_docs[dimension] = index;
|
||||
selects_code[dimension] = index - arrayp->lsbConst();
|
||||
toggleVarRecurse(nodep, chgVarp, arrayp->nextp()->castRange(),
|
||||
dimension+1, selects_docs, selects_code);
|
||||
}
|
||||
} else { // No more arraying - just each bit in the width
|
||||
if (nodep->rangep()) {
|
||||
for (int bitindex_docs=nodep->lsb(); bitindex_docs<nodep->msb()+1; bitindex_docs++) {
|
||||
toggleVarBottom(nodep, chgVarp,
|
||||
dimension, selects_docs, selects_code,
|
||||
true, bitindex_docs);
|
||||
void toggleVarBottom(AstNodeDType* dtypep, int depth, // per-iteration
|
||||
const ToggleEnt& above,
|
||||
AstVar* varp, AstVar* chgVarp) { // Constant
|
||||
AstCoverToggle* newp
|
||||
= new AstCoverToggle (varp->fileline(),
|
||||
newCoverInc(varp->fileline(), "", "v_toggle",
|
||||
varp->name()+above.m_comment),
|
||||
above.m_varRefp->cloneTree(true),
|
||||
above.m_chgRefp->cloneTree(true));
|
||||
m_modp->addStmtp(newp);
|
||||
}
|
||||
|
||||
void toggleVarRecurse(AstNodeDType* dtypep, int depth, // per-iteration
|
||||
const ToggleEnt& above,
|
||||
AstVar* varp, AstVar* chgVarp) { // Constant
|
||||
if (AstBasicDType* bdtypep = dtypep->castBasicDType()) {
|
||||
if (bdtypep->rangep()) {
|
||||
for (int index_docs=bdtypep->lsb(); index_docs<bdtypep->msb()+1; index_docs++) {
|
||||
int index_code = index_docs - bdtypep->lsb();
|
||||
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
|
||||
new AstSel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code, 1),
|
||||
new AstSel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code, 1));
|
||||
toggleVarBottom(dtypep, depth+1,
|
||||
newent,
|
||||
varp, chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
} else {
|
||||
toggleVarBottom(nodep, chgVarp,
|
||||
dimension, selects_docs, selects_code,
|
||||
false, 0);
|
||||
toggleVarBottom(dtypep, depth+1,
|
||||
above,
|
||||
varp, chgVarp);
|
||||
}
|
||||
}
|
||||
}
|
||||
void toggleVarBottom(AstVar* nodep, AstVar* chgVarp,
|
||||
int dimension, vector<int>& selects_docs, vector<int>& selects_code,
|
||||
bool bitsel, int bitindex_docs) {
|
||||
string comment = nodep->name();
|
||||
AstNode* varRefp = new AstVarRef(nodep->fileline(), nodep, false);
|
||||
AstNode* chgRefp = new AstVarRef(nodep->fileline(), chgVarp, true);
|
||||
// Now determine the name of, and how to get to the bit of this slice
|
||||
for (int dim=0; dim<dimension; dim++) {
|
||||
// Comments are strings, not symbols, so we don't need __BRA__ __KET__
|
||||
comment += "["+cvtToStr(selects_docs[dim])+"]";
|
||||
varRefp = new AstArraySel(nodep->fileline(), varRefp, selects_code[dim]);
|
||||
chgRefp = new AstArraySel(nodep->fileline(), chgRefp, selects_code[dim]);
|
||||
else if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) {
|
||||
int index_code = index_docs - adtypep->lsb();
|
||||
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
|
||||
new AstArraySel(varp->fileline(), above.m_varRefp->cloneTree(true), index_code),
|
||||
new AstArraySel(varp->fileline(), above.m_chgRefp->cloneTree(true), index_code));
|
||||
toggleVarRecurse(adtypep->dtypeSkipRefp(), depth+1,
|
||||
newent,
|
||||
varp, chgVarp);
|
||||
newent.cleanup();
|
||||
}
|
||||
}
|
||||
if (bitsel) {
|
||||
comment += "["+cvtToStr(bitindex_docs)+"]";
|
||||
int bitindex_code = bitindex_docs - nodep->lsb();
|
||||
varRefp = new AstSel(nodep->fileline(), varRefp, bitindex_code, 1);
|
||||
chgRefp = new AstSel(nodep->fileline(), chgRefp, bitindex_code, 1);
|
||||
else {
|
||||
dtypep->v3fatalSrc("Unexpected node data type in toggle coverage generation: "<<dtypep->prettyTypeName());
|
||||
}
|
||||
AstCoverToggle* newp = new AstCoverToggle (nodep->fileline(),
|
||||
newCoverInc(nodep->fileline(), "", "v_toggle", comment),
|
||||
varRefp, chgRefp);
|
||||
m_modp->addStmtp(newp);
|
||||
}
|
||||
|
||||
// VISITORS - LINE COVERAGE
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+28
-14
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -22,6 +22,8 @@
|
||||
// Remove any unreferenced modules
|
||||
// Remove any unreferenced variables
|
||||
//
|
||||
// NOTE: If redo this, consider using maybePointedTo()/broken() ish scheme
|
||||
// instead of needing as many visitors.
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
@@ -55,7 +57,7 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
DeadModVisitor(AstModule* nodep) {
|
||||
DeadModVisitor(AstNodeModule* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~DeadModVisitor() {}
|
||||
@@ -68,7 +70,7 @@ class DeadVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire Netlist:
|
||||
// AstModule::user() -> int. Count of number of cells referencing this module.
|
||||
// AstNodeModule::user() -> int. Count of number of cells referencing this module.
|
||||
// AstVar::user() -> int. Count of number of references
|
||||
// AstVarScope::user() -> int. Count of number of references
|
||||
AstUser1InUse m_inuser1;
|
||||
@@ -93,16 +95,31 @@ private:
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->modp()->user1(nodep->modp()->user1() + 1);
|
||||
nodep->modp()->user1Inc();
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->varScopep()) {
|
||||
nodep->varScopep()->user1(nodep->varScopep()->user1() + 1);
|
||||
nodep->varScopep()->varp()->user1(nodep->varScopep()->varp()->user1() + 1);
|
||||
nodep->varScopep()->user1Inc();
|
||||
nodep->varScopep()->varp()->user1Inc();
|
||||
}
|
||||
if (nodep->varp()) {
|
||||
nodep->varp()->user1(nodep->varp()->user1() + 1);
|
||||
nodep->varp()->user1Inc();
|
||||
}
|
||||
if (nodep->packagep()) {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->packagep()) {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->packagep()) {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||
@@ -128,13 +145,10 @@ private:
|
||||
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*) {
|
||||
if (nodep->isOutputter()) m_sideEffect=true;
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
@@ -145,9 +159,9 @@ private:
|
||||
// after we've done all the generate blocks
|
||||
for (bool retry=true; retry; ) {
|
||||
retry=false;
|
||||
AstModule* nextmodp;
|
||||
for (AstModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
|
||||
nextmodp = modp->nextp()->castModule();
|
||||
AstNodeModule* nextmodp;
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
|
||||
nextmodp = modp->nextp()->castNodeModule();
|
||||
if (modp->level()>2 && modp->user1()==0) {
|
||||
// > 2 because L1 is the wrapper, L2 is the top user module
|
||||
UINFO(4," Dead module "<<modp<<endl);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+16
-21
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
// AstVarScope::user1p() -> AstVarScope*. Points to temp var created.
|
||||
// AstVarScope::user2p() -> AstActive*. Points to activity block of signal
|
||||
// AstVarScope::user4p() -> AstAlwaysPost*. Post block for this variable
|
||||
// AstVar::user1() -> VarUsage. Tracks delayed vs non-delayed usage
|
||||
// AstVarScope::user5() -> VarUsage. Tracks delayed vs non-delayed usage
|
||||
// AstVar::user2() -> bool. Set true if already made warning
|
||||
// AstVar::user4() -> int. Vector number, for assignment creation
|
||||
// AstVarRef::user2() -> bool. Set true if already processed
|
||||
@@ -88,6 +88,7 @@ private:
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
|
||||
enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 };
|
||||
|
||||
@@ -98,7 +99,7 @@ private:
|
||||
bool m_inDly; // True in delayed assignments
|
||||
bool m_inLoop; // True in for loops
|
||||
bool m_inInitial; // True in intial blocks
|
||||
typedef std::map<pair<AstModule*,string>,AstVar*> VarMap;
|
||||
typedef std::map<pair<AstNodeModule*,string>,AstVar*> VarMap;
|
||||
VarMap m_modVarMap; // Table of new var names created under module
|
||||
V3Double0 m_statSharedSet;// Statistic tracking
|
||||
|
||||
@@ -110,37 +111,30 @@ private:
|
||||
return level;
|
||||
}
|
||||
|
||||
void markVarUsage(AstVar* nodep, uint32_t flags) {
|
||||
void markVarUsage(AstVarScope* nodep, uint32_t flags) {
|
||||
//UINFO(4," MVU "<<flags<<" "<<nodep<<endl);
|
||||
nodep->user1( nodep->user1() | flags );
|
||||
if ((nodep->user1() & VU_DLY) && (nodep->user1() & VU_NONDLY)) {
|
||||
nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<<nodep->prettyName());
|
||||
nodep->user5( nodep->user5() | flags );
|
||||
if ((nodep->user5() & VU_DLY) && (nodep->user5() & VU_NONDLY)) {
|
||||
nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<<nodep->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
AstVarScope* createVarSc(AstVarScope* oldvarscp, string name, int width/*0==fromoldvar*/) {
|
||||
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
|
||||
if (!oldvarscp->scopep()) oldvarscp->v3fatalSrc("Var unscoped");
|
||||
AstVar* varp;
|
||||
AstModule* addmodp = oldvarscp->scopep()->modp();
|
||||
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
|
||||
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
|
||||
VarMap::iterator iter = m_modVarMap.find(make_pair(addmodp,name));
|
||||
if (iter != m_modVarMap.end()) {
|
||||
// Created module's AstVar earlier under some other scope
|
||||
varp = iter->second;
|
||||
} else {
|
||||
AstRange* rangep = NULL;
|
||||
if (width==0) {
|
||||
rangep = new AstRange(oldvarscp->fileline(),
|
||||
oldvarscp->varp()->msb(),
|
||||
oldvarscp->varp()->lsb());
|
||||
} else if (width==1) {
|
||||
rangep = NULL;
|
||||
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
|
||||
varp->widthSignedFrom(oldvarscp);
|
||||
} else {
|
||||
rangep = new AstRange(oldvarscp->fileline(),
|
||||
width-1, 0);
|
||||
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), width);
|
||||
}
|
||||
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, rangep);
|
||||
if (width==0) varp->widthSignedFrom(oldvarscp);
|
||||
addmodp->addStmtp(varp);
|
||||
m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp));
|
||||
}
|
||||
@@ -165,6 +159,7 @@ private:
|
||||
arrayselp = lhsp->castArraySel();
|
||||
}
|
||||
if (!arrayselp) nodep->v3fatalSrc("No arraysel under bitsel?");
|
||||
if (arrayselp->length()!=1) nodep->v3fatalSrc("ArraySel with length!=1 should have been removed in V3Slice");
|
||||
|
||||
UINFO(4,"AssignDlyArray: "<<nodep<<endl);
|
||||
//
|
||||
@@ -335,7 +330,7 @@ private:
|
||||
&& nodep->lhsp()->castSel()->fromp()->castArraySel())) {
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newlhsp = createDlyArray(nodep, lhsp);
|
||||
if (m_inLoop) nodep->v3warn(BLKLOOPINIT,"Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
|
||||
if (m_inLoop) nodep->v3warn(E_BLKLOOPINIT,"Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
|
||||
if (newlhsp) {
|
||||
nodep->lhsp(newlhsp);
|
||||
} else {
|
||||
@@ -355,7 +350,7 @@ private:
|
||||
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
UINFO(4,"AssignDlyVar: "<<nodep<<endl);
|
||||
markVarUsage(nodep->varp(), VU_DLY);
|
||||
markVarUsage(nodep->varScopep(), VU_DLY);
|
||||
if (!m_activep) nodep->v3fatalSrc("<= not under sensitivity block");
|
||||
if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
|
||||
AstVarScope* oldvscp = nodep->varScopep();
|
||||
@@ -417,7 +412,7 @@ private:
|
||||
//UINFO(9,"NBA "<<nodep<<endl);
|
||||
if (!m_inInitial) {
|
||||
UINFO(4,"AssignNDlyVar: "<<nodep<<endl);
|
||||
markVarUsage(nodep->varp(), VU_NONDLY);
|
||||
markVarUsage(nodep->varScopep(), VU_NONDLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+5
-4
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -46,7 +46,7 @@ private:
|
||||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current block
|
||||
AstNode* m_stmtp; // Current statement
|
||||
int m_depth; // How deep in an expression
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
// Width, not widthMin, as we may be in middle of BITSEL expression which
|
||||
// though it's one bit wide, needs the mask in the upper bits.
|
||||
// (Someday we'll have a valid bitmask instead of widths....)
|
||||
new AstRange(nodep->fileline(), nodep->width()-1, 0));
|
||||
AstLogicPacked(), nodep->width());
|
||||
if (!m_funcp) nodep->v3fatalSrc("Deep expression not under a function");
|
||||
m_funcp->addInitsp(varp);
|
||||
// Replace node tree with reference to var
|
||||
@@ -85,7 +85,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_funcp = NULL;
|
||||
@@ -131,6 +131,7 @@ private:
|
||||
|
||||
//--------------------
|
||||
// Marking of non-static functions (because they might need "this")
|
||||
// (Here just to avoid another iteration)
|
||||
void needNonStaticFunc(AstNode* nodep) {
|
||||
if (!m_funcp) nodep->v3fatalSrc("Non-static accessor not under a function");
|
||||
if (m_funcp->isStatic()) {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -44,7 +44,7 @@ private:
|
||||
// NODE STATE
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
int m_depth; // How deep in an expression
|
||||
int m_deepNum; // How many functions made
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_deepNum = 0;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+7
-7
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -52,7 +52,7 @@ private:
|
||||
typedef multimap<string,AstCFunc*> FuncMmap;
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope
|
||||
bool m_needThis; // Add thisp to function
|
||||
FuncMmap m_modFuncs; // Name of public functions added
|
||||
@@ -121,8 +121,8 @@ private:
|
||||
newfuncp->isStatic(false);
|
||||
newfuncp->addInitsp(
|
||||
new AstCStmt(newfuncp->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
newfuncp->addInitsp(new AstCStmt(newfuncp->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
newfuncp->addInitsp(new AstCStmt(newfuncp->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
topFuncp->addNextHere(newfuncp);
|
||||
// In the body, call each function if it matches the given scope
|
||||
for (FuncMmap::iterator eachIt = it; eachIt!=m_modFuncs.end() && eachIt->first==name; ++eachIt) {
|
||||
@@ -166,7 +166,7 @@ private:
|
||||
}
|
||||
}
|
||||
// Not really any way the user could do this, and we'd need to come up with some return value
|
||||
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DISPLAY,
|
||||
//newfuncp->addStmtsp(new AstDisplay (newfuncp->fileline(), AstDisplayType::DT_DISPLAY,
|
||||
// string("%%Error: ")+name+"() called with bad scope", NULL));
|
||||
//newfuncp->addStmtsp(new AstStop (newfuncp->fileline()));
|
||||
if (debug()>=9) newfuncp->dumpTree(cout," newfunc: ");
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
m_modFuncs.clear();
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -224,7 +224,7 @@ private:
|
||||
if (m_needThis) {
|
||||
nodep->v3fatalSrc("old code");
|
||||
// Really we should have more node types for backend optimization of this stuff
|
||||
string text = " "+v3Global.opt.modPrefix() + "_" + m_modp->name()
|
||||
string text = v3Global.opt.modPrefix() + "_" + m_modp->name()
|
||||
+"* thisp = &("+m_scopep->nameVlSym()+");\n";
|
||||
nodep->addInitsp(new AstCStmt(nodep->fileline(), text));
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2011 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+341
-172
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user