mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 16:44:11 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -3,6 +3,32 @@ 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.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".
|
||||
|
||||
+55
-19
@@ -134,10 +134,9 @@ INST_PROJ_FILES = \
|
||||
bin/verilator \
|
||||
bin/verilator_includer \
|
||||
bin/verilator_profcfunc \
|
||||
include/verilated.[chv]* \
|
||||
include/verilated.mk \
|
||||
include/verilatedos.[chv]* \
|
||||
include/verilated_*.[chv]* \
|
||||
include/*.[chv]* \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
INST_PROJ_BIN_FILES = \
|
||||
verilator_bin \
|
||||
@@ -245,11 +244,15 @@ VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
||||
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||
VL_INST_MAN_FILES = verilator.1
|
||||
|
||||
VL_INST_INC_FILES = \
|
||||
include/*.[chv]* include/verilated.mk \
|
||||
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_FILES = \
|
||||
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 \
|
||||
@@ -267,20 +270,25 @@ installbin:
|
||||
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)/include/vltstd
|
||||
for p in $(VL_INST_INC_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
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
|
||||
for p in $(VL_INST_DATA_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
|
||||
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
|
||||
@@ -288,8 +296,9 @@ 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_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_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
|
||||
@@ -306,6 +315,7 @@ 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
|
||||
@@ -313,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
|
||||
@@ -330,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
|
||||
@@ -337,11 +375,8 @@ 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
|
||||
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||
@@ -402,6 +437,7 @@ 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))
|
||||
|
||||
+39
-18
@@ -1389,20 +1389,20 @@ Verilator configuration commands.
|
||||
|
||||
=item coverage_off [-file "<filename>" [-lines <line> [ - <line> ]]]
|
||||
|
||||
Disable coverage for the specified filename (or all files if ommitted) and
|
||||
range of line numbers (or all lines if ommitted). Often used to ignore an
|
||||
Disable coverage for the specified filename (or all files if omitted) and
|
||||
range of line numbers (or all lines if omitted). Often used to ignore an
|
||||
entire module for coverage analysis purposes.
|
||||
|
||||
=item lint_off -msg <message> [-file "<filename>" [-lines <line> [ - <line>]]]
|
||||
|
||||
Disables the specified lint warning in the specified filename (or all files
|
||||
if ommitted) and range of line numbers (or all lines if ommitted).
|
||||
if omitted) and range of line numbers (or all lines if omitted).
|
||||
|
||||
=item tracing_off [-file "<filename>" [-lines <line> [ - <line> ]]]
|
||||
|
||||
Disable waveform tracing for all future signals declared in the specified
|
||||
filename (or all files if ommitted) and range of line numbers (or all lines
|
||||
if ommitted).
|
||||
filename (or all files if omitted) and range of line numbers (or all lines
|
||||
if omitted).
|
||||
|
||||
=back
|
||||
|
||||
@@ -1644,7 +1644,7 @@ Often used to ignore an entire module for coverage analysis purposes.
|
||||
|
||||
=item /*verilator coverage_on*/
|
||||
|
||||
Specifies that following lines of code should have coverage reenabled (if
|
||||
Specifies that following lines of code should have coverage re-enabled (if
|
||||
appropriate --coverage flags are passed) after being disabled earlier with
|
||||
/*verilator coverage_off*/.
|
||||
|
||||
@@ -1770,6 +1770,18 @@ signal. This will not declare this module public, which means the name of
|
||||
the signal or path to it may change based upon the module inlining which
|
||||
takes place.
|
||||
|
||||
=item /*verilator public_flat_rd*/ (variable)
|
||||
|
||||
Used after a input, output, register, or wire declaration to indicate the
|
||||
signal should be declared public_flat (see above), but read-only.
|
||||
|
||||
=item /*verilator public_flat_rw @(<edge_list>) */ (variable)
|
||||
|
||||
Used after a input, output, register, or wire declaration to indicate the
|
||||
signal should be declared public_flat_rd (see above), and also writable,
|
||||
where writes should be considered to have the timing specified by the given
|
||||
sensitivity edge list.
|
||||
|
||||
=item /*verilator public_module*/
|
||||
|
||||
Used after a module statement to indicate the module should not be inlined
|
||||
@@ -1819,14 +1831,17 @@ program will find for you.
|
||||
Verilator supports only the Synthesis subset with a few minor additions
|
||||
such as $stop, $finish and $display. That is, you cannot use hierarchical
|
||||
references, events or similar features of the Verilog language. It also
|
||||
simulates as Synopsys's Design Compiler would; namely a block of the form
|
||||
simulates as Synopsys's Design Compiler would; namely a block of the form:
|
||||
|
||||
always @ (x) y = x & z;
|
||||
|
||||
will recompute y when there is a change in x or a change in z, which is
|
||||
what Design Compiler will synthesize. A compliant simulator would only
|
||||
calculate y if x changes. (Use verilog-mode's /*AS*/ or Verilog 2001's
|
||||
always @* to prevent these issues.)
|
||||
This will recompute y when there is even a potential for change in x or a
|
||||
change in z, that is when the flops computing x or z evaluate (which is
|
||||
what Design Compiler will synthesize.) A compliant simulator would only
|
||||
calculate y if x changes. Use verilog-mode's /*AS*/ or Verilog 2001's
|
||||
always @* to reduce missing activity items. Avoid putting $displays in
|
||||
combo blocks, as they may print multiple times when not desired, even on
|
||||
compliant simulators as event ordering is not specified.
|
||||
|
||||
=head2 Dotted cross-hierarchy references
|
||||
|
||||
@@ -2597,8 +2612,8 @@ allows you to modify Verilator for internal use without distributing the
|
||||
modified version. But please contribute back to the community!
|
||||
|
||||
One limit is that you cannot under either license release a commercial
|
||||
simulation product incorporating Verilator without making the source code
|
||||
available.
|
||||
Verilog simulation product incorporating Verilator without making the
|
||||
source code available.
|
||||
|
||||
=item Why is Verilation so slow?
|
||||
|
||||
@@ -2620,8 +2635,10 @@ in your main loop call "trace_object->dump(time)" every time step, and
|
||||
finally call "trace_object->close()". For an example, see below and the
|
||||
test_c/sim_main.cpp file of the distribution.
|
||||
|
||||
You also need to compile verilated_vcd_c.cpp and add it to your link. This
|
||||
is done for you if using the Verilator --exe flag.
|
||||
You also need to compile verilated_vcd_c.cpp and add it to your link,
|
||||
preferably by adding the dependancies in $(VK_GLOBAL_OBJS) to your
|
||||
Makefile's link rule. This is done for you if using the Verilator --exe
|
||||
flag.
|
||||
|
||||
Note you can also call ->trace on multiple Verilated objects with the same
|
||||
trace file if you want all data to land in the same output file.
|
||||
@@ -2658,8 +2675,10 @@ Alternatively you may use the C++ trace mechanism described in the previous
|
||||
question, however the timescale and timeprecision will not inherited from
|
||||
your SystemC settings.
|
||||
|
||||
You also need to compile verilated_vcd_sc.cpp and add it to your link.
|
||||
This is done for you if using the Verilator --exe flag.
|
||||
You also need to compile verilated_vcd_sc.cpp and verilated_vcd_c.cpp and
|
||||
add them to your link, preferably by adding the dependancies in
|
||||
$(VK_GLOBAL_OBJS) to your Makefile's link rule. This is done for you if
|
||||
using the Verilator --exe flag.
|
||||
|
||||
Note you can also call ->trace on multiple Verilated objects with the same
|
||||
trace file if you want all data to land in the same output file.
|
||||
@@ -2765,7 +2784,9 @@ simulator knows the current time. See the "CONNECTING TO C++" examples.
|
||||
=item Why do I get "undefined reference to `VL_RAND_RESET_I' or `Verilated::...'"?
|
||||
|
||||
You need to link your compiled Verilated code against the verilated.cpp
|
||||
file found in the include directory of the Verilator kit.
|
||||
file found in the include directory of the Verilator kit. This is one
|
||||
target in the $(VK_GLOBAL_OBJS) make variable, which should be part of your
|
||||
Makefile's link rule.
|
||||
|
||||
=item Is the PLI supported?
|
||||
|
||||
|
||||
+76
-6
@@ -38,7 +38,7 @@ int Verilated::s_randReset = 0;
|
||||
VerilatedVoidCb Verilated::s_flushCb = NULL;
|
||||
|
||||
// Keep below together in one cache line
|
||||
int Verilated::s_debug = 1;
|
||||
int Verilated::s_debug = 0;
|
||||
bool Verilated::s_calcUnusedSigs = false;
|
||||
bool Verilated::s_gotFinish = false;
|
||||
bool Verilated::s_assertOn = true;
|
||||
@@ -833,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;
|
||||
@@ -861,7 +861,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
_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");
|
||||
}
|
||||
}
|
||||
@@ -878,7 +878,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
|
||||
// Final checks
|
||||
fclose(fp);
|
||||
if (end != VL_UL(0xffffffff) && addr != (end+1)) {
|
||||
if (VL_UNLIKELY(end != VL_UL(0xffffffff) && addr != (end+1))) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmem file ended before specified ending-address");
|
||||
}
|
||||
}
|
||||
@@ -995,6 +995,10 @@ 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);
|
||||
}
|
||||
@@ -1010,6 +1014,23 @@ 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
|
||||
|
||||
@@ -1017,12 +1038,14 @@ 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
|
||||
}
|
||||
|
||||
@@ -1047,10 +1070,10 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) {
|
||||
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
||||
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; }
|
||||
} else {
|
||||
if (funcnum >= m_funcnumMax) {
|
||||
if (VL_UNLIKELY(funcnum >= m_funcnumMax)) {
|
||||
vl_fatal(__FILE__,__LINE__,"","Internal: Bad funcnum vs. pre-finalize maximum");
|
||||
}
|
||||
if (!m_callbacksp) { // First allocation
|
||||
if (VL_UNLIKELY(!m_callbacksp)) { // First allocation
|
||||
m_callbacksp = new void* [m_funcnumMax];
|
||||
memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*));
|
||||
}
|
||||
@@ -1058,6 +1081,47 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* 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 '")
|
||||
@@ -1085,6 +1149,12 @@ void VerilatedScope::scopeDump() const {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
@@ -66,9 +66,33 @@ 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
|
||||
|
||||
@@ -138,6 +162,9 @@ 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
|
||||
@@ -155,6 +182,7 @@ class VerilatedScope {
|
||||
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
|
||||
@@ -162,9 +190,13 @@ public: // But internals only - called from VerilatedModule's
|
||||
~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;
|
||||
@@ -247,6 +279,8 @@ public:
|
||||
// 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; }
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_heavy.h"
|
||||
#include "verilated_syms.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -41,13 +42,6 @@ class VerilatedScope;
|
||||
//======================================================================
|
||||
// Types
|
||||
|
||||
struct VerilatedCStrCmp {
|
||||
// For ordering maps keyed by const char*'s
|
||||
bool operator() (const char *a, const char *b) const {
|
||||
return std::strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
|
||||
|
||||
@@ -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
|
||||
+39
-12
@@ -154,6 +154,39 @@ void VerilatedVcd::openNext (bool incFilename) {
|
||||
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; }
|
||||
@@ -201,7 +234,7 @@ void VerilatedVcd::printStr (const char* str) {
|
||||
|
||||
void VerilatedVcd::printQuad (vluint64_t n) {
|
||||
char buf [100];
|
||||
sprintf(buf,"%" VL_PRI64 "u",(long long unsigned)n);
|
||||
sprintf(buf,"%" VL_PRI64 "u", n);
|
||||
printStr(buf);
|
||||
}
|
||||
|
||||
@@ -227,10 +260,10 @@ void VerilatedVcd::bufferFlush () {
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
char* wp = m_wrBufp;
|
||||
while (1) {
|
||||
size_t remaining = (m_writep - wp);
|
||||
ssize_t remaining = (m_writep - wp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
int got = write (m_fd, wp, remaining);
|
||||
ssize_t got = write (m_fd, wp, remaining);
|
||||
if (got>0) {
|
||||
wp += got;
|
||||
m_wroteBytes += got;
|
||||
@@ -314,13 +347,7 @@ void VerilatedVcd::dumpHeader () {
|
||||
printStr(doubleToTimescale(m_timeRes).c_str());
|
||||
printStr(" $end\n");
|
||||
|
||||
// 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);
|
||||
}
|
||||
makeNameMap();
|
||||
|
||||
// Signal header
|
||||
assert (m_modDepth==0);
|
||||
@@ -346,7 +373,7 @@ void VerilatedVcd::dumpHeader () {
|
||||
// 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--; }
|
||||
//cout <<"hier "<<hiername<<endl<<" lp "<<lp<<endl<<" np "<<np<<endl;
|
||||
//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;
|
||||
@@ -394,7 +421,7 @@ void VerilatedVcd::module (string name) {
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
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;
|
||||
|
||||
@@ -99,6 +99,7 @@ private:
|
||||
void closePrev();
|
||||
void closeErr();
|
||||
void openNext();
|
||||
void makeNameMap();
|
||||
void printIndent (int levelchange);
|
||||
void printStr (const char* str);
|
||||
void printQuad (vluint64_t n);
|
||||
|
||||
+24
-2
@@ -126,8 +126,13 @@ typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibili
|
||||
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)
|
||||
|
||||
@@ -141,6 +146,14 @@ 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
|
||||
@@ -149,8 +162,13 @@ 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
|
||||
|
||||
//=========================================================================
|
||||
@@ -160,7 +178,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#ifdef _WIN32
|
||||
# define VL_PRI64 "I64"
|
||||
#else // Linux or compliant Unix flavors
|
||||
# define VL_PRI64 "ll"
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
# define VL_PRI64 "l"
|
||||
# else
|
||||
# define VL_PRI64 "ll"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -59,9 +59,9 @@ sub test {
|
||||
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 --exe foo.v");
|
||||
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 for this to work
|
||||
#Need .c file, and --exe for this to work
|
||||
#run("cd $testdir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
@@ -126,6 +126,7 @@ sub prep {
|
||||
#
|
||||
$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;
|
||||
|
||||
+29
-23
@@ -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
|
||||
|
||||
@@ -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,6 +320,24 @@ 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::ET_ANYEDGE
|
||||
@@ -366,7 +373,6 @@ public:
|
||||
// CONSTUCTORS
|
||||
ActiveVisitor(AstNetlist* nodep) {
|
||||
m_scopeFinalp = NULL;
|
||||
m_alwaysp = NULL;
|
||||
m_itemCombo = false;
|
||||
m_itemSequent = false;
|
||||
nodep->accept(*this);
|
||||
|
||||
@@ -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
-2
@@ -177,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;
|
||||
|
||||
+9
-1
@@ -179,6 +179,8 @@ public:
|
||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
||||
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
|
||||
};
|
||||
@@ -186,7 +188,8 @@ public:
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"EXPR_BITS", "VAR_BASE",
|
||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
||||
"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];
|
||||
@@ -819,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 {
|
||||
@@ -827,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 {
|
||||
@@ -835,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 {
|
||||
@@ -843,6 +849,7 @@ 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 {
|
||||
@@ -851,6 +858,7 @@ public:
|
||||
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; }
|
||||
|
||||
+50
-5
@@ -137,6 +137,43 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||
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;
|
||||
@@ -258,13 +295,15 @@ uint32_t AstVar::arrayElements() const {
|
||||
return entries;
|
||||
}
|
||||
|
||||
uint32_t AstVar::dimensions() const {
|
||||
// How many array dimensions does this Var have?
|
||||
uint32_t dim = 0;
|
||||
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()) {
|
||||
dim += 1;
|
||||
if (adtypep->isPacked()) packed += 1;
|
||||
else unpacked += 1;
|
||||
dtypep = adtypep->dtypep();
|
||||
}
|
||||
else {
|
||||
@@ -272,7 +311,7 @@ uint32_t AstVar::dimensions() const {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dim;
|
||||
return make_pair(packed, unpacked);
|
||||
}
|
||||
|
||||
// Special operators
|
||||
@@ -348,6 +387,8 @@ string AstScopeName::scopeSymName() const {
|
||||
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, "__");
|
||||
@@ -464,6 +505,10 @@ 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()<<"]";
|
||||
|
||||
+38
-5
@@ -204,13 +204,17 @@ public:
|
||||
|
||||
struct AstArrayDType : public AstNodeDType {
|
||||
// Array data type, ie "some_dtype var_name [2:0]"
|
||||
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep)
|
||||
: AstNodeDType(fl) {
|
||||
private:
|
||||
bool m_packed;
|
||||
public:
|
||||
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep, bool isPacked=false)
|
||||
: AstNodeDType(fl), m_packed(isPacked) {
|
||||
setOp1p(dtypep);
|
||||
setOp2p(rangep);
|
||||
widthSignedFrom(dtypep);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
|
||||
virtual void dump(ostream& str);
|
||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
|
||||
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
@@ -225,6 +229,7 @@ struct AstArrayDType : public AstNodeDType {
|
||||
int lsb() const { return arrayp()->lsbConst(); }
|
||||
int elementsConst() const { return arrayp()->elementsConst(); }
|
||||
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
|
||||
bool isPacked() const { return m_packed; }
|
||||
};
|
||||
|
||||
struct AstBasicDType : public AstNodeDType {
|
||||
@@ -542,8 +547,10 @@ private:
|
||||
bool m_sc:1; // SystemC variable
|
||||
bool m_scClocked:1; // SystemC sc_clk<> needed
|
||||
bool m_scSensitive:1;// SystemC sensitive() needed
|
||||
bool m_sigPublic:1; // User C code accesses this signal
|
||||
bool m_sigPublic:1; // User C code accesses this signal or is top signal
|
||||
bool m_sigModPublic:1;// User C code accesses this signal and module
|
||||
bool m_sigUserRdPublic:1; // User C code accesses this signal, read only
|
||||
bool m_sigUserRWPublic:1; // User C code accesses this signal, read-write
|
||||
bool m_usedClock:1; // Signal used as a clock
|
||||
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
|
||||
bool m_funcLocal:1; // Local variable for a function
|
||||
@@ -561,7 +568,7 @@ private:
|
||||
m_primaryIO=false;
|
||||
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
||||
m_usedClock=false; m_usedParam=false;
|
||||
m_sigPublic=false; m_sigModPublic=false;
|
||||
m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false;
|
||||
m_funcLocal=false; m_funcReturn=false;
|
||||
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
||||
@@ -607,12 +614,14 @@ public:
|
||||
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
||||
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
|
||||
void combineType(AstVarType type);
|
||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeDimensionp(int depth) const;
|
||||
uint32_t dimensions() const;
|
||||
pair<uint32_t,uint32_t> dimensions() const;
|
||||
AstNode* valuep() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
|
||||
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than a AstConst
|
||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||
@@ -628,6 +637,8 @@ public:
|
||||
void usedParam(bool flag) { m_usedParam = flag; }
|
||||
void sigPublic(bool flag) { m_sigPublic = flag; }
|
||||
void sigModPublic(bool flag) { m_sigModPublic = flag; }
|
||||
void sigUserRdPublic(bool flag) { m_sigUserRdPublic = flag; if (flag) sigPublic(true); }
|
||||
void sigUserRWPublic(bool flag) { m_sigUserRWPublic = flag; if (flag) sigUserRdPublic(true); }
|
||||
void sc(bool flag) { m_sc = flag; }
|
||||
void scSensitive(bool flag) { m_scSensitive = flag; }
|
||||
void primaryIO(bool flag) { m_primaryIO = flag; }
|
||||
@@ -670,6 +681,8 @@ public:
|
||||
bool isScSensitive() const { return m_scSensitive; }
|
||||
bool isSigPublic() const;
|
||||
bool isSigModPublic() const { return m_sigModPublic; }
|
||||
bool isSigUserRdPublic() const { return m_sigUserRdPublic; }
|
||||
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
bool isConst() const { return m_isConst; }
|
||||
bool isStatic() const { return m_isStatic; }
|
||||
@@ -699,6 +712,8 @@ public:
|
||||
combineType(typevarp->varType());
|
||||
if (typevarp->isSigPublic()) sigPublic(true);
|
||||
if (typevarp->isSigModPublic()) sigModPublic(true);
|
||||
if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true);
|
||||
if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true);
|
||||
if (typevarp->attrScClocked()) attrScClocked(true);
|
||||
}
|
||||
void inlineAttrReset(const string& name) {
|
||||
@@ -1265,6 +1280,24 @@ struct AstAlways : public AstNode {
|
||||
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
||||
};
|
||||
|
||||
struct AstAlwaysPublic : public AstNodeStmt {
|
||||
// "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/
|
||||
// Body statements are just AstVarRefs to the public signals
|
||||
AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
||||
: AstNodeStmt(fl) {
|
||||
addNOp1p(sensesp); addNOp2p(bodysp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(AlwaysPublic, ALWAYSPUBLIC)
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
//
|
||||
AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list
|
||||
AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate
|
||||
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
|
||||
// Special accessors
|
||||
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
||||
};
|
||||
|
||||
struct AstAlwaysPost : public AstNode {
|
||||
// Like always but post assignments for memory assignment IFs
|
||||
AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
||||
|
||||
@@ -642,6 +642,9 @@ private:
|
||||
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);
|
||||
}
|
||||
|
||||
+1
-2
@@ -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
-2
@@ -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();
|
||||
|
||||
|
||||
+8
-11
@@ -95,31 +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()->user1(nodep->packagep()->user1() + 1);
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->packagep()) {
|
||||
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->packagep()) {
|
||||
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||
@@ -145,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);
|
||||
}
|
||||
|
||||
|
||||
+8
-5
@@ -149,6 +149,8 @@ public:
|
||||
if (decind) ofp()->blockDec();
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic*, AstNUser*) {
|
||||
}
|
||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||
puts(nodep->hiername());
|
||||
puts(nodep->funcp()->name());
|
||||
@@ -541,17 +543,18 @@ public:
|
||||
}
|
||||
for (int word=VL_WORDS_I(nodep->num().minWidth())-1; word>0; word--) {
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x", (long long)(nodep->num().dataWord(word)));
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x", (vluint64_t)(nodep->num().dataWord(word)));
|
||||
}
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x)", (long long)(nodep->num().dataWord(0)));
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x)", (vluint64_t)(nodep->num().dataWord(0)));
|
||||
} else if (nodep->isQuad()) {
|
||||
vluint64_t num = nodep->toUQuad();
|
||||
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", (long long)num);
|
||||
else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", (long long)num);
|
||||
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
|
||||
else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", num);
|
||||
} else {
|
||||
uint32_t num = nodep->toUInt();
|
||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||
if (num<10) puts(cvtToStr(num));
|
||||
else ofp()->printf("0x%" VL_PRI64 "x", (long long)num);
|
||||
else ofp()->printf("0x%" VL_PRI64 "x", (vluint64_t)num);
|
||||
//Unneeded-Causes %lx format warnings:
|
||||
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
|
||||
}
|
||||
|
||||
+134
-6
@@ -45,13 +45,24 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
struct ScopeNameData { string m_symName; string m_prettyName;
|
||||
ScopeNameData(const string& symName, const string& prettyName)
|
||||
: m_symName(symName), m_prettyName(prettyName) {}
|
||||
};
|
||||
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
||||
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
||||
: m_scopep(scopep), m_funcp(funcp), m_modp(modp) {}
|
||||
};
|
||||
struct ScopeVarData { string m_scopeName; string m_varBasePretty; AstVar* m_varp;
|
||||
AstNodeModule* m_modp; AstScope* m_scopep;
|
||||
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp, AstNodeModule* modp, AstScope* scopep)
|
||||
: m_scopeName(scopeName), m_varBasePretty(varBasePretty), m_varp(varp), m_modp(modp), m_scopep(scopep) {}
|
||||
};
|
||||
typedef map<string,ScopeFuncData> ScopeFuncs;
|
||||
typedef map<string,AstScopeName*> ScopeNames;
|
||||
typedef map<string,ScopeVarData> ScopeVars;
|
||||
typedef map<string,ScopeNameData> ScopeNames;
|
||||
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
|
||||
typedef pair<AstNodeModule*,AstVar*> ModVarPair;
|
||||
struct CmpName {
|
||||
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
||||
return lhsp.first->name() < rhsp.first->name();
|
||||
@@ -71,8 +82,10 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
AstNodeModule* m_modp; // Current module
|
||||
vector<ScopeModPair> m_scopes; // Every scope by module
|
||||
vector<AstCFunc*> m_dpis; // DPI functions
|
||||
vector<ModVarPair> m_modVars; // Each public {mod,var}
|
||||
ScopeNames m_scopeNames; // Each unique AstScopeName
|
||||
ScopeFuncs m_scopeFuncs; // Each {scope,dpiexportfunc}
|
||||
ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func}
|
||||
ScopeVars m_scopeVars; // Each {scope,public-var}
|
||||
V3LanguageWords m_words; // Reserved word detector
|
||||
int m_coverBins; // Coverage bin number
|
||||
int m_labelNum; // Next label number
|
||||
@@ -95,10 +108,65 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
void varsExpand() {
|
||||
// We didn'e have all m_scopes loaded when we encountered variables, so expand them now
|
||||
// It would be less code if each module inserted its own variables.
|
||||
// Someday. For now public isn't common.
|
||||
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
AstScope* scopep = it->first; AstNodeModule* smodp = it->second;
|
||||
for (vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end(); ++it) {
|
||||
AstNodeModule* modp = it->first;
|
||||
if (modp == smodp) {
|
||||
AstVar* varp = it->second;
|
||||
// Need to split the module + var name into the original-ish full scope and variable name under that scope.
|
||||
// The module instance name is included later, when we know the scopes this module is under
|
||||
string whole = scopep->name()+"__DOT__"+varp->name();
|
||||
string scpName;
|
||||
string varBase;
|
||||
if (whole.substr(0,10) == "__DOT__TOP") whole.replace(0,10,"");
|
||||
string::size_type pos = whole.rfind("__DOT__");
|
||||
if (pos != string::npos) {
|
||||
scpName = whole.substr(0,pos);
|
||||
varBase = whole.substr(pos+strlen("__DOT__"));
|
||||
} else {
|
||||
varBase = whole;
|
||||
}
|
||||
//UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl);
|
||||
string varBasePretty = AstNode::prettyName(varBase);
|
||||
string scpPretty = AstNode::prettyName(scpName);
|
||||
string scpSym;
|
||||
{
|
||||
string out = scpName;
|
||||
string::size_type pos;
|
||||
while ((pos=out.find("__PVT__")) != string::npos) {
|
||||
out.replace(pos, 7, "");
|
||||
}
|
||||
if (out.substr(0,10) == "TOP__DOT__") out.replace(0,10,"");
|
||||
if (out.substr(0,4) == "TOP.") out.replace(0,4,"");
|
||||
while ((pos=out.find(".")) != string::npos) {
|
||||
out.replace(pos, 1, "__");
|
||||
}
|
||||
while ((pos=out.find("__DOT__")) != string::npos) {
|
||||
out.replace(pos, 7, "__");
|
||||
}
|
||||
scpSym = out;
|
||||
}
|
||||
//UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
|
||||
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
|
||||
m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty)));
|
||||
}
|
||||
m_scopeVars.insert(make_pair(scpSym + " " + varp->name(),
|
||||
ScopeVarData(scpSym, varBasePretty, varp, modp, scopep)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||
// Collect list of scopes
|
||||
nodep->iterateChildren(*this);
|
||||
varsExpand();
|
||||
|
||||
// Sort by names, so line/process order matters less
|
||||
sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
||||
@@ -125,8 +193,9 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
string name = nodep->scopeSymName();
|
||||
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettyName()<<" ss "<<name<<endl);
|
||||
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
||||
m_scopeNames.insert(make_pair(name, nodep));
|
||||
m_scopeNames.insert(make_pair(name, ScopeNameData(name, nodep->scopePrettyName())));
|
||||
}
|
||||
if (nodep->dpiExport()) {
|
||||
if (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
|
||||
@@ -134,6 +203,12 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||
ScopeFuncData(nodep, m_funcp, m_modp)));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->isSigUserRdPublic()) {
|
||||
m_modVars.push_back(make_pair(m_modp, nodep));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
||||
// Assign numbers to all bins, so we know how big of an array to use
|
||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||
@@ -255,7 +330,7 @@ void EmitCSyms::emitSymHdr() {
|
||||
|
||||
puts("\n// SCOPE NAMES\n");
|
||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||
puts("VerilatedScope __Vscope_"+it->second->scopeSymName()+";\n");
|
||||
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
|
||||
}
|
||||
|
||||
puts("\n// CREATORS\n");
|
||||
@@ -345,8 +420,8 @@ void EmitCSyms::emitSymImp() {
|
||||
|
||||
puts("// Setup scope names\n");
|
||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||
puts("__Vscope_"+it->second->scopeSymName()+".configure(this,name(),");
|
||||
putsQuoted(it->second->scopePrettyName());
|
||||
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
|
||||
putsQuoted(it->second.m_prettyName);
|
||||
puts(");\n");
|
||||
}
|
||||
|
||||
@@ -367,6 +442,59 @@ void EmitCSyms::emitSymImp() {
|
||||
puts("));\n");
|
||||
}
|
||||
}
|
||||
// It would be less code if each module inserted its own variables.
|
||||
// Someday. For now public isn't common.
|
||||
for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
|
||||
AstNodeModule* modp = it->second.m_modp;
|
||||
AstScope* scopep = it->second.m_scopep;
|
||||
AstVar* varp = it->second.m_varp;
|
||||
//
|
||||
int dim=0;
|
||||
string bounds;
|
||||
if (AstBasicDType* basicp = varp->basicp()) {
|
||||
// Range is always first, it's not in "C" order
|
||||
if (basicp->rangep()) {
|
||||
bounds += " ,"; bounds += cvtToStr(basicp->rangep()->msbConst());
|
||||
bounds += ","; bounds += cvtToStr(basicp->rangep()->lsbConst());
|
||||
dim++;
|
||||
}
|
||||
for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) {
|
||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||
bounds += " ,"; bounds += cvtToStr(adtypep->arrayp()->msbConst());
|
||||
bounds += ","; bounds += cvtToStr(adtypep->arrayp()->lsbConst());
|
||||
dim++;
|
||||
dtypep = adtypep->dtypep();
|
||||
}
|
||||
else break; // AstBasicDType - nothing below, 1
|
||||
}
|
||||
}
|
||||
//
|
||||
if (dim>2) {
|
||||
puts("//UNSUP "); // VerilatedImp can't deal with >2d arrays
|
||||
}
|
||||
puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,");
|
||||
putsQuoted(it->second.m_varBasePretty);
|
||||
puts(", &(");
|
||||
if (modp->isTop()) {
|
||||
puts(scopep->nameDotless());
|
||||
puts("p->");
|
||||
} else {
|
||||
puts(scopep->nameDotless());
|
||||
puts(".");
|
||||
}
|
||||
puts(varp->name());
|
||||
puts("), ");
|
||||
puts(varp->vlEnumType()); // VLVT_UINT32 etc
|
||||
puts(",");
|
||||
puts(varp->vlEnumDir()); // VLVD_IN etc
|
||||
if (varp->isSigUserRWPublic()) puts("|VLVF_PUB_RW");
|
||||
else if (varp->isSigUserRdPublic()) puts("|VLVF_PUB_RD");
|
||||
puts(",");
|
||||
puts(cvtToStr(dim));
|
||||
puts(bounds);
|
||||
puts(");\n");
|
||||
}
|
||||
puts("}\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
putqs(nodep,"end\n");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
putfs(nodep,"/*verilator public_flat_rw ");
|
||||
if (m_sensesp) m_sensesp->iterateAndNext(*this); // In active
|
||||
else nodep->sensesp()->iterateAndNext(*this);
|
||||
putqs(nodep," ");
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
putqs(nodep,"*/\n");
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
putfs(nodep," "+nodep->verilogKwd()+" ");
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
class ExpandVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> bool. Processed
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNode* m_stmtp; // Current statement
|
||||
@@ -76,12 +78,14 @@ private:
|
||||
}
|
||||
|
||||
void insertBefore (AstNode* placep, AstNode* newp) {
|
||||
newp->user1(1); // Already processed, don't need to re-iterate
|
||||
AstNRelinker linker;
|
||||
placep->unlinkFrBack(&linker);
|
||||
newp->addNext(placep);
|
||||
linker.relink(newp);
|
||||
}
|
||||
void replaceWithDelete (AstNode* nodep, AstNode* newp) {
|
||||
newp->user1(1); // Already processed, don't need to re-iterate
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
@@ -306,6 +310,7 @@ private:
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstExtend* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->isWide()) {
|
||||
// See under ASSIGN(EXTEND)
|
||||
@@ -344,6 +349,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
||||
if (nodep->widthMin()!=(int)nodep->widthConst()) nodep->v3fatalSrc("Width mismatch");
|
||||
@@ -640,6 +646,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstConcat* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->isWide()) {
|
||||
// See under ASSIGN(WIDE)
|
||||
@@ -679,6 +686,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstReplicate* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->isWide()) {
|
||||
// See under ASSIGN(WIDE)
|
||||
@@ -740,6 +748,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstChangeXor* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
|
||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||
@@ -754,6 +763,7 @@ private:
|
||||
}
|
||||
|
||||
void visitEqNeq(AstNodeBiop* nodep) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize EQ/NEQ "<<nodep<<endl);
|
||||
@@ -779,6 +789,7 @@ private:
|
||||
virtual void visit(AstNeq* nodep, AstNUser*) { visitEqNeq (nodep); }
|
||||
|
||||
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize REDOR "<<nodep<<endl);
|
||||
@@ -802,6 +813,7 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize REDAND "<<nodep<<endl);
|
||||
@@ -830,6 +842,7 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize REDXOR "<<nodep<<endl);
|
||||
@@ -840,6 +853,7 @@ private:
|
||||
newp = (newp==NULL) ? eqp : (new AstXor (nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstRedXor (nodep->fileline(), newp);
|
||||
UINFO(8," Wordize REDXORnew "<<newp<<endl);
|
||||
replaceWithDelete(nodep, newp); nodep=NULL;
|
||||
}
|
||||
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
|
||||
@@ -847,11 +861,13 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
m_stmtp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_stmtp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
if (nodep->user1Inc()) return; // Process once
|
||||
m_stmtp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
bool did = false;
|
||||
|
||||
+47
-24
@@ -44,6 +44,8 @@
|
||||
#include "V3PreShell.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
// If change this code, run a test with the below size set very small
|
||||
//#define INFILTER_IPC_BUFSIZ 16
|
||||
#define INFILTER_IPC_BUFSIZ 64*1024 // For debug, try this as a small number
|
||||
#define INFILTER_CACHE_MAX 64*1024 // Maximum bytes to cache if same file read twice
|
||||
|
||||
@@ -271,6 +273,7 @@ void V3File::createMakeDir() {
|
||||
|
||||
class V3InFilterImp {
|
||||
typedef map<string,string> FileContentsMap;
|
||||
typedef V3InFilter::StrList StrList;
|
||||
|
||||
FileContentsMap m_contentsMap; // Cache of file contents
|
||||
bool m_readEof; // Received EOF on read
|
||||
@@ -292,27 +295,27 @@ private:
|
||||
return level;
|
||||
}
|
||||
|
||||
bool readContents(const string& filename, string& out) {
|
||||
if (m_pid) return readContentsFilter(filename,out);
|
||||
else return readContentsFile(filename,out);
|
||||
bool readContents(const string& filename, StrList& outl) {
|
||||
if (m_pid) return readContentsFilter(filename,outl);
|
||||
else return readContentsFile(filename,outl);
|
||||
}
|
||||
bool readContentsFile(const string& filename, string& out) {
|
||||
bool readContentsFile(const string& filename, StrList& outl) {
|
||||
int fd = open (filename.c_str(), O_RDONLY);
|
||||
if (!fd) return false;
|
||||
m_readEof = false;
|
||||
out = readBlocks(fd, -1);
|
||||
readBlocks(fd, -1, outl);
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
bool readContentsFilter(const string& filename, string& out) {
|
||||
if (filename!="" || out!="") {} // Prevent unused
|
||||
bool readContentsFilter(const string& filename, StrList& outl) {
|
||||
if (filename!="" || outl.empty()) {} // Prevent unused
|
||||
#ifdef INFILTER_PIPE
|
||||
writeFilter("read \""+filename+"\"\n");
|
||||
string line = readFilterLine();
|
||||
if (line.find("Content-Length") != string::npos) {
|
||||
int len = 0;
|
||||
sscanf(line.c_str(), "Content-Length: %d\n", &len);
|
||||
out = readBlocks(m_readFd, len);
|
||||
readBlocks(m_readFd, len, outl);
|
||||
return true;
|
||||
} else {
|
||||
if (line!="") v3error("--pipe-filter protocol error, unexpected: "<<line);
|
||||
@@ -334,15 +337,19 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
string readBlocks(int fd, int size=-1) {
|
||||
string readBlocks(int fd, int size, StrList& outl) {
|
||||
string out;
|
||||
char buf[INFILTER_IPC_BUFSIZ];
|
||||
while (!m_readEof && (size<0 || size>(int)out.length())) {
|
||||
int todo = INFILTER_IPC_BUFSIZ;
|
||||
if (size>0 && size<INFILTER_IPC_BUFSIZ) todo = size;
|
||||
int got = read (fd, buf, todo);
|
||||
ssize_t sizegot = 0;
|
||||
while (!m_readEof && (size<0 || size>sizegot)) {
|
||||
ssize_t todo = INFILTER_IPC_BUFSIZ;
|
||||
if (size>0 && size<todo) todo = size;
|
||||
ssize_t got = read (fd, buf, todo);
|
||||
//UINFO(9,"RD GOT g "<< got<<" e "<<errno<<" "<<strerror(errno)<<endl); usleep(50*1000);
|
||||
if (got>0) out.append(buf, got);
|
||||
if (got>0) {
|
||||
outl.push_back(string(buf, got));
|
||||
sizegot += got;
|
||||
}
|
||||
else if (errno == EINTR || errno == EAGAIN
|
||||
#ifdef EWOULDBLOCK
|
||||
|| errno == EWOULDBLOCK
|
||||
@@ -358,9 +365,11 @@ private:
|
||||
UINFO(9,"readFilterLine\n");
|
||||
string line;
|
||||
while (!m_readEof) {
|
||||
string c = readBlocks(m_readFd, 1);
|
||||
line += c;
|
||||
if (c == "\n") {
|
||||
StrList outl;
|
||||
readBlocks(m_readFd, 1, outl);
|
||||
string onechar = listString(outl);
|
||||
line += onechar;
|
||||
if (onechar == "\n") {
|
||||
if (line == "\n") { line=""; continue; }
|
||||
else break;
|
||||
}
|
||||
@@ -477,21 +486,35 @@ private:
|
||||
protected:
|
||||
friend class V3InFilter;
|
||||
// Read file contents and return it
|
||||
bool readWholefile(const string& filename, string& out) {
|
||||
bool readWholefile(const string& filename, StrList& outl) {
|
||||
FileContentsMap::iterator it = m_contentsMap.find(filename);
|
||||
if (it != m_contentsMap.end()) {
|
||||
out = it->second;
|
||||
outl.push_back(it->second);
|
||||
return true;
|
||||
}
|
||||
if (!readContents(filename, out)) return false;
|
||||
if (out.length() < INFILTER_CACHE_MAX) {
|
||||
if (!readContents(filename, outl)) return false;
|
||||
if (listSize(outl) < INFILTER_CACHE_MAX) {
|
||||
// Cache small files (only to save space)
|
||||
// It's quite common to `include "timescale" thousands of times
|
||||
// This isn't so important if it's just a open(), but filtering can be slow
|
||||
m_contentsMap.insert(make_pair(filename,out));
|
||||
m_contentsMap.insert(make_pair(filename,listString(outl)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t listSize(StrList& sl) {
|
||||
size_t out = 0;
|
||||
for (StrList::iterator it=sl.begin(); it!=sl.end(); ++it) {
|
||||
out += it->length();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
string listString(StrList& sl) {
|
||||
string out;
|
||||
for (StrList::iterator it=sl.begin(); it!=sl.end(); ++it) {
|
||||
out += *it;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
// CONSTRUCTORS
|
||||
V3InFilterImp(const string& command) {
|
||||
m_readEof = false;
|
||||
@@ -512,9 +535,9 @@ protected:
|
||||
V3InFilter::V3InFilter(const string& command) { m_impp = new V3InFilterImp(command); }
|
||||
V3InFilter::~V3InFilter() { if (m_impp) delete m_impp; m_impp=NULL; }
|
||||
|
||||
bool V3InFilter::readWholefile(const string& filename, string& out) {
|
||||
bool V3InFilter::readWholefile(const string& filename, V3InFilter::StrList& outl) {
|
||||
if (!m_impp) v3fatalSrc("readWholefile on invalid filter");
|
||||
return m_impp->readWholefile(filename, out);
|
||||
return m_impp->readWholefile(filename, outl);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
+5
-1
@@ -28,6 +28,7 @@
|
||||
#include <cstdio>
|
||||
#include <stack>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <fstream>
|
||||
|
||||
//============================================================================
|
||||
@@ -79,9 +80,12 @@ class V3InFilterImp;
|
||||
class V3InFilter {
|
||||
V3InFilterImp* m_impp;
|
||||
public:
|
||||
// TYPES
|
||||
typedef list<string> StrList;
|
||||
|
||||
// METHODS
|
||||
// Read file contents and return it. Return true on success.
|
||||
bool readWholefile(const string& filename, string& out);
|
||||
bool readWholefile(const string& filename, StrList& outl);
|
||||
|
||||
// CONSTRUCTORS
|
||||
V3InFilter(const string& command);
|
||||
|
||||
@@ -357,6 +357,12 @@ private:
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
bool lastslow = m_inSlow;
|
||||
m_inSlow = true;
|
||||
iterateNewStmt(nodep, "AlwaysPublic", NULL);
|
||||
m_inSlow = lastslow;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep, "User C Function", "User C Function");
|
||||
}
|
||||
|
||||
+19
-3
@@ -57,6 +57,7 @@ private:
|
||||
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
|
||||
// Cleared each cell
|
||||
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
|
||||
// AstVar::user3() // bool Don't alias the user4, keep it as signal
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
@@ -151,6 +152,10 @@ private:
|
||||
UINFO(6,"One-to-one "<<connectRefp<<endl);
|
||||
UINFO(6," -to "<<pinNewVarp<<endl);
|
||||
pinNewVarp->user2p(connectRefp);
|
||||
// Public output inside the cell must go via an assign rather than alias
|
||||
// Else the public logic will set the alias, loosing the value to be propagated up
|
||||
// (InOnly isn't a problem as the AssignAlias will create the assignment for us)
|
||||
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
|
||||
}
|
||||
// Cleanup var names, etc, to not conflict
|
||||
m_cellp = nodep;
|
||||
@@ -175,6 +180,7 @@ private:
|
||||
// user2p is either a const or a var.
|
||||
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
|
||||
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
|
||||
UINFO(1,"connectto: "<<nodep->user2p()->castNode()<<endl);
|
||||
if (!exprconstp && !exprvarrefp) {
|
||||
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
||||
}
|
||||
@@ -182,6 +188,15 @@ private:
|
||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
exprconstp->cloneTree(true)));
|
||||
} else if (nodep->user3()) {
|
||||
// Public variable at the lower module end - we need to make sure we propagate
|
||||
// the logic changes up and down; if we aliased, we might remove the change detection
|
||||
// on the output variable.
|
||||
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
|
||||
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
|
||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
} else {
|
||||
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
@@ -216,8 +231,9 @@ private:
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (m_cellp) {
|
||||
if (nodep->varp()->user2p() // It's being converted to a alias.
|
||||
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases
|
||||
if (nodep->varp()->user2p() // It's being converted to an alias.
|
||||
&& !nodep->varp()->user3()
|
||||
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
|
||||
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
|
||||
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
|
||||
if (exprconstp) {
|
||||
@@ -355,7 +371,7 @@ private:
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||
nodep->modp()->user3( nodep->modp()->user3() + 1);
|
||||
nodep->modp()->user3Inc();
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstPragma* nodep, AstNUser*) {
|
||||
|
||||
+1
-2
@@ -89,8 +89,7 @@ private:
|
||||
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
|
||||
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(1);
|
||||
if (!nodep->user1Inc()) {
|
||||
// Simplify it
|
||||
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
|
||||
// Make a ASSIGNW (expr, pin)
|
||||
|
||||
+30
-10
@@ -77,8 +77,7 @@ private:
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true); // Process only once.
|
||||
if (!nodep->user1Inc()) { // Process only once.
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
checkExpected(nodep);
|
||||
// Due to a need to get the arguments, the ParseRefs are under here,
|
||||
@@ -165,8 +164,7 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true); // Process only once.
|
||||
if (!nodep->user1Inc()) { // Process only once.
|
||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
m_dotText = "";
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
@@ -194,8 +192,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
// Excludes simple AstSel, see above
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true); // Process only once.
|
||||
if (!nodep->user1Inc()) { // Process only once.
|
||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
||||
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
||||
@@ -217,8 +214,7 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstText* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true); // Process only once.
|
||||
if (!nodep->user1Inc()) { // Process only once.
|
||||
if (m_exp != AstParseRefExp::PX_NONE) {
|
||||
UINFO(7," "<<nodep<<endl);
|
||||
if (m_inModDot) { // Dotted part, just pass up
|
||||
@@ -274,12 +270,22 @@ private:
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->sigPublic(true); m_varp->sigModPublic(true);
|
||||
m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->sigPublic(true);
|
||||
m_varp->sigUserRWPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->sigUserRdPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||
@@ -294,6 +300,20 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
// AlwaysPublic was attached under a var, but it's a statement that should be
|
||||
// at the same level as the var
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_varp) {
|
||||
nodep->unlinkFrBack();
|
||||
m_varp->addNext(nodep);
|
||||
// lvalue is true, because we know we have a verilator public_flat_rw
|
||||
// but someday we may be more general
|
||||
bool lvalue = m_varp->isSigUserRWPublic();
|
||||
nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {
|
||||
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
||||
// Must remember what names we've already created, and combine duplicates
|
||||
|
||||
+1
-2
@@ -109,8 +109,7 @@ private:
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(1);
|
||||
if (!nodep->user1Inc()) {
|
||||
if (nodep->aboveScopep()) nodep->aboveScopep()->iterate(*this);
|
||||
if (nodep->aboveCellp()) nodep->aboveCellp()->iterate(*this);
|
||||
// Always recompute name (as many level above scope may have changed)
|
||||
|
||||
+1
-1
@@ -1023,7 +1023,7 @@ V3Options::V3Options() {
|
||||
m_outputSplitCTrace = 0;
|
||||
m_traceDepth = 0;
|
||||
m_unrollCount = 64;
|
||||
m_unrollStmts = 100;
|
||||
m_unrollStmts = 30000;
|
||||
|
||||
m_compLimitParens = 0;
|
||||
m_compLimitBlocks = 0;
|
||||
|
||||
+4
-1
@@ -375,7 +375,7 @@ private:
|
||||
OrderLoopId processMoveLoopCurrent();
|
||||
|
||||
string cfuncName(AstNodeModule* modp, AstSenTree* domainp, AstScope* scopep, AstNode* forWhatp) {
|
||||
modp->user3(1+modp->user3());
|
||||
modp->user3Inc();
|
||||
int funcnum = modp->user3();
|
||||
string name = (domainp->hasCombo() ? "_combo"
|
||||
: (domainp->hasInitial() ? "_initial"
|
||||
@@ -666,6 +666,9 @@ private:
|
||||
iterateNewStmt(nodep);
|
||||
m_inPost = false;
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
|
||||
+3
-3
@@ -66,12 +66,12 @@ V3ParseImp::~V3ParseImp() {
|
||||
if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); }
|
||||
}
|
||||
|
||||
int V3ParseImp::ppInputToLex(char* buf, int max_size) {
|
||||
int got = 0;
|
||||
size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) {
|
||||
size_t got = 0;
|
||||
while (got < max_size // Haven't got enough
|
||||
&& !m_ppBuffers.empty()) { // And something buffered
|
||||
string front = m_ppBuffers.front(); m_ppBuffers.pop_front();
|
||||
int len = front.length();
|
||||
size_t len = front.length();
|
||||
if (len > (max_size-got)) { // Front string too big
|
||||
string remainder = front.substr(max_size-got);
|
||||
front = front.substr(0, max_size-got);
|
||||
|
||||
+3
-3
@@ -260,7 +260,7 @@ public:
|
||||
static const char* tokenName(int tok);
|
||||
|
||||
void ppPushText(const string& text) { m_ppBuffers.push_back(text); }
|
||||
int ppInputToLex(char* buf, int max_size);
|
||||
size_t ppInputToLex(char* buf, size_t max_size);
|
||||
|
||||
static V3ParseImp* parsep() { return s_parsep; }
|
||||
|
||||
@@ -278,7 +278,7 @@ public:
|
||||
m_stringps.push_back(strp);
|
||||
return strp;
|
||||
}
|
||||
string* newString(const char* text, int length) {
|
||||
string* newString(const char* text, size_t length) {
|
||||
string* strp = new string (text, length);
|
||||
m_stringps.push_back(strp);
|
||||
return strp;
|
||||
@@ -307,7 +307,7 @@ public:
|
||||
void statePushVlg(); // Parser -> lexer communication
|
||||
void statePop(); // Parser -> lexer communication
|
||||
int stateVerilogRecent(); // Parser -> lexer communication
|
||||
int flexPpInputToLex(char* buf, int max_size) { return ppInputToLex(buf,max_size); }
|
||||
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf,max_size); }
|
||||
|
||||
//==== Symbol tables
|
||||
V3ParseSym* symp() { return &m_sym; }
|
||||
|
||||
+10
-3
@@ -27,6 +27,7 @@
|
||||
#ifndef _VPREPROCLEX_H_ // Guard
|
||||
#define _VPREPROCLEX_H_ 1
|
||||
|
||||
#include <deque>
|
||||
#include <stack>
|
||||
|
||||
#include "V3Error.h"
|
||||
@@ -112,7 +113,7 @@ void yy_delete_buffer( YY_BUFFER_STATE b );
|
||||
#define KEEPCMT_SUB 2
|
||||
|
||||
//======================================================================
|
||||
// Class entry for each per-lexter state
|
||||
// Class entry for each per-lexer state
|
||||
|
||||
class V3PreLex {
|
||||
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
|
||||
@@ -120,6 +121,7 @@ class V3PreLex {
|
||||
|
||||
// Parse state
|
||||
stack<YY_BUFFER_STATE> m_bufferStack; // Stack of inserted text above current point
|
||||
deque<string> m_buffers; ///< Buffer of characters to process
|
||||
|
||||
// State to lexer
|
||||
static V3PreLex* s_currentLexp; // Current lexing point
|
||||
@@ -143,13 +145,15 @@ class V3PreLex {
|
||||
m_defCmtSlash = false;
|
||||
m_pslParenLevel = 0;
|
||||
m_pslMoreNeeded = false;
|
||||
initFirstBuffer();
|
||||
}
|
||||
~V3PreLex() {
|
||||
while (!m_bufferStack.empty()) { yy_delete_buffer(m_bufferStack.top()); m_bufferStack.pop(); }
|
||||
}
|
||||
void initFirstBuffer();
|
||||
|
||||
// Called by V3PreLex.l from lexer
|
||||
void appendDefValue(const char* text, int len);
|
||||
void appendDefValue(const char* text, size_t len);
|
||||
void lineDirective(const char* text);
|
||||
void incLineno() { m_curFilelinep->incLineno(); }
|
||||
// Called by V3PreProc.cpp to inform lexer
|
||||
@@ -157,10 +161,13 @@ class V3PreLex {
|
||||
void pushStateDefForm();
|
||||
void pushStateDefValue();
|
||||
void pushStateIncFilename();
|
||||
void scanBytes(const string& strg);
|
||||
void scanBytes(const char* strp, size_t len);
|
||||
void scanBytesBack(const string& str);
|
||||
size_t inputToLex(char* buf, size_t max_size);
|
||||
/// Called by VPreproc.cpp to get data from lexer
|
||||
YY_BUFFER_STATE currentBuffer();
|
||||
int currentStartState();
|
||||
void dumpSummary();
|
||||
void dumpStack();
|
||||
};
|
||||
|
||||
|
||||
+63
-4
@@ -33,6 +33,9 @@ V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
|
||||
|
||||
#define LEXP V3PreLex::s_currentLexp
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
result = LEXP->inputToLex(buf,max_size);
|
||||
|
||||
// Accessors, because flex keeps changing the type of yyleng
|
||||
char* yyourtext() { return yytext; }
|
||||
size_t yyourleng() { return yyleng; }
|
||||
@@ -44,7 +47,7 @@ static bool optPsl() { return V3PreProc::optPsl(); }
|
||||
static bool pedantic() { return LEXP->m_pedantic; }
|
||||
static void yyerror(char* msg) { LEXP->m_curFilelinep->v3error(msg); }
|
||||
static void yyerrorf(const char* msg) { LEXP->m_curFilelinep->v3error(msg); }
|
||||
static void appendDefValue(const char* t,int l) { LEXP->appendDefValue(t,l); }
|
||||
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t,l); }
|
||||
static int pslParenLevel() { return LEXP->m_pslParenLevel; }
|
||||
static void pslParenLevelInc() { LEXP->m_pslParenLevel++; }
|
||||
static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; }
|
||||
@@ -78,6 +81,7 @@ crnl [\r]*[\n]
|
||||
quote [\"]
|
||||
backslash [\\]
|
||||
symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
|
||||
word [a-zA-Z0-9_]+
|
||||
drop [\032]
|
||||
psl [p]sl
|
||||
|
||||
@@ -113,6 +117,7 @@ psl [p]sl
|
||||
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
|
||||
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
|
||||
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
|
||||
<STRMODE>{word} { yymore(); }
|
||||
<STRMODE>[^\"\\] { yymore(); }
|
||||
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
|
||||
<STRMODE>{backslash}. { yymore(); }
|
||||
@@ -177,6 +182,7 @@ psl [p]sl
|
||||
appendDefValue(yytext,yyleng-2); appendDefValue((char*)"\n",1); } /* Return but not \ */
|
||||
<DEFCMT>{crnl} { linenoInc(); yymore(); if (LEXP->m_defCmtSlash) yyerrorf("One line of /* ... */ is missing \\ before newline");
|
||||
BEGIN(CMTMODE); }
|
||||
<DEFCMT>{word} { yymore(); }
|
||||
<DEFCMT>. { yymore(); }
|
||||
<DEFCMT><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
||||
|
||||
@@ -241,6 +247,7 @@ psl [p]sl
|
||||
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
||||
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
|
||||
<CMTBEGM,CMTMODE><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
||||
<CMTMODE>{word} { yymore(); }
|
||||
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
|
||||
<CMTMODE>. { yymore(); }
|
||||
|
||||
@@ -290,12 +297,57 @@ void V3PreLex::pushStateIncFilename() {
|
||||
yymore();
|
||||
}
|
||||
|
||||
void V3PreLex::scanBytes(const string& strg) {
|
||||
yy_scan_bytes(strg.c_str(), strg.length());
|
||||
void V3PreLex::initFirstBuffer() {
|
||||
// Called from constructor to make first buffer
|
||||
// yy_create_buffer also sets yy_fill_buffer=1 so reads from YY_INPUT
|
||||
yy_switch_to_buffer(yy_create_buffer(NULL, YY_BUF_SIZE));
|
||||
m_bufferStack.push(currentBuffer());
|
||||
yyrestart(NULL);
|
||||
}
|
||||
|
||||
size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
|
||||
// We need a custom YY_INPUT because we can't use flex buffers.
|
||||
// Flex buffers are limited to 2GB, and we can't chop into 2G pieces
|
||||
// because buffers can't end in the middle of tokens.
|
||||
// m_buffers only applies to the "base" buffer when there's no scanBytes outstanding
|
||||
// It won't be called on scan_buffers as they don't have yy_fill_buffer set.
|
||||
//
|
||||
//if (debug()) { cout<<"- pp:inputToLex ITL s="<<max_size<<" bs="<<m_bufferStack.size()<<endl; dumpSummary(); }
|
||||
// For testing, use really small chunks
|
||||
//if (max_size > 13) max_size=13;
|
||||
size_t got = 0;
|
||||
while (got < max_size // Haven't got enough
|
||||
&& !m_buffers.empty()) { // And something buffered
|
||||
string front = m_buffers.front(); m_buffers.pop_front();
|
||||
size_t len = front.length();
|
||||
if (len > (max_size-got)) { // Front string too big
|
||||
string remainder = front.substr(max_size-got);
|
||||
front = front.substr(0, max_size-got);
|
||||
m_buffers.push_front(remainder); // Put back remainder for next time
|
||||
len = (max_size-got);
|
||||
}
|
||||
strncpy(buf+got, front.c_str(), len);
|
||||
got += len;
|
||||
}
|
||||
//if (debug()) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf,got)<<"'"<<endl; }
|
||||
return got;
|
||||
}
|
||||
|
||||
void V3PreLex::scanBytes(const char* strp, size_t len) {
|
||||
// Note buffers also appended in ::scanBytesBack
|
||||
// Not "m_buffers.push_front(string(strp,len))" as we need a `define
|
||||
// to take effect immediately, in the middle of the current buffer
|
||||
yy_scan_bytes(strp, len);
|
||||
m_bufferStack.push(currentBuffer()); // yy_scan_bytes makes new buffer
|
||||
}
|
||||
|
||||
void V3PreLex::appendDefValue(const char* textp, int len) {
|
||||
void V3PreLex::scanBytesBack(const string& str) {
|
||||
// Initial creation, that will pull from YY_INPUT==inputToLex
|
||||
// Note buffers also appended in ::scanBytes
|
||||
m_buffers.push_back(str);
|
||||
}
|
||||
|
||||
void V3PreLex::appendDefValue(const char* textp, size_t len) {
|
||||
// Append given text to current definition value being formed
|
||||
m_defValue.append(textp,len);
|
||||
}
|
||||
@@ -314,8 +366,15 @@ void V3PreLex::lineDirective(const char* textp) {
|
||||
V3File::addSrcDepend(m_curFilelinep->filename());
|
||||
}
|
||||
|
||||
void V3PreLex::dumpSummary() {
|
||||
cout<<"- pp::dumpSummary curBuf="<<(void*)(currentBuffer())
|
||||
<<" nBuf="<<m_bufferStack.size()
|
||||
<<" yyfill="<<currentBuffer()->yy_fill_buffer<<endl;
|
||||
}
|
||||
|
||||
void V3PreLex::dumpStack() {
|
||||
// For debug use
|
||||
dumpSummary();
|
||||
stack<YY_BUFFER_STATE> tmpstack = m_bufferStack;
|
||||
printf(" bufferStack[%p]:",this);
|
||||
while (!tmpstack.empty()) {
|
||||
|
||||
+49
-16
@@ -23,12 +23,14 @@
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <fstream>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include "V3Error.h"
|
||||
#include "V3Global.h"
|
||||
@@ -108,6 +110,7 @@ public:
|
||||
struct V3PreProcImp : public V3PreProc {
|
||||
// TYPES
|
||||
typedef std::map<string,V3Define> DefinesMap;
|
||||
typedef V3InFilter::StrList StrList;
|
||||
|
||||
// debug() -> see V3PreShellImp::debug
|
||||
|
||||
@@ -165,7 +168,7 @@ private:
|
||||
|
||||
bool commentTokenMatch(string& cmdr, const char* strg);
|
||||
string trimWhitespace(const string& strg, bool trailing);
|
||||
void unputString(const string& strg, bool first=false);
|
||||
void unputString(const string& strg);
|
||||
|
||||
void parsingOn() {
|
||||
m_off--;
|
||||
@@ -323,9 +326,11 @@ void V3PreProcImp::comment(const string& text) {
|
||||
if ((cp[0]=='v' || cp[0]=='V')
|
||||
&& 0==(strncmp(cp+1,"erilator",8))) {
|
||||
cp+=strlen("verilator");
|
||||
if (*cp == '_') fileline()->v3error("Extra underscore in meta-comment; use /*verilator {...}*/ not /*verilator_{...}*/");
|
||||
} else if (0==(strncmp(cp,"synopsys",strlen("synopsys")))) {
|
||||
cp+=strlen("synopsys");
|
||||
synth = true;
|
||||
if (*cp == '_') fileline()->v3error("Extra underscore in meta-comment; use /*synopsys {...}*/ not /*synopsys_{...}*/");
|
||||
} else if (0==(strncmp(cp,"cadence",strlen("cadence")))) {
|
||||
cp+=strlen("cadence");
|
||||
synth = true;
|
||||
@@ -369,6 +374,13 @@ void V3PreProcImp::comment(const string& text) {
|
||||
//}
|
||||
// else ignore the comment we don't recognize
|
||||
} // else no assertions
|
||||
} else if ((pos=cmd.find("public_flat_rw")) != string::npos) {
|
||||
// "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)"
|
||||
cmd = cmd.substr(pos+strlen("public_flat_rw"));
|
||||
while (isspace(cmd[0])) cmd = cmd.substr(1);
|
||||
if ((pos=cmd.find("*/")) != string::npos)
|
||||
cmd.replace(pos, 2, "");
|
||||
insertUnreadback ("/*verilator public_flat_rw*/ "+cmd+" /**/");
|
||||
} else {
|
||||
insertUnreadback ("/*verilator "+cmd+"*/");
|
||||
}
|
||||
@@ -405,18 +417,19 @@ const char* V3PreProcImp::tokenName(int tok) {
|
||||
}
|
||||
}
|
||||
|
||||
void V3PreProcImp::unputString(const string& strg, bool first) {
|
||||
void V3PreProcImp::unputString(const string& strg) {
|
||||
// Note: The preliminary call in ::openFile bypasses this function
|
||||
// We used to just m_lexp->unputString(strg.c_str());
|
||||
// However this can lead to "flex scanner push-back overflow"
|
||||
// so instead we scan from a temporary buffer, then on EOF return.
|
||||
// This is also faster than the old scheme, amazingly.
|
||||
if (!first) { // Else the initial creation
|
||||
if (1) {
|
||||
if (m_lexp->m_bufferStack.empty() || m_lexp->m_bufferStack.top()!=m_lexp->currentBuffer()) {
|
||||
fileline()->v3fatalSrc("bufferStack missing current buffer; will return incorrectly");
|
||||
// Hard to debug lost text as won't know till much later
|
||||
}
|
||||
}
|
||||
m_lexp->scanBytes(strg);
|
||||
m_lexp->scanBytes(strg.c_str(), strg.length());
|
||||
}
|
||||
|
||||
string V3PreProcImp::trimWhitespace(const string& strg, bool trailing) {
|
||||
@@ -591,22 +604,14 @@ void V3PreProcImp::openFile(FileLine* fl, V3InFilter* filterp, const string& fil
|
||||
|
||||
V3File::addSrcDepend(filename);
|
||||
|
||||
string wholefile;
|
||||
// Read a list<string> with the whole file.
|
||||
StrList wholefile;
|
||||
bool ok = filterp->readWholefile(filename, wholefile/*ref*/);
|
||||
if (!ok) {
|
||||
fileline()->v3error("File not found: "+filename+"\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter all DOS CR's en-mass. This avoids bugs with lexing CRs in the wrong places.
|
||||
// This will also strip them from strings, but strings aren't supposed to be multi-line without a "\"
|
||||
string wholefilecr;
|
||||
size_t wholesize = wholefile.length();
|
||||
for (size_t i=0; i<wholesize; i++) { // Not a c_str(), as we keep '\0's for now.
|
||||
if (wholefile[i] != '\r' && wholefile[i] != '\0') wholefilecr += wholefile[i];
|
||||
}
|
||||
wholefile.resize(0); // free memory
|
||||
|
||||
if (m_lexp) {
|
||||
// We allow the same include file twice, because occasionally it pops
|
||||
// up, with guards preventing a real recursion.
|
||||
@@ -627,7 +632,35 @@ void V3PreProcImp::openFile(FileLine* fl, V3InFilter* filterp, const string& fil
|
||||
addLineComment(1); // Enter
|
||||
|
||||
yy_flex_debug = (debug()>4)?1:0;
|
||||
unputString(wholefilecr,true);
|
||||
|
||||
// Filter all DOS CR's en-mass. This avoids bugs with lexing CRs in the wrong places.
|
||||
// This will also strip them from strings, but strings aren't supposed to be multi-line without a "\"
|
||||
for (StrList::iterator it=wholefile.begin(); it!=wholefile.end(); ++it) {
|
||||
// We don't end-loop at \0 as we allow and strip mid-string '\0's (for now).
|
||||
bool strip = false;
|
||||
const char* sp = it->data();
|
||||
const char* ep = sp + it->length();
|
||||
// Only process if needed, as saves extra string allocations
|
||||
for (const char* cp=sp; cp<ep; cp++) {
|
||||
if (VL_UNLIKELY(*cp == '\r' || *cp == '\0')) {
|
||||
strip = true; break;
|
||||
}
|
||||
}
|
||||
if (strip) {
|
||||
string out; out.reserve(it->length());
|
||||
for (const char* cp=sp; cp<ep; cp++) {
|
||||
if (!(*cp == '\r' || *cp == '\0')) {
|
||||
out += *cp;
|
||||
}
|
||||
}
|
||||
*it = out;
|
||||
}
|
||||
|
||||
// Push the data to an internal buffer.
|
||||
m_lexp->scanBytesBack(*it);
|
||||
// Reclaim memory; the push saved the string contents for us
|
||||
*it = "";
|
||||
}
|
||||
}
|
||||
|
||||
void V3PreProcImp::insertUnreadbackAtBol(const string& text) {
|
||||
@@ -762,7 +795,7 @@ int V3PreProcImp::getToken() {
|
||||
// We're off or processed the comment specially. If there are newlines
|
||||
// in it, we also return the newlines as TEXT so that the linenumber
|
||||
// count is maintained for downstream tools
|
||||
for (int len=0; len<yyourleng(); len++) { if (yyourtext()[len]=='\n') m_lineAdd++; }
|
||||
for (size_t len=0; len<yyourleng(); len++) { if (yyourtext()[len]=='\n') m_lineAdd++; }
|
||||
goto next_tok;
|
||||
}
|
||||
if (tok==VP_LINE) {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
|
||||
class V3InFilter;
|
||||
|
||||
+7
-2
@@ -48,9 +48,12 @@ protected:
|
||||
//---------------------------------------
|
||||
// METHODS
|
||||
|
||||
static int debug() {
|
||||
static int debug(bool reset=false) {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
if (VL_UNLIKELY(level < 0) || reset) {
|
||||
level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
if (s_preprocp) s_preprocp->debug(debug());
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
@@ -72,6 +75,8 @@ protected:
|
||||
}
|
||||
|
||||
void preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) {
|
||||
debug(true); // Recheck if debug on - first check was before command line passed
|
||||
|
||||
// Preprocess the given module, putting output in vppFilename
|
||||
UINFONL(1," Preprocessing "<<modname<<endl);
|
||||
|
||||
|
||||
+1
-2
@@ -196,9 +196,8 @@ private:
|
||||
}
|
||||
void visitShift (AstNodeBiop* nodep) {
|
||||
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
|
||||
if (!nodep->user2()) {
|
||||
if (!nodep->user2Inc()) {
|
||||
UINFO(4," ShiftFix "<<nodep<<endl);
|
||||
nodep->user2(true);
|
||||
if (nodep->widthMin()<=64 // Else we'll use large operators which work right
|
||||
// C operator's width must be < maximum shift which is based on Verilog width
|
||||
&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
|
||||
|
||||
@@ -165,6 +165,14 @@ private:
|
||||
m_scopep->addActivep(clonep);
|
||||
clonep->iterateChildren(*this); // We iterate under the *clone*
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
clonep->iterateChildren(*this); // We iterate under the *clone*
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
@@ -291,6 +299,9 @@ private:
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
|
||||
+176
-34
@@ -54,6 +54,14 @@ class SliceCloneVisitor : public AstNVisitor {
|
||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
||||
|
||||
// ENUMS
|
||||
enum RedOp { // The type of unary operation to be expanded
|
||||
REDOP_UNKNOWN, // Unknown/Unsupported
|
||||
REDOP_OR, // Or Reduction
|
||||
REDOP_AND, // And Reduction
|
||||
REDOP_XOR, // Xor Reduction
|
||||
REDOP_XNOR}; // Xnor Reduction
|
||||
|
||||
// STATE
|
||||
vector<vector<unsigned> > m_selBits; // Indexes of the ArraySel we are expanding
|
||||
int m_vecIdx; // Current vector index
|
||||
@@ -76,8 +84,9 @@ class SliceCloneVisitor : public AstNVisitor {
|
||||
if (m_vecIdx == (int)m_selBits.size()) {
|
||||
m_selBits.push_back(vector<unsigned>());
|
||||
AstVar* varp = m_refp->varp();
|
||||
int dimensions = varp->dimensions();
|
||||
for (int i = 0; i < dimensions; ++i) {
|
||||
pair<uint32_t,uint32_t> arrDim = varp->dimensions();
|
||||
uint32_t dimensions = arrDim.first + arrDim.second;
|
||||
for (uint32_t i = 0; i < dimensions; ++i) {
|
||||
m_selBits[m_vecIdx].push_back(0);
|
||||
}
|
||||
}
|
||||
@@ -112,6 +121,7 @@ class SliceCloneVisitor : public AstNVisitor {
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
if (nodep->user2() < 2) return; // Don't need clones
|
||||
m_selBits.clear();
|
||||
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
|
||||
for (int i = 0; i < nodep->user2(); ++i) {
|
||||
@@ -124,13 +134,77 @@ class SliceCloneVisitor : public AstNVisitor {
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
||||
}
|
||||
|
||||
// Not all Uniop nodes should be cloned down to a single bit
|
||||
void cloneUniop(AstNodeUniop* nodep) {
|
||||
if (nodep->user2() < 2) return; // Don't need clones
|
||||
m_selBits.clear();
|
||||
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
|
||||
|
||||
// Figure out what type of operation this is so we don't have to cast on
|
||||
// every clone.
|
||||
RedOp redOpType = REDOP_UNKNOWN;
|
||||
if (nodep->castRedOr()) redOpType = REDOP_OR;
|
||||
else if (nodep->castRedAnd()) redOpType = REDOP_AND;
|
||||
else if (nodep->castRedXor()) redOpType = REDOP_XOR;
|
||||
else if (nodep->castRedXnor()) redOpType = REDOP_XNOR;
|
||||
|
||||
AstNode* lhsp = NULL;
|
||||
AstNode* rhsp = NULL;
|
||||
for (int i = 0; i < nodep->user2(); ++i) {
|
||||
// Clone the node and iterate over the clone
|
||||
m_vecIdx = -1;
|
||||
AstNodeUniop* clonep = nodep->cloneTree(false)->castNodeUniop();
|
||||
clonep->iterateChildren(*this);
|
||||
if (!lhsp) lhsp = clonep;
|
||||
else rhsp = clonep;
|
||||
if (lhsp && rhsp) {
|
||||
switch (redOpType) {
|
||||
case REDOP_OR:
|
||||
lhsp = new AstLogOr(nodep->fileline(), lhsp, rhsp);
|
||||
break;
|
||||
case REDOP_AND:
|
||||
lhsp = new AstLogAnd(nodep->fileline(), lhsp, rhsp);
|
||||
break;
|
||||
case REDOP_XOR:
|
||||
lhsp = new AstXor(nodep->fileline(), lhsp, rhsp);
|
||||
break;
|
||||
case REDOP_XNOR:
|
||||
lhsp = new AstXnor(nodep->fileline(), lhsp, rhsp);
|
||||
break;
|
||||
default: // REDOP_UNKNOWN
|
||||
nodep->v3fatalSrc("Unsupported: Unary operation on multiple packed dimensions");
|
||||
break;
|
||||
}
|
||||
rhsp = NULL;
|
||||
}
|
||||
}
|
||||
nodep->addNextHere(lhsp);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
||||
cloneUniop(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
||||
cloneUniop(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
||||
cloneUniop(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstRedXnor* nodep, AstNUser*) {
|
||||
cloneUniop(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SliceCloneVisitor(AstNodeAssign* assignp) {
|
||||
SliceCloneVisitor(AstNode* assignp) {
|
||||
assignp->accept(*this);
|
||||
}
|
||||
virtual ~SliceCloneVisitor() {}
|
||||
@@ -142,15 +216,20 @@ class SliceVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// Cleared on netlist
|
||||
// AstNodeAssign::user1() -> bool. True if find is complete
|
||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
||||
// AstUniop::user1() -> bool. True if find is complete
|
||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||
// AstNode::user2() -> int. The number of clones needed for this node
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// TYPEDEFS
|
||||
typedef pair<uint32_t, uint32_t> ArrayDimensions; // Array Dimensions (packed, unpacked)
|
||||
|
||||
// STATE
|
||||
AstNode* m_assignp; // Assignment we are under
|
||||
AstNodeVarRef* m_lhsVarRefp; // Var on the LHS
|
||||
bool m_extend; // We have found an extend node
|
||||
bool m_assignError; // True if the current assign already has an error
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -178,15 +257,13 @@ class SliceVisitor : public AstNVisitor {
|
||||
return dim;
|
||||
}
|
||||
|
||||
AstNode* insertImplicit(AstVarRef* nodep, unsigned start, unsigned count) {
|
||||
AstArraySel* insertImplicit(AstNode* nodep, unsigned start, unsigned count) {
|
||||
// Insert any implicit slices as explicit slices (ArraySel nodes).
|
||||
// Return a new pointer to replace fromp() in the ArraySel.
|
||||
AstVarRef* fromp = nodep;
|
||||
if (!fromp) nodep->v3fatalSrc("NULL VarRef passed to insertImplicit");
|
||||
AstVar* varp = fromp->varp();
|
||||
// Get the DType and insert a new ArraySel
|
||||
AstArraySel* topp = NULL;
|
||||
AstArraySel* bottomp = NULL;
|
||||
// Return a new pointer to replace nodep() in the ArraySel.
|
||||
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
||||
if (!refp) nodep->v3fatalSrc("No VarRef in user1 of node "<<nodep);
|
||||
AstVar* varp = refp->varp();
|
||||
AstNode* topp = nodep;
|
||||
for (unsigned i = start; i < start + count; ++i) {
|
||||
AstNodeDType* dtypep = varp->dtypeDimensionp(i-1);
|
||||
AstArrayDType* adtypep = dtypep->castArrayDType();
|
||||
@@ -197,17 +274,13 @@ class SliceVisitor : public AstNVisitor {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
}
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, new AstConst(nodep->fileline(),lsb));
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), topp, new AstConst(nodep->fileline(),lsb));
|
||||
newp->user1p(refp);
|
||||
newp->start(lsb);
|
||||
newp->length(msb - lsb + 1);
|
||||
if (!topp) topp = newp;
|
||||
fromp = newp->fromp()->unlinkFrBack()->castVarRef();
|
||||
|
||||
if (bottomp) bottomp->fromp(newp);
|
||||
bottomp = newp;
|
||||
topp = newp->castNode();
|
||||
}
|
||||
bottomp->fromp(fromp);
|
||||
return topp;
|
||||
return topp->castArraySel();
|
||||
}
|
||||
|
||||
int countClones(AstArraySel* nodep) {
|
||||
@@ -228,9 +301,12 @@ class SliceVisitor : public AstNVisitor {
|
||||
// The LHS/RHS of an Assign may be to a Var that is an array. In this
|
||||
// case we need to create a slice accross the entire Var
|
||||
if (m_assignp && !nodep->backp()->castArraySel()) {
|
||||
uint32_t dimensions = nodep->varp()->dimensions();
|
||||
pair<uint32_t,uint32_t> arrDim = nodep->varp()->dimensions();
|
||||
uint32_t dimensions = arrDim.first + arrDim.second;
|
||||
if (dimensions > 0) {
|
||||
AstNode* newp = insertImplicit(nodep->cloneTree(false), 1, dimensions);
|
||||
AstVarRef* clonep = nodep->cloneTree(false);
|
||||
clonep->user1p(nodep);
|
||||
AstNode* newp = insertImplicit(clonep, 1, dimensions);
|
||||
nodep->replaceWith(newp); nodep = NULL;
|
||||
newp->accept(*this);
|
||||
}
|
||||
@@ -239,8 +315,18 @@ class SliceVisitor : public AstNVisitor {
|
||||
|
||||
virtual void visit(AstExtend* nodep, AstNUser*) {
|
||||
m_extend = true;
|
||||
if (m_assignp && m_assignp->user2() > 1) {
|
||||
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
m_assignError = true;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||
m_extend = true;
|
||||
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
|
||||
m_assignp->v3error("Unsupported: Assignment between a constant and an array slice");
|
||||
m_assignError = true;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
@@ -249,22 +335,24 @@ class SliceVisitor : public AstNVisitor {
|
||||
if (!m_assignp) return;
|
||||
unsigned dim = explicitDimensions(nodep);
|
||||
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
||||
unsigned implicit = refp->varp()->dimensions() - dim;
|
||||
pair<uint32_t,uint32_t> arrDim = refp->varp()->dimensions();
|
||||
uint32_t implicit = (arrDim.first + arrDim.second) - dim;
|
||||
if (implicit > 0) {
|
||||
AstNode* backp = refp->backp();
|
||||
AstNode* newp = insertImplicit(refp->cloneTree(false), dim+1, implicit);
|
||||
backp->castArraySel()->fromp()->replaceWith(newp);
|
||||
AstArraySel* newp = insertImplicit(nodep->cloneTree(false), dim+1, implicit);
|
||||
nodep->replaceWith(newp); nodep = newp;
|
||||
}
|
||||
int clones = countClones(nodep);
|
||||
if (m_assignp->user2() > 0 && m_assignp->user2() != clones) {
|
||||
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
|
||||
} else if (m_assignp->user2() == 0) {
|
||||
} else if (m_assignp->user2() == 0 && !m_assignError) {
|
||||
if (m_extend && clones > 1) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
m_assignError = true;
|
||||
}
|
||||
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp() && !m_assignp->castAssignDly()) {
|
||||
// LHS Var != RHS Var for a non-delayed assignment
|
||||
// LHS Var != RHS Var for a non-delayed assignment
|
||||
m_assignp->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides");
|
||||
m_assignError = true;
|
||||
}
|
||||
m_assignp->user2(clones);
|
||||
}
|
||||
@@ -272,8 +360,9 @@ class SliceVisitor : public AstNVisitor {
|
||||
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
m_extend = true;
|
||||
if (m_assignp && m_assignp->user2() > 1) {
|
||||
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
m_assignError = true;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
@@ -314,6 +403,7 @@ class SliceVisitor : public AstNVisitor {
|
||||
void findImplicit(AstNodeAssign* nodep) {
|
||||
if (m_assignp) nodep->v3fatalSrc("Found a NodeAssign under another NodeAssign");
|
||||
m_assignp = nodep;
|
||||
m_assignError = false;
|
||||
m_extend = false;
|
||||
nodep->user1(true);
|
||||
// Record the LHS Var so we can check if the Var on the RHS is the same
|
||||
@@ -322,9 +412,7 @@ class SliceVisitor : public AstNVisitor {
|
||||
// Iterate children looking for ArraySel nodes. From that we get the number of elements
|
||||
// in the array so we know how many times we need to clone this assignment.
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->user2() > 1) {
|
||||
SliceCloneVisitor scv(nodep);
|
||||
}
|
||||
if (nodep->user2() > 1) SliceCloneVisitor scv(nodep);
|
||||
m_assignp = NULL;
|
||||
}
|
||||
|
||||
@@ -335,6 +423,60 @@ class SliceVisitor : public AstNVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
void expandUniOp(AstNodeUniop* nodep) {
|
||||
nodep->user1(true);
|
||||
unsigned dim = 0;
|
||||
if (AstArraySel* selp = nodep->lhsp()->castArraySel()) {
|
||||
// We have explicit dimensions, either packed or unpacked
|
||||
dim = explicitDimensions(selp);
|
||||
}
|
||||
if (dim == 0 && !nodep->lhsp()->castVarRef()) {
|
||||
// No ArraySel or VarRef, not something we can expand
|
||||
nodep->iterateChildren(*this);
|
||||
} else {
|
||||
AstVarRef* refp = findVarRefRecurse(nodep->lhsp());
|
||||
ArrayDimensions varDim = refp->varp()->dimensions();
|
||||
if ((int)(dim - varDim.second) < 0) {
|
||||
// Unpacked dimensions are referenced first, make sure we have them all
|
||||
nodep->v3error("Unary operator used across unpacked dimensions");
|
||||
} else if ((int)(dim - (varDim.first + varDim.second)) < 0) {
|
||||
// Implicit packed dimensions are allowed, make them explicit
|
||||
uint32_t newDim = (varDim.first + varDim.second) - dim;
|
||||
AstNode* clonep = nodep->lhsp()->cloneTree(false);
|
||||
clonep->user1p(refp);
|
||||
AstNode* newp = insertImplicit(clonep, dim+1, newDim);
|
||||
nodep->lhsp()->replaceWith(newp); refp = NULL;
|
||||
int clones = countClones(nodep->lhsp()->castArraySel());
|
||||
nodep->user2(clones);
|
||||
SliceCloneVisitor scv(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
expandUniOp(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
expandUniOp(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
expandUniOp(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstRedXnor* nodep, AstNUser*) {
|
||||
if (!nodep->user1()) {
|
||||
expandUniOp(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -354,6 +496,6 @@ public:
|
||||
// Link class functions
|
||||
|
||||
void V3Slice::sliceAll(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SliceVisitor visitor(rootp);
|
||||
}
|
||||
|
||||
+1
-3
@@ -1066,10 +1066,8 @@ private:
|
||||
AstNode* prevInsStmtp = m_insStmtp;
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
||||
if (!nodep->user1()) { // Just one creation needed per function
|
||||
if (!nodep->user1Inc()) { // Just one creation needed per function
|
||||
// Expand functions in it
|
||||
nodep->user1(true);
|
||||
|
||||
int modes = 0;
|
||||
if (nodep->dpiImport()) modes++;
|
||||
if (nodep->dpiExport()) modes++;
|
||||
|
||||
+2
-4
@@ -322,8 +322,7 @@ private:
|
||||
|
||||
void visit(AstSel* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(1);
|
||||
if (!nodep->user1Inc()) {
|
||||
// Guard against reading/writing past end of bit vector array
|
||||
int maxmsb = 0;
|
||||
bool lvalue = false;
|
||||
@@ -373,8 +372,7 @@ private:
|
||||
|
||||
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(1);
|
||||
if (!nodep->user1Inc()) {
|
||||
if (debug()==9) nodep->dumpTree(cout,"-in: ");
|
||||
// Guard against reading/writing past end of arrays
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
||||
|
||||
+23
-12
@@ -82,6 +82,20 @@ private:
|
||||
: v3Global.opt.unrollCount();
|
||||
}
|
||||
|
||||
bool bodySizeOverRecurse(AstNode* nodep, int& bodySize, int bodyLimit) {
|
||||
if (!nodep) return false;
|
||||
bodySize++;
|
||||
// Exit once exceeds limits, rather than always total
|
||||
// so don't go O(n^2) when can't unroll
|
||||
if (bodySize > bodyLimit) return true;
|
||||
if (bodySizeOverRecurse(nodep->op1p(), bodySize, bodyLimit)) return true;
|
||||
if (bodySizeOverRecurse(nodep->op2p(), bodySize, bodyLimit)) return true;
|
||||
if (bodySizeOverRecurse(nodep->op3p(), bodySize, bodyLimit)) return true;
|
||||
if (bodySizeOverRecurse(nodep->op4p(), bodySize, bodyLimit)) return true;
|
||||
// Tail recurse.
|
||||
return bodySizeOverRecurse(nodep->nextp(), bodySize, bodyLimit);
|
||||
}
|
||||
|
||||
bool forUnrollCheck(AstNode* nodep,
|
||||
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
||||
AstNode* precondsp, AstNode* condp,
|
||||
@@ -174,22 +188,19 @@ private:
|
||||
//
|
||||
if (!m_generate) {
|
||||
UINFO(8, " ~Iters: "<<((valStop - valInit)/valInc)<<" c="<<unrollCount()<<endl);
|
||||
if (((valStop - valInit)/valInc) > unrollCount())
|
||||
int loops = ((valStop - valInit)/valInc);
|
||||
if (loops > unrollCount())
|
||||
return cantUnroll(nodep, "too many iterations");
|
||||
|
||||
// Less than 10 statements in the body?
|
||||
int bodySize = 0;
|
||||
for (AstNode* bodp = precondsp; bodp; bodp=bodp->nextp()) {
|
||||
bodySize++;
|
||||
}
|
||||
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
|
||||
bodySize++;
|
||||
}
|
||||
for (AstNode* bodp = incp; bodp; bodp=bodp->nextp()) {
|
||||
bodySize++;
|
||||
}
|
||||
if (bodySize > v3Global.opt.unrollStmts())
|
||||
int bodyLimit = v3Global.opt.unrollStmts();
|
||||
if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
|
||||
if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
|
||||
return cantUnroll(nodep, "too many statements");
|
||||
}
|
||||
}
|
||||
//
|
||||
// Now, make sure there's no assignment to this variable in the loop
|
||||
@@ -349,7 +360,7 @@ private:
|
||||
nodep->incsp(), nodep->bodysp())) {
|
||||
pushDeletep(nodep); nodep=NULL; // Did replacement
|
||||
} else {
|
||||
nodep->v3error("For loop doesn't have genvar index, or is misformed");
|
||||
nodep->v3error("For loop doesn't have genvar index, or is malformed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -990,8 +990,9 @@ private:
|
||||
lastloop = true; // so exit early; next loop will correct it
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
|
||||
&& !pinp->castCvtPackString()
|
||||
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
|
||||
&& !pinp->castCvtPackString()
|
||||
&& !pinp->castSFormatF() // Already generates a string
|
||||
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
|
||||
UINFO(4," Add CvtPackString: "<<pinp<<endl);
|
||||
AstNRelinker handle;
|
||||
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
//**********************************************************************
|
||||
//**** Version and host name
|
||||
|
||||
#define DTVERSION "Verilator 3.801 2010/03/17"
|
||||
#define DTVERSION "Verilator 3.802 2010/05/01"
|
||||
|
||||
//**********************************************************************
|
||||
//**** Functions
|
||||
|
||||
+7
-1
@@ -144,6 +144,7 @@ crnl [\r]*[\n]
|
||||
id [a-zA-Z_][a-zA-Z0-9_$]*
|
||||
/* escaped identifier */
|
||||
escid \\[^ \t\f\r\n]+
|
||||
word [a-zA-Z0-9_]+
|
||||
|
||||
%%
|
||||
|
||||
@@ -632,6 +633,8 @@ escid \\[^ \t\f\r\n]+
|
||||
"/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; }
|
||||
"/*verilator public*/" { FL; return yVL_PUBLIC; }
|
||||
"/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; }
|
||||
"/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; }
|
||||
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
|
||||
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
|
||||
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
||||
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
|
||||
@@ -645,7 +648,8 @@ escid \\[^ \t\f\r\n]+
|
||||
"/*verilator lint_restore*/" {PARSEP->verilatorCmtLintRestore(); }
|
||||
"/*verilator lint_save*/" {PARSEP->verilatorCmtLintSave(); }
|
||||
|
||||
"/*"[^*]*"*/" {PARSEP->verilatorCmtBad(yytext); }
|
||||
"/**/" { }
|
||||
"/*"[^*]+"*/" {PARSEP->verilatorCmtBad(yytext); }
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
@@ -829,12 +833,14 @@ escid \\[^ \t\f\r\n]+
|
||||
<STRING>\" { yy_pop_state();
|
||||
FL; yylval.strp = PARSEP->newString(yytext+1,yyleng-2);
|
||||
return yaSTRING; }
|
||||
<STRING>{word} { yymore(); }
|
||||
<STRING>. { yymore(); }
|
||||
|
||||
/************************************************************************/
|
||||
/* Attributes */
|
||||
<ATTRMODE>{crnl} { yymore(); NEXTLINE(); }
|
||||
<ATTRMODE>"*)" { yy_pop_state(); }
|
||||
<ATTRMODE>{word} { yymore(); }
|
||||
<ATTRMODE>. { yymore(); }
|
||||
<ATTRMODE><<EOF>> { yyerrorf("EOF in (*");
|
||||
yyleng = 0; yy_pop_state(); }
|
||||
|
||||
+40
-26
@@ -84,7 +84,7 @@ public:
|
||||
}
|
||||
|
||||
// METHODS
|
||||
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep);
|
||||
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
|
||||
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
|
||||
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
||||
AstText* createTextQuoted(FileLine* fileline, string text) {
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
}
|
||||
return pkgp;
|
||||
}
|
||||
AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp) {
|
||||
AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp, bool isPacked) {
|
||||
// If dtypep isn't basic, don't use this, call createArray() instead
|
||||
if (!rangesp) {
|
||||
return dtypep;
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
dtypep->rangep(finalp);
|
||||
dtypep->implicit(false);
|
||||
}
|
||||
return createArray(dtypep, rangearraysp);
|
||||
return createArray(dtypep, rangearraysp, isPacked);
|
||||
}
|
||||
}
|
||||
string deQuote(FileLine* fileline, string text);
|
||||
@@ -434,6 +434,8 @@ class AstSenTree;
|
||||
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
|
||||
%token<fl> yVL_PUBLIC "/*verilator public*/"
|
||||
%token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/"
|
||||
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
|
||||
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
|
||||
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
||||
|
||||
%token<fl> yP_TICK "'"
|
||||
@@ -817,7 +819,7 @@ port<nodep>: // ==IEEE: port
|
||||
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
||||
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
||||
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
|
||||
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3)); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
||||
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,false)); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
||||
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
|
||||
{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
|
||||
//
|
||||
@@ -1029,7 +1031,7 @@ port_declaration<nodep>: // ==IEEE: port_declaration
|
||||
list_of_variable_decl_assignments { $$ = $6; }
|
||||
| port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
|
||||
list_of_variable_decl_assignments { $$ = $6; }
|
||||
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4)); }
|
||||
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4,false)); }
|
||||
list_of_variable_decl_assignments { $$ = $6; }
|
||||
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
|
||||
list_of_variable_decl_assignments { $$ = $5; }
|
||||
@@ -1079,7 +1081,7 @@ data_type<dtypep>: // ==IEEE: data_type
|
||||
// // This expansion also replicated elsewhere, IE data_type__AndID
|
||||
data_typeNoRef { $$ = $1; }
|
||||
// // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension }
|
||||
| ps_type packed_dimensionListE { $$ = GRAMMARP->createArray($1,$2); }
|
||||
| ps_type packed_dimensionListE { $$ = GRAMMARP->createArray($1,$2,true); }
|
||||
//UNSUP class_scope_type packed_dimensionListE { UNSUP }
|
||||
// // IEEE: class_type
|
||||
//UNSUP class_typeWithoutId { $$ = $1; }
|
||||
@@ -1088,7 +1090,7 @@ data_type<dtypep>: // ==IEEE: data_type
|
||||
;
|
||||
|
||||
data_typeBasic<dtypep>: // IEEE: part of data_type
|
||||
integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); }
|
||||
integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
|
||||
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
||||
//UNSUP non_integer_type { UNSUP }
|
||||
;
|
||||
@@ -1190,12 +1192,12 @@ enum_base_typeE<dtypep>: // IEEE: enum_base_type
|
||||
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
|
||||
// // Not in spec, but obviously "enum [1:0]" should work
|
||||
// // implicit_type expanded, without empty
|
||||
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2); }
|
||||
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,false); }
|
||||
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
||||
//
|
||||
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
||||
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); }
|
||||
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2); }
|
||||
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,false); }
|
||||
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, false); }
|
||||
;
|
||||
|
||||
enum_nameList<nodep>:
|
||||
@@ -1244,7 +1246,7 @@ data_declarationVarFront: // IEEE: part of data_declaration
|
||||
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
|
||||
constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($4); }
|
||||
| constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT)); }
|
||||
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5)); }
|
||||
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5,false)); }
|
||||
//
|
||||
// // Expanded: "constE lifetimeE data_type"
|
||||
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
|
||||
@@ -1261,13 +1263,13 @@ constE: // IEEE: part of data_declaration
|
||||
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
|
||||
// // Also expanded in data_declaration
|
||||
/* empty */ { $$ = NULL; }
|
||||
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2); }
|
||||
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,false); }
|
||||
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
||||
;
|
||||
|
||||
type_declaration<nodep>: // ==IEEE: type_declaration
|
||||
// // Use idAny, as we can redeclare a typedef on an existing typedef
|
||||
/*U*/ yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, GRAMMARP->createArray($2,$4)); SYMP->reinsert($$); }
|
||||
yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, GRAMMARP->createArray($2,$4,false)); SYMP->reinsert($$); }
|
||||
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
|
||||
// // Combines into above "data_type id" rule
|
||||
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
|
||||
@@ -1541,6 +1543,10 @@ sigAttr<nodep>:
|
||||
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
|
||||
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); }
|
||||
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); }
|
||||
| yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); }
|
||||
| yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); }
|
||||
| yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW);
|
||||
$$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); }
|
||||
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
||||
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
||||
;
|
||||
@@ -1557,7 +1563,7 @@ rangeList<rangep>: // IEEE: {packed_dimension}
|
||||
|
||||
wirerangeE<dtypep>:
|
||||
/* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit
|
||||
| rangeList { $$ = GRAMMARP->addRange(new AstBasicDType(CRELINE(), LOGIC),$1); } // not implicit
|
||||
| rangeList { $$ = GRAMMARP->addRange(new AstBasicDType(CRELINE(), LOGIC),$1,false); } // not implicit
|
||||
;
|
||||
|
||||
// IEEE: select
|
||||
@@ -1665,13 +1671,18 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
|
||||
| '.' idSVKwd { $$ = NULL; PINNUMINC(); }
|
||||
| '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
|
||||
| '.' idAny '(' ')' { $$ = NULL; PINNUMINC(); }
|
||||
// // mintypmax is expanded here, as it might be a UDP or gate primitive
|
||||
| '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); }
|
||||
//UNSUP '.' idAny '(' expr ':' expr ')' { }
|
||||
//UNSUP '.' idAny '(' expr ':' expr ':' expr ')' { }
|
||||
// // For parameters
|
||||
//UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); }
|
||||
// // For parameters
|
||||
//UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); }
|
||||
//
|
||||
| expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
|
||||
//UNSUP expr ':' expr { }
|
||||
//UNSUP expr ':' expr ':' expr { }
|
||||
// // Floatnum should only occur with UDPs, but since ports aren't floats, it's legal to round always
|
||||
| yaFLOATNUM { $$ = new AstPin($<fl>1,PINNUMINC(),"",new AstConst($<fl>1,AstConst::Unsized32(),(int)(($1<0)?($1-0.5):($1+0.5)))); }
|
||||
;
|
||||
@@ -1679,6 +1690,12 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
|
||||
//************************************************
|
||||
// EventControl lists
|
||||
|
||||
attr_event_control<sentreep>: // ==IEEE: event_control
|
||||
'@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); }
|
||||
| '@' '(' '*' ')' { $$ = NULL; }
|
||||
| '@' '*' { $$ = NULL; }
|
||||
;
|
||||
|
||||
event_controlE<sentreep>:
|
||||
/* empty */ { $$ = NULL; }
|
||||
| event_control { $$ = $1; }
|
||||
@@ -2145,7 +2162,7 @@ funcId<ftaskp>: // IEEE: function_data_type_or_implicit + part of function_bod
|
||||
SYMP->pushNewUnder($$, NULL); }
|
||||
| signingE rangeList tfIdScoped
|
||||
{ $$ = new AstFunc ($<fl>3,*$<strp>3,NULL,
|
||||
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2));
|
||||
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2,false));
|
||||
SYMP->pushNewUnder($$, NULL); }
|
||||
| signing tfIdScoped
|
||||
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,
|
||||
@@ -2215,14 +2232,14 @@ tf_port_item<nodep>: // ==IEEE: tf_port_item
|
||||
|
||||
tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type
|
||||
data_type { VARDTYPE($1); }
|
||||
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2)); }
|
||||
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, false)); }
|
||||
| signing { VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1)); }
|
||||
| yVAR data_type { VARDTYPE($2); }
|
||||
| yVAR implicit_typeE { VARDTYPE($2); }
|
||||
//
|
||||
| tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ }
|
||||
| tf_port_itemDir data_type { VARDTYPE($2); }
|
||||
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3)); }
|
||||
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,false)); }
|
||||
| tf_port_itemDir signing { VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $2)); }
|
||||
| tf_port_itemDir yVAR data_type { VARDTYPE($3); }
|
||||
| tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); }
|
||||
@@ -2891,16 +2908,13 @@ concurrent_assertion_statement<nodep>: // ==IEEE: concurrent_assertion_statement
|
||||
|
||||
property_spec<nodep>: // IEEE: property_spec
|
||||
//UNSUP: This rule has been super-specialized to what is supported now
|
||||
'@' '(' senitemEdge ')' property_specDisable expr { $$ = new AstPslClocked($1,$3,$5,$6); }
|
||||
'@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' expr
|
||||
{ $$ = new AstPslClocked($1,$3,$8,$10); }
|
||||
| '@' '(' senitemEdge ')' expr { $$ = new AstPslClocked($1,$3,NULL,$5); }
|
||||
| property_specDisable expr { $$ = new AstPslClocked($2->fileline(),NULL,$1,$2); }
|
||||
| yDISABLE yIFF '(' expr ')' expr { $$ = new AstPslClocked($4->fileline(),NULL,$4,$6); }
|
||||
| expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); }
|
||||
;
|
||||
|
||||
property_specDisable<nodep>: // IEEE: part of property_spec
|
||||
yDISABLE yIFF '(' expr ')' { $$ = $4; }
|
||||
;
|
||||
|
||||
immediate_assert_statement<nodep>: // ==IEEE: immediate_assert_statement
|
||||
// // action_block expanded here, for compatibility with AstVAssert
|
||||
yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, GRAMMARP->createDisplayError($1)); }
|
||||
@@ -3054,7 +3068,7 @@ AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int v
|
||||
return nodep;
|
||||
}
|
||||
|
||||
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep) {
|
||||
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked) {
|
||||
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
||||
AstNodeDType* arrayp = basep;
|
||||
if (rangep) { // Maybe no range - return unmodified base type
|
||||
@@ -3062,7 +3076,7 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep)
|
||||
while (rangep) {
|
||||
AstRange* prevp = rangep->backp()->castRange();
|
||||
if (prevp) rangep->unlinkFrBack();
|
||||
arrayp = new AstArrayDType(rangep->fileline(), arrayp, rangep);
|
||||
arrayp = new AstArrayDType(rangep->fileline(), arrayp, rangep, isPacked);
|
||||
rangep = prevp;
|
||||
}
|
||||
}
|
||||
@@ -3094,7 +3108,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
|
||||
}
|
||||
|
||||
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
||||
AstNodeDType* arrayDTypep = createArray(dtypep,arrayp);
|
||||
AstNodeDType* arrayDTypep = createArray(dtypep,arrayp,false);
|
||||
|
||||
AstVar* nodep = new AstVar(fileline, type, name, arrayDTypep);
|
||||
nodep->addAttrsp(attrsp);
|
||||
|
||||
+39
-3
@@ -40,6 +40,7 @@ our @Orig_ARGV = @ARGV;
|
||||
our @Orig_ARGV_Sw; foreach (@Orig_ARGV) { push @Orig_ARGV_Sw, $_ if /^-/ && !/^-j/; }
|
||||
|
||||
$Debug = 0;
|
||||
my $opt_atsim;
|
||||
my $opt_benchmark;
|
||||
my @opt_tests;
|
||||
my $opt_gdb;
|
||||
@@ -61,6 +62,7 @@ Getopt::Long::config ("pass_through");
|
||||
if (! GetOptions (
|
||||
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
|
||||
"debug" => \&debug,
|
||||
"atsim|athdl!"=> \$opt_atsim,
|
||||
"gdb!" => \$opt_gdb,
|
||||
"gdbbt!" => \$opt_gdbbt,
|
||||
"gdbsim!" => \$opt_gdbsim,
|
||||
@@ -86,7 +88,7 @@ $opt_jobs = calc_jobs() if defined $opt_jobs && $opt_jobs==0;
|
||||
|
||||
$Fork->max_proc($opt_jobs);
|
||||
|
||||
if (!$opt_iv && !$opt_vcs && !$opt_nc && !$opt_vlt) {
|
||||
if (!$opt_atsim && !$opt_iv && !$opt_vcs && !$opt_nc && !$opt_vlt) {
|
||||
$opt_vlt = 1;
|
||||
}
|
||||
|
||||
@@ -101,6 +103,7 @@ my $leftcnt=0; my $okcnt=0; my $failcnt=0; my $skcnt=0;
|
||||
my @fails;
|
||||
|
||||
foreach my $testpl (@opt_tests) {
|
||||
one_test(pl_filename => $testpl, atsim=>1) if $opt_atsim;
|
||||
one_test(pl_filename => $testpl, iv=>1) if $opt_iv;
|
||||
one_test(pl_filename => $testpl, nc=>1) if $opt_nc;
|
||||
one_test(pl_filename => $testpl, vcs=>1) if $opt_vcs;
|
||||
@@ -261,6 +264,12 @@ sub new {
|
||||
v_flags2 => [], # Overridden in some sim files
|
||||
v_other_filenames => [], # After the filename so we can spec multiple files
|
||||
all_run_flags => [],
|
||||
# ATSIM
|
||||
atsim => 0,
|
||||
atsim_flags => [split(/\s+/,"-c +sv +define+atsim"),
|
||||
"+sv_dir+$self->{obj_dir}/.athdl_compile"],
|
||||
atsim_flags2 => [], # Overridden in some sim files
|
||||
atsimrun_flags => [],
|
||||
# IV
|
||||
iv => 0,
|
||||
iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")],
|
||||
@@ -288,6 +297,7 @@ sub new {
|
||||
%$self};
|
||||
bless $self, $class;
|
||||
|
||||
$self->{mode} ||= "atsim" if $self->{atsim};
|
||||
$self->{mode} ||= "vcs" if $self->{vcs};
|
||||
$self->{mode} ||= "vlt" if $self->{vlt};
|
||||
$self->{mode} ||= "nc" if $self->{nc};
|
||||
@@ -387,6 +397,20 @@ sub compile {
|
||||
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
|
||||
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
|
||||
|
||||
if ($param{atsim}) {
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/atsim_compile.log",
|
||||
fails=>$param{fails},
|
||||
cmd=>[($ENV{VERILATOR_ATSIM}||"atsim"),
|
||||
@{$param{atsim_flags}},
|
||||
@{$param{atsim_flags2}},
|
||||
@{$param{v_flags}},
|
||||
@{$param{v_flags2}},
|
||||
$param{top_filename},
|
||||
$param{top_shell_filename},
|
||||
@{$param{v_other_filenames}},
|
||||
]);
|
||||
}
|
||||
if ($param{vcs}) {
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/vcs_compile.log",
|
||||
@@ -511,6 +535,14 @@ sub execute {
|
||||
my $run_env = $param{run_env};
|
||||
$run_env .= ' ' if $run_env;
|
||||
|
||||
if ($param{atsim}) {
|
||||
$self->_run(logfile=>"$self->{obj_dir}/atsim_sim.log",
|
||||
fails=>$param{fails},
|
||||
cmd=>["echo q | ".$run_env."$self->{obj_dir}/athdl_sv",
|
||||
@{$param{atsimrun_flags}},
|
||||
@{$param{all_run_flags}},
|
||||
]);
|
||||
}
|
||||
if ($param{iv}) {
|
||||
$self->_run(logfile=>"$self->{obj_dir}/iv_sim.log",
|
||||
fails=>$param{fails},
|
||||
@@ -522,7 +554,7 @@ sub execute {
|
||||
if ($param{nc}) {
|
||||
$self->_run(logfile=>"$self->{obj_dir}/nc_sim.log",
|
||||
fails=>$param{fails},
|
||||
cmd=>[$run_env.($ENV{VERILATOR_NCVERILOG}||"ncverilog"),
|
||||
cmd=>["echo q | ".$run_env.($ENV{VERILATOR_NCVERILOG}||"ncverilog"),
|
||||
@{$param{ncrun_flags}},
|
||||
@{$param{all_run_flags}},
|
||||
]);
|
||||
@@ -531,7 +563,7 @@ sub execute {
|
||||
#my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,";
|
||||
#$fh->print("quit\n"); $fh->close;
|
||||
$self->_run(logfile=>"$self->{obj_dir}/vcs_sim.log",
|
||||
cmd=>[$run_env."./simv",
|
||||
cmd=>["echo q | ".$run_env."./simv",
|
||||
@{$param{all_run_flags}},
|
||||
],
|
||||
%param,
|
||||
@@ -1166,6 +1198,10 @@ driver.pl invokes Verilator or another simulator on each little test file.
|
||||
|
||||
=over 4
|
||||
|
||||
=item --atsim
|
||||
|
||||
Run using ATSIM.
|
||||
|
||||
=item --benchmark [<cycles>]
|
||||
|
||||
Show execution times of each step. If an optional number is given,
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--stats"],
|
||||
verilator_flags2 => ["--stats"],
|
||||
);
|
||||
|
||||
if ($Self->{v3}) {
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--stats"],
|
||||
verilator_flags2 => ["--stats"],
|
||||
);
|
||||
|
||||
if ($Self->{v3}) {
|
||||
|
||||
@@ -16,7 +16,7 @@ compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
fails => 1,
|
||||
fails => $Self->{vlt},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
@@ -16,7 +16,7 @@ compile (
|
||||
|
||||
execute (
|
||||
check_finished=>0,
|
||||
fails=>1,
|
||||
fails=> $Self->{vlt},
|
||||
expect=>
|
||||
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis full_case'
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ compile (
|
||||
|
||||
execute (
|
||||
check_finished=>0,
|
||||
fails=>1,
|
||||
fails => $Self->{v3},
|
||||
expect=>
|
||||
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis parallel_case'
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
||||
|
||||
compile (
|
||||
v_flags2 => [$Self->{v3}?"--stats --O3 -x-assign fast":""],
|
||||
verilator_flags2 => ["--stats --O3 -x-assign fast"],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
||||
|
||||
compile (
|
||||
v_flags2 => [$Self->{v3}?"--stats --O3 -x-assign fast":""],
|
||||
verilator_flags2 => ["--stats --O3 -x-assign fast"],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--x-assign 0"],
|
||||
verilator_flags2 => ["--x-assign 0"],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--stats"],
|
||||
verilator_flags2 => ["--stats"],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => [$Self->{v3}?'--sp --coverage-line':''],
|
||||
verilator_flags2 => ['--sp --coverage-line'],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -48,7 +48,11 @@ module t (/*AUTOARG*/
|
||||
toggle <= '1;
|
||||
end
|
||||
else if (cyc==5) begin
|
||||
`ifdef VERILATOR
|
||||
$c("call_task();");
|
||||
`else
|
||||
call_task();
|
||||
`endif
|
||||
end
|
||||
else if (cyc==10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => [$Self->{v3}?'--assert --sp --coverage-user':''],
|
||||
verilator_flags2 => ['--assert --sp --coverage-user'],
|
||||
);
|
||||
|
||||
execute (
|
||||
@@ -20,7 +20,8 @@ execute (
|
||||
# Allow old Perl format dump, or new binary dump
|
||||
# Check that the hierarchy doesn't include __PVT__
|
||||
# Otherwise our coverage reports would look really ugly
|
||||
file_grep ($Self->{coverage_filename}, qr/(top\.v\.sub.*.cyc_eq_5)/);
|
||||
file_grep ($Self->{coverage_filename}, qr/(top\.v\.sub.*.cyc_eq_5)/)
|
||||
if $Self->{vlt};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => [$Self->{v3}?'--sp --coverage-toggle --stats':''],
|
||||
verilator_flags2 => ['--sp --coverage-toggle --stats'],
|
||||
);
|
||||
|
||||
execute (
|
||||
@@ -18,7 +18,8 @@ execute (
|
||||
# Read the input .v file and do any CHECK_COVER requests
|
||||
inline_checks();
|
||||
|
||||
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+25/i);
|
||||
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+25/i)
|
||||
if $Self->{vlt};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -22,6 +22,7 @@ if (!-r "$root/.git") {
|
||||
my $cmd = "cd $root && fgrep -n include $files | sort";
|
||||
my $grep = `$cmd`;
|
||||
foreach my $line (split /\n/, $grep) {
|
||||
next if $line =~ /vpi_user.h/; # IEEE Standard file - can't change it
|
||||
my $hit;
|
||||
$hit = 1 if $line =~ /\bassert\.h/;
|
||||
$hit = 1 if $line =~ /\bctype\.h/;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//*************************************************************************
|
||||
|
||||
#include <cstdio>
|
||||
#include <svdpi.h>
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//*************************************************************************
|
||||
|
||||
#include <cstdio>
|
||||
#include <svdpi.h>
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
//*************************************************************************
|
||||
|
||||
#include <cstdio>
|
||||
#include <svdpi.h>
|
||||
#include <cstring>
|
||||
#include "svdpi.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define T_PRI64 "I64"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <svdpi.h>
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//*************************************************************************
|
||||
|
||||
#include <cstdio>
|
||||
#include <svdpi.h>
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// -*- 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.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "Vt_dpi_var.h"
|
||||
#include "verilated.h"
|
||||
#include "svdpi.h"
|
||||
|
||||
#include "verilated_syms.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
struct MyMon {
|
||||
vluint32_t* sigsp[2];
|
||||
MyMon() { sigsp[0]=NULL; sigsp[1]=NULL; }
|
||||
};
|
||||
MyMon mons[2];
|
||||
|
||||
void mon_register_a(const char* namep, void* sigp, bool isOut) {
|
||||
// Callback from initial block in monitor
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("- mon_register_a(\"%s\", %p, %d);\n", namep, sigp, isOut);
|
||||
#endif
|
||||
mons[0].sigsp[isOut] = (vluint32_t*)sigp;
|
||||
}
|
||||
|
||||
void mon_do(MyMon* monp) {
|
||||
if (!monp->sigsp[0]) vl_fatal(__FILE__,__LINE__,"","never registered");
|
||||
if (!monp->sigsp[1]) vl_fatal(__FILE__,__LINE__,"","never registered");
|
||||
*monp->sigsp[1] = (*(monp->sigsp[0]))+1;
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("- mon_do(%08x(&%p) -> %08x(&%p));\n",
|
||||
*(monp->sigsp[0]), monp->sigsp[0], *(monp->sigsp[1]), monp->sigsp[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mon_class_name(const char* namep) {
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("- mon_class_name(\"%s\");\n", namep);
|
||||
#endif
|
||||
// Check the C's calling name of "" doesn't lead to extra dots in the name()
|
||||
if (namep && namep[0]=='.') vl_fatal(__FILE__,__LINE__,"", (string("Unexp class name ")+namep).c_str());
|
||||
}
|
||||
|
||||
extern "C" void mon_scope_name(const char* namep);
|
||||
void mon_scope_name(const char* namep) {
|
||||
const char* modp = svGetNameFromScope(svGetScope());
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep);
|
||||
#endif
|
||||
if (strcmp(namep,"t.sub")) vl_fatal(__FILE__,__LINE__,"", (string("Unexp scope name ")+namep).c_str());
|
||||
if (strcmp(modp,"t.sub")) vl_fatal(__FILE__,__LINE__,"", (string("Unexp dpiscope name ")+modp).c_str());
|
||||
}
|
||||
|
||||
extern "C" void mon_register_b(const char* namep, int isOut);
|
||||
void mon_register_b(const char* namep, int isOut) {
|
||||
const char* modp = svGetNameFromScope(svGetScope());
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("- mon_register_b('%s', \"%s\", %d);\n", modp, namep, isOut);
|
||||
#endif
|
||||
// Use scope to get pointer and size of signal
|
||||
const VerilatedScope* scopep = Verilated::dpiScope();
|
||||
const VerilatedVar* varp = scopep->varFind(namep);
|
||||
if (!varp) {
|
||||
VL_PRINTF("%%Warning: mon_register_b signal not found: \"%s\"\n", namep);
|
||||
} else if (varp->vltype() != VLVT_UINT32) {
|
||||
VL_PRINTF("%%Warning: wrong type for signal: \"%s\"\n", namep);
|
||||
} else {
|
||||
vluint32_t* datap = (vluint32_t*)(varp->datap());
|
||||
VL_PRINTF("- mon_register_b('%s', \"%s\", %p, %d);\n", modp, namep, datap, isOut);
|
||||
mons[1].sigsp[isOut] = (vluint32_t*)(varp->datap());
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void mon_register_done();
|
||||
void mon_register_done() {
|
||||
const char* modp = svGetNameFromScope(svGetScope());
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("- mon_register_done('%s');\n", modp);
|
||||
#endif
|
||||
// Print list of all signals - if we didn't register2 anything we'd pick them off here
|
||||
const VerilatedScope* scopep = Verilated::dpiScope();
|
||||
if (VerilatedVarNameMap* varsp = scopep->varsp()) {
|
||||
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
|
||||
it != varsp->end(); ++it) {
|
||||
VL_PRINTF("- mon2: %s\n", it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void mon_eval();
|
||||
void mon_eval() {
|
||||
// Callback from always@ negedge
|
||||
mon_do(&mons[0]);
|
||||
mon_do(&mons[1]);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
unsigned int main_time = false;
|
||||
|
||||
double sc_time_stamp () {
|
||||
return main_time;
|
||||
}
|
||||
int main(int argc, char **argv, char **env) {
|
||||
double sim_time = 1100;
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Verilated::debug(0);
|
||||
|
||||
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
|
||||
|
||||
#ifdef VERILATOR
|
||||
# ifdef TEST_VERBOSE
|
||||
Verilated::scopesDump();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
main_time += 10;
|
||||
|
||||
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += 1;
|
||||
topp->eval();
|
||||
topp->clk = !topp->clk;
|
||||
//mon_do();
|
||||
}
|
||||
if (!Verilated::gotFinish()) {
|
||||
vl_fatal(__FILE__,__LINE__,"main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
||||
delete topp; topp=NULL;
|
||||
exit(0L);
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["--exe --no-l2name $Self->{t_dir}/t_dpi_var.cpp"],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,91 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Copyright 2010 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
|
||||
wire monclk = ~clk;
|
||||
|
||||
int in;
|
||||
int fr_a;
|
||||
int fr_b;
|
||||
int fr_chk;
|
||||
sub sub (.*);
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] cyc==%0d in=%x fr_a=%x b=%x fr_chk=%x\n",$time, cyc, in, fr_a, fr_b, fr_chk);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
in <= {in[30:0], in[31]^in[2]^in[0]};
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
in <= 32'hd70a4497;
|
||||
end
|
||||
else if (cyc<3) begin
|
||||
end
|
||||
else if (cyc<10) begin
|
||||
if (fr_chk != fr_a) $stop;
|
||||
if (fr_chk != fr_b) $stop;
|
||||
end
|
||||
else if (cyc==10) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge t.monclk) begin
|
||||
mon_eval();
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
import "DPI-C" context function void mon_scope_name (input string formatted /*verilator sformat*/ );
|
||||
import "DPI-C" context function void mon_register_b(string name, int isOut);
|
||||
import "DPI-C" context function void mon_register_done();
|
||||
import "DPI-C" context function void mon_eval();
|
||||
|
||||
module sub (/*AUTOARG*/
|
||||
// Outputs
|
||||
fr_a, fr_b, fr_chk,
|
||||
// Inputs
|
||||
in
|
||||
);
|
||||
|
||||
`systemc_imp_header
|
||||
void mon_class_name(const char* namep);
|
||||
void mon_register_a(const char* namep, void* sigp, bool isOut);
|
||||
`verilog
|
||||
|
||||
input int in /*verilator public_flat_rd*/;
|
||||
output int fr_a /*verilator public_flat_rw @(posedge t.monclk)*/;
|
||||
output int fr_b /*verilator public_flat_rw @(posedge t.monclk)*/;
|
||||
output int fr_chk;
|
||||
|
||||
always @* fr_chk = in + 1;
|
||||
|
||||
initial begin
|
||||
// Test the naming
|
||||
$c("mon_class_name(name());");
|
||||
mon_scope_name("%m");
|
||||
// Scheme A - pass pointer directly
|
||||
$c("mon_register_a(\"in\",&",in,",false);");
|
||||
$c("mon_register_a(\"fr_a\",&",fr_a,",true);");
|
||||
// Scheme B - use VPIish callbacks to see what signals exist
|
||||
mon_register_b("in", 0);
|
||||
mon_register_b("fr_b", 1);
|
||||
mon_register_done();
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -7,6 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} or $Self->skip("Verilator only test");
|
||||
|
||||
$Self->_run (cmd=>["cd $Self->{obj_dir}"
|
||||
." && g++ -c ../../t/t_flag_ldflags_a.cpp"
|
||||
." && ar r t_flag_ldflags_a.a t_flag_ldflags_a.o"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//*************************************************************************
|
||||
|
||||
#include <cstdio>
|
||||
#include <svdpi.h>
|
||||
#include "svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ module t (
|
||||
|
||||
chk chk (.clk (clk),
|
||||
.rst_l (1'b1),
|
||||
.expr (|crc),
|
||||
.expr (|crc)
|
||||
);
|
||||
|
||||
always @ (posedge clk) begin
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t_task (/*AUTOARG*/
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
@@ -37,10 +37,14 @@ module t (clk);
|
||||
if ( cyc >= 4 ) begin
|
||||
dindex = dindex + 2; //*** Error line
|
||||
$display("%m: DIndex increment %d", cyc);
|
||||
`ifdef VERILATOR
|
||||
$c("VL_PRINTF(\"Hello1?\\n\");");
|
||||
`endif
|
||||
end
|
||||
`ifdef VERILATOR
|
||||
$c("VL_PRINTF(\"Hello2?\\n\");");
|
||||
$c("VL_PRINTF(\"Hello3?\\n\");");
|
||||
`endif
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t_func (/*AUTOARG*/
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} or $Self->skip("Verilator only test");
|
||||
|
||||
compile (
|
||||
);
|
||||
# No execute
|
||||
|
||||
@@ -12,7 +12,7 @@ my $pubtask = ($Self->{v3} && verilator_version() =~ /\(public_tasks\)/); # TBD
|
||||
top_filename("t/t_func_public.v");
|
||||
|
||||
compile (
|
||||
v_flags2 => [($pubtask?'-DVERILATOR_PUBLIC_TASKS':''), "--trace"],
|
||||
verilator_flags2 => [($pubtask?'-DVERILATOR_PUBLIC_TASKS':''), "--trace"],
|
||||
fails => $fail,
|
||||
);
|
||||
|
||||
|
||||
@@ -7,12 +7,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} or $Self->skip("Verilator only test");
|
||||
|
||||
$Self->_run(fails=>1,
|
||||
cmd=>["perl","../bin/verilator",
|
||||
"--help"],
|
||||
logfile=>"$Self->{obj_dir}/t_help.log",
|
||||
tee=>0,
|
||||
) if $Self->{v3};
|
||||
);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t_initial (/*AUTOARG*/
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
top_filename("t/t_inst_tree.v");
|
||||
|
||||
compile (
|
||||
v_flags2 => ['+define+NOUSE_INLINE', '+define+USE_PUBLIC', '--stats'],
|
||||
verilator_flags2 => ['+define+NOUSE_INLINE', '+define+USE_PUBLIC', '--stats'],
|
||||
);
|
||||
|
||||
if ($Self->{v3}) {
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ['-public'],
|
||||
verilator_flags2 => ['-public'],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
||||
@@ -28,7 +28,7 @@ long long get_memory_usage() {
|
||||
if (!fp) return 0;
|
||||
|
||||
int ps_ign;
|
||||
long long ps_vsize, ps_rss;
|
||||
vluint64_t ps_vsize, ps_rss;
|
||||
int items = fscanf(fp, ("%d (%*[^) ]) %*1s %d %*d %*d %*d %*d %u"
|
||||
" %u %u %u %u %d %d %d %d"
|
||||
" %*d %*d %*u %*u %d %" VL_PRI64 "u %" VL_PRI64 "u "),
|
||||
@@ -61,7 +61,7 @@ void make_and_destroy () {
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
long long firstUsage = get_memory_usage();
|
||||
vluint64_t firstUsage = get_memory_usage();
|
||||
|
||||
// Warmup phase
|
||||
for (int i=0; i<1000; i++) {
|
||||
@@ -77,7 +77,7 @@ int main (int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
long long leaked = get_memory_usage() - firstUsage;
|
||||
vluint64_t leaked = get_memory_usage() - firstUsage;
|
||||
if (leaked > 64*1024) { // Have to allow some slop for this code.
|
||||
printf ("Leaked %" VL_PRI64 "d bytes, or ~ %" VL_PRI64 "d bytes/construt\n", leaked, leaked/loops);
|
||||
vl_fatal(__FILE__,__LINE__,"top", "Leaked memory\n");
|
||||
|
||||
@@ -7,6 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->{vlt} or $Self->skip("Verilator only test");
|
||||
|
||||
compile (
|
||||
v_flags => ["-Wno-IMPLICIT"],
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t_arith(/*AUTOARG*/
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->skip("Verilator only test") if !$Self->{vlt};
|
||||
|
||||
compile (
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
|
||||
@@ -90,7 +90,6 @@ module fifo (/*AUTOARG*/
|
||||
// verilator lint_off VARHIDDEN
|
||||
reg [65:0] fifo[0:fifoDepth-1];
|
||||
// verilator lint_on VARHIDDEN
|
||||
reg [`PTRBITSM1:0] wrPtr, rdPtr;
|
||||
|
||||
//reg [65:0] temp;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t_mem (/*AUTOARG*/
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
@@ -91,4 +91,89 @@ module t (/*AUTOARG*/
|
||||
end
|
||||
end
|
||||
|
||||
// Test for mixed implicit/explicit dimensions and all implicit packed
|
||||
logic [3:0][7:0][1:0] vld [1:0][1:0];
|
||||
logic [3:0][7:0][1:0] vld2;
|
||||
|
||||
// There are specific nodes for Or, Xor, Xnor and And
|
||||
logic vld_or;
|
||||
logic vld2_or;
|
||||
assign vld_or = |vld[0][0];
|
||||
assign vld2_or = |vld2;
|
||||
|
||||
logic vld_xor;
|
||||
logic vld2_xor;
|
||||
assign vld_xor = ^vld[0][0];
|
||||
assign vld2_xor = ^vld2;
|
||||
|
||||
logic vld_xnor;
|
||||
logic vld2_xnor;
|
||||
assign vld_xnor = ~^vld[0][0];
|
||||
assign vld2_xnor = ~^vld2;
|
||||
|
||||
logic vld_and;
|
||||
logic vld2_and;
|
||||
assign vld_and = &vld[0][0];
|
||||
assign vld2_and = &vld2;
|
||||
|
||||
// Bit reductions should be cloned, other unary operations should clone the
|
||||
// entire assign.
|
||||
logic [3:0][7:0][1:0] not_lhs;
|
||||
logic [3:0][7:0][1:0] not_rhs;
|
||||
assign not_lhs = ~not_rhs;
|
||||
|
||||
// Test an AstNodeUniop that shouldn't be expanded
|
||||
logic [3:0][7:0][1:0] vld2_inv;
|
||||
assign vld2_inv = ~vld2;
|
||||
|
||||
initial begin
|
||||
for (int i=0; i<4; i=i+2) begin
|
||||
for (int j=0; j<8; j=j+2) begin
|
||||
vld[0][0][i][j] = 2'b00;
|
||||
vld[0][0][i+1][j+1] = 2'b00;
|
||||
vld2[i][j] = 2'b00;
|
||||
vld2[i+1][j+1] = 2'b00;
|
||||
not_rhs[i][j] = i[1:0];
|
||||
not_rhs[i+1][j+1] = i[1:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
logic [3:0] expect_cyc; initial expect_cyc = 'd15;
|
||||
|
||||
always @(posedge clk) begin
|
||||
expect_cyc <= expect_cyc + 1;
|
||||
for (int i=0; i<4; i=i+1) begin
|
||||
for (int j=0; j<8; j=j+1) begin
|
||||
vld[0][0][i][j] <= vld[0][0][i][j] + 1;
|
||||
vld2[i][j] <= vld2[i][j] + 1;
|
||||
if (not_rhs[i][j] != ~not_lhs[i][j]) $stop;
|
||||
not_rhs[i][j] <= not_rhs[i][j] + 1;
|
||||
end
|
||||
end
|
||||
if (cyc % 8 == 0) begin
|
||||
vld[0][0][0][0] <= vld[0][0][0][0] - 1;
|
||||
vld2[0][0] <= vld2[0][0] - 1;
|
||||
end
|
||||
if (expect_cyc < 8 && !vld_xor) $stop;
|
||||
else if (expect_cyc > 7 && vld_xor) $stop;
|
||||
|
||||
if (expect_cyc < 8 && vld_xnor) $stop;
|
||||
else if (expect_cyc > 7 && !vld_xnor) $stop;
|
||||
|
||||
if (expect_cyc == 15 && vld_or) $stop;
|
||||
else if (expect_cyc == 11 && vld_or) $stop;
|
||||
else if (expect_cyc != 15 && expect_cyc != 11 && !vld_or) $stop;
|
||||
|
||||
if (expect_cyc == 10 && !vld_and) $stop;
|
||||
else if (expect_cyc == 14 && !vld_and) $stop;
|
||||
else if (expect_cyc != 10 && expect_cyc != 14 && vld_and) $stop;
|
||||
|
||||
if (vld_xor != vld2_xor) $stop;
|
||||
if (vld_xnor != vld2_xnor) $stop;
|
||||
if (vld_or != vld2_or) $stop;
|
||||
if (vld_and != vld2_and) $stop;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2010 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_mem_packed_bad.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
|
||||
%Error: t/t_mem_packed_bad.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
|
||||
%Error: t/t_mem_packed_bad.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
|
||||
%Error: t/t_mem_packed_bad.v:\d+: Unsupported: Assignment between packed arrays of different dimensions
|
||||
%Error: Exiting due to.*',
|
||||
) if $Self->{v3};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,34 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2010 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
integer cyc; initial cyc = 0;
|
||||
|
||||
logic [1:0][27:0] ch01;
|
||||
logic [1:0][27:0] ch02;
|
||||
logic [1:0][27:0] ch03;
|
||||
logic [27:0] ch04[1:0];
|
||||
|
||||
/* verilator lint_off WIDTH */
|
||||
always @ (posedge clk) begin
|
||||
// LHS is a 2D packed array, RHS is 1D packed or Const. Unsupported.
|
||||
ch01 <= {{2{28'd4}}};
|
||||
ch02 <= {{2{cyc}}};
|
||||
ch03 <= 56'd0;
|
||||
// LHS is 1D packed, 1D unpacked, this should never work.
|
||||
ch04 <= 56'd0;
|
||||
$display("ch01: %0x %0x", ch01[0], ch01[1]);
|
||||
$display("ch01: %0x %0x", ch02[0], ch02[1]);
|
||||
$display("ch01: %0x %0x", ch03[0], ch03[1]);
|
||||
$display("ch01: %0x %0x", ch04[0], ch04[1]);
|
||||
end
|
||||
/* verilator lint_on WIDTH */
|
||||
|
||||
endmodule
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--stats"],
|
||||
verilator_flags2 => ["--stats"],
|
||||
);
|
||||
|
||||
if ($Self->{v3}) {
|
||||
|
||||
@@ -7,15 +7,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
$Self->skip("Verilator only test") if !$Self->{vlt};
|
||||
|
||||
compile (
|
||||
fails=>$Self->{v3},
|
||||
nc=>0, # Need to get it not to give the prompt
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error-MODDUP: t/t_mod_dup_bad.v:\d+: Duplicate declaration of module: a
|
||||
%Error-MODDUP: t/t_mod_dup_bad.v:\d+: ... Location of original declaration
|
||||
.*
|
||||
%Error: Exiting due to.*',
|
||||
) if $Self->{v3};
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user