mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 00:23:35 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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,151 @@ 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.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 +1649,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-2010 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
+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/
|
||||
|
||||
+124
-61
@@ -9,7 +9,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -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,18 +106,19 @@ 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/*.cpp \
|
||||
test_regress/t/*.h \
|
||||
@@ -125,6 +126,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
test_regress/t/*.mem \
|
||||
test_regress/t/*.out \
|
||||
test_regress/t/*.pl \
|
||||
test_regress/t/*.pf \
|
||||
test_regress/t/*.v* \
|
||||
verilator.* \
|
||||
|
||||
@@ -132,10 +134,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 +144,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 +206,7 @@ verilator.1: bin/verilator
|
||||
pod2man $< $@
|
||||
|
||||
verilator.txt: bin/verilator
|
||||
pod2text $< $@
|
||||
$(POD2TEXT) $< $@
|
||||
|
||||
verilator.html: bin/verilator
|
||||
pod2html $< >$@
|
||||
@@ -225,49 +227,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 +323,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 +340,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 +375,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 +396,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 +416,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 +432,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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
|
||||
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-2010.
|
||||
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)
|
||||
|
||||
+632
-267
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-2010 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-2010 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-2010 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-2010 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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
+191
-40
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -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,11 +386,7 @@ 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
|
||||
@@ -266,11 +397,11 @@ static inline void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) {
|
||||
|
||||
/// 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 +668,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 +687,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 +733,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 +934,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);
|
||||
@@ -823,7 +954,7 @@ static inline QData VL_UNARYMIN_Q(QData data) { return -data; }
|
||||
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
|
||||
|
||||
|
||||
+14
-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-2010 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.
|
||||
######################################################################
|
||||
@@ -26,6 +26,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 +45,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 +58,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 +117,6 @@ endif
|
||||
|
||||
ifeq ($(VM_SC),1)
|
||||
LIBS += -lm -lstdc++
|
||||
ifeq ($(VM_TRACE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
@@ -120,10 +124,6 @@ endif
|
||||
|
||||
ifeq ($(VM_PCLI),1)
|
||||
LIBS += -lm -lstdc++
|
||||
ifeq ($(VM_TRACE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
@@ -136,6 +136,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 +173,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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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> 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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software;
|
||||
// you can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
//
|
||||
// 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
|
||||
+93
-16
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||
// Version 2.0.
|
||||
@@ -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-2010 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-2010 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-2010 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-2010 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-2010 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-2010 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-2010 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-2010 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-2010 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-2010 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-2010 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
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2010-2010 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;
|
||||
|
||||
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-2010 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.
|
||||
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
# 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-2010 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. As described in the System-Perl README, you will need to set
|
||||
SYSTEMC and/or SYSTEMC_KIT to point to this download. Also, set
|
||||
SYSTEMC_ARCH to the architecture name you used with SystemC, generally
|
||||
'linux' or 'cygwin'.
|
||||
|
||||
=item
|
||||
|
||||
If you will be using SystemPerl or coverage, download and install
|
||||
Verilog-Perl, L<http://www.veripool.org/verilog-perl>.
|
||||
|
||||
=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.
|
||||
|
||||
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; you just point to the tarball.
|
||||
|
||||
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
||||
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
||||
./configure
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
Finally, if you are configuring Verilator to be part of a RPM or other
|
||||
distribution package system, you may want to tune the various install
|
||||
directories and use the --enable-defenv configure flag. This will take the
|
||||
current value of VERILATOR_ROOT, SYSTEMC, SYSTEMC_ARCH, SYSTEMPERL, and
|
||||
SYSTEMPERL_INCLUDE and build them as defaults into the executable.
|
||||
|
||||
=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 sheme 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>.
|
||||
|
||||
Verilator assumes you did a make in the SystemC kit directory. If not, you
|
||||
will need to populate C<$SYSTEMC/include> and C<$SYSTEMC/lib-linux>
|
||||
appropriately.
|
||||
|
||||
=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-2010 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.
|
||||
+9
-9
@@ -7,7 +7,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -40,11 +40,10 @@ 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
|
||||
|
||||
UNDER_GIT = $(wildcard ../.git/logs/HEAD)
|
||||
@@ -61,17 +60,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::
|
||||
|
||||
+39
-15
@@ -7,7 +7,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -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 \
|
||||
@@ -208,9 +228,10 @@ RAW_OBJS = \
|
||||
|
||||
# Non-concatable
|
||||
OBJS += \
|
||||
V3Parse.o \
|
||||
V3ParseImp.o \
|
||||
V3ParseGrammar.o \
|
||||
V3ParseLex.o \
|
||||
V3PreProc.o \
|
||||
V3Read.o \
|
||||
|
||||
#### Linking
|
||||
|
||||
@@ -245,10 +266,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 +297,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 <$< >$@
|
||||
|
||||
######################################################################
|
||||
######################################################################
|
||||
|
||||
+35
-29
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -197,7 +197,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 +250,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 +263,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 +300,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
|
||||
@@ -331,17 +320,35 @@ private:
|
||||
ActiveDlyVisitor dlyvisitor (nodep);
|
||||
}
|
||||
}
|
||||
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 +373,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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+5
-2
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+21
-24
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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,8 +177,7 @@ 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;
|
||||
@@ -217,7 +214,7 @@ private:
|
||||
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 +225,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 +254,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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+25
-16
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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() {
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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]";
|
||||
}
|
||||
|
||||
+845
-232
File diff suppressed because it is too large
Load Diff
+4
-52
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -48,7 +48,7 @@
|
||||
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
|
||||
@@ -62,7 +62,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 +135,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 +142,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);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+25
-1
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+10
-7
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+11
-10
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+2
-3
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2008-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2008-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+14
-16
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+8
-4
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Configuration Files
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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_ignFiles; // Ignores for each filename
|
||||
|
||||
static V3ConfigIgnores s_singleton; // Singleton (not via local static, as that's slow)
|
||||
|
||||
V3ConfigIgnores() { m_lastLineno = -1; }
|
||||
~V3ConfigIgnores() {}
|
||||
|
||||
// METHODS
|
||||
inline IgnLines* findLines(const string& filename) {
|
||||
IgnFiles::iterator it = m_ignFiles.find(filename);
|
||||
if (it != m_ignFiles.end()) {
|
||||
return &(it->second);
|
||||
} else {
|
||||
m_ignFiles.insert(make_pair(filename, IgnLines()));
|
||||
it = m_ignFiles.find(filename);
|
||||
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.
|
||||
IgnLines* linesp = findLines(filename);
|
||||
m_lastIt = linesp->begin();
|
||||
m_lastEnd = linesp->end();
|
||||
}
|
||||
|
||||
public:
|
||||
inline static V3ConfigIgnores& singleton() { return s_singleton; }
|
||||
|
||||
void addIgnore(V3ErrorCode code, string filename, int lineno, bool on) {
|
||||
// Insert
|
||||
IgnLines* linesp = findLines(filename);
|
||||
UINFO(9,"config addIgnore "<<filename<<":"<<lineno<<", "<<code<<", "<<on<<endl);
|
||||
linesp->insert(V3ConfigLine(code, lineno, on));
|
||||
if (m_lastFilename == filename) {
|
||||
// Flush the match cache, due to a change in the rules.
|
||||
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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
//
|
||||
// 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
|
||||
+104
-35
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Read.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Signed.h"
|
||||
@@ -97,6 +96,7 @@ private:
|
||||
// ** only when m_warn/m_expensive 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
|
||||
@@ -105,7 +105,7 @@ private:
|
||||
bool m_warn; // Output warnings
|
||||
bool m_cpp; // C++ conversions only
|
||||
bool m_expensive; // Enable computationally expensive optimizations
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNode* m_scopep; // Current scope
|
||||
|
||||
// METHODS
|
||||
@@ -307,13 +307,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 +323,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 +395,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 +433,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
|
||||
@@ -771,9 +782,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
|
||||
@@ -866,7 +877,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;
|
||||
@@ -1054,14 +1065,14 @@ private:
|
||||
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 (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
|
||||
&& !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 +1083,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) {
|
||||
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;
|
||||
@@ -1149,8 +1182,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 +1191,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;
|
||||
}
|
||||
@@ -1244,16 +1279,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
|
||||
@@ -1283,7 +1318,7 @@ private:
|
||||
&& 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->varp()->valuep() // Not already constified
|
||||
&& !varrefp->varScopep() // Not scoped (or each scope may have different initial value)
|
||||
&& !m_params) {
|
||||
// ASSIGNW (VARREF, const) -> INITIAL ( ASSIGN (VARREF, const) )
|
||||
@@ -1299,7 +1334,7 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1379,7 +1414,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -1434,6 +1469,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*) {
|
||||
@@ -1447,7 +1488,8 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->condp()->isZero()) {
|
||||
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
||||
nodep->unlinkFrBack();
|
||||
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (operandBoolShift(nodep->condp())) {
|
||||
@@ -1459,6 +1501,30 @@ private:
|
||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
||||
|
||||
//-----
|
||||
// Jump elimination
|
||||
|
||||
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_expensive) { 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_expensive && !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
|
||||
@@ -1484,7 +1550,7 @@ private:
|
||||
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)");
|
||||
TREEOP("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)");
|
||||
@@ -1687,6 +1753,9 @@ private:
|
||||
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
|
||||
TREEOP ("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, nodep->lhsp()->castConst()->num().toString())");
|
||||
|
||||
|
||||
// Possible futures:
|
||||
// (a?(b?y:x):y) -> (a&&!b)?x:y
|
||||
@@ -1742,7 +1811,7 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+71
-58
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+28
-14
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+16
-21
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+5
-4
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+7
-7
@@ -7,7 +7,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -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-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+341
-172
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
+22
-4
@@ -8,7 +8,7 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
|
||||
virtual void putsIntTopInclude() {
|
||||
puts("#include \"systemc.h\"\n");
|
||||
puts("#include \"verilatedsc.h\"\n");
|
||||
puts("#include \"verilated_sc.h\"\n");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
|
||||
virtual void putsIntTopInclude() {
|
||||
puts("#include \"systemperl.h\"\n");
|
||||
puts("#include \"verilatedsc.h\"\n");
|
||||
puts("#include \"verilated_sc.h\"\n");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
static string symClassName() { return v3Global.opt.prefix()+"__Syms"; }
|
||||
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
|
||||
static string symTopAssign() { return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
|
||||
static string modClassName(AstModule* modp) { // Return name of current module being processed
|
||||
static string modClassName(AstNodeModule* modp) { // Return name of current module being processed
|
||||
if (modp->isTop()) {
|
||||
return v3Global.opt.prefix();
|
||||
} else {
|
||||
@@ -136,6 +136,24 @@ public:
|
||||
v3Global.rootp()->addFilesp(cfilep);
|
||||
return cfilep;
|
||||
}
|
||||
string cFuncArgs(AstCFunc* nodep) {
|
||||
// Return argument list for given C function
|
||||
string args = nodep->argTypes();
|
||||
// Might be a user function with argument list.
|
||||
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args+= ", ";
|
||||
if (nodep->dpiImport() || nodep->dpiExportWrapper())
|
||||
args += portp->dpiArgType(true,false);
|
||||
else if (nodep->funcPublic())
|
||||
args += portp->cPubArgType(true,false);
|
||||
else args += portp->vlArgType(true,false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
EmitCBaseVisitor() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user