Merge from master for release.
This commit is contained in:
commit
702140bf93
|
|
@ -23,6 +23,8 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
CI_RUNS_ON: ${{ matrix.os }}
|
||||
CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }}-coverage
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
|
@ -32,7 +34,7 @@ jobs:
|
|||
cache-name: ccache
|
||||
with:
|
||||
path: ${{ github.workspace }}/.ccache
|
||||
key: coverage-${{ env.cache-name }}-${{ github.sha }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }}
|
||||
restore-keys: coverage-${{ env.cache-name }}
|
||||
|
||||
- name: Install dependencies for build
|
||||
|
|
@ -44,14 +46,11 @@ jobs:
|
|||
run: |
|
||||
./ci/ci-script.bash
|
||||
|
||||
mkdir tarball/
|
||||
cp -vr bin tarball/
|
||||
cp -vr src/obj*/*.gcno tarball/
|
||||
tar cvzf verilator-${CI_COMMIT}.tgz -C ./tarball .
|
||||
tar cvzf verilator-${CI_COMMIT}-coverage.tgz bin src/obj*/*.o src/obj*/*.gcno
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
path: verilator-${{ env.CI_COMMIT }}.tgz
|
||||
path: verilator-${{ env.CI_COMMIT }}-coverage.tgz
|
||||
|
||||
|
||||
Test:
|
||||
|
|
@ -73,6 +72,8 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: test
|
||||
CI_RUNS_ON: ${{ matrix.os }}
|
||||
CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }}-coverage
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
|
@ -82,14 +83,15 @@ jobs:
|
|||
cache-name: ccache
|
||||
with:
|
||||
path: ${{ github.workspace }}/.ccache
|
||||
key: coverage-${{ env.cache-name }}-${{ github.sha }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }}
|
||||
restore-keys: coverage-${{ env.cache-name }}
|
||||
|
||||
- uses: actions/download-artifact@v2
|
||||
|
||||
- name: Install Verilator and test dependencies
|
||||
run: |
|
||||
tar xvzf artifact/verilator-${CI_COMMIT}.tgz
|
||||
tar xvzf artifact/verilator-${CI_COMMIT}-coverage.tgz
|
||||
touch src/obj*/*.o src/obj*/*.gcno
|
||||
./ci/ci-install.bash
|
||||
|
||||
- name: Test
|
||||
|
|
|
|||
31
Changes
31
Changes
|
|
@ -3,6 +3,37 @@ Revision history for Verilator
|
|||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
* Verilator 4.110 2021-02-25
|
||||
|
||||
*** Optimize bit operations and others (#2186) (#2632) (#2633) (#2751) (#2800) [Yutetsu TAKATSUKASA]
|
||||
|
||||
**** Support concat selection (#2721).
|
||||
|
||||
**** Support struct scopes when dumping structs to VCD (#2776) [Alex Torregrosa]
|
||||
|
||||
**** Generate SELRANGE for potentially unreachable code (#2625) (#2754) [Pierre-Henri Horrein]
|
||||
|
||||
**** For --flatten, override inlining of public and no_inline modules (#2761) [James Hanlon]
|
||||
|
||||
**** Fix little endian interface pin swizzling (#2475). [Don Owen]
|
||||
|
||||
**** Fix range inheritance on port without data type (#2753). [Embedded Go]
|
||||
|
||||
**** Fix TIMESCALE warnings on primitives (#2763). [Xuanqi]
|
||||
|
||||
**** Fix to exclude strings from toggle coverage (#2766) (#2767) [Paul Wright]
|
||||
|
||||
**** Fix $fread extra semicolon inside statements. [Leendert van Doorn]
|
||||
|
||||
**** Fix class extends with VM_PARALLEL_BUILDS (#2775). [Iru Cai]
|
||||
|
||||
**** Fix shifts by > 32 bit values (#2785). [qrq992]
|
||||
|
||||
**** Fix examples not flushing vcd (#2787). [Richard E George]
|
||||
|
||||
**** Fix little endian packed array pattern assignment (#2795). [Alex Torregrosa]
|
||||
|
||||
|
||||
* Verilator 4.108 2021-01-10
|
||||
|
||||
** Many VPI changes for IEEE compatibility, which may alter behavior from previous releases.
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ analyzer-include:
|
|||
-rm -rf examples/*/obj*
|
||||
scan-build $(MAKE) -k examples
|
||||
|
||||
format: clang-format yapf
|
||||
format: clang-format yapf format-pl-exec
|
||||
|
||||
CLANGFORMAT = clang-format
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
|
|
@ -479,6 +479,8 @@ YAPF_FLAGS = -i
|
|||
YAPF_FILES = \
|
||||
examples/xml_py/vl_file_copy \
|
||||
examples/xml_py/vl_hier_graph \
|
||||
src/astgen \
|
||||
src/bisonpre \
|
||||
src/config_rev \
|
||||
src/cppcheck_filtered \
|
||||
src/flexfix \
|
||||
|
|
@ -493,6 +495,10 @@ YAPF_FILES = \
|
|||
yapf:
|
||||
$(YAPF) $(YAPF_FLAGS) $(YAPF_FILES)
|
||||
|
||||
format-pl-exec:
|
||||
-chmod a+x test_regress/t/*.pl
|
||||
|
||||
|
||||
ftp: info
|
||||
|
||||
install-msg:
|
||||
|
|
|
|||
|
|
@ -455,11 +455,11 @@ ARGUMENTS"> for the detailed description of these arguments.
|
|||
+verilator+debug Enable debugging
|
||||
+verilator+debugi+<value> Enable debugging at a level
|
||||
+verilator+help Display help
|
||||
+verilator+prof+threads+file+I<filename> Set profile filename
|
||||
+verilator+prof+threads+start+I<value> Set profile starting point
|
||||
+verilator+prof+threads+window+I<value> Set profile duration
|
||||
+verilator+rand+reset+I<value> Set random reset technique
|
||||
+verilator+seed+I<value> Set random seed
|
||||
+verilator+prof+threads+file+<filename> Set profile filename
|
||||
+verilator+prof+threads+start+<value> Set profile starting point
|
||||
+verilator+prof+threads+window+<value> Set profile duration
|
||||
+verilator+rand+reset+<value> Set random reset technique
|
||||
+verilator+seed+<value> Set random seed
|
||||
+verilator+noassert Disable assert checking
|
||||
+verilator+V Verbose version and config
|
||||
+verilator+version Show version and exit
|
||||
|
|
@ -756,7 +756,7 @@ is fairly standard across Verilog tools while -D is similar to GCC.
|
|||
|
||||
Select the debug executable of Verilator (if available), and enable more
|
||||
internal assertions (equivalent to C<--debug-check>), debugging messages
|
||||
(equivalent to C<--debugi 4>), and intermediate form dump files (equivalent
|
||||
(equivalent to C<--debugi 3>), and intermediate form dump files (equivalent
|
||||
to C<--dump-treei 3>).
|
||||
|
||||
=item --debug-check
|
||||
|
|
@ -2546,6 +2546,27 @@ called from Verilog by querying the scope of that function. See the
|
|||
sections on DPI Context Functions and DPI Header Isolation below and the
|
||||
comments within the svdpi.h header for more information.
|
||||
|
||||
=head2 DPI Imports that access signals
|
||||
|
||||
If a DPI import accesses a signal through the VPI Verilator will not be
|
||||
able to know what variables are accessed and may schedule the code
|
||||
inappropriately. Ideally pass the values as inputs/outputs so the VPI is
|
||||
not required. Alternatively a workaround is to use a non-inlined task as a
|
||||
wrapper:
|
||||
|
||||
logic din;
|
||||
|
||||
// This DPI function will read "din"
|
||||
import "DPI-C" context function void dpi_that_accesses_din();
|
||||
|
||||
always @ (...)
|
||||
dpi_din_args(din);
|
||||
|
||||
task dpi_din_args(input din);
|
||||
/* verilator no_inline_task */
|
||||
dpi_that_accesses_din();
|
||||
endtask
|
||||
|
||||
=head2 DPI Display Functions
|
||||
|
||||
Verilator allows writing $display like functions using this syntax:
|
||||
|
|
@ -5229,7 +5250,7 @@ want all data to land in the same output file.
|
|||
topp->trace(tfp, 99); // Trace 99 levels of hierarchy
|
||||
tfp->open("obj_dir/t_trace_ena_cc/simx.vcd");
|
||||
...
|
||||
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
|
||||
while (vl_time_stamp64() < sim_time && !Verilated::gotFinish()) {
|
||||
main_time += #;
|
||||
tfp->dump(main_time);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
|||
stat bin/verilator_bin_dbg
|
||||
fi
|
||||
else
|
||||
nodist/code_coverage --stages 1-2
|
||||
nodist/code_coverage --stages 0-2
|
||||
fi
|
||||
elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
##############################################################################
|
||||
|
|
@ -97,34 +97,34 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
coverage-all)
|
||||
nodist/code_coverage --stages 3-
|
||||
nodist/code_coverage --stages 1-
|
||||
;;
|
||||
coverage-dist)
|
||||
nodist/code_coverage --stages 3- --scenarios=--dist
|
||||
nodist/code_coverage --stages 1- --scenarios=--dist
|
||||
;;
|
||||
coverage-vlt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=0/4
|
||||
;;
|
||||
coverage-vlt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=1/4
|
||||
;;
|
||||
coverage-vlt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=2/4
|
||||
;;
|
||||
coverage-vlt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vlt --hashset=3/4
|
||||
;;
|
||||
coverage-vltmt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=0/4
|
||||
;;
|
||||
coverage-vltmt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=1/4
|
||||
;;
|
||||
coverage-vltmt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=2/4
|
||||
;;
|
||||
coverage-vltmt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
|
||||
nodist/code_coverage --stages 1- --scenarios=--vltmt --hashset=3/4
|
||||
;;
|
||||
*)
|
||||
fatal "Unknown test: $TESTS"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.108 2021-01-10],
|
||||
AC_INIT([Verilator],[4.110 2021-02-25],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
|||
|
||||
Ahmed El-Mahmoudy
|
||||
Alex Chadwick
|
||||
Àlex Torregrosa
|
||||
Andreas Kuster
|
||||
Chris Randall
|
||||
Conor McCullough
|
||||
Dan Petrisko
|
||||
|
|
@ -49,6 +51,7 @@ Marshal Qiao
|
|||
Matthew Ballance
|
||||
Michael Killough
|
||||
Mike Popoloski
|
||||
Morten Borup Petersen
|
||||
Nandu Raj
|
||||
Nathan Kohagen
|
||||
Nathan Myers
|
||||
|
|
@ -57,12 +60,14 @@ Paul Wright
|
|||
Peter Horvath
|
||||
Peter Monsson
|
||||
Philipp Wagner
|
||||
Pierre-Henri Horrein
|
||||
Pieter Kapsenberg
|
||||
Piotr Binkowski
|
||||
Qingyao Sun
|
||||
Rafal Kapuscik
|
||||
Richard Myers
|
||||
Rupert Swarbrick
|
||||
Samuel Riedel
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
|
|
|
|||
|
|
@ -96,8 +96,6 @@
|
|||
Don't merge if any combining would form circ logic (out goes back to in)
|
||||
** Multiple assignments each bit can become single assign with concat
|
||||
Make sure a SEL of a CONCAT can get the single bit back.
|
||||
** Usually blocks/values
|
||||
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
||||
** Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||
** I-cache packing improvements (what/how?)
|
||||
** Data cache organization (order of vars in class)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ run:
|
|||
|
||||
@echo
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
cmake --build build -j
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ run:
|
|||
|
||||
@echo
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
cmake --build build -j
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ run:
|
|||
|
||||
@echo
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
cmake --build build -j
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ run:
|
|||
|
||||
@echo
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
cmake --build build -j
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ run:
|
|||
|
||||
@echo
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
cmake --build build -j
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
|
|
|||
|
|
@ -38,5 +38,5 @@ int main(int argc, char** argv, char** env) {
|
|||
delete top;
|
||||
|
||||
// Return good completion status
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,5 +71,6 @@ int main(int argc, char** argv, char** env) {
|
|||
top = nullptr;
|
||||
|
||||
// Return good completion status
|
||||
exit(0);
|
||||
// Don't use exit() or destructor won't get called
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,5 +102,6 @@ int main(int argc, char** argv, char** env) {
|
|||
#endif
|
||||
|
||||
// Return good completion status
|
||||
exit(0);
|
||||
// Don't use exit() or destructor won't get called
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <sstream>
|
||||
#include <sys/stat.h> // mkdir
|
||||
#include <list>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
// clang-format off
|
||||
|
|
@ -44,18 +45,12 @@
|
|||
constexpr unsigned VL_VALUE_STRING_MAX_WIDTH = 8192;
|
||||
|
||||
//===========================================================================
|
||||
// Static sanity checks (when get C++11 can use static_assert)
|
||||
// Static sanity checks
|
||||
|
||||
typedef union {
|
||||
// cppcheck-suppress unusedStructMember // Unused as is assertion
|
||||
char vluint8_incorrect[(sizeof(vluint8_t) == 1) ? 1 : -1];
|
||||
// cppcheck-suppress unusedStructMember // Unused as is assertion
|
||||
char vluint16_incorrect[(sizeof(vluint16_t) == 2) ? 1 : -1];
|
||||
// cppcheck-suppress unusedStructMember // Unused as is assertion
|
||||
char vluint32_incorrect[(sizeof(vluint32_t) == 4) ? 1 : -1];
|
||||
// cppcheck-suppress unusedStructMember // Unused as is assertion
|
||||
char vluint64_incorrect[(sizeof(vluint64_t) == 8) ? 1 : -1];
|
||||
} vl_static_checks_t;
|
||||
static_assert(sizeof(vluint8_t) == 1, "vluint8_t is missized");
|
||||
static_assert(sizeof(vluint16_t) == 2, "vluint8_t is missized");
|
||||
static_assert(sizeof(vluint32_t) == 4, "vluint8_t is missized");
|
||||
static_assert(sizeof(vluint64_t) == 8, "vluint8_t is missized");
|
||||
|
||||
//===========================================================================
|
||||
// Global variables
|
||||
|
|
@ -264,7 +259,6 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
|
|||
// Overall class init
|
||||
|
||||
Verilated::Serialized::Serialized() {
|
||||
s_debug = 0;
|
||||
s_calcUnusedSigs = false;
|
||||
s_gotFinish = false;
|
||||
s_assertOn = true;
|
||||
|
|
@ -327,19 +321,16 @@ vluint64_t vl_rand64() VL_MT_SAFE {
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
// VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
|
||||
// LCOV_EXCL_START
|
||||
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) {
|
||||
if (i < (VL_WORDS_I(obits) - 1)) {
|
||||
outwp[i] = vl_rand64();
|
||||
} else {
|
||||
outwp[i] = vl_rand64() & VL_MASK_E(obits);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = vl_rand64();
|
||||
outwp[VL_WORDS_I(obits) - 1] = vl_rand64() & VL_MASK_E(obits);
|
||||
return outwp;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
#endif
|
||||
|
||||
IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE {
|
||||
Verilated::randSeed(static_cast<int>(seed));
|
||||
|
|
@ -365,13 +356,8 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
|||
return data;
|
||||
}
|
||||
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) {
|
||||
if (i < (VL_WORDS_I(obits) - 1)) {
|
||||
outwp[i] = VL_RAND_RESET_I(32);
|
||||
} else {
|
||||
outwp[i] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32);
|
||||
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
||||
return outwp;
|
||||
}
|
||||
|
||||
|
|
@ -1342,8 +1328,6 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
|
|||
VerilatedImp::fdClose(fdi);
|
||||
}
|
||||
|
||||
void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); }
|
||||
|
||||
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE {
|
||||
static VL_THREAD_LOCAL std::string t_output; // static only for speed
|
||||
t_output = "";
|
||||
|
|
@ -1511,19 +1495,19 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
|
|||
IData entry = read_elements + start - array_lsb;
|
||||
if (width <= 8) {
|
||||
CData* datap = &(reinterpret_cast<CData*>(memp))[entry];
|
||||
if (shift == start_shift) { *datap = 0; }
|
||||
if (shift == start_shift) *datap = 0;
|
||||
*datap |= (c << shift) & VL_MASK_I(width);
|
||||
} else if (width <= 16) {
|
||||
SData* datap = &(reinterpret_cast<SData*>(memp))[entry];
|
||||
if (shift == start_shift) { *datap = 0; }
|
||||
if (shift == start_shift) *datap = 0;
|
||||
*datap |= (c << shift) & VL_MASK_I(width);
|
||||
} else if (width <= VL_IDATASIZE) {
|
||||
IData* datap = &(reinterpret_cast<IData*>(memp))[entry];
|
||||
if (shift == start_shift) { *datap = 0; }
|
||||
if (shift == start_shift) *datap = 0;
|
||||
*datap |= (c << shift) & VL_MASK_I(width);
|
||||
} else if (width <= VL_QUADSIZE) {
|
||||
QData* datap = &(reinterpret_cast<QData*>(memp))[entry];
|
||||
if (shift == start_shift) { *datap = 0; }
|
||||
if (shift == start_shift) *datap = 0;
|
||||
*datap |= ((static_cast<QData>(c) << static_cast<QData>(shift)) & VL_MASK_Q(width));
|
||||
} else {
|
||||
WDataOutP datap = &(reinterpret_cast<WDataOutP>(memp))[entry * VL_WORDS_I(width)];
|
||||
|
|
@ -1910,19 +1894,19 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
|||
int value = (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
|
||||
if (m_bits <= 8) {
|
||||
CData* datap = reinterpret_cast<CData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
if (!innum) *datap = 0;
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
|
||||
} else if (m_bits <= 16) {
|
||||
SData* datap = reinterpret_cast<SData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
if (!innum) *datap = 0;
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
|
||||
} else if (m_bits <= VL_IDATASIZE) {
|
||||
IData* datap = reinterpret_cast<IData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
if (!innum) *datap = 0;
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(m_bits);
|
||||
} else if (m_bits <= VL_QUADSIZE) {
|
||||
QData* datap = reinterpret_cast<QData*>(valuep);
|
||||
if (!innum) { *datap = 0; }
|
||||
if (!innum) *datap = 0;
|
||||
*datap = ((*datap << static_cast<QData>(shift)) + static_cast<QData>(value))
|
||||
& VL_MASK_Q(m_bits);
|
||||
} else {
|
||||
|
|
@ -2122,7 +2106,7 @@ void VL_WRITEMEM_N(bool hex, // Hex format, else binary
|
|||
|
||||
// Helper function for conversion of timescale strings
|
||||
// Converts (1|10|100)(s|ms|us|ns|ps|fs) to power of then
|
||||
int VL_TIME_STR_CONVERT(const char* strp) {
|
||||
int VL_TIME_STR_CONVERT(const char* strp) VL_PURE {
|
||||
int scale = 0;
|
||||
if (!strp) return 0;
|
||||
if (*strp++ != '1') return 0;
|
||||
|
|
@ -2143,14 +2127,14 @@ int VL_TIME_STR_CONVERT(const char* strp) {
|
|||
if (*strp) return 0;
|
||||
return scale;
|
||||
}
|
||||
static const char* vl_time_str(int scale) {
|
||||
static const char* vl_time_str(int scale) VL_PURE {
|
||||
static const char* const names[]
|
||||
= {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us",
|
||||
"100ns", "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"};
|
||||
if (VL_UNLIKELY(scale > 2 || scale < -15)) scale = 0;
|
||||
return names[2 - scale];
|
||||
}
|
||||
double vl_time_multiplier(int scale) {
|
||||
double vl_time_multiplier(int scale) VL_PURE {
|
||||
// Return timescale multipler -18 to +18
|
||||
// For speed, this does not check for illegal values
|
||||
if (scale < 0) {
|
||||
|
|
@ -2217,7 +2201,7 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
|
|||
|
||||
void Verilated::debug(int level) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_mutex);
|
||||
s_s.s_debug = level;
|
||||
s_ns.s_debug = level;
|
||||
if (level) {
|
||||
#ifdef VL_DEBUG
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- Verilated::debug is on."
|
||||
|
|
@ -2473,7 +2457,11 @@ void Verilated::endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAF
|
|||
VerilatedThreadMsgQueue::flush(evalMsgQp);
|
||||
}
|
||||
|
||||
void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
void Verilated::endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
// It doesn't work to set endOfEvalReqd on the threadpool thread
|
||||
// and then check it on the eval thread since it's thread local.
|
||||
// It should be ok to call into endOfEvalGuts, it returns immediately
|
||||
// if there are no transactions.
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("End-of-eval cleanup\n"););
|
||||
evalMsgQp->process();
|
||||
}
|
||||
|
|
@ -2483,12 +2471,12 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
|||
// VerilatedImp:: Constructors
|
||||
|
||||
// verilated.o may exist both in protect-lib and main module.
|
||||
// Both the main module and the protec-lib refer the same instance of
|
||||
// Both the main module and the protect-lib refer the same instance of
|
||||
// static variables such as Verilated or VerilatedImplData.
|
||||
// This is important to share the state such as Verilated::gotFinish.
|
||||
// But the sharing may cause double-free error when shutting down because destructors
|
||||
// are called twice.
|
||||
// 1st time:From protec-lib shared object on the way of unloading after exitting main()
|
||||
// 1st time:From protect-lib shared object on the way of unloading after exiting main()
|
||||
// 2nd time:From main executable.
|
||||
//
|
||||
// To avoid the trouble, all member variables are enclosed in VerilatedImpU union.
|
||||
|
|
@ -2695,7 +2683,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
|
|||
if (!finalize) {
|
||||
// Need two passes so we know array size to create
|
||||
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
||||
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum + 1; }
|
||||
if (funcnum >= m_funcnumMax) m_funcnumMax = funcnum + 1;
|
||||
} else {
|
||||
if (VL_UNCOVERABLE(funcnum >= m_funcnumMax)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", // LCOV_EXCL_LINE
|
||||
|
|
|
|||
|
|
@ -265,24 +265,12 @@ public:
|
|||
#define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits
|
||||
#define VL_OUTW(name, msb, lsb, words) WData name[words] ///< Declare output signal, 65+ bits
|
||||
|
||||
#define VL_PIN_NOP(instname, pin, port) ///< Connect a pin, ala SP_PIN
|
||||
#define VL_CELL(instname, type) ///< Declare a cell, ala SP_CELL
|
||||
|
||||
/// Declare a module, ala SC_MODULE
|
||||
#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule
|
||||
// Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical)
|
||||
|
||||
/// Constructor, ala SC_CTOR
|
||||
#define VL_CTOR(modname) modname(const char* __VCname = "")
|
||||
|
||||
/// Constructor declaration for C++, ala SP_CTOR_IMPL
|
||||
#define VL_CTOR_IMP(modname) \
|
||||
modname::modname(const char* __VCname) \
|
||||
: VerilatedModule(__VCname)
|
||||
|
||||
/// Constructor declaration for SystemC, ala SP_CTOR_IMPL
|
||||
#define VL_SC_CTOR_IMP(modname) modname::modname(sc_module_name)
|
||||
|
||||
//=========================================================================
|
||||
// Functions overridable by user defines
|
||||
// (Internals however must use VL_PRINTF_MT, which calls these.)
|
||||
|
|
@ -376,7 +364,6 @@ class Verilated final {
|
|||
|
||||
static struct Serialized { // All these members serialized/deserialized
|
||||
// Fast path
|
||||
int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||
bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||
bool s_gotFinish; ///< A $finish statement executed
|
||||
bool s_assertOn; ///< Assertions are enabled
|
||||
|
|
@ -396,6 +383,7 @@ class Verilated final {
|
|||
static struct NonSerialized { // Non-serialized information
|
||||
// These are reloaded from on command-line settings, so do not need to persist
|
||||
// Fast path
|
||||
int s_debug = 0; ///< See accessors... only when VL_DEBUG set
|
||||
vluint64_t s_profThreadsStart = 1; ///< +prof+threads starting time
|
||||
vluint32_t s_profThreadsWindow = 2; ///< +prof+threads window size
|
||||
// Slow path
|
||||
|
|
@ -438,6 +426,18 @@ private:
|
|||
public:
|
||||
// METHODS - User called
|
||||
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
#ifdef VL_DEBUG
|
||||
/// Return debug level
|
||||
/// When multithreaded this may not immediately react to another thread
|
||||
/// changing the level (no mutex)
|
||||
static inline int debug() VL_MT_SAFE { return s_ns.s_debug; }
|
||||
#else
|
||||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||
static constexpr int debug() VL_PURE { return 0; }
|
||||
#endif
|
||||
|
||||
/// Select initial value of otherwise uninitialized signals.
|
||||
////
|
||||
/// 0 = Set to zeros
|
||||
|
|
@ -451,17 +451,6 @@ public:
|
|||
/// Random seed extended to 64 bits, and defaulted if user seed==0
|
||||
static vluint64_t randSeedDefault64() VL_MT_SAFE;
|
||||
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
#ifdef VL_DEBUG
|
||||
/// Return debug level
|
||||
/// When multithreaded this may not immediately react to another thread
|
||||
/// changing the level (no mutex)
|
||||
static inline int debug() VL_MT_SAFE { return s_s.s_debug; }
|
||||
#else
|
||||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||
static constexpr int debug() VL_PURE { return 0; }
|
||||
#endif
|
||||
/// Enable calculation of unused signals
|
||||
static void calcUnusedSigs(bool flag) VL_MT_SAFE;
|
||||
static bool calcUnusedSigs() VL_MT_SAFE { ///< Return calcUnusedSigs value
|
||||
|
|
@ -479,7 +468,7 @@ public:
|
|||
static bool gotFinish() VL_MT_SAFE { return s_s.s_gotFinish; } ///< Return if got a $finish
|
||||
/// Allow traces to at some point be enabled (disables some optimizations)
|
||||
static void traceEverOn(bool flag) VL_MT_SAFE {
|
||||
if (flag) { calcUnusedSigs(flag); }
|
||||
if (flag) calcUnusedSigs(flag);
|
||||
}
|
||||
/// Enable/disable assertions
|
||||
static void assertOn(bool flag) VL_MT_SAFE;
|
||||
|
|
@ -507,7 +496,9 @@ public:
|
|||
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void runFlushCallbacks() VL_MT_SAFE;
|
||||
#ifndef VL_NO_LEGACY
|
||||
static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated
|
||||
#endif
|
||||
/// Callbacks to run prior to termination
|
||||
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
|
||||
|
|
@ -575,35 +566,29 @@ public:
|
|||
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
|
||||
static int exportFuncNum(const char* namep) VL_MT_SAFE;
|
||||
|
||||
// Internal: Serialization setup
|
||||
static constexpr size_t serialized1Size() VL_PURE { return sizeof(s_s); }
|
||||
static constexpr void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // For Serialize only
|
||||
static size_t serialized2Size() VL_PURE;
|
||||
static void* serialized2Ptr() VL_MT_UNSAFE;
|
||||
#ifdef VL_THREADED
|
||||
/// Set the mtaskId, called when an mtask starts
|
||||
/// Internal: Set the mtaskId, called when an mtask starts
|
||||
static void mtaskId(vluint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
|
||||
static vluint32_t mtaskId() VL_MT_SAFE { return t_s.t_mtaskId; }
|
||||
static void endOfEvalReqdInc() VL_MT_SAFE { ++t_s.t_endOfEvalReqd; }
|
||||
static void endOfEvalReqdDec() VL_MT_SAFE { --t_s.t_endOfEvalReqd; }
|
||||
|
||||
/// Called at end of each thread mtask, before finishing eval
|
||||
/// Internal: Called at end of each thread mtask, before finishing eval
|
||||
static void endOfThreadMTask(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) { endOfThreadMTaskGuts(evalMsgQp); }
|
||||
}
|
||||
/// Called at end of eval loop
|
||||
static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
// It doesn't work to set endOfEvalReqd on the threadpool thread
|
||||
// and then check it on the eval thread since it's thread local.
|
||||
// It should be ok to call into endOfEvalGuts, it returns immediately
|
||||
// if there are no transactions.
|
||||
endOfEvalGuts(evalMsgQp);
|
||||
if (VL_UNLIKELY(t_s.t_endOfEvalReqd)) endOfThreadMTaskGuts(evalMsgQp);
|
||||
}
|
||||
/// Internal: Called at end of eval loop
|
||||
static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef VL_THREADED
|
||||
static void endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
static void endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -655,7 +640,9 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
|||
extern vluint64_t vl_rand64() VL_MT_SAFE;
|
||||
inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
|
||||
inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
|
||||
#ifndef VL_NO_LEGACY
|
||||
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signal
|
||||
#endif
|
||||
extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE;
|
||||
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
|
||||
vluint64_t rnd = vl_rand64();
|
||||
|
|
@ -867,7 +854,6 @@ inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_sta
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#define VL_TIME_I() (static_cast<IData>(vl_time_stamp64()))
|
||||
#define VL_TIME_Q() (static_cast<QData>(vl_time_stamp64()))
|
||||
#define VL_TIME_D() (static_cast<double>(vl_time_stamp64()))
|
||||
|
||||
|
|
@ -876,8 +862,9 @@ inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_sta
|
|||
// Can't use multiply in Q flavor, as might lose precision
|
||||
#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast<QData>(scale))
|
||||
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast<double>(scale))
|
||||
|
||||
/// Time imported from units to time precision
|
||||
double vl_time_multiplier(int scale);
|
||||
double vl_time_multiplier(int scale) VL_PURE;
|
||||
|
||||
/// Evaluate expression if debug enabled
|
||||
#ifdef VL_DEBUG
|
||||
|
|
@ -890,10 +877,6 @@ double vl_time_multiplier(int scale);
|
|||
# define VL_DEBUG_IF(text) do {} while (false)
|
||||
#endif
|
||||
|
||||
/// Collect coverage analysis for this line
|
||||
#ifndef SP_AUTO_COVER3
|
||||
# define SP_AUTO_COVER3(what,file,line)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
//=========================================================================
|
||||
|
|
@ -1268,7 +1251,7 @@ static inline IData VL_COUNTBITS_W(int lbits, int words, WDataInP lwp, IData ctr
|
|||
EData r = 0;
|
||||
IData wordLbits = 32;
|
||||
for (int i = 0; i < words; ++i) {
|
||||
if (i == words - 1) { wordLbits = lbits % 32; }
|
||||
if (i == words - 1) wordLbits = lbits % 32;
|
||||
r += VL_COUNTBITS_E(wordLbits, lwp[i], ctrl0, ctrl1, ctrl2);
|
||||
}
|
||||
return r;
|
||||
|
|
@ -1341,7 +1324,7 @@ static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) VL_MT_SAFE {
|
|||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
|
||||
for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) {
|
||||
if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) { return i * VL_EDATASIZE + bit + 1; }
|
||||
if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) return i * VL_EDATASIZE + bit + 1;
|
||||
}
|
||||
// Can't get here - one bit must be set
|
||||
}
|
||||
|
|
@ -1638,8 +1621,8 @@ static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp, WDataInP lwp,
|
|||
WData rwstore[VL_MULS_MAX_WORDS];
|
||||
WDataInP ltup = lwp;
|
||||
WDataInP rtup = rwp;
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
|
||||
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if (lsign) ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp));
|
||||
if (rsign) rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp));
|
||||
if ((lsign && !rsign) || (!lsign && rsign)) {
|
||||
WData qNoSign[VL_MULS_MAX_WORDS];
|
||||
VL_DIV_WWW(lbits, qNoSign, ltup, rtup);
|
||||
|
|
@ -1660,8 +1643,8 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp, WDataInP lwp,
|
|||
WData rwstore[VL_MULS_MAX_WORDS];
|
||||
WDataInP ltup = lwp;
|
||||
WDataInP rtup = rwp;
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
|
||||
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if (lsign) ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp));
|
||||
if (rsign) rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp));
|
||||
if (lsign) { // Only dividend sign matters for modulus
|
||||
WData qNoSign[VL_MULS_MAX_WORDS];
|
||||
VL_MODDIV_WWW(lbits, qNoSign, ltup, rtup);
|
||||
|
|
@ -2145,6 +2128,12 @@ static inline WDataOutP VL_SHIFTL_WWW(int obits, int lbits, int rbits, WDataOutP
|
|||
}
|
||||
return VL_SHIFTL_WWI(obits, lbits, 32, owp, lwp, rwp[0]);
|
||||
}
|
||||
static inline WDataOutP VL_SHIFTL_WWQ(int obits, int lbits, int rbits, WDataOutP owp, WDataInP lwp,
|
||||
QData rd) VL_MT_SAFE {
|
||||
WData rwp[VL_WQ_WORDS_E];
|
||||
VL_SET_WQ(rwp, rd);
|
||||
return VL_SHIFTL_WWW(obits, lbits, rbits, owp, lwp, rwp);
|
||||
}
|
||||
static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
|
|
@ -2153,6 +2142,11 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, WDataInP
|
|||
}
|
||||
return VL_CLEAN_II(obits, obits, lhs << rwp[0]);
|
||||
}
|
||||
static inline IData VL_SHIFTL_IIQ(int obits, int lbits, int rbits, IData lhs,
|
||||
QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return VL_CLEAN_II(obits, obits, lhs << rhs);
|
||||
}
|
||||
static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE {
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) {
|
||||
if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more
|
||||
|
|
@ -2162,6 +2156,11 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP
|
|||
// Above checks rwp[1]==0 so not needed in below shift
|
||||
return VL_CLEAN_QQ(obits, obits, lhs << (static_cast<QData>(rwp[0])));
|
||||
}
|
||||
static inline QData VL_SHIFTL_QQQ(int obits, int lbits, int rbits, QData lhs,
|
||||
QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs << rhs);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_SHIFTR: oclean=lclean; rclean==clean;
|
||||
// Important: Unlike most other funcs, the shift might well be a computed
|
||||
|
|
@ -2223,6 +2222,14 @@ static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs, WDataInP
|
|||
// Above checks rwp[1]==0 so not needed in below shift
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast<QData>(rwp[0])));
|
||||
}
|
||||
static inline IData VL_SHIFTR_IIQ(int obits, int, int rbits, IData lhs, QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
|
||||
}
|
||||
static inline QData VL_SHIFTR_QQQ(int obits, int, int rbits, QData lhs, QData rhs) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0;
|
||||
return VL_CLEAN_QQ(obits, obits, lhs >> rhs);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean;
|
||||
static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) VL_PURE {
|
||||
|
|
@ -2277,7 +2284,7 @@ static inline WDataOutP VL_SHIFTRS_WWW(int obits, int lbits, int rbits, WDataOut
|
|||
WDataInP lwp, WDataInP rwp) VL_MT_SAFE {
|
||||
EData overshift = 0; // Huge shift 1>>32 or more
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i];
|
||||
if (VL_UNLIKELY(overshift)) {
|
||||
if (VL_UNLIKELY(overshift || rwp[0] >= obits)) {
|
||||
int lmsw = VL_WORDS_I(obits) - 1;
|
||||
EData sign = VL_SIGNONES_E(lbits, lwp[lmsw]);
|
||||
for (int j = 0; j <= lmsw; ++j) owp[j] = sign;
|
||||
|
|
@ -2296,7 +2303,7 @@ static inline IData VL_SHIFTRS_IIW(int obits, int lbits, int rbits, IData lhs,
|
|||
WDataInP rwp) VL_MT_SAFE {
|
||||
EData overshift = 0; // Huge shift 1>>32 or more
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i];
|
||||
if (VL_UNLIKELY(overshift)) {
|
||||
if (VL_UNLIKELY(overshift || rwp[0] >= obits)) {
|
||||
IData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative
|
||||
return VL_CLEAN_II(obits, obits, sign);
|
||||
}
|
||||
|
|
@ -2306,13 +2313,14 @@ static inline QData VL_SHIFTRS_QQW(int obits, int lbits, int rbits, QData lhs,
|
|||
WDataInP rwp) VL_MT_SAFE {
|
||||
EData overshift = 0; // Huge shift 1>>32 or more
|
||||
for (int i = 1; i < VL_WORDS_I(rbits); ++i) overshift |= rwp[i];
|
||||
if (VL_UNLIKELY(overshift)) {
|
||||
if (VL_UNLIKELY(overshift || rwp[0] >= obits)) {
|
||||
QData sign = -(lhs >> (lbits - 1)); // ffff_ffff if negative
|
||||
return VL_CLEAN_QQ(obits, obits, sign);
|
||||
}
|
||||
return VL_SHIFTRS_QQI(obits, lbits, 32, lhs, rwp[0]);
|
||||
}
|
||||
static inline IData VL_SHIFTRS_IIQ(int obits, int lbits, int rbits, IData lhs, QData rhs) VL_PURE {
|
||||
static inline IData VL_SHIFTRS_IIQ(int obits, int lbits, int rbits, IData lhs,
|
||||
QData rhs) VL_MT_SAFE {
|
||||
WData rwp[VL_WQ_WORDS_E];
|
||||
VL_SET_WQ(rwp, rhs);
|
||||
return VL_SHIFTRS_IIW(obits, lbits, rbits, lhs, rwp);
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ public:
|
|||
// Keys -> strings
|
||||
std::string keys[MAX_KEYS];
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
if (ckeyps[i] && ckeyps[i][0]) { keys[i] = ckeyps[i]; }
|
||||
if (ckeyps[i] && ckeyps[i][0]) keys[i] = ckeyps[i];
|
||||
}
|
||||
// Ignore empty keys
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
|||
m_code2symbol.clear();
|
||||
|
||||
// Allocate string buffer for arrays
|
||||
if (!m_strbuf) { m_strbuf = new char[maxBits() + 32]; }
|
||||
if (!m_strbuf) m_strbuf = new char[maxBits() + 32];
|
||||
}
|
||||
|
||||
void VerilatedFst::close() {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ protected:
|
|||
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex);
|
||||
|
||||
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
|
||||
/// Map the represents scope hierarchy
|
||||
/// Map that represents scope hierarchy
|
||||
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex);
|
||||
|
||||
// Slow - somewhat static:
|
||||
|
|
@ -417,7 +417,7 @@ public: // But only for verilated*.cpp
|
|||
const VerilatedLockGuard lock(s_s.v.m_hierMapMutex);
|
||||
VerilatedHierarchyMap& map = s_s.v.m_hierMap;
|
||||
if (map.find(fromp) == map.end()) return;
|
||||
VerilatedScopeVector& scopes = map[fromp];
|
||||
auto& scopes = map[fromp];
|
||||
const auto it = find(scopes.begin(), scopes.end(), top);
|
||||
if (it != scopes.end()) scopes.erase(it);
|
||||
}
|
||||
|
|
@ -595,7 +595,7 @@ private:
|
|||
}
|
||||
} else {
|
||||
// MCD Case
|
||||
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
|
||||
for (size_t i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
|
||||
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.v.m_fdps[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct VerilatedCStrCmp {
|
|||
};
|
||||
|
||||
/// Map of sorted scope names to find associated scope class
|
||||
// This is a class instead of typedef/using to allow forward declaration in verilated.h
|
||||
class VerilatedScopeNameMap final
|
||||
: public std::map<const char*, const VerilatedScope*, VerilatedCStrCmp> {
|
||||
public:
|
||||
|
|
@ -51,16 +52,17 @@ public:
|
|||
};
|
||||
|
||||
/// Map of sorted variable names to find associated variable class
|
||||
// This is a class instead of typedef/using to allow forward declaration in verilated.h
|
||||
class VerilatedVarNameMap final : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||
public:
|
||||
VerilatedVarNameMap() = default;
|
||||
~VerilatedVarNameMap() = default;
|
||||
};
|
||||
|
||||
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
|
||||
|
||||
/// Map of parent scope to vector of children scopes
|
||||
// This is a class instead of typedef/using to allow forward declaration in verilated.h
|
||||
class VerilatedHierarchyMap final
|
||||
: public std::unordered_map<const VerilatedScope*, VerilatedScopeVector> {
|
||||
: public std::unordered_map<const VerilatedScope*, std::vector<const VerilatedScope*>> {
|
||||
public:
|
||||
VerilatedHierarchyMap() = default;
|
||||
~VerilatedHierarchyMap() = default;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public:
|
|||
// Non blocking get
|
||||
bool tryGet(T& result) {
|
||||
const VerilatedLockGuard lockGuard(m_mutex);
|
||||
if (m_queue.empty()) { return false; }
|
||||
if (m_queue.empty()) return false;
|
||||
result = m_queue.front();
|
||||
m_queue.pop_front();
|
||||
return true;
|
||||
|
|
@ -222,7 +222,7 @@ protected:
|
|||
void declCode(vluint32_t code, vluint32_t bits, bool tri);
|
||||
|
||||
/// Is this an escape?
|
||||
bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
||||
bool isScopeEscape(char c) { return c != '\f' && (isspace(c) || c == m_scopeEscape); }
|
||||
/// Character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||
char scopeEscape() { return m_scopeEscape; }
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,9 @@ void VerilatedVcd::openNext(bool incFilename) {
|
|||
name[pos - 2] = '0';
|
||||
if ((++(name[pos - 3])) > '9') {
|
||||
name[pos - 3] = '0';
|
||||
if ((++(name[pos - 4])) > '9') { name[pos - 4] = '0'; }
|
||||
if ((++(name[pos - 4])) > '9') { //
|
||||
name[pos - 4] = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -164,7 +166,7 @@ void VerilatedVcd::openNext(bool incFilename) {
|
|||
}
|
||||
|
||||
bool VerilatedVcd::preChangeDump() {
|
||||
if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > m_rolloverMB)) { openNext(true); }
|
||||
if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > m_rolloverMB)) openNext(true);
|
||||
return isOpen();
|
||||
}
|
||||
|
||||
|
|
@ -401,13 +403,22 @@ void VerilatedVcd::dumpHeader() {
|
|||
if (*np == ' ') np++;
|
||||
if (*np == '\t') break; // tab means signal name starts
|
||||
printIndent(1);
|
||||
printStr("$scope module ");
|
||||
// Find character after name end
|
||||
const char* sp = np;
|
||||
while (*sp && *sp != ' ' && *sp != '\t' && *sp != '\f') sp++;
|
||||
|
||||
if (*sp == '\f') {
|
||||
printStr("$scope struct ");
|
||||
} else {
|
||||
printStr("$scope module ");
|
||||
}
|
||||
|
||||
for (; *np && *np != ' ' && *np != '\t'; np++) {
|
||||
if (*np == '[') {
|
||||
printStr("(");
|
||||
} else if (*np == ']') {
|
||||
printStr(")");
|
||||
} else {
|
||||
} else if (*np != '\f') {
|
||||
*m_writep++ = *np;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ private:
|
|||
inline void bufferCheck() {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_writep > m_wrFlushp)) { bufferFlush(); }
|
||||
if (VL_UNLIKELY(m_writep > m_wrFlushp)) bufferFlush();
|
||||
}
|
||||
void closePrev();
|
||||
void closeErr();
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public:
|
|||
// METHODS
|
||||
/// Called by SystemC simulate()
|
||||
virtual void cycle(bool delta_cycle) {
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -742,7 +742,7 @@ PLI_INT32 VerilatedVpioReasonCb::dovpi_remove_cb() {
|
|||
|
||||
VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE {
|
||||
VerilatedVpiImp::assertOneCheck();
|
||||
if (VL_UNLIKELY(!s_s.m_errorInfop)) { s_s.m_errorInfop = new VerilatedVpiError(); }
|
||||
if (VL_UNLIKELY(!s_s.m_errorInfop)) s_s.m_errorInfop = new VerilatedVpiError();
|
||||
return s_s.m_errorInfop;
|
||||
}
|
||||
|
||||
|
|
@ -1235,7 +1235,7 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
|||
if (scopename.find('.') == std::string::npos) {
|
||||
// This is a toplevel, hence search in our TOP ports first.
|
||||
scopep = Verilated::scopeFind("TOP");
|
||||
if (scopep) { varp = scopep->varFind(baseNamep); }
|
||||
if (scopep) varp = scopep->varFind(baseNamep);
|
||||
}
|
||||
if (!varp) {
|
||||
scopep = Verilated::scopeFind(scopename.c_str());
|
||||
|
|
@ -2112,10 +2112,12 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
|
|||
return _error_info_p->level; // return error severity level
|
||||
}
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
PLI_INT32 vpi_free_object(vpiHandle object) {
|
||||
// vpi_free_object is IEEE deprecated, use vpi_release_handle
|
||||
return vpi_release_handle(object);
|
||||
}
|
||||
#endif
|
||||
|
||||
PLI_INT32 vpi_release_handle(vpiHandle object) {
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_release_handle %p\n", object););
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1)))
|
||||
# define VL_ATTR_PURE __attribute__((pure))
|
||||
# define VL_ATTR_UNUSED __attribute__((unused))
|
||||
# define VL_ATTR_WEAK __attribute__((weak))
|
||||
# define VL_FUNC __func__
|
||||
# if defined(__clang__) && defined(VL_THREADED)
|
||||
# define VL_ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__)))
|
||||
|
|
@ -87,6 +88,9 @@
|
|||
#ifndef VL_ATTR_UNUSED
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
#endif
|
||||
#ifndef VL_ATTR_WEAK
|
||||
# define VL_ATTR_WEAK ///< Function external that is optionally defined
|
||||
#endif
|
||||
#ifndef VL_FUNC
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
#endif
|
||||
|
|
@ -133,8 +137,10 @@
|
|||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||
#endif
|
||||
|
||||
#define VL_THREAD ///< Deprecated
|
||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
#ifndef VL_NO_LEGACY
|
||||
# define VL_THREAD ///< Deprecated
|
||||
# define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
#endif
|
||||
|
||||
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||
|
|
@ -144,7 +150,9 @@
|
|||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
||||
///< protected to make sure single-caller
|
||||
|
||||
#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
|
||||
#ifndef VL_NO_LEGACY
|
||||
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
|
||||
#endif
|
||||
|
||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
|
@ -184,16 +192,18 @@
|
|||
// C++-2011
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK)
|
||||
# ifndef VL_NO_LEGACY
|
||||
// These are deprecated historical defines. We leave them in case users referenced them.
|
||||
# define VL_EQ_DELETE = delete
|
||||
# define vl_unique_ptr std::unique_ptr
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# define VL_FINAL final
|
||||
# define VL_MUTABLE mutable
|
||||
# define VL_OVERRIDE override
|
||||
# define VL_EQ_DELETE = delete
|
||||
# define vl_unique_ptr std::unique_ptr
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# define VL_FINAL final
|
||||
# define VL_MUTABLE mutable
|
||||
# define VL_OVERRIDE override
|
||||
# endif
|
||||
#else
|
||||
# error "Verilator requires a C++11 or newer compiler"
|
||||
#endif
|
||||
|
|
@ -358,12 +368,15 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
||||
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
||||
#define VL_IDATASIZE 32 ///< Bits in a IData / word
|
||||
#define VL_WORDSIZE VL_IDATASIZE ///< Legacy define
|
||||
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
||||
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
|
||||
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
|
||||
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
# define VL_WORDSIZE VL_IDATASIZE ///< Legacy define
|
||||
#endif
|
||||
|
||||
/// Bytes this number of bits needs (1 bit=1 byte)
|
||||
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
|
||||
/// Words/EDatas this number of bits needs (1 bit=1 word)
|
||||
|
|
|
|||
|
|
@ -26,10 +26,15 @@ def test():
|
|||
sys.exit("%Error: Run code_coverage from the top of the verilator kit")
|
||||
exec(open("./nodist/code_coverage.dat").read())
|
||||
|
||||
if Args.stage_enabled[0]:
|
||||
ci_fold_start("distclean")
|
||||
print("Stage 0: distclean")
|
||||
run("make distclean || true")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[1]:
|
||||
ci_fold_start("configure")
|
||||
print("Stage 1: configure (coverage on)")
|
||||
run("make distclean || true")
|
||||
run("autoconf")
|
||||
# Exceptions can pollute the branch coverage data
|
||||
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'"
|
||||
|
|
@ -87,8 +92,8 @@ def test():
|
|||
if re.search(regexp, dat):
|
||||
# Remove .gcda/.gcno for files we don't care about before we slowly
|
||||
# read them
|
||||
os.unlink(dat)
|
||||
os.unlink(gcno)
|
||||
unlink_ok(dat)
|
||||
unlink_ok(gcno)
|
||||
del dats[dat]
|
||||
break
|
||||
|
||||
|
|
@ -305,18 +310,24 @@ def source_globs(*dirs):
|
|||
def run(command):
|
||||
# run a system command, check errors
|
||||
print("\t%s" % command)
|
||||
os.system(command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status < 0:
|
||||
raise Exception("%Error: Command failed " + command + ", stopped")
|
||||
|
||||
|
||||
def unlink_ok(filename):
|
||||
try:
|
||||
os.unlink(filename)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def ci_fold_start(action):
|
||||
print("::group::" + action)
|
||||
print("::group::" + action, flush=True)
|
||||
|
||||
|
||||
def ci_fold_end():
|
||||
print("::endgroup::\n")
|
||||
print("::endgroup::\n", flush=True)
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
|
@ -387,7 +398,7 @@ if True:
|
|||
start = int(match_from.group(1))
|
||||
else:
|
||||
os.exit("%Error: --stages not understood: " + Args.stages)
|
||||
for n in range(1, 100):
|
||||
for n in range(0, 100):
|
||||
Args.stage_enabled[n] = False
|
||||
for n in range(start, end + 1):
|
||||
Args.stage_enabled[n] = True
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ V3Number_test: V3Number_test.o
|
|||
#### Modules
|
||||
|
||||
%__gen.cpp: %.cpp $(ASTGEN) V3Ast.h V3AstNodes.h
|
||||
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
||||
$(PYTHON3) $(ASTGEN) -I $(srcdir) $*.cpp
|
||||
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
|
|
@ -315,18 +315,18 @@ serial:: V3Ast__gen_classes.h V3ParseBison.c
|
|||
serial_vlcov:: vlcovgen.d
|
||||
|
||||
vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h
|
||||
$(PERL) $(VLCOVGEN) --srcdir $(srcdir)
|
||||
$(PYTHON3) $(VLCOVGEN) --srcdir $(srcdir)
|
||||
touch $@
|
||||
|
||||
V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h
|
||||
$(PERL) $(ASTGEN) -I$(srcdir) --classes
|
||||
$(PYTHON3) $(ASTGEN) -I $(srcdir) --classes
|
||||
|
||||
V3ParseBison.h: V3ParseBison.c
|
||||
|
||||
# Have only one output file in this rule to prevent parallel make issues
|
||||
V3ParseBison.c: verilog.y $(BISONPRE)
|
||||
@echo "If you get errors from verilog.y below, try upgrading bison to version 1.875 or newer."
|
||||
$(PERL) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $<
|
||||
$(PYTHON3) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $<
|
||||
|
||||
V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
||||
${LEX} --version
|
||||
|
|
@ -340,7 +340,7 @@ V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
|||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX)
|
||||
$(PERL) $(FLEXFIX) V3PreLex <$< >$@
|
||||
$(PYTHON3) $(FLEXFIX) V3PreLex <$< >$@
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ public:
|
|||
for (const auto& vrp : m_outputs) {
|
||||
LatchDetectGraphVertex* vertp = castVertexp(vrp->varp()->user1p());
|
||||
vertp->user(true); // Identify the output vertex we are checking paths _to_
|
||||
if (!latchCheckInternal(castVertexp(verticesBeginp()))) { latch_detected = true; }
|
||||
if (!latchCheckInternal(castVertexp(verticesBeginp()))) latch_detected = true;
|
||||
if (latch_detected && !latch_expected) {
|
||||
nodep->v3warn(
|
||||
LATCH,
|
||||
|
|
@ -185,7 +185,7 @@ public:
|
|||
<< " (not all control paths of combinational always assign a value)\n"
|
||||
<< nodep->warnMore()
|
||||
<< "... Suggest use of always_latch for intentional latches");
|
||||
if (debug() >= 9) { dumpDotFilePrefixed("latch_" + vrp->name()); }
|
||||
if (debug() >= 9) dumpDotFilePrefixed("latch_" + vrp->name());
|
||||
}
|
||||
vertp->user(false); // Clear again (see above)
|
||||
vrp->varp()->isLatched(latch_detected);
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ private:
|
|||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
||||
if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); }
|
||||
if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp);
|
||||
|
||||
AstNode* past = new AstPast(fl, lhsp, nullptr);
|
||||
past->dtypeFrom(lhsp);
|
||||
|
|
|
|||
|
|
@ -1104,7 +1104,7 @@ void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) con
|
|||
os << indent << " ";
|
||||
dumpPtrs(os);
|
||||
}
|
||||
if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); }
|
||||
if (s_debugFileline >= 9) os << fileline()->warnContextSecondary();
|
||||
if (maxDepth == 1) {
|
||||
if (op1p() || op2p() || op3p() || op4p()) os << indent << "1: ...(maxDepth)\n";
|
||||
} else {
|
||||
|
|
|
|||
10
src/V3Ast.h
10
src/V3Ast.h
|
|
@ -1706,7 +1706,7 @@ public:
|
|||
}
|
||||
}
|
||||
void dtypeFrom(AstNode* fromp) {
|
||||
if (fromp) { dtypep(fromp->dtypep()); }
|
||||
if (fromp) dtypep(fromp->dtypep());
|
||||
}
|
||||
void dtypeChgSigned(bool flag = true);
|
||||
void dtypeChgWidth(int width, int widthMin);
|
||||
|
|
@ -1922,7 +1922,7 @@ public:
|
|||
virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV
|
||||
// For documentation on emitC format see EmitCStmts::emitOpName
|
||||
virtual string emitC() = 0;
|
||||
virtual string emitSimpleOperator() { return ""; }
|
||||
virtual string emitSimpleOperator() { return ""; } // "" means not ok to use
|
||||
virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS
|
||||
virtual bool cleanOut() const = 0; // True if output has extra upper bits zero
|
||||
// Someday we will generically support data types on every math node
|
||||
|
|
@ -2547,7 +2547,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
|
|
@ -2614,7 +2614,7 @@ class AstNodeStream VL_NOT_FINAL : public AstNodeBiop {
|
|||
public:
|
||||
AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
: AstNodeBiop{t, fl, lhsp, rhsp} {
|
||||
if (lhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); }
|
||||
if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeStream)
|
||||
};
|
||||
|
|
@ -2811,7 +2811,7 @@ public:
|
|||
ASTNODE_BASE_FUNCS(NodeFTaskRef)
|
||||
virtual const char* broken() const override;
|
||||
virtual void cloneRelink() override {
|
||||
if (m_taskp && m_taskp->clonep()) { m_taskp = m_taskp->clonep(); }
|
||||
if (m_taskp && m_taskp->clonep()) m_taskp = m_taskp->clonep();
|
||||
}
|
||||
virtual void dump(std::ostream& str = std::cout) const override;
|
||||
virtual string name() const override { return m_name; } // * = Var name
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const char* AstNodeVarRef::broken() const {
|
|||
}
|
||||
|
||||
void AstNodeVarRef::cloneRelink() {
|
||||
if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); }
|
||||
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
||||
}
|
||||
|
||||
string AstNodeVarRef::hiernameProtect() const {
|
||||
|
|
@ -99,7 +99,7 @@ void AstNodeCCall::dump(std::ostream& str) const {
|
|||
}
|
||||
}
|
||||
void AstNodeCCall::cloneRelink() {
|
||||
if (m_funcp && m_funcp->clonep()) { m_funcp = m_funcp->clonep(); }
|
||||
if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep();
|
||||
}
|
||||
const char* AstNodeCCall::broken() const {
|
||||
BROKEN_RTN(m_funcp && !m_funcp->brokeExists());
|
||||
|
|
@ -1098,7 +1098,7 @@ void AstNode::dump(std::ostream& str) const {
|
|||
} else {
|
||||
str << " @dt=" << nodeAddr(dtypep()) << "@";
|
||||
}
|
||||
if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); }
|
||||
if (AstNodeDType* dtp = dtypep()) dtp->dumpSmall(str);
|
||||
} else { // V3Broken will throw an error
|
||||
if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
|
||||
}
|
||||
|
|
@ -1230,9 +1230,9 @@ void AstEnumItemRef::dump(std::ostream& str) const {
|
|||
}
|
||||
void AstIfaceRefDType::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (cellName() != "") { str << " cell=" << cellName(); }
|
||||
if (ifaceName() != "") { str << " if=" << ifaceName(); }
|
||||
if (modportName() != "") { str << " mp=" << modportName(); }
|
||||
if (cellName() != "") str << " cell=" << cellName();
|
||||
if (ifaceName() != "") str << " if=" << ifaceName();
|
||||
if (modportName() != "") str << " mp=" << modportName();
|
||||
if (cellp()) {
|
||||
str << " -> ";
|
||||
cellp()->dump(str);
|
||||
|
|
@ -1388,7 +1388,7 @@ void AstNodeDType::dump(std::ostream& str) const {
|
|||
void AstNodeDType::dumpSmall(std::ostream& str) const {
|
||||
str << "(" << (generic() ? "G/" : "") << ((isSigned() && !isDouble()) ? "s" : "")
|
||||
<< (isNosign() ? "n" : "") << (isDouble() ? "d" : "") << (isString() ? "str" : "");
|
||||
if (!isDouble() && !isString()) { str << "w" << (widthSized() ? "" : "u") << width(); }
|
||||
if (!isDouble() && !isString()) str << "w" << (widthSized() ? "" : "u") << width();
|
||||
if (!widthSized()) str << "/" << widthMin();
|
||||
str << ")";
|
||||
}
|
||||
|
|
@ -1640,7 +1640,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
|
|||
this->AstNodeStmt::dump(str);
|
||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||
str << " -> ";
|
||||
if (dotted() != "") { str << ".=" << dotted() << " "; }
|
||||
if (dotted() != "") str << ".=" << dotted() << " ";
|
||||
if (taskp()) {
|
||||
taskp()->dump(str);
|
||||
} else {
|
||||
|
|
@ -1676,7 +1676,7 @@ void AstCoverDecl::dump(std::ostream& str) const {
|
|||
str << " -> ";
|
||||
this->dataDeclNullp()->dump(str);
|
||||
} else {
|
||||
if (binNum()) { str << " bin" << std::dec << binNum(); }
|
||||
if (binNum()) str << " bin" << std::dec << binNum();
|
||||
}
|
||||
}
|
||||
void AstCoverInc::dump(std::ostream& str) const {
|
||||
|
|
|
|||
|
|
@ -539,8 +539,8 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_keyDTypep && m_keyDTypep->clonep()) { m_keyDTypep = m_keyDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
if (m_keyDTypep && m_keyDTypep->clonep()) m_keyDTypep = m_keyDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
|
|
@ -641,7 +641,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstAssocArrayDType* asamep = static_cast<const AstAssocArrayDType*>(samep);
|
||||
|
|
@ -760,7 +760,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstNodeArrayDType* asamep = static_cast<const AstNodeArrayDType*>(samep);
|
||||
|
|
@ -971,7 +971,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstConstDType* sp = static_cast<const AstConstDType*>(samep);
|
||||
|
|
@ -1140,7 +1140,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstQueueDType* asamep = static_cast<const AstQueueDType*>(samep);
|
||||
|
|
@ -1217,8 +1217,8 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_typedefp && m_typedefp->clonep()) { m_typedefp = m_typedefp->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_typedefp && m_typedefp->clonep()) m_typedefp = m_typedefp->clonep();
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstRefDType* asamep = static_cast<const AstRefDType*>(samep);
|
||||
|
|
@ -1486,7 +1486,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
virtual void cloneRelink() override {
|
||||
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
|
||||
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
|
||||
}
|
||||
virtual bool same(const AstNode* samep) const override {
|
||||
const AstEnumDType* sp = static_cast<const AstEnumDType*>(samep);
|
||||
|
|
@ -2047,7 +2047,7 @@ public:
|
|||
, m_origName{name} {
|
||||
init();
|
||||
combineType(type);
|
||||
if (examplep->childDTypep()) { childDTypep(examplep->childDTypep()->cloneTree(true)); }
|
||||
if (examplep->childDTypep()) childDTypep(examplep->childDTypep()->cloneTree(true));
|
||||
dtypeFrom(examplep);
|
||||
m_declKwd = examplep->declKwd();
|
||||
}
|
||||
|
|
@ -2170,7 +2170,7 @@ public:
|
|||
return ((isIO() || isSignal())
|
||||
&& (isIO() || isBitLogic())
|
||||
// Wrapper would otherwise duplicate wrapped module's coverage
|
||||
&& !isSc() && !isPrimaryIO() && !isConst() && !isDouble());
|
||||
&& !isSc() && !isPrimaryIO() && !isConst() && !isDouble() && !isString());
|
||||
}
|
||||
bool isClassMember() const { return varType() == AstVarType::MEMBER; }
|
||||
bool isStatementTemp() const { return (varType() == AstVarType::STMTTEMP); }
|
||||
|
|
@ -2677,7 +2677,7 @@ public:
|
|||
}
|
||||
ASTNODE_NODE_FUNCS(MemberSel)
|
||||
virtual void cloneRelink() override {
|
||||
if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); }
|
||||
if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep();
|
||||
}
|
||||
virtual const char* broken() const override {
|
||||
BROKEN_RTN(m_varp && !m_varp->brokeExists());
|
||||
|
|
@ -7294,7 +7294,7 @@ class AstShiftL final : public AstNodeBiop {
|
|||
public:
|
||||
AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER(fl, lhsp, rhsp) {
|
||||
if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); }
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ShiftL)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
|
|
@ -7305,7 +7305,9 @@ public:
|
|||
}
|
||||
virtual string emitVerilog() override { return "%k(%l %f<< %r)"; }
|
||||
virtual string emitC() override { return "VL_SHIFTL_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
virtual string emitSimpleOperator() override { return "<<"; }
|
||||
virtual string emitSimpleOperator() override {
|
||||
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : "<<";
|
||||
}
|
||||
virtual bool cleanOut() const override { return false; }
|
||||
virtual bool cleanLhs() const override { return false; }
|
||||
virtual bool cleanRhs() const override { return true; }
|
||||
|
|
@ -7316,7 +7318,7 @@ class AstShiftR final : public AstNodeBiop {
|
|||
public:
|
||||
AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER(fl, lhsp, rhsp) {
|
||||
if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); }
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ShiftR)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
|
|
@ -7327,7 +7329,9 @@ public:
|
|||
}
|
||||
virtual string emitVerilog() override { return "%k(%l %f>> %r)"; }
|
||||
virtual string emitC() override { return "VL_SHIFTR_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
virtual string emitSimpleOperator() override { return ">>"; }
|
||||
virtual string emitSimpleOperator() override {
|
||||
return (rhsp()->isWide() || rhsp()->isQuad()) ? "" : ">>";
|
||||
}
|
||||
virtual bool cleanOut() const override { return false; }
|
||||
virtual bool cleanLhs() const override { return true; }
|
||||
virtual bool cleanRhs() const override { return true; }
|
||||
|
|
@ -7342,7 +7346,7 @@ public:
|
|||
AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0)
|
||||
: ASTGEN_SUPER(fl, lhsp, rhsp) {
|
||||
// Important that widthMin be correct, as opExtend requires it after V3Expand
|
||||
if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::SIGNED); }
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ShiftRS)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override {
|
||||
|
|
@ -9044,7 +9048,7 @@ public:
|
|||
, m_cleanOut{cleanOut}
|
||||
, m_pure{true} {
|
||||
addNOp1p(new AstText(fl, textStmt, true));
|
||||
if (setwidth) { dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); }
|
||||
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(CMath)
|
||||
virtual bool isGateOptimizable() const override { return m_pure; }
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public:
|
|||
m_tlFuncp->isStatic(false);
|
||||
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
|
||||
m_tlFuncp->argTypes(m_argsp);
|
||||
if (stmt != "") { m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); }
|
||||
if (stmt != "") m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
m_funcp = m_tlFuncp;
|
||||
m_modp->addStmtp(m_tlFuncp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ private:
|
|||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
if (VN_IS(nodep, Always)) { m_alwaysp = nodep; }
|
||||
if (VN_IS(nodep, Always)) m_alwaysp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -599,7 +599,7 @@ private:
|
|||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
if (senedited) { senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); }
|
||||
if (senedited) senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree);
|
||||
if (traceDests) {
|
||||
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->dstDomainp(senoutp);
|
||||
|
|
|
|||
|
|
@ -162,10 +162,10 @@ private:
|
|||
void operandQuadop(AstNodeQuadop* nodep) {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) { ensureClean(nodep->lhsp()); }
|
||||
if (nodep->cleanRhs()) { ensureClean(nodep->rhsp()); }
|
||||
if (nodep->cleanThs()) { ensureClean(nodep->thsp()); }
|
||||
if (nodep->cleanFhs()) { ensureClean(nodep->fhsp()); }
|
||||
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
||||
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
||||
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
||||
if (nodep->cleanFhs()) ensureClean(nodep->fhsp());
|
||||
// no setClean.. must do it in each user routine.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ private:
|
|||
// BOTHEDGE: var ^ var_last
|
||||
// HIGHEDGE: var
|
||||
// LOWEDGE: ~var
|
||||
// ANYEDGE: var ^ var_last
|
||||
AstNode* newp = nullptr;
|
||||
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public:
|
|||
T* resolve(const string& name) {
|
||||
// Lookup if it was resolved before, typically not
|
||||
auto it = m_mapResolved.find(name);
|
||||
if (VL_UNLIKELY(it != m_mapResolved.end())) { return &it->second; }
|
||||
if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second;
|
||||
|
||||
T* newp = nullptr;
|
||||
// Cannot be resolved, create if matched
|
||||
|
|
|
|||
522
src/V3Const.cpp
522
src/V3Const.cpp
|
|
@ -29,9 +29,9 @@
|
|||
#include "V3Ast.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Simulate.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
//######################################################################
|
||||
// Utilities
|
||||
|
|
@ -76,6 +76,421 @@ public:
|
|||
bool found() const { return m_found; }
|
||||
};
|
||||
|
||||
// This visitor can be used in the post-expanded Ast from V3Expand, where the Ast satisfies:
|
||||
// - Constants are 64 bit at most (because words are accessed via AstWordSel)
|
||||
// - Variables are scoped.
|
||||
class ConstBitOpTreeVisitor final : public AstNVisitor {
|
||||
// TYPES
|
||||
|
||||
struct LeafInfo { // Leaf node (either AstConst or AstVarRef)
|
||||
bool m_polarity = true;
|
||||
int m_lsb = 0;
|
||||
int m_wordIdx = -1; // -1 means AstWordSel is not used.
|
||||
AstVarRef* m_refp = nullptr;
|
||||
AstConst* m_constp = nullptr;
|
||||
};
|
||||
// Collect information for each Variable to transform as below
|
||||
class VarInfo final {
|
||||
// MEMBERS
|
||||
int m_constResult = -1; // -1: result is not constant, 0 or 1: result of this tree
|
||||
ConstBitOpTreeVisitor* m_parentp; // ConstBitOpTreeVisitor that holds this VarInfo
|
||||
AstVarRef* m_refp; // Points the variable that this VarInfo covers
|
||||
V3Number m_bitPolarity; // Coefficient of each bit
|
||||
static int widthOfRef(AstVarRef* refp) {
|
||||
if (AstWordSel* selp = VN_CAST(refp->backp(), WordSel)) return selp->width();
|
||||
return refp->width();
|
||||
}
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
bool hasConstantResult() const { return m_constResult >= 0; }
|
||||
void setPolarity(bool compBit, int bit) {
|
||||
UASSERT_OBJ(!hasConstantResult(), m_refp, "Already has result of " << m_constResult);
|
||||
if (m_bitPolarity.bitIsX(bit)) { // The bit is not yet set
|
||||
m_bitPolarity.setBit(bit, compBit);
|
||||
} else { // Priviously set the bit
|
||||
const bool sameFlag = m_bitPolarity.bitIs1(bit) == compBit;
|
||||
if (m_parentp->isXorTree()) {
|
||||
// ^{x[0], ~x[0], x[2], x[3]} === ~^{x[2], x[3]}
|
||||
UASSERT_OBJ(sameFlag, m_refp, "Only true is set in Xor tree");
|
||||
m_bitPolarity.setBit(bit, 'x');
|
||||
} else { // And, Or
|
||||
// Can ignore this nodep as the bit is already registered
|
||||
if (sameFlag) return; // a & a == a, b | b == b
|
||||
// Otherwise result is constant
|
||||
m_constResult = m_parentp->isAndTree() ? 0 : 1;
|
||||
m_bitPolarity.setAllBitsX(); // The variable is not referred anymore
|
||||
}
|
||||
}
|
||||
}
|
||||
AstNode* getResult() const {
|
||||
FileLine* fl = m_refp->fileline();
|
||||
AstNode* srcp = VN_CAST(m_refp->backp(), WordSel);
|
||||
if (!srcp) srcp = m_refp;
|
||||
const int width = widthOfRef(m_refp);
|
||||
|
||||
if (hasConstantResult())
|
||||
return new AstConst{fl,
|
||||
V3Number{srcp, width, static_cast<vluint32_t>(m_constResult)}};
|
||||
|
||||
AstConst* maskValuep = new AstConst{fl, V3Number{srcp, width, 0}};
|
||||
maskValuep->num().opBitsNonX(m_bitPolarity); // 'x' -> 0, 0->1, 1->1
|
||||
// Let AstConst be in lhs as it is the common convention
|
||||
AstAnd* maskedp = new AstAnd{fl, maskValuep, srcp->cloneTree(false)};
|
||||
AstNode* resultp;
|
||||
if (m_parentp->isXorTree()) {
|
||||
resultp = new AstRedXor{fl, maskedp};
|
||||
resultp->dtypep()->widthForce(width, 1);
|
||||
} else {
|
||||
AstConst* compValuep = maskValuep->cloneTree(false);
|
||||
compValuep->num().opBitsOne(m_bitPolarity); // 'x'->0, 0->0, 1->1
|
||||
if (m_parentp->isAndTree()) {
|
||||
resultp = new AstEq{fl, compValuep, maskedp};
|
||||
} else { // Or
|
||||
compValuep->num().opXor(V3Number{compValuep->num()}, maskValuep->num());
|
||||
resultp = new AstNeq{fl, compValuep, maskedp};
|
||||
}
|
||||
}
|
||||
return resultp;
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
VarInfo(ConstBitOpTreeVisitor* parent, AstVarRef* refp)
|
||||
: m_parentp(parent)
|
||||
, m_refp(refp)
|
||||
, m_bitPolarity(refp, widthOfRef(refp)) {
|
||||
m_bitPolarity.setAllBitsX();
|
||||
}
|
||||
};
|
||||
|
||||
// MEMBERS
|
||||
bool m_failed = false;
|
||||
bool m_polarity = true; // Flip when AstNot comes
|
||||
int m_ops = 0; // Number of operations such as And, Or, Xor, Sel...
|
||||
int m_lsb = 0; // Current LSB
|
||||
LeafInfo* m_leafp = nullptr; // AstConst or AstVarRef that currently looking for
|
||||
AstNode* m_rootp; // Root of this AST subtree
|
||||
AstNode* m_curOpp = nullptr; // The node that should be added to m_frozenNodes
|
||||
|
||||
AstUser4InUse m_inuser4;
|
||||
std::vector<AstNode*> m_frozenNodes; // Nodes that cannot be optimized
|
||||
std::vector<VarInfo*> m_varInfos; // VarInfo for each variable, [0] is nullptr
|
||||
|
||||
// NODE STATE
|
||||
// AstVarRef::user4u -> Base index of m_varInfos that points VarInfo
|
||||
// AstVarScope::user4u -> Same as AstVarRef::user4
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
bool isAndTree() const { return VN_IS(m_rootp, And); }
|
||||
bool isOrTree() const { return VN_IS(m_rootp, Or); }
|
||||
bool isXorTree() const { return VN_IS(m_rootp, Xor) || VN_IS(m_rootp, RedXor); }
|
||||
|
||||
#define CONST_BITOP_RETURN_IF(cond, nodep) \
|
||||
if (setFailed(cond, #cond, nodep, __LINE__)) return
|
||||
|
||||
#define CONST_BITOP_SET_FAILED(reason, nodep) setFailed(true, reason, nodep, __LINE__)
|
||||
|
||||
bool setFailed(bool fail, const char* reason, AstNode* nodep, int line) {
|
||||
if (fail) {
|
||||
UINFO(9, "cannot optimize " << m_rootp << " reason:" << reason << " called from line:"
|
||||
<< line << " when checking:" << nodep << std::endl);
|
||||
// if (debug() >= 9) m_rootp->dumpTree(std::cout << "Root node:\n");
|
||||
}
|
||||
m_failed |= fail;
|
||||
return m_failed;
|
||||
}
|
||||
void incrOps(const AstNode* nodep, int line) {
|
||||
++m_ops;
|
||||
UINFO(9, "Increment to " << m_ops << " " << nodep << " called from line " << line << "\n");
|
||||
}
|
||||
VarInfo& getVarInfo(const LeafInfo& ref) {
|
||||
UASSERT_OBJ(ref.m_refp, m_rootp, "null varref in And/Or/Xor optimization");
|
||||
AstNode* nodep = ref.m_refp->varScopep();
|
||||
if (!nodep) nodep = ref.m_refp->varp(); // Not scoped
|
||||
int baseIdx = nodep->user4();
|
||||
if (baseIdx == 0) { // Not set yet
|
||||
baseIdx = m_varInfos.size();
|
||||
const int numWords
|
||||
= ref.m_refp->dtypep()->isWide() ? ref.m_refp->dtypep()->widthWords() : 1;
|
||||
m_varInfos.resize(m_varInfos.size() + numWords, nullptr);
|
||||
nodep->user4(baseIdx);
|
||||
}
|
||||
const size_t idx = baseIdx + std::max(0, ref.m_wordIdx);
|
||||
VarInfo* varInfop = m_varInfos[idx];
|
||||
if (!varInfop) {
|
||||
varInfop = new VarInfo{this, ref.m_refp};
|
||||
m_varInfos[idx] = varInfop;
|
||||
}
|
||||
return *varInfop;
|
||||
}
|
||||
|
||||
// Traverse down to see AstConst or AstVarRef
|
||||
LeafInfo findLeaf(AstNode* nodep, bool expectConst) {
|
||||
LeafInfo info;
|
||||
{
|
||||
VL_RESTORER(m_leafp);
|
||||
m_leafp = &info;
|
||||
iterate(nodep);
|
||||
}
|
||||
|
||||
bool ok = !m_failed;
|
||||
if (expectConst)
|
||||
ok &= !info.m_refp && info.m_constp;
|
||||
else
|
||||
ok &= info.m_refp && !info.m_constp;
|
||||
return ok ? info : LeafInfo{};
|
||||
}
|
||||
AstNode* combineTree(AstNode* lhsp, AstNode* rhsp) {
|
||||
if (!lhsp) return rhsp;
|
||||
if (isAndTree())
|
||||
return new AstAnd(m_rootp->fileline(), lhsp, rhsp);
|
||||
else if (isOrTree())
|
||||
return new AstOr(m_rootp->fileline(), lhsp, rhsp);
|
||||
else {
|
||||
UASSERT_OBJ(isXorTree(), m_rootp, "must be either Xor or RedXor");
|
||||
return new AstXor(m_rootp->fileline(), lhsp, rhsp);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) override {
|
||||
CONST_BITOP_SET_FAILED("Hit unexpected op", nodep);
|
||||
}
|
||||
virtual void visit(AstCCast* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstShiftR* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
AstConst* constp = VN_CAST(nodep->rhsp(), Const);
|
||||
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
|
||||
m_lsb += constp->toUInt();
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->lhsp());
|
||||
m_lsb -= constp->toUInt();
|
||||
}
|
||||
virtual void visit(AstNot* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(nodep->widthMin() != 1, nodep);
|
||||
AstNode* lhsp = nodep->lhsp();
|
||||
CONST_BITOP_RETURN_IF(VN_IS(lhsp, And) || VN_IS(lhsp, Or) || VN_IS(lhsp, Const), lhsp);
|
||||
incrOps(nodep, __LINE__);
|
||||
m_polarity = !m_polarity;
|
||||
iterateChildren(nodep);
|
||||
// Don't restore m_polarity for Xor as it counts parity of the entire tree
|
||||
if (!isXorTree()) m_polarity = !m_polarity;
|
||||
}
|
||||
virtual void visit(AstWordSel* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
AstConst* constp = VN_CAST(nodep->bitp(), Const);
|
||||
CONST_BITOP_RETURN_IF(!constp, nodep->rhsp());
|
||||
UASSERT_OBJ(m_leafp->m_wordIdx == -1, nodep, "Unexpected nested WordSel");
|
||||
m_leafp->m_wordIdx = constp->toSInt();
|
||||
iterate(nodep->fromp());
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
UASSERT_OBJ(!m_leafp->m_refp, nodep, m_leafp->m_refp << " is already set");
|
||||
m_leafp->m_refp = nodep;
|
||||
m_leafp->m_polarity = m_polarity;
|
||||
m_leafp->m_lsb = m_lsb;
|
||||
}
|
||||
virtual void visit(AstConst* nodep) override {
|
||||
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
|
||||
UASSERT_OBJ(!m_leafp->m_constp, nodep, m_leafp->m_constp << " is already set");
|
||||
m_leafp->m_constp = nodep;
|
||||
m_leafp->m_lsb = m_lsb;
|
||||
}
|
||||
|
||||
virtual void visit(AstRedXor* nodep) override { // Expect '^(mask & v)'
|
||||
CONST_BITOP_RETURN_IF(!VN_IS(m_rootp, Xor), nodep);
|
||||
AstAnd* andp = VN_CAST(nodep->lhsp(), And);
|
||||
CONST_BITOP_RETURN_IF(!andp, nodep->lhsp());
|
||||
|
||||
auto mask = findLeaf(andp->lhsp(), true);
|
||||
CONST_BITOP_RETURN_IF(!mask.m_constp || mask.m_lsb != 0, andp->lhsp());
|
||||
|
||||
LeafInfo leaf = findLeaf(andp->rhsp(), false);
|
||||
CONST_BITOP_RETURN_IF(!leaf.m_refp, andp->rhsp());
|
||||
|
||||
incrOps(nodep, __LINE__);
|
||||
incrOps(andp, __LINE__);
|
||||
const V3Number& maskNum = mask.m_constp->num();
|
||||
VarInfo& varInfo = getVarInfo(leaf);
|
||||
for (int i = 0; i < maskNum.width(); ++i) {
|
||||
// Set true, m_treePolarity takes care of the entire parity
|
||||
if (maskNum.bitIs1(i)) varInfo.setPolarity(true, i + leaf.m_lsb);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeBiop* nodep) override {
|
||||
auto isConst = [](AstNode* nodep, vluint64_t v) -> bool {
|
||||
AstConst* constp = VN_CAST(nodep, Const);
|
||||
return constp && constp->toUQuad() == v;
|
||||
};
|
||||
if (nodep->type() == m_rootp->type()) { // And, Or, Xor
|
||||
CONST_BITOP_RETURN_IF(!m_polarity && isXorTree(), nodep);
|
||||
incrOps(nodep, __LINE__);
|
||||
VL_RESTORER(m_curOpp);
|
||||
VL_RESTORER(m_leafp);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
LeafInfo leafInfo;
|
||||
m_leafp = &leafInfo;
|
||||
m_curOpp = i == 0 ? nodep->lhsp() : nodep->rhsp();
|
||||
const size_t origFrozens = m_frozenNodes.size();
|
||||
const int origOps = m_ops;
|
||||
const bool origFailed = m_failed;
|
||||
iterate(m_curOpp);
|
||||
if (leafInfo.m_constp || m_failed) {
|
||||
// Rvert changes in leaf
|
||||
if (m_frozenNodes.size() > origFrozens) m_frozenNodes.resize(origFrozens);
|
||||
m_frozenNodes.push_back(m_curOpp);
|
||||
m_ops = origOps;
|
||||
m_failed = origFailed;
|
||||
} else if (leafInfo.m_refp) {
|
||||
VarInfo& varInfo = getVarInfo(leafInfo);
|
||||
if (!varInfo.hasConstantResult()) {
|
||||
varInfo.setPolarity(isXorTree() || leafInfo.m_polarity, leafInfo.m_lsb);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (VN_IS(m_rootp, Xor) && VN_IS(nodep, Eq) && isConst(nodep->lhsp(), 0)
|
||||
&& VN_IS(nodep->rhsp(), And)) { // 0 == (1 & RedXor)
|
||||
AstAnd* andp = static_cast<AstAnd*>(nodep->rhsp()); // already checked above
|
||||
CONST_BITOP_RETURN_IF(!isConst(andp->lhsp(), 1), andp->lhsp());
|
||||
AstRedXor* redXorp = VN_CAST(andp->rhsp(), RedXor);
|
||||
CONST_BITOP_RETURN_IF(!redXorp, andp->rhsp());
|
||||
incrOps(nodep, __LINE__);
|
||||
incrOps(andp, __LINE__);
|
||||
m_polarity = !m_polarity;
|
||||
iterate(redXorp);
|
||||
return;
|
||||
} else if (VN_IS(m_rootp, Xor) && VN_IS(nodep, And) && isConst(nodep->lhsp(), 1)
|
||||
&& (VN_IS(nodep->rhsp(), Xor)
|
||||
|| VN_IS(nodep->rhsp(), RedXor))) { // 1 & (v[3] ^ v[2])
|
||||
incrOps(nodep, __LINE__);
|
||||
iterate(nodep->rhsp());
|
||||
return;
|
||||
} else if ((isAndTree() && VN_IS(nodep, Eq)) || (isOrTree() && VN_IS(nodep, Neq))) {
|
||||
CONST_BITOP_RETURN_IF(!m_polarity, nodep);
|
||||
const bool maskFlip = isOrTree();
|
||||
LeafInfo comp = findLeaf(nodep->lhsp(), true);
|
||||
CONST_BITOP_RETURN_IF(!comp.m_constp || comp.m_lsb != 0, nodep->lhsp());
|
||||
|
||||
AstAnd* andp = VN_CAST(nodep->rhsp(), And); // comp == (mask & v)
|
||||
CONST_BITOP_RETURN_IF(!andp, nodep->rhsp());
|
||||
|
||||
LeafInfo mask = findLeaf(andp->lhsp(), true);
|
||||
CONST_BITOP_RETURN_IF(!mask.m_constp || mask.m_lsb != 0, andp->lhsp());
|
||||
|
||||
LeafInfo ref = findLeaf(andp->rhsp(), false);
|
||||
CONST_BITOP_RETURN_IF(!ref.m_refp, andp->rhsp());
|
||||
|
||||
VarInfo& varInfo = getVarInfo(ref);
|
||||
|
||||
const V3Number maskNum = mask.m_constp->num();
|
||||
const V3Number compNum = comp.m_constp->num();
|
||||
for (int i = 0; i < maskNum.width() && !varInfo.hasConstantResult(); ++i) {
|
||||
const int bit = i + ref.m_lsb;
|
||||
if (maskNum.bitIs0(i)) continue;
|
||||
varInfo.setPolarity(compNum.bitIs1(i) ^ maskFlip, bit);
|
||||
}
|
||||
incrOps(nodep, __LINE__);
|
||||
incrOps(andp, __LINE__);
|
||||
return;
|
||||
}
|
||||
CONST_BITOP_SET_FAILED("Mixture of different ops cannot be optimized", nodep);
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
ConstBitOpTreeVisitor(AstNode* nodep, int ops)
|
||||
: m_ops(ops)
|
||||
, m_rootp(nodep) {
|
||||
// Fill nullptr at [0] because AstVarScope::user4 is 0 by default
|
||||
m_varInfos.push_back(nullptr);
|
||||
CONST_BITOP_RETURN_IF(!isAndTree() && !isOrTree() && !isXorTree(), nodep);
|
||||
AstNode::user4ClearTree();
|
||||
if (AstNodeBiop* biopp = VN_CAST(nodep, NodeBiop)) {
|
||||
iterate(biopp);
|
||||
} else {
|
||||
incrOps(nodep, __LINE__);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
UASSERT_OBJ(isXorTree() || m_polarity, nodep, "must be the original polarity");
|
||||
}
|
||||
virtual ~ConstBitOpTreeVisitor() {
|
||||
for (size_t i = 0; i < m_varInfos.size(); ++i) {
|
||||
VL_DO_DANGLING(delete m_varInfos[i], m_varInfos[i]);
|
||||
}
|
||||
}
|
||||
#undef CONST_BITOP_RETURN_IF
|
||||
#undef CONST_BITOP_SET_FAILED
|
||||
|
||||
public:
|
||||
// Transform as below.
|
||||
// v[0] & v[1] => 2'b11 == (2'b11 & v)
|
||||
// v[0] | v[1] => 2'b00 != (2'b11 & v)
|
||||
// v[0] ^ v[1] => ^{2'b11 & v}
|
||||
// (3'b011 == (3'b011 & v)) & v[2] => 3'b111 == (3'b111 & v)
|
||||
// (3'b000 != (3'b011 & v)) | v[2] => 3'b000 != (3'b111 & v)
|
||||
// Reduction ops are transformed in the same way.
|
||||
// &{v[0], v[1]} => 2'b11 == (2'b11 & v)
|
||||
static AstNode* simplify(AstNode* nodep, int ops, VDouble0& reduction) {
|
||||
ConstBitOpTreeVisitor visitor{nodep, ops};
|
||||
if (visitor.m_failed || visitor.m_varInfos.size() == 1) return nullptr;
|
||||
|
||||
// Two ops for each varInfo. (And and Eq)
|
||||
const int vars = visitor.m_varInfos.size() - 1;
|
||||
int constTerms = 0;
|
||||
for (const VarInfo* v : visitor.m_varInfos) {
|
||||
if (v && v->hasConstantResult()) ++constTerms;
|
||||
}
|
||||
// Expected number of ops after this simplification
|
||||
// e.g. (comp0 == (mask0 & var0)) & (comp1 == (mask1 & var1)) & ....
|
||||
// e.g. redXor(mask1 & var0) ^ redXor(mask1 & var1)
|
||||
// 2 ops per variables, numVars - 1 ops among variables
|
||||
int expOps = 2 * (vars - constTerms) + vars - 1;
|
||||
expOps += 2 * visitor.m_frozenNodes.size();
|
||||
if (visitor.isXorTree()) {
|
||||
++expOps; // AstRedXor::cleanOut() == false, so need 1 & redXor
|
||||
if (!visitor.m_polarity) ++expOps; // comparison with 0
|
||||
}
|
||||
if (visitor.m_ops <= expOps) return nullptr; // Unless benefitial, return
|
||||
|
||||
reduction += visitor.m_ops - expOps;
|
||||
|
||||
AstNode* resultp = nullptr;
|
||||
// VarInfo in visitor.m_varInfos appears in deterministic order,
|
||||
// so the optimized AST is deterministic too.
|
||||
for (const VarInfo* varinfop : visitor.m_varInfos) {
|
||||
if (!varinfop) continue;
|
||||
AstNode* partialresultp = varinfop->getResult();
|
||||
resultp = visitor.combineTree(resultp, partialresultp);
|
||||
}
|
||||
AstNode* frozensp = nullptr;
|
||||
for (AstNode* frozenp : visitor.m_frozenNodes) {
|
||||
frozenp->unlinkFrBack();
|
||||
frozensp = visitor.combineTree(frozensp, frozenp);
|
||||
}
|
||||
if (frozensp) resultp = visitor.combineTree(resultp, frozensp);
|
||||
|
||||
if (visitor.isXorTree()) {
|
||||
// VL_REDXOR_N functions don't guarantee to return only 0/1
|
||||
const int width = resultp->width();
|
||||
FileLine* fl = nodep->fileline();
|
||||
resultp = new AstAnd{fl, new AstConst{fl, V3Number{nodep, width, 1}}, resultp};
|
||||
if (!visitor.m_polarity) {
|
||||
resultp = new AstEq{fl, new AstConst{fl, V3Number{nodep, width, 0}}, resultp};
|
||||
resultp->dtypep()->widthForce(1, 1);
|
||||
}
|
||||
}
|
||||
if (resultp->width() != nodep->width()) {
|
||||
resultp = new AstCCast{resultp->fileline(), resultp, nodep};
|
||||
}
|
||||
return resultp;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Const state, as a visitor of each AstNode
|
||||
|
||||
|
|
@ -104,6 +519,7 @@ private:
|
|||
AstArraySel* m_selp = nullptr; // Current select
|
||||
AstNode* m_scopep = nullptr; // Current scope
|
||||
AstAttrOf* m_attrp = nullptr; // Current attribute
|
||||
VDouble0 m_statBitOpReduction; // Ops reduced in ConstBitOpTreeVisitor
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -168,6 +584,34 @@ private:
|
|||
return (lp && VN_IS(lp->lhsp(), Const) && VN_IS(np->rhsp(), Const)
|
||||
&& lp->width() == np->width());
|
||||
}
|
||||
bool matchRedundantClean(AstAnd* andp) {
|
||||
// Remove And with constant one inserted by V3Clean
|
||||
// 1 & (a == b) -> (IData)(a == b)
|
||||
// When bool is casted to int, the value is either 0 or 1
|
||||
AstConst* constp = VN_CAST(andp->lhsp(), Const);
|
||||
UASSERT_OBJ(constp && constp->isOne(), andp->lhsp(), "TRREEOPC must meet this condition");
|
||||
AstNode* rhsp = andp->rhsp();
|
||||
AstCCast* ccastp = nullptr;
|
||||
auto isEqOrNeq
|
||||
= [](AstNode* nodep) -> bool { return VN_IS(nodep, Eq) || VN_IS(nodep, Neq); };
|
||||
if (isEqOrNeq(rhsp)) {
|
||||
ccastp = new AstCCast{andp->fileline(), rhsp->unlinkFrBack(), andp};
|
||||
} else if (AstCCast* tmpp = VN_CAST(rhsp, CCast)) {
|
||||
if (isEqOrNeq(tmpp->lhsp())) {
|
||||
if (tmpp->width() == andp->width()) {
|
||||
tmpp->unlinkFrBack();
|
||||
ccastp = tmpp;
|
||||
} else {
|
||||
ccastp = new AstCCast{andp->fileline(), tmpp->lhsp()->unlinkFrBack(), andp};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ccastp) {
|
||||
andp->replaceWith(ccastp);
|
||||
VL_DO_DANGLING(andp->deleteTree(), andp);
|
||||
}
|
||||
return ccastp;
|
||||
}
|
||||
|
||||
static bool operandAndOrSame(const AstNode* nodep) {
|
||||
// OR( AND(VAL,x), AND(VAL,y)) -> AND(VAL,OR(x,y))
|
||||
|
|
@ -242,6 +686,36 @@ private:
|
|||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
bool matchBitOpTree(AstNode* nodep) {
|
||||
AstNode* newp = nullptr;
|
||||
bool tried = false;
|
||||
if (AstAnd* andp = VN_CAST(nodep, And)) { // 1 & BitOpTree
|
||||
if (AstConst* bitMaskp = VN_CAST(andp->lhsp(), Const)) {
|
||||
if (bitMaskp->num().toUQuad() != 1) return false;
|
||||
newp = ConstBitOpTreeVisitor::simplify(andp->rhsp(), 1, m_statBitOpReduction);
|
||||
tried = true;
|
||||
}
|
||||
}
|
||||
if (!tried) {
|
||||
// (comp == BitOpTree) & BitOpTree
|
||||
// (comp != BitOpTree) | BitOpTree
|
||||
newp = ConstBitOpTreeVisitor::simplify(nodep, 0, m_statBitOpReduction);
|
||||
}
|
||||
if (newp) {
|
||||
UINFO(4, "Transformed leaf of bit tree to " << newp << std::endl);
|
||||
if (debug() >= 9) {
|
||||
static int c = 0;
|
||||
std::cout << "Call matchBitOpTree[" << c << "]\n";
|
||||
nodep->dumpTree(std::cout);
|
||||
std::cout << "\nResult:\n";
|
||||
newp->dumpTree(std::cout);
|
||||
++c;
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
static bool operandShiftSame(const AstNode* nodep) {
|
||||
const AstNodeBiop* np = VN_CAST_CONST(nodep, NodeBiop);
|
||||
{
|
||||
|
|
@ -1741,8 +2215,8 @@ private:
|
|||
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
|
||||
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
|
||||
// But might be same name with different scopes
|
||||
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) { return true; }
|
||||
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) { return false; }
|
||||
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) return true;
|
||||
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) return false;
|
||||
// Or rarely, different data types
|
||||
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
|
||||
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
|
||||
|
|
@ -2128,7 +2602,7 @@ private:
|
|||
// Ignored, can eliminate early
|
||||
virtual void visit(AstSysIgnore* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_doNConst) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); }
|
||||
if (m_doNConst) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
// Simplify
|
||||
|
|
@ -2221,17 +2695,18 @@ private:
|
|||
// ("AstOr {%a, AstAnd{AstNot{%b}, %c}} if %a.width1 if %a==%b", "AstOr{%a,%c}; %b.delete");
|
||||
// Lhs/rhs would be implied; for non math operations you'd need $lhsp etc.
|
||||
|
||||
// Lint Checks
|
||||
// v--- * * This op done on Verilog or C+++ mode, in all non-m_doConst stages
|
||||
// v--- *1* These ops are always first, as we warn before replacing
|
||||
// v--- *V* This op is a verilog op, only in m_doV mode
|
||||
// v--- *C* This op works on all constant children, allowed in m_doConst mode
|
||||
// v--- *S* This op specifies a type should use short-circuiting of its lhs op
|
||||
// v--- *C* This op is a (C)++ op, only in m_doCpp mode
|
||||
// v--- *V* This op is a (V)erilog op, only in m_doV mode
|
||||
// v--- *A* This op works on (A)ll constant children, allowed in m_doConst mode
|
||||
// v--- *S* This op specifies a type should use (S)hort-circuiting of its lhs op
|
||||
|
||||
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
|
||||
// Generic constants on both side. Do this first to avoid other replacements
|
||||
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque(), nodep->isPredictOptimizable()}", "replaceConst(nodep)");
|
||||
TREEOPC("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPA("AstNodeBiop {$lhsp.castConst, $rhsp.castConst, nodep->isPredictOptimizable()}", "replaceConst(nodep)");
|
||||
TREEOPA("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque(), nodep->isPredictOptimizable()}", "replaceConst(nodep)");
|
||||
TREEOPA("AstNodeQuadop{$lhsp.castConst, $rhsp.castConst, $thsp.castConst, $fhsp.castConst}", "replaceConst(nodep)");
|
||||
// Zero on one side or the other
|
||||
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp.isZero, $rhsp, isTPure($rhsp)}", "replaceZero(nodep)"); // Can't use replaceZeroChkPure as we make this pattern in ChkPure
|
||||
|
|
@ -2290,12 +2765,13 @@ private:
|
|||
TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
|
||||
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
|
||||
TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b)
|
||||
// Trinary ops
|
||||
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
|
||||
TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
|
||||
TREEOP ("AstNodeCond{$condp.isNeqZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr1p)");
|
||||
TREEOPC("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)");
|
||||
TREEOPC("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)");
|
||||
TREEOPA("AstNodeCond{$condp.isZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr2p)");
|
||||
TREEOPA("AstNodeCond{$condp.isNeqZero, $expr1p.castConst, $expr2p.castConst}", "replaceWChild(nodep,$expr1p)");
|
||||
TREEOP ("AstNodeCond{$condp, operandsSame($expr1p,,$expr2p)}","replaceWChild(nodep,$expr1p)");
|
||||
// This visit function here must allow for short-circuiting.
|
||||
TREEOPS("AstCond {$lhsp.isZero}", "replaceWIteratedThs(nodep)");
|
||||
|
|
@ -2446,6 +2922,8 @@ private:
|
|||
TREEOPV("AstRedAnd{$lhsp.castExtend, $lhsp->width() > VN_CAST($lhsp,,Extend)->lhsp()->width()}", "replaceZero(nodep)"); // &{0,...} => 0 Prevents compiler limited range error
|
||||
TREEOPV("AstRedOr {$lhsp.castExtend}", "AstRedOr {$lhsp->castExtend()->lhsp()}");
|
||||
TREEOPV("AstRedXor{$lhsp.castExtend}", "AstRedXor{$lhsp->castExtend()->lhsp()}");
|
||||
TREEOP ("AstRedXor{$lhsp.castXor, VN_IS(VN_CAST($lhsp,,Xor)->lhsp(),,Const)}", "AstXor{AstRedXor{$lhsp->castXor()->lhsp()}, AstRedXor{$lhsp->castXor()->rhsp()}}"); // ^(const ^ a) => (^const)^(^a)
|
||||
TREEOPC("AstAnd {nodep->widthMin() == 1, $lhsp.castConst, $rhsp.castRedXor, matchBitOpTree(nodep)}", "DONE");
|
||||
TREEOPV("AstOneHot{$lhsp.width1}", "replaceWLhs(nodep)");
|
||||
TREEOPV("AstOneHot0{$lhsp.width1}", "replaceNum(nodep,1)");
|
||||
// Binary AND/OR is faster than logical and/or (usually)
|
||||
|
|
@ -2467,6 +2945,9 @@ private:
|
|||
TREEOP ("AstAnd {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
TREEOP ("AstOr {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
TREEOP ("AstXor {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
TREEOPC("AstAnd {nodep->widthMin() == 1, matchBitOpTree(nodep)}", "DONE");
|
||||
TREEOPC("AstOr {nodep->widthMin() == 1, matchBitOpTree(nodep)}", "DONE");
|
||||
TREEOPC("AstXor {nodep->widthMin() == 1, matchBitOpTree(nodep)}", "DONE");
|
||||
// Note can't simplify a extend{extends}, extends{extend}, as the sign
|
||||
// bits end up in the wrong places
|
||||
TREEOPV("AstExtend {$lhsp.castExtend}", "replaceExtend(nodep, VN_CAST(nodep->lhsp(), Extend)->lhsp())");
|
||||
|
|
@ -2486,7 +2967,7 @@ private:
|
|||
TREEOPV("AstSel{$fromp.castSub, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castXor, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castShiftR, operandSelShiftLower(nodep)}", "DONE");
|
||||
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||
TREEOPA("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.castConst, operandSelReplicate(nodep) }", "DONE");
|
||||
// V3Tristate requires selects below BufIf1.
|
||||
|
|
@ -2502,9 +2983,9 @@ private:
|
|||
TREEOPV("AstLogIf{$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
|
||||
TREEOPV("AstLogEq{$lhsp, $rhsp}", "replaceLogEq(nodep)");
|
||||
// Strings
|
||||
TREEOPC("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPC("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())");
|
||||
TREEOPA("AstPutcN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPA("AstSubstrN{$lhsp.castConst, $rhsp.castConst, $thsp.castConst}", "replaceConst(nodep)");
|
||||
TREEOPA("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, VN_CAST(nodep->lhsp(), Const)->num().toString())");
|
||||
// Custom
|
||||
// Implied by AstIsUnbounded::numberOperate: V("AstIsUnbounded{$lhsp.castConst}", "replaceNum(nodep, 0)");
|
||||
TREEOPV("AstIsUnbounded{$lhsp.castUnbounded}", "replaceNum(nodep, 1)");
|
||||
|
|
@ -2564,7 +3045,12 @@ public:
|
|||
}
|
||||
// clang-format on
|
||||
}
|
||||
virtual ~ConstVisitor() override = default;
|
||||
virtual ~ConstVisitor() override {
|
||||
if (m_doCpp) {
|
||||
V3Stats::addStat("Optimizations, Const bit op reduction", m_statBitOpReduction);
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
// Operate starting at a random place
|
||||
return iterateSubtreeReturnEdits(nodep);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ private:
|
|||
int instances = 0;
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (VN_IS(stmtp, Scope)) {
|
||||
if (++instances > 1) { return false; }
|
||||
if (++instances > 1) return false;
|
||||
}
|
||||
}
|
||||
return (instances == 1);
|
||||
|
|
|
|||
|
|
@ -693,7 +693,7 @@ public:
|
|||
iterateAndNextNull(nodep->offset());
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->operation());
|
||||
puts(")==-1?-1:0)");
|
||||
puts(") == -1 ? -1 : 0)");
|
||||
}
|
||||
virtual void visit(AstFTell* nodep) override {
|
||||
puts("VL_FTELL_I(");
|
||||
|
|
@ -703,7 +703,7 @@ public:
|
|||
virtual void visit(AstFRewind* nodep) override {
|
||||
puts("(VL_FSEEK_I(");
|
||||
iterateAndNextNull(nodep->filep());
|
||||
puts(", 0, 0)==-1?-1:0)");
|
||||
puts(", 0, 0) == -1 ? -1 : 0)");
|
||||
}
|
||||
virtual void visit(AstFRead* nodep) override {
|
||||
puts("VL_FREAD_I(");
|
||||
|
|
@ -748,7 +748,7 @@ public:
|
|||
} else {
|
||||
puts(cvtToStr(array_size));
|
||||
}
|
||||
puts(");\n");
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) override {
|
||||
if (!nodep->lhsp()->isWide()) puts("(void)");
|
||||
|
|
@ -1035,8 +1035,8 @@ public:
|
|||
emitIQW(nodep);
|
||||
puts("OI(");
|
||||
puts(cvtToStr(nodep->widthMin()));
|
||||
if (nodep->lhsp()) { puts("," + cvtToStr(nodep->lhsp()->widthMin())); }
|
||||
if (nodep->rhsp()) { puts("," + cvtToStr(nodep->rhsp()->widthMin())); }
|
||||
if (nodep->lhsp()) puts("," + cvtToStr(nodep->lhsp()->widthMin()));
|
||||
if (nodep->rhsp()) puts("," + cvtToStr(nodep->rhsp()->widthMin()));
|
||||
puts(",");
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(", ");
|
||||
|
|
@ -2026,7 +2026,7 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp,
|
|||
nextComma = ",";
|
||||
needComma = false;
|
||||
}
|
||||
if (pos[1] == ' ') { ++pos; } // Must do even if no nextComma
|
||||
if (pos[1] == ' ') ++pos; // Must do even if no nextComma
|
||||
} else if (pos[0] == '%') {
|
||||
++pos;
|
||||
bool detail = false;
|
||||
|
|
@ -2427,10 +2427,12 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
|
|||
if (VN_IS(modp, Class)) {
|
||||
modp->v3fatalSrc("constructors should be AstCFuncs instead");
|
||||
} else if (optSystemC() && modp->isTop()) {
|
||||
puts("VL_SC_CTOR_IMP(" + prefixNameProtect(modp) + ")");
|
||||
puts(prefixNameProtect(modp) + "::" + prefixNameProtect(modp) + "(sc_module_name)");
|
||||
} else {
|
||||
puts("VL_CTOR_IMP(" + prefixNameProtect(modp) + ")");
|
||||
first = false; // VL_CTOR_IMP includes the first ':'
|
||||
puts(prefixNameProtect(modp) + "::" + prefixNameProtect(modp)
|
||||
+ "(const char* __VCname)\n");
|
||||
puts(" : VerilatedModule(__VCname)\n");
|
||||
first = false; // printed the first ':'
|
||||
}
|
||||
emitVarCtors(&first);
|
||||
if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first);
|
||||
|
|
@ -3080,6 +3082,13 @@ void EmitCImp::emitIntTop(AstNodeModule*) {
|
|||
|
||||
void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
puts("\n//==========\n\n");
|
||||
|
||||
if (AstClass* classp = VN_CAST(modp, Class)) {
|
||||
if (classp->extendsp())
|
||||
puts("#include \"" + prefixNameProtect(classp->extendsp()->classp()->classOrPackagep())
|
||||
+ ".h\"\n");
|
||||
}
|
||||
|
||||
emitModCUse(modp, VUseType::INT_INCLUDE);
|
||||
|
||||
// Declare foreign instances up front to make C++ happy
|
||||
|
|
@ -3177,7 +3186,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
|||
puts("virtual ~" + prefixNameProtect(modp) + "();\n");
|
||||
} else if (optSystemC()) {
|
||||
ofp()->putsPrivate(false); // public:
|
||||
puts("VL_CTOR(" + prefixNameProtect(modp) + ");\n");
|
||||
puts(prefixNameProtect(modp) + "(const char* __VCname = \"\");\n");
|
||||
puts("~" + prefixNameProtect(modp) + "();\n");
|
||||
} else {
|
||||
ofp()->putsPrivate(false); // public:
|
||||
|
|
@ -3868,7 +3877,7 @@ public:
|
|||
// Put out the file
|
||||
newOutCFile(0);
|
||||
|
||||
if (m_slow) { emitTraceSlow(); }
|
||||
if (m_slow) emitTraceSlow();
|
||||
|
||||
iterate(v3Global.rootp());
|
||||
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@ private:
|
|||
|
||||
puts("\n//======================\n\n");
|
||||
|
||||
puts(topClassName() + "* topp;\n");
|
||||
puts("\n");
|
||||
puts("// Requires -DVL_TIME_STAMP64\n");
|
||||
v3Global.opt.addCFlags("-DVL_TIME_STAMP64");
|
||||
puts("vluint64_t main_time = 0;\n");
|
||||
|
|
@ -67,10 +65,15 @@ private:
|
|||
puts("// Setup defaults and parse command line\n");
|
||||
puts("Verilated::debug(0);\n");
|
||||
puts("Verilated::commandArgs(argc, argv);\n");
|
||||
puts("\n");
|
||||
|
||||
puts("// Construct the Verilated model, from Vtop.h generated from Verilating\n");
|
||||
puts("topp = new " + topClassName() + "(\"top\");\n");
|
||||
puts("const std::unique_ptr<" + topClassName() + "> topp{new " + topClassName() + "};\n");
|
||||
puts("\n");
|
||||
|
||||
puts("// Evaluate initials\n");
|
||||
puts("topp->eval(); // Evaluate\n");
|
||||
puts("\n");
|
||||
|
||||
puts("// Simulate until $finish\n");
|
||||
puts("while (!Verilated::gotFinish()) {\n");
|
||||
|
|
@ -88,8 +91,7 @@ private:
|
|||
|
||||
puts("// Final model cleanup\n");
|
||||
puts("topp->final();\n");
|
||||
puts("VL_DO_DANGLING(delete topp, topp);\n");
|
||||
puts("exit(0);\n");
|
||||
puts("return 0;\n");
|
||||
puts("}\n");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class CMakeEmitter final {
|
|||
static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value,
|
||||
const string& cache_type = "", const string& docstring = "") {
|
||||
of << "set(" << name << " " << raw_value;
|
||||
if (!cache_type.empty()) { of << " CACHE " << cache_type << " \"" << docstring << "\""; }
|
||||
if (!cache_type.empty()) of << " CACHE " << cache_type << " \"" << docstring << "\"";
|
||||
of << ")\n";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ class EmitCSyms final : EmitCBaseVisitor {
|
|||
virtual void visit(AstVar* nodep) override {
|
||||
nameCheck(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (nodep->isSigUserRdPublic()) { m_modVars.emplace_back(make_pair(m_modp, nodep)); }
|
||||
if (nodep->isSigUserRdPublic()) m_modVars.emplace_back(make_pair(m_modp, nodep));
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep) override {
|
||||
// Assign numbers to all bins, so we know how big of an array to use
|
||||
|
|
@ -620,7 +620,7 @@ void EmitCSyms::emitSymImp() {
|
|||
+ "& os) {\n");
|
||||
puts("// LOCAL STATE\n");
|
||||
// __Vm_namep presumably already correct
|
||||
if (v3Global.opt.trace()) { puts("os" + op + "__Vm_activity;\n"); }
|
||||
if (v3Global.opt.trace()) puts("os" + op + "__Vm_activity;\n");
|
||||
puts("os" + op + "__Vm_didInit;\n");
|
||||
puts("// SUBCELL STATE\n");
|
||||
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end();
|
||||
|
|
|
|||
|
|
@ -101,10 +101,10 @@ public:
|
|||
// have them.
|
||||
} else if (support == 2 && !slow) {
|
||||
putMakeClassEntry(of, "verilated.cpp");
|
||||
if (v3Global.dpi()) { putMakeClassEntry(of, "verilated_dpi.cpp"); }
|
||||
if (v3Global.opt.vpi()) { putMakeClassEntry(of, "verilated_vpi.cpp"); }
|
||||
if (v3Global.opt.savable()) { putMakeClassEntry(of, "verilated_save.cpp"); }
|
||||
if (v3Global.opt.coverage()) { putMakeClassEntry(of, "verilated_cov.cpp"); }
|
||||
if (v3Global.dpi()) putMakeClassEntry(of, "verilated_dpi.cpp");
|
||||
if (v3Global.opt.vpi()) putMakeClassEntry(of, "verilated_vpi.cpp");
|
||||
if (v3Global.opt.savable()) putMakeClassEntry(of, "verilated_save.cpp");
|
||||
if (v3Global.opt.coverage()) putMakeClassEntry(of, "verilated_cov.cpp");
|
||||
if (v3Global.opt.trace()) {
|
||||
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
|
|
@ -117,7 +117,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.mtasks()) { putMakeClassEntry(of, "verilated_threads.cpp"); }
|
||||
if (v3Global.opt.mtasks()) putMakeClassEntry(of, "verilated_threads.cpp");
|
||||
} else if (support == 2 && slow) {
|
||||
} else {
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
|
|
@ -298,8 +298,8 @@ class EmitMkHierVerilation final {
|
|||
of.puts("VM_HIER_RUN_DIR := " + cwd + "\n");
|
||||
of.puts("# Common options for hierarchical blocks\n");
|
||||
const string fullpath_bin = V3Os::filenameRealPath(v3Global.opt.bin());
|
||||
const string perl_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
|
||||
of.puts("VM_HIER_VERILATOR := " + perl_wrapper + "\n");
|
||||
const string verilator_wrapper = V3Os::filenameDir(fullpath_bin) + "/verilator";
|
||||
of.puts("VM_HIER_VERILATOR := " + verilator_wrapper + "\n");
|
||||
of.puts("VM_HIER_INPUT_FILES := \\\n");
|
||||
const V3StringList& vFiles = v3Global.opt.vFiles();
|
||||
for (const string& i : vFiles) of.puts("\t" + V3Os::filenameRealPath(i) + " \\\n");
|
||||
|
|
|
|||
|
|
@ -815,7 +815,7 @@ public:
|
|||
AstSenTree* domainp, bool user3mark)
|
||||
: EmitVBaseVisitor{false, domainp}
|
||||
, m_formatter{os, prefix, flWidth} {
|
||||
if (user3mark) { AstUser3InUse::check(); }
|
||||
if (user3mark) AstUser3InUse::check();
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~EmitVPrefixedVisitor() override = default;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class EmitXmlFileVisitor final : public AstNVisitor {
|
|||
|
||||
// XML methods
|
||||
void outputId(AstNode* nodep) {
|
||||
if (!nodep->user1()) { nodep->user1(++m_id); }
|
||||
if (!nodep->user1()) nodep->user1(++m_id);
|
||||
puts("\"" + cvtToStr(nodep->user1()) + "\"");
|
||||
}
|
||||
void outputTag(AstNode* nodep, const string& tagin) {
|
||||
|
|
@ -336,7 +336,7 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
if (nodep->modp()->dead()) { return; }
|
||||
if (nodep->modp()->dead()) return;
|
||||
if (!m_hasChildren) m_os << ">\n";
|
||||
m_os << "<cell " << nodep->fileline()->xml() << " "
|
||||
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
|
||||
|
|
|
|||
|
|
@ -364,12 +364,12 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
|
|||
// Assertion without object, generally UOBJASSERT preferred
|
||||
#define UASSERT(condition, stmsg) \
|
||||
do { \
|
||||
if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); } \
|
||||
if (VL_UNCOVERABLE(!(condition))) v3fatalSrc(stmsg); \
|
||||
} while (false)
|
||||
// Assertion with object
|
||||
#define UASSERT_OBJ(condition, obj, stmsg) \
|
||||
do { \
|
||||
if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); } \
|
||||
if (VL_UNCOVERABLE(!(condition))) (obj)->v3fatalSrc(stmsg); \
|
||||
} while (false)
|
||||
// For use in V3Ast static functions only
|
||||
#define UASSERT_STATIC(condition, stmsg) \
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ void V3File::createMakeDir() {
|
|||
if (!created) {
|
||||
created = true;
|
||||
V3Os::createDir(v3Global.opt.makeDir());
|
||||
if (v3Global.opt.hierTop()) { V3Os::createDir(v3Global.opt.hierTopDataDir()); }
|
||||
if (v3Global.opt.hierTop()) V3Os::createDir(v3Global.opt.hierTopDataDir());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -787,11 +787,11 @@ void V3OutFormatter::puts(const char* strg) {
|
|||
wordstart = false;
|
||||
break;
|
||||
case 'e':
|
||||
if (wordstart && m_lang == LA_VERILOG && tokenEnd(cp)) { indentDec(); }
|
||||
if (wordstart && m_lang == LA_VERILOG && tokenEnd(cp)) indentDec();
|
||||
wordstart = false;
|
||||
break;
|
||||
case 'm':
|
||||
if (wordstart && m_lang == LA_VERILOG && tokenStart(cp, "module")) { indentInc(); }
|
||||
if (wordstart && m_lang == LA_VERILOG && tokenStart(cp, "module")) indentInc();
|
||||
wordstart = false;
|
||||
break;
|
||||
default: wordstart = false; break;
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ void FileLine::modifyStateInherit(const FileLine* fromp) {
|
|||
// Any warnings that are off in "from", become off in "this".
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (fromp->warnIsOff(code)) { warnOff(code, true); }
|
||||
if (fromp->warnIsOff(code)) warnOff(code, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -358,7 +358,7 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
|||
} else if (!V3Error::errorContexted()) {
|
||||
nsstr << warnContextPrimary();
|
||||
}
|
||||
if (!m_waive) { V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str()); }
|
||||
if (!m_waive) V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str());
|
||||
V3Error::v3errorEnd(nsstr, lstr.str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ private:
|
|||
virtual void visit(AstNode* nodep) override {
|
||||
// *** Special iterator
|
||||
if (!m_isSimple) return; // Fastpath
|
||||
if (++m_ops > v3Global.opt.gateStmts()) { clearSimple("--gate-stmts exceeded"); }
|
||||
if (++m_ops > v3Global.opt.gateStmts()) clearSimple("--gate-stmts exceeded");
|
||||
if (!(m_dedupe ? nodep->isGateDedupable() : nodep->isGateOptimizable()) //
|
||||
|| !nodep->isPure() || nodep->isBrancher()) {
|
||||
UINFO(5, "Non optimizable type: " << nodep << endl);
|
||||
|
|
@ -282,7 +282,7 @@ public:
|
|||
// Iterate
|
||||
iterate(nodep);
|
||||
// Check results
|
||||
if (!m_substTreep) { clearSimple("No assignment found\n"); }
|
||||
if (!m_substTreep) clearSimple("No assignment found\n");
|
||||
for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin(); it != m_rhsVarRefs.end();
|
||||
++it) {
|
||||
if (m_lhsVarRef && m_lhsVarRef->varScopep() == (*it)->varScopep()) {
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
|||
<< (edgep->dotLabel() != "" ? edgep->dotLabel() : "") << "\""
|
||||
<< " weight=" << edgep->weight() << " color=" << edgep->dotColor();
|
||||
if (edgep->dotStyle() != "") *logp << " style=" << edgep->dotStyle();
|
||||
// if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without
|
||||
// if (edgep->cutable()) *logp << ",constraint=false"; // to rank without
|
||||
// following edges
|
||||
*logp << "];\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,7 +271,9 @@ private:
|
|||
}
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (!vertexp->user()) { vertexIterate(vertexp, 1); }
|
||||
if (!vertexp->user()) { //
|
||||
vertexIterate(vertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ private:
|
|||
for (V3GraphVertex *nextp, *vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
if (!vertexp->user()) { VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp); }
|
||||
if (!vertexp->user()) VL_DO_DANGLING(vertexp->unlinkDelete(m_graphp), vertexp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ public:
|
|||
// Wrap curIt. Expect to wrap, and make another pass, to find
|
||||
// newly-ready elements that could have appeared ahead of the
|
||||
// m_last iterator
|
||||
if (curIt == m_readyVertices.end()) { curIt = m_readyVertices.begin(); }
|
||||
if (curIt == m_readyVertices.end()) curIt = m_readyVertices.begin();
|
||||
}
|
||||
|
||||
if (curIt != m_readyVertices.end()) {
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const {
|
|||
for (const auto& hierblockp : m_children) *of << hierblockp->hierBlockArgs().front() << "\n";
|
||||
// Hierarchical blocks should not use multi-threading,
|
||||
// but needs to be thread safe when top is multi-threaded.
|
||||
if (v3Global.opt.threads() > 0) { *of << "--threads 1\n"; }
|
||||
if (v3Global.opt.threads() > 0) *of << "--threads 1\n";
|
||||
*of << v3Global.opt.allArgsStringForHierBlock(false) << "\n";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ private:
|
|||
// If inlining moves post-scope this can perhaps be relaxed.
|
||||
cantInline("modIface", true);
|
||||
}
|
||||
if (m_modp->modPublic()) cantInline("modPublic", false);
|
||||
if (m_modp->modPublic() && (m_modp->isTop() || !v3Global.opt.flatten())) {
|
||||
cantInline("modPublic", false);
|
||||
}
|
||||
|
||||
iterateChildren(nodep);
|
||||
m_modp = nullptr;
|
||||
|
|
@ -137,7 +139,7 @@ private:
|
|||
} else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
|
||||
if (!m_modp) {
|
||||
nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE
|
||||
} else {
|
||||
} else if (!v3Global.opt.flatten()) {
|
||||
cantInline("Pragma NO_INLINE_MODULE", false);
|
||||
}
|
||||
// Remove so don't propagate to upper cell...
|
||||
|
|
@ -379,8 +381,8 @@ private:
|
|||
string name = m_cellp->name() + "__DOT__" + nodep->name();
|
||||
if (!nodep->isFuncLocal() && !nodep->isClassMember()) nodep->inlineAttrReset(name);
|
||||
if (!m_cellp->isTrace()) nodep->trace(false);
|
||||
if (debug() >= 9) { nodep->dumpTree(cout, "varchanged:"); }
|
||||
if (debug() >= 9 && nodep->valuep()) { nodep->valuep()->dumpTree(cout, "varchangei:"); }
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "varchanged:");
|
||||
if (debug() >= 9 && nodep->valuep()) nodep->valuep()->dumpTree(cout, "varchangei:");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
|
|
@ -593,7 +595,7 @@ private:
|
|||
// Cleanup var names, etc, to not conflict
|
||||
{ InlineRelinkVisitor(newmodp, m_modp, nodep); }
|
||||
// Move statements to top module
|
||||
if (debug() >= 9) { newmodp->dumpTree(cout, "fixmod:"); }
|
||||
if (debug() >= 9) newmodp->dumpTree(cout, "fixmod:");
|
||||
AstNode* stmtsp = newmodp->stmtsp();
|
||||
if (stmtsp) stmtsp->unlinkFrBackWithNext();
|
||||
if (stmtsp) m_modp->addStmtp(stmtsp);
|
||||
|
|
@ -601,7 +603,7 @@ private:
|
|||
VL_DO_DANGLING(newmodp->deleteTree(), newmodp); // Clear any leftover ports, etc
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
if (debug() >= 9) { m_modp->dumpTree(cout, "donemod:"); }
|
||||
if (debug() >= 9) m_modp->dumpTree(cout, "donemod:");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -636,7 +638,7 @@ private:
|
|||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); }
|
||||
virtual void visit(AstModule* nodep) override {
|
||||
if (nodep->isTop()) { iterateChildren(nodep); }
|
||||
if (nodep->isTop()) iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCell* nodep) override {
|
||||
VL_RESTORER(m_scope);
|
||||
|
|
|
|||
|
|
@ -396,7 +396,8 @@ private:
|
|||
AstNode* prevPinp = nullptr;
|
||||
// Clone the var referenced by the pin, and clone each var referenced by the varref
|
||||
// Clone pin varp:
|
||||
for (int i = pinArrp->lo(); i <= pinArrp->hi(); ++i) {
|
||||
for (int in = 0; in < pinArrp->elementsConst(); ++in) {
|
||||
int i = pinArrp->left() + in * pinArrp->declRange().leftToRightInc();
|
||||
string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
||||
AstVar* varNewp = nullptr;
|
||||
|
||||
|
|
@ -429,16 +430,20 @@ private:
|
|||
newp->modVarp(varNewp);
|
||||
newp->name(newp->name() + "__BRA__" + cvtToStr(i) + "__KET__");
|
||||
// And replace exprp with a new varxref
|
||||
int offset = 0;
|
||||
const AstVarRef* varrefp = VN_CAST(newp->exprp(), VarRef);
|
||||
int offset = 0;
|
||||
if (varrefp) {
|
||||
} else if (AstSliceSel* slicep = VN_CAST(newp->exprp(), SliceSel)) {
|
||||
varrefp = VN_CAST(slicep->fromp(), VarRef);
|
||||
UASSERT(VN_IS(slicep->rhsp(), Const), "Slices should be constant");
|
||||
offset = VN_CAST(slicep->rhsp(), Const)->toSInt();
|
||||
}
|
||||
if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); }
|
||||
string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__";
|
||||
int expr_i = i;
|
||||
if (auto* exprArrp = VN_CAST(newp->exprp()->dtypep(), UnpackArrayDType))
|
||||
expr_i = exprArrp->left()
|
||||
+ (in + offset) * exprArrp->declRange().leftToRightInc();
|
||||
if (!varrefp) newp->exprp()->v3error("Unexpected connection to arrayed port");
|
||||
string newname = varrefp->name() + "__BRA__" + cvtToStr(expr_i) + "__KET__";
|
||||
AstVarXRef* newVarXRefp
|
||||
= new AstVarXRef(nodep->fileline(), newname, "", VAccess::WRITE);
|
||||
newVarXRefp->varp(newp->modVarp());
|
||||
|
|
@ -538,7 +543,7 @@ public:
|
|||
// Done. Constant.
|
||||
} else {
|
||||
// Make a new temp wire
|
||||
// if (1 || debug() >= 9) { pinp->dumpTree(cout, "-in_pin:"); }
|
||||
// if (1 || debug() >= 9) pinp->dumpTree(cout, "-in_pin:");
|
||||
V3Inst::checkOutputShort(pinp);
|
||||
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
||||
string newvarname
|
||||
|
|
@ -570,8 +575,8 @@ public:
|
|||
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, VAccess::READ));
|
||||
}
|
||||
if (assignp) cellp->addNextHere(assignp);
|
||||
// if (debug()) { pinp->dumpTree(cout, "- out:"); }
|
||||
// if (debug()) { assignp->dumpTree(cout, "- aout:"); }
|
||||
// if (debug()) pinp->dumpTree(cout, "- out:");
|
||||
// if (debug()) assignp->dumpTree(cout, "- aout:");
|
||||
}
|
||||
return assignp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ public:
|
|||
bool operator<(const LifeLocation& b) const {
|
||||
unsigned a_id = mtaskp ? mtaskp->id() : 0;
|
||||
unsigned b_id = b.mtaskp ? b.mtaskp->id() : 0;
|
||||
if (a_id < b_id) { return true; }
|
||||
if (b_id < a_id) { return false; }
|
||||
if (a_id < b_id) return true;
|
||||
if (b_id < a_id) return false;
|
||||
return sequence < b.sequence;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -453,7 +453,9 @@ private:
|
|||
nodep->hasIfaceVar(true);
|
||||
}
|
||||
}
|
||||
if (nodep->modp()) { iterateChildren(nodep); }
|
||||
if (nodep->modp()) { //
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
UINFO(4, " Link Cell done: " << nodep << endl);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ public:
|
|||
symp->classOrPackagep(classOrPackagep);
|
||||
symp->fallbackp(abovep);
|
||||
nodep->user1p(symp);
|
||||
if (name != "") { checkDuplicate(abovep, nodep, name); }
|
||||
if (name != "") checkDuplicate(abovep, nodep, name);
|
||||
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
|
||||
abovep->reinsert(name, symp);
|
||||
return symp;
|
||||
|
|
@ -409,7 +409,7 @@ public:
|
|||
// Mark the given variable name as being allowed to be implicitly declared
|
||||
if (nodep) {
|
||||
const auto it = m_implicitNameSet.find(make_pair(nodep, varname));
|
||||
if (it == m_implicitNameSet.end()) { m_implicitNameSet.emplace(nodep, varname); }
|
||||
if (it == m_implicitNameSet.end()) m_implicitNameSet.emplace(nodep, varname);
|
||||
}
|
||||
}
|
||||
bool implicitOk(AstNodeModule* nodep, const string& varname) {
|
||||
|
|
@ -2107,7 +2107,7 @@ private:
|
|||
&& (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
|
||||
m_ds.m_unlinkedScopep = nodep->lhsp();
|
||||
}
|
||||
if (VN_IS(nodep->lhsp(), LambdaArgRef)) { m_ds.m_unlinkedScopep = nodep->lhsp(); }
|
||||
if (VN_IS(nodep->lhsp(), LambdaArgRef)) m_ds.m_unlinkedScopep = nodep->lhsp();
|
||||
if (!m_ds.m_dotErr) { // Once something wrong, give up
|
||||
// Top 'final' dot RHS is final RHS, else it's a
|
||||
// DOT(DOT(x,*here*),real-rhs) which we consider a RHS
|
||||
|
|
@ -2152,7 +2152,7 @@ private:
|
|||
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
|
||||
UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep,
|
||||
"ParseRefs should no longer exist");
|
||||
if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); }
|
||||
if (nodep->name() == "super") nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
|
||||
DotStates lastStates = m_ds;
|
||||
bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
|
||||
if (start) {
|
||||
|
|
|
|||
|
|
@ -102,11 +102,12 @@ void V3LinkLevel::timescaling(const ModVec& mods) {
|
|||
|
||||
for (AstNodeModule* nodep : mods) {
|
||||
if (nodep->timeunit().isNone()) {
|
||||
if (modTimedp && !VN_IS(nodep, Iface)
|
||||
if (modTimedp && !VN_IS(nodep, Iface) && !VN_IS(nodep, Primitive)
|
||||
&& !(VN_IS(nodep, Package) && VN_CAST(nodep, Package)->isDollarUnit())) {
|
||||
nodep->v3warn(TIMESCALEMOD,
|
||||
"Timescale missing on this module as other modules have "
|
||||
"it (IEEE 1800-2017 3.14.2.2)\n"
|
||||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< modTimedp->warnOther()
|
||||
<< "... Location of module with timescale\n"
|
||||
<< modTimedp->warnContextSecondary());
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
m_ftaskp = nullptr;
|
||||
if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); }
|
||||
if (nodep->dpiExport()) nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -235,11 +235,9 @@ private:
|
|||
fromp->cloneTree(false)));
|
||||
} else if (VN_IS(basefromp, Replicate)) {
|
||||
// From {...}[...] syntax in IEEE 2017
|
||||
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Select of concatenation");
|
||||
nodep = nullptr;
|
||||
if (basefromp) UINFO(1, " Related node: " << basefromp << endl);
|
||||
} else {
|
||||
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
|
||||
if (basefromp) UINFO(1, " Related node: " << basefromp << endl);
|
||||
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ private:
|
|||
return condp;
|
||||
} else if (AstAnd* const andp = VN_CAST(rhsp, And)) {
|
||||
if (AstNodeCond* const condp = VN_CAST(andp->rhsp(), NodeCond)) {
|
||||
if (VN_IS(andp->lhsp(), Const)) { return condp; }
|
||||
if (VN_IS(andp->lhsp(), Const)) return condp;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
|
@ -174,7 +174,9 @@ private:
|
|||
} else if (AstNodeCond* const condp = extractCond(rhsp)) {
|
||||
AstNode* const resp
|
||||
= condTrue ? condp->expr1p()->unlinkFrBack() : condp->expr2p()->unlinkFrBack();
|
||||
if (condp == rhsp) { return resp; }
|
||||
if (condp == rhsp) { //
|
||||
return resp;
|
||||
}
|
||||
if (AstAnd* const andp = VN_CAST(rhsp, And)) {
|
||||
UASSERT_OBJ(andp->rhsp() == condp, rhsp, "Should not try to fold this");
|
||||
return new AstAnd(andp->fileline(), andp->lhsp()->cloneTree(false), resp);
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ V3Number& V3Number::setLongS(vlsint32_t value) {
|
|||
return *this;
|
||||
}
|
||||
V3Number& V3Number::setDouble(double value) {
|
||||
if (VL_UNCOVERABLE(width() != 64)) { v3fatalSrc("Real operation on wrong sized number"); }
|
||||
if (VL_UNCOVERABLE(width() != 64)) v3fatalSrc("Real operation on wrong sized number");
|
||||
m_double = true;
|
||||
union {
|
||||
double d;
|
||||
|
|
@ -951,10 +951,10 @@ bool V3Number::isAnyZ() const {
|
|||
bool V3Number::isLtXZ(const V3Number& rhs) const {
|
||||
// Include X/Z in comparisons for sort ordering
|
||||
for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) {
|
||||
if (this->bitIs1(bit) && rhs.bitIs0(bit)) { return true; }
|
||||
if (rhs.bitIs1(bit) && this->bitIs0(bit)) { return false; }
|
||||
if (this->bitIsXZ(bit)) { return true; }
|
||||
if (rhs.bitIsXZ(bit)) { return false; }
|
||||
if (this->bitIs1(bit) && rhs.bitIs0(bit)) return true;
|
||||
if (rhs.bitIs1(bit) && this->bitIs0(bit)) return false;
|
||||
if (this->bitIsXZ(bit)) return true;
|
||||
if (rhs.bitIsXZ(bit)) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1347,14 +1347,14 @@ V3Number& V3Number::opLogAnd(const V3Number& lhs, const V3Number& rhs) {
|
|||
loutc = 1;
|
||||
break;
|
||||
}
|
||||
if (lhs.bitIsXZ(bit) && loutc == 0) { loutc = 'x'; }
|
||||
if (lhs.bitIsXZ(bit) && loutc == 0) loutc = 'x';
|
||||
}
|
||||
for (int bit = 0; bit < rhs.width(); bit++) {
|
||||
if (rhs.bitIs1(bit)) {
|
||||
routc = 1;
|
||||
break;
|
||||
}
|
||||
if (rhs.bitIsXZ(bit) && routc == 0) { routc = 'x'; }
|
||||
if (rhs.bitIsXZ(bit) && routc == 0) routc = 'x';
|
||||
}
|
||||
char outc = 'x';
|
||||
if (routc == 1 && loutc == 1) outc = 1;
|
||||
|
|
@ -1528,7 +1528,7 @@ bool V3Number::isCaseEq(const V3Number& rhs) const {
|
|||
if (this->width() != rhs.width()) return false;
|
||||
|
||||
for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) {
|
||||
if (this->bitIs(bit) != rhs.bitIs(bit)) { return false; }
|
||||
if (this->bitIs(bit) != rhs.bitIs(bit)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ private:
|
|||
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
|
||||
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
|
||||
}
|
||||
|
||||
public:
|
||||
bool bitIs0(int bit) const {
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return !bitIsXZ(m_width - 1);
|
||||
|
|
@ -144,6 +146,8 @@ private:
|
|||
return ((~m_value[bit / 32] & (1UL << (bit & 31)))
|
||||
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t bitsValue(int lsb, int nbits) const {
|
||||
uint32_t v = 0;
|
||||
for (int bitn = 0; bitn < nbits; bitn++) { v |= (bitIs1(lsb + bitn) << bitn); }
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ void test(const string& lhss, const string& op, const string& rhss, const string
|
|||
|
||||
V3Number ok(fl, 1);
|
||||
ok.opCaseEq(expnum, gotnum);
|
||||
if (ok.toUInt() != 1) { v3fatalSrc("%Error:Test FAILED"); }
|
||||
if (ok.toUInt() != 1) v3fatalSrc("%Error:Test FAILED");
|
||||
|
||||
free(l1);
|
||||
free(r1);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Os.h"
|
||||
#include "V3Options.h"
|
||||
|
|
@ -864,10 +865,10 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) {
|
|||
}
|
||||
|
||||
// Default prefix to the filename
|
||||
if (prefix() == "" && topModule() != "") m_prefix = string("V") + topModule();
|
||||
if (prefix() == "" && vFilesList.size() >= 1) {
|
||||
m_prefix = string("V") + V3Os::filenameNonExt(*(vFilesList.begin()));
|
||||
}
|
||||
if (prefix() == "" && topModule() != "")
|
||||
m_prefix = string("V") + AstNode::encodeName(topModule());
|
||||
if (prefix() == "" && vFilesList.size() >= 1)
|
||||
m_prefix = string("V") + AstNode::encodeName(V3Os::filenameNonExt(*(vFilesList.begin())));
|
||||
if (modPrefix() == "") m_modPrefix = prefix();
|
||||
|
||||
// Find files in makedir
|
||||
|
|
@ -1369,7 +1370,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||
string msg = sw + strlen("-Werror-");
|
||||
V3ErrorCode code(msg.c_str());
|
||||
if (code == V3ErrorCode::EC_ERROR) {
|
||||
if (!isFuture(msg)) { fl->v3fatal("Unknown warning specified: " << sw); }
|
||||
if (!isFuture(msg)) fl->v3fatal("Unknown warning specified: " << sw);
|
||||
} else {
|
||||
V3Error::pretendError(code, true);
|
||||
}
|
||||
|
|
@ -1402,7 +1403,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
|||
string msg = sw + strlen("-Wwarn-");
|
||||
V3ErrorCode code(msg.c_str());
|
||||
if (code == V3ErrorCode::EC_ERROR) {
|
||||
if (!isFuture(msg)) { fl->v3fatal("Unknown warning specified: " << sw); }
|
||||
if (!isFuture(msg)) fl->v3fatal("Unknown warning specified: " << sw);
|
||||
} else {
|
||||
FileLine::globalWarnOff(code, false);
|
||||
V3Error::pretendError(code, false);
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ public:
|
|||
for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (OrderLogicVertex* lvertexp = dynamic_cast<OrderLogicVertex*>(itp)) {
|
||||
T_MoveVertex* moveVxp = m_logic2move[lvertexp];
|
||||
if (moveVxp) { iterate(moveVxp, lvertexp, lvertexp->domainp()); }
|
||||
if (moveVxp) iterate(moveVxp, lvertexp, lvertexp->domainp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1661,7 +1661,7 @@ void OrderVisitor::processMovePrepReady() {
|
|||
UINFO(5, " MovePrepReady\n");
|
||||
for (OrderMoveVertex* vertexp = m_pomWaiting.begin(); vertexp;) {
|
||||
OrderMoveVertex* nextp = vertexp->pomWaitingNextp();
|
||||
if (vertexp->isWait() && vertexp->inEmpty()) { processMoveReadyOne(vertexp); }
|
||||
if (vertexp->isWait() && vertexp->inEmpty()) processMoveReadyOne(vertexp);
|
||||
vertexp = nextp;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ string V3Os::trueRandom(size_t size) {
|
|||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
NTSTATUS hr = BCryptGenRandom(nullptr, reinterpret_cast<BYTE*>(data), size,
|
||||
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
if (!BCRYPT_SUCCESS(hr)) { v3fatal("Could not acquire random data."); }
|
||||
if (!BCRYPT_SUCCESS(hr)) v3fatal("Could not acquire random data.");
|
||||
#else
|
||||
std::ifstream is("/dev/urandom", std::ios::in | std::ios::binary);
|
||||
// This read uses the size of the buffer.
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) {
|
|||
string V3ParseImp::lexParseTag(const char* textp) {
|
||||
string tmp = textp + strlen("/*verilator tag ");
|
||||
string::size_type pos;
|
||||
if ((pos = tmp.rfind("*/")) != string::npos) { tmp.erase(pos); }
|
||||
if ((pos = tmp.rfind("*/")) != string::npos) tmp.erase(pos);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +468,7 @@ void V3ParseImp::tokenPipeline() {
|
|||
V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead
|
||||
{
|
||||
size_t depth = tokenPipeScanParam(0);
|
||||
if (tokenPeekp(depth)->token == yP_COLONCOLON) { token = yaID__CC; }
|
||||
if (tokenPeekp(depth)->token == yP_COLONCOLON) token = yaID__CC;
|
||||
}
|
||||
yylval = curValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ void V3ParseImp::yylexReadTok() {
|
|||
void V3ParseImp::lexNew() {
|
||||
if (m_lexerp) delete m_lexerp; // Restart from clean slate.
|
||||
m_lexerp = new V3Lexer();
|
||||
if (debugFlex() >= 9) { m_lexerp->set_debug(~0); }
|
||||
if (debugFlex() >= 9) m_lexerp->set_debug(~0);
|
||||
}
|
||||
|
||||
void V3ParseImp::lexDestroy() {
|
||||
|
|
|
|||
|
|
@ -749,8 +749,8 @@ public:
|
|||
|| LogicMTask::pathExistsFrom(m_bp, m_ap, nullptr));
|
||||
}
|
||||
bool operator<(const SiblingMC& other) const {
|
||||
if (m_ap->id() < other.m_ap->id()) { return true; }
|
||||
if (m_ap->id() > other.m_ap->id()) { return false; }
|
||||
if (m_ap->id() < other.m_ap->id()) return true;
|
||||
if (m_ap->id() > other.m_ap->id()) return false;
|
||||
return m_bp->id() < other.m_bp->id();
|
||||
}
|
||||
};
|
||||
|
|
@ -1245,7 +1245,7 @@ private:
|
|||
for (SibpSet::iterator it = m_mtask2sibs[mtaskp].begin(); it != m_mtask2sibs[mtaskp].end();
|
||||
++it) {
|
||||
const SiblingMC* pairp = *it;
|
||||
if (!pairp->removedFromSb()) { m_sb.removeElem(pairp); }
|
||||
if (!pairp->removedFromSb()) m_sb.removeElem(pairp);
|
||||
LogicMTask* otherp = (pairp->bp() == mtaskp) ? pairp->ap() : pairp->bp();
|
||||
size_t erased = m_mtask2sibs[otherp].erase(pairp);
|
||||
UASSERT_OBJ(erased > 0, otherp, "Expected existing mtask");
|
||||
|
|
@ -1409,7 +1409,7 @@ private:
|
|||
return 1 + edgeScore(edgep);
|
||||
}
|
||||
const SiblingMC* sibsp = dynamic_cast<const SiblingMC*>(pairp);
|
||||
if (sibsp) { return siblingScore(sibsp); }
|
||||
if (sibsp) return siblingScore(sibsp);
|
||||
v3fatalSrc("Failed to cast pairp to either MTaskEdge or SiblingMC in mergeCandidateScore");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1472,10 +1472,10 @@ private:
|
|||
const LogicMTask* bp = *reinterpret_cast<const LogicMTask* const*>(vbp);
|
||||
uint32_t aCp = ap->critPathCost(*wp) + ap->stepCost();
|
||||
uint32_t bCp = bp->critPathCost(*wp) + bp->stepCost();
|
||||
if (aCp < bCp) { return -1; }
|
||||
if (aCp > bCp) { return 1; }
|
||||
if (ap->id() < bp->id()) { return -1; }
|
||||
if (ap->id() > bp->id()) { return 1; }
|
||||
if (aCp < bCp) return -1;
|
||||
if (aCp > bCp) return 1;
|
||||
if (ap->id() < bp->id()) return -1;
|
||||
if (ap->id() > bp->id()) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1534,7 +1534,7 @@ private:
|
|||
for (unsigned i = 0; i < chain_len; ++i) {
|
||||
LogicMTask* mtp = new LogicMTask(&mtasks, nullptr);
|
||||
mtp->setCost(1);
|
||||
if (lastp) { new MTaskEdge(&mtasks, lastp, mtp, 1); }
|
||||
if (lastp) new MTaskEdge(&mtasks, lastp, mtp, 1);
|
||||
lastp = mtp;
|
||||
}
|
||||
partInitCriticalPaths(&mtasks);
|
||||
|
|
@ -1802,7 +1802,7 @@ private:
|
|||
++it) {
|
||||
LogicMTask* mtaskp = *it;
|
||||
if (mergedp) {
|
||||
if (mergedp->cost() < mtaskp->cost()) { mergedp = mtaskp; }
|
||||
if (mergedp->cost() < mtaskp->cost()) mergedp = mtaskp;
|
||||
} else {
|
||||
mergedp = mtaskp;
|
||||
}
|
||||
|
|
@ -1983,7 +1983,7 @@ public:
|
|||
for (V3GraphVertex* vxp = m_mtasksp->verticesBeginp(); vxp;
|
||||
vxp = vxp->verticesNextp()) {
|
||||
LogicMTask* mtaskp = dynamic_cast<LogicMTask*>(vxp);
|
||||
if (hasDpiHazard(mtaskp)) { tasksByRank[vxp->rank()].insert(mtaskp); }
|
||||
if (hasDpiHazard(mtaskp)) tasksByRank[vxp->rank()].insert(mtaskp);
|
||||
}
|
||||
mergeSameRankTasks(&tasksByRank);
|
||||
}
|
||||
|
|
@ -2415,7 +2415,7 @@ void V3Partition::go(V3Graph* mtasksp) {
|
|||
mtasksp->orderPreRanked();
|
||||
|
||||
int targetParFactor = v3Global.opt.threads();
|
||||
if (targetParFactor < 2) { v3fatalSrc("We should not reach V3Partition when --threads <= 1"); }
|
||||
if (targetParFactor < 2) v3fatalSrc("We should not reach V3Partition when --threads <= 1");
|
||||
|
||||
// Set cpLimit to roughly totalGraphCost / nThreads
|
||||
//
|
||||
|
|
|
|||
|
|
@ -953,7 +953,7 @@ int V3PreProcImp::getStateToken() {
|
|||
|
||||
// Most states emit white space and comments between tokens. (Unless collecting a string)
|
||||
if (tok == VP_WHITE && state() != ps_STRIFY) return tok;
|
||||
if (tok == VP_BACKQUOTE && state() != ps_STRIFY) { tok = VP_TEXT; }
|
||||
if (tok == VP_BACKQUOTE && state() != ps_STRIFY) tok = VP_TEXT;
|
||||
if (tok == VP_COMMENT) {
|
||||
if (!m_off) {
|
||||
if (m_lexp->m_keepComments == KEEPCMT_SUB) {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public:
|
|||
// CONSTANTS
|
||||
enum MiscConsts {
|
||||
DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error
|
||||
LINE_TOKEN_MAX = 20000, // How many tokens on a line before an error
|
||||
LINE_TOKEN_MAX = 40000, // How many tokens on a line before an error
|
||||
INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error
|
||||
// Streams deep (sometimes `def deep) before an error.
|
||||
// Set more than DEFINE_RECURSION_LEVEL_MAX or INCLUDE_DEPTH_MAX.
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ private:
|
|||
m_tmpDeclsp = new AstTextBlock(fl);
|
||||
txtp->addNodep(m_tmpDeclsp);
|
||||
txtp->addText(fl, "\ntime last_combo_seqnum__V;\n");
|
||||
if (m_hasClk) { txtp->addText(fl, "time last_seq_seqnum__V;\n\n"); }
|
||||
if (m_hasClk) txtp->addText(fl, "time last_seq_seqnum__V;\n\n");
|
||||
|
||||
// CPP hash value
|
||||
addComment(txtp, fl, "Hash value to make sure this file and the corresponding");
|
||||
|
|
@ -425,7 +425,7 @@ private:
|
|||
m_comboPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->name() + "\n");
|
||||
m_comboIgnorePortsp->addNodep(varp->cloneTree(false));
|
||||
if (m_hasClk) { m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); }
|
||||
if (m_hasClk) m_comboIgnoreParamsp->addText(fl, varp->name() + "\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cComboInsp->addText(fl, cInputConnection(varp));
|
||||
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class SliceVisitor final : public AstNVisitor {
|
|||
AstNode* newp = nodep->cloneType // AstNodeAssign
|
||||
(cloneAndSel(nodep->lhsp(), elements, offset),
|
||||
cloneAndSel(nodep->rhsp(), elements, offset));
|
||||
if (debug() >= 9) { newp->dumpTree(cout, "-new "); }
|
||||
if (debug() >= 9) newp->dumpTree(cout, "-new ");
|
||||
newlistp = AstNode::addNextNull(newlistp, newp);
|
||||
}
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " Deslice-Dn: ");
|
||||
|
|
|
|||
|
|
@ -853,7 +853,7 @@ public:
|
|||
// If this is AstVarRef and referred in the sensitivity list of always@,
|
||||
// return the sensitivity item
|
||||
AstSenItem* backSenItemp() const {
|
||||
if (AstVarRef* refp = VN_CAST(m_nodep, VarRef)) { return VN_CAST(refp->backp(), SenItem); }
|
||||
if (AstVarRef* refp = VN_CAST(m_nodep, VarRef)) return VN_CAST(refp->backp(), SenItem);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
|
@ -971,7 +971,7 @@ class SplitPackedVarVisitor final : public AstNVisitor, public SplitVarImpl {
|
|||
nodep->attrSplitVar(false);
|
||||
} else { // Finally find a good candidate
|
||||
const bool inserted = m_refs.insert(std::make_pair(nodep, PackedVarRef(nodep))).second;
|
||||
if (inserted) { UINFO(3, nodep->prettyNameQ() << " is added to candidate list.\n"); }
|
||||
if (inserted) UINFO(3, nodep->prettyNameQ() << " is added to candidate list.\n");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ public:
|
|||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
degree++;
|
||||
}
|
||||
if (degree & 1) { result.push_back(tspvp->key()); }
|
||||
if (degree & 1) result.push_back(tspvp->key());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -402,7 +402,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
// Make this TSP implementation work for graphs of size 0 or 1
|
||||
// which, unfortunately, is a special case as the following
|
||||
// code assumes >= 2 nodes.
|
||||
if (states.empty()) { return; }
|
||||
if (states.empty()) return;
|
||||
if (states.size() == 1) {
|
||||
resultp->push_back(*(states.begin()));
|
||||
return;
|
||||
|
|
@ -482,7 +482,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
while (i != max_cost_idx) {
|
||||
new_result.push_back((*resultp)[i]);
|
||||
i++;
|
||||
if (i >= resultp->size()) { i = 0; }
|
||||
if (i >= resultp->size()) i = 0;
|
||||
}
|
||||
new_result.push_back((*resultp)[i]);
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,9 @@ private:
|
|||
if (m_totalBytes > TABLE_TOTAL_BYTES) {
|
||||
chkvis.clearOptimizable(nodep, "Table out of memory");
|
||||
}
|
||||
if (!m_outWidth || !m_inWidth) { chkvis.clearOptimizable(nodep, "Table has no outputs"); }
|
||||
if (!m_outWidth || !m_inWidth) { //
|
||||
chkvis.clearOptimizable(nodep, "Table has no outputs");
|
||||
}
|
||||
UINFO(4, " Test: Opt=" << (chkvis.optimizable() ? "OK" : "NO")
|
||||
<< ", Instrs=" << chkvis.instrCount()
|
||||
<< " Data=" << chkvis.dataCount() << " inw=" << m_inWidth
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ private:
|
|||
}
|
||||
// Likewise, all FTask->scope mappings
|
||||
for (AstNode* stmtp = nodep->blocksp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstNodeFTask* taskp = VN_CAST(stmtp, NodeFTask)) { taskp->user3p(nodep); }
|
||||
if (AstNodeFTask* taskp = VN_CAST(stmtp, NodeFTask)) taskp->user3p(nodep);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -786,8 +786,8 @@ private:
|
|||
// Static doesn't need save-restore as if below will re-fill proper value
|
||||
stmt += "static int __Vfuncnum = -1;\n";
|
||||
// First time init (faster than what the compiler does if we did a singleton
|
||||
stmt += "if (VL_UNLIKELY(__Vfuncnum==-1)) { __Vfuncnum = Verilated::exportFuncNum(\""
|
||||
+ nodep->cname() + "\"); }\n";
|
||||
stmt += "if (VL_UNLIKELY(__Vfuncnum == -1)) __Vfuncnum = Verilated::exportFuncNum(\""
|
||||
+ nodep->cname() + "\");\n";
|
||||
// If the find fails, it will throw an error
|
||||
stmt += "const VerilatedScope* __Vscopep = Verilated::dpiScope();\n";
|
||||
// If dpiScope is fails and is null; the exportFind function throws and error
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "V3Stats.h"
|
||||
|
||||
#include <map>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -299,7 +300,7 @@ private:
|
|||
nextp = itp->verticesNextp();
|
||||
if (TraceActivityVertex* const vtxp = dynamic_cast<TraceActivityVertex*>(itp)) {
|
||||
// Leave in the always vertex for later use.
|
||||
if (vtxp != m_alwaysVtxp && !vtxp->outBeginp()) { vtxp->unlinkDelete(&m_graph); }
|
||||
if (vtxp != m_alwaysVtxp && !vtxp->outBeginp()) vtxp->unlinkDelete(&m_graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -645,7 +646,7 @@ private:
|
|||
}
|
||||
}
|
||||
ifp = new AstIf(flp, condp, nullptr, nullptr);
|
||||
if (!always) { ifp->branchPred(VBranchPred::BP_UNLIKELY); }
|
||||
if (!always) ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
subFuncp->addStmtsp(ifp);
|
||||
subStmts += EmitCBaseCounterVisitor(ifp).count();
|
||||
prevActSet = &actSet;
|
||||
|
|
|
|||
|
|
@ -295,7 +295,15 @@ private:
|
|||
VL_RESTORER(m_traShowname);
|
||||
VL_RESTORER(m_traValuep);
|
||||
{
|
||||
m_traShowname += string(" ") + itemp->prettyName();
|
||||
// Add @ to mark as struct
|
||||
// Since it is not a valid symbol for verilog variable names, no
|
||||
// collision should happen
|
||||
if (v3Global.opt.traceFormat().fst()) {
|
||||
m_traShowname += string(" ") + itemp->prettyName();
|
||||
} else {
|
||||
m_traShowname += string("\f ") + itemp->prettyName();
|
||||
}
|
||||
|
||||
if (VN_IS(nodep, StructDType)) {
|
||||
m_traValuep
|
||||
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
|
||||
|
|
|
|||
|
|
@ -365,10 +365,10 @@ private:
|
|||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
if (bodysp) { VL_DO_DANGLING(pushDeletep(bodysp), bodysp); }
|
||||
if (precondsp) { VL_DO_DANGLING(pushDeletep(precondsp), precondsp); }
|
||||
if (initp) { VL_DO_DANGLING(pushDeletep(initp), initp); }
|
||||
if (incp && !incp->backp()) { VL_DO_DANGLING(pushDeletep(incp), incp); }
|
||||
if (bodysp) VL_DO_DANGLING(pushDeletep(bodysp), bodysp);
|
||||
if (precondsp) VL_DO_DANGLING(pushDeletep(precondsp), precondsp);
|
||||
if (initp) VL_DO_DANGLING(pushDeletep(initp), initp);
|
||||
if (incp && !incp->backp()) VL_DO_DANGLING(pushDeletep(incp), incp);
|
||||
if (debug() >= 9 && newbodysp) newbodysp->dumpTree(cout, "- _new: ");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -385,7 +385,7 @@ private:
|
|||
// Grab initial value
|
||||
AstNode* initp = nullptr; // Should be statement before the while.
|
||||
if (nodep->backp()->nextp() == nodep) initp = nodep->backp();
|
||||
if (initp) { VL_DO_DANGLING(V3Const::constifyEdit(initp), initp); }
|
||||
if (initp) VL_DO_DANGLING(V3Const::constifyEdit(initp), initp);
|
||||
if (nodep->backp()->nextp() == nodep) initp = nodep->backp();
|
||||
// Grab assignment
|
||||
AstNode* incp = nullptr; // Should be last statement
|
||||
|
|
|
|||
|
|
@ -804,8 +804,8 @@ private:
|
|||
}
|
||||
// We're extracting, so just make sure the expression is at least wide enough.
|
||||
if (nodep->fromp()->width() < width) {
|
||||
nodep->v3error("Extracting " << width << " bits from only "
|
||||
<< nodep->fromp()->width() << " bit number");
|
||||
nodep->v3warn(SELRANGE, "Extracting " << width << " bits from only "
|
||||
<< nodep->fromp()->width() << " bit number");
|
||||
// Extend it.
|
||||
AstNodeDType* subDTypep
|
||||
= nodep->findLogicDType(width, width, nodep->fromp()->dtypep()->numeric());
|
||||
|
|
@ -2669,7 +2669,7 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"r_" + nodep->name(), withp);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) { newp->makeStatement(); }
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique"
|
||||
|| nodep->name() == "unique_index") {
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
|
|
@ -2762,7 +2762,7 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"r_" + nodep->name(), withp);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) { newp->makeStatement(); }
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|
||||
|| nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
AstWith* withp = nullptr;
|
||||
|
|
@ -2876,7 +2876,7 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
nodep->name(), nullptr);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) { newp->makeStatement(); }
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "push_back" || nodep->name() == "push_front") {
|
||||
methodOkArguments(nodep, 1, 1);
|
||||
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
|
||||
|
|
@ -2894,7 +2894,7 @@ private:
|
|||
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
|
||||
"r_" + nodep->name(), withp);
|
||||
newp->dtypeFrom(adtypep->subDTypep());
|
||||
if (!nodep->firstAbovep()) { newp->makeStatement(); }
|
||||
if (!nodep->firstAbovep()) newp->makeStatement();
|
||||
} else if (nodep->name() == "reverse" || nodep->name() == "shuffle"
|
||||
|| nodep->name() == "sort" || nodep->name() == "rsort") {
|
||||
AstWith* withp = nullptr;
|
||||
|
|
@ -3427,9 +3427,10 @@ private:
|
|||
void patternArray(AstPattern* nodep, AstNodeArrayDType* arrayDtp, AstPatMember* defaultp) {
|
||||
VNumRange range = arrayDtp->declRange();
|
||||
PatVecMap patmap = patVectorMap(nodep, range);
|
||||
UINFO(9, "ent " << range.hi() << " to " << range.lo() << endl);
|
||||
UINFO(9, "ent " << range.left() << " to " << range.right() << endl);
|
||||
AstNode* newp = nullptr;
|
||||
for (int ent = range.hi(); ent >= range.lo(); --ent) {
|
||||
for (int entn = 0, ent = range.left(); entn < range.elements();
|
||||
++entn, ent += range.leftToRightInc()) {
|
||||
AstPatMember* newpatp = nullptr;
|
||||
AstPatMember* patp = nullptr;
|
||||
const auto it = patmap.find(ent);
|
||||
|
|
@ -5592,7 +5593,7 @@ private:
|
|||
AstNodeBiop* replaceWithDVersion(AstNodeBiop* nodep) {
|
||||
// Given a signed/unsigned node type, create the opposite type
|
||||
// Return new node or nullptr if nothing
|
||||
if (nodep->doubleFlavor()) { return nullptr; }
|
||||
if (nodep->doubleFlavor()) return nullptr;
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ private:
|
|||
nodep->replaceWith(fromp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); }
|
||||
if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp);
|
||||
}
|
||||
virtual void visit(AstSelExtract* nodep) override {
|
||||
// Select of a range specified part of an array, i.e. "array[2:3]"
|
||||
|
|
@ -369,10 +369,11 @@ private:
|
|||
lsb = x;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["
|
||||
<< msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<< lsb << ":" << msb << "]");
|
||||
nodep->v3warn(
|
||||
SELRANGE,
|
||||
"[" << msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted [" << lsb
|
||||
<< ":" << msb << "]");
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
|
|
@ -398,10 +399,11 @@ private:
|
|||
lsb = x;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["
|
||||
<< msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<< lsb << ":" << msb << "]");
|
||||
nodep->v3warn(
|
||||
SELRANGE,
|
||||
"[" << msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted [" << lsb
|
||||
<< ":" << msb << "]");
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
|
|
@ -419,10 +421,11 @@ private:
|
|||
} else if (VN_IS(ddtypep, NodeUOrStructDType)) {
|
||||
// Classes aren't little endian
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["
|
||||
<< msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<< lsb << ":" << msb << "]");
|
||||
nodep->v3warn(
|
||||
SELRANGE,
|
||||
"[" << msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted [" << lsb
|
||||
<< ":" << msb << "]");
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
|
|
@ -455,9 +458,9 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
// delete whatever we didn't use in reconstruction
|
||||
if (!fromp->backp()) { VL_DO_DANGLING(pushDeletep(fromp), fromp); }
|
||||
if (!msbp->backp()) { VL_DO_DANGLING(pushDeletep(msbp), msbp); }
|
||||
if (!lsbp->backp()) { VL_DO_DANGLING(pushDeletep(lsbp), lsbp); }
|
||||
if (!fromp->backp()) VL_DO_DANGLING(pushDeletep(fromp), fromp);
|
||||
if (!msbp->backp()) VL_DO_DANGLING(pushDeletep(msbp), msbp);
|
||||
if (!lsbp->backp()) VL_DO_DANGLING(pushDeletep(lsbp), lsbp);
|
||||
}
|
||||
|
||||
void replaceSelPlusMinus(AstNodePreSel* nodep) {
|
||||
|
|
@ -560,9 +563,9 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
// delete whatever we didn't use in reconstruction
|
||||
if (!fromp->backp()) { VL_DO_DANGLING(pushDeletep(fromp), fromp); }
|
||||
if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); }
|
||||
if (!widthp->backp()) { VL_DO_DANGLING(pushDeletep(widthp), widthp); }
|
||||
if (!fromp->backp()) VL_DO_DANGLING(pushDeletep(fromp), fromp);
|
||||
if (!rhsp->backp()) VL_DO_DANGLING(pushDeletep(rhsp), rhsp);
|
||||
if (!widthp->backp()) VL_DO_DANGLING(pushDeletep(widthp), widthp);
|
||||
}
|
||||
virtual void visit(AstSelPlus* nodep) override { replaceSelPlusMinus(nodep); }
|
||||
virtual void visit(AstSelMinus* nodep) override { replaceSelPlusMinus(nodep); }
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ void VlcTop::annotateCalc() {
|
|||
for (int lni = start; start && lni <= end; ++lni) {
|
||||
source.incCount(lni, point.column(), point.count(), ok);
|
||||
}
|
||||
if (!*covp) { break; }
|
||||
if (!*covp) break;
|
||||
start = 0; // Prep for next
|
||||
end = 0;
|
||||
range = false;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
998
src/bisonpre
998
src/bisonpre
File diff suppressed because it is too large
Load Diff
|
|
@ -1380,9 +1380,9 @@ portDirNetE: // IEEE: part of port, optional net type and/or direction
|
|||
/* empty */ { }
|
||||
// // Per spec, if direction given default the nettype.
|
||||
// // The higher level rule may override this VARDTYPE with one later in the parse.
|
||||
| port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr/*default_nettype*/); }
|
||||
| port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr/*default_nettype*/); } // net_type calls VARDECL
|
||||
| net_type { } // net_type calls VARDECL
|
||||
| port_direction { VARDECL(PORT); VARDTYPE_NDECL(nullptr); }
|
||||
| port_direction { VARDECL(PORT); } net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL
|
||||
| net_type { VARDTYPE_NDECL(nullptr); } // net_type calls VARDECL
|
||||
;
|
||||
|
||||
port_declNetE: // IEEE: part of port_declaration, optional net type
|
||||
|
|
@ -2209,7 +2209,7 @@ type_declaration<nodep>: // ==IEEE: type_declaration
|
|||
AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true);
|
||||
$$ = GRAMMARP->createTypedef($<fl>5, *$5, $7, dtp, $6); }
|
||||
// //
|
||||
| yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';'
|
||||
| yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ dtypeAttrListE ';'
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); }
|
||||
// // Allow redeclaring same typedef again
|
||||
// // Alternative is use of idAny below, but this will cause conflicts with ablve
|
||||
|
|
|
|||
|
|
@ -598,15 +598,19 @@ sub new {
|
|||
.(($^O eq "darwin" )
|
||||
? " -Wl,-undefined,dynamic_lookup"
|
||||
: " -export-dynamic")
|
||||
.($opt_verbose ? " -DTEST_VERBOSE=1":"")
|
||||
." -o $self->{obj_dir}/libvpi.so"],
|
||||
tool_c_flags => [],
|
||||
# ATSIM
|
||||
atsim => 0,
|
||||
atsim_define => 'ATSIM',
|
||||
atsim_flags => [split(/\s+/,"-c +sv +define+ATSIM"),
|
||||
"+sv_dir+$self->{obj_dir}/.athdl_compile"],
|
||||
atsim_flags2 => [], # Overridden in some sim files
|
||||
atsim_run_flags => [],
|
||||
# GHDL
|
||||
ghdl => 0,
|
||||
ghdl_define => 'GHDL',
|
||||
ghdl_work_dir => "$self->{obj_dir}/ghdl_compile",
|
||||
ghdl_flags => [($::Debug?"-v":""),
|
||||
"--workdir=$self->{obj_dir}/ghdl_compile", ],
|
||||
|
|
@ -614,29 +618,34 @@ sub new {
|
|||
ghdl_run_flags => [],
|
||||
# IV
|
||||
iv => 0,
|
||||
iv_define => 'IVERILOG',
|
||||
iv_flags => [split(/\s+/,"+define+IVERILOG -g2012 -o $self->{obj_dir}/simiv")],
|
||||
iv_flags2 => [], # Overridden in some sim files
|
||||
iv_pli => 0, # need to use pli
|
||||
iv_run_flags => [],
|
||||
# VCS
|
||||
vcs => 0,
|
||||
vcs_define => 'VCS',
|
||||
vcs_flags => [split(/\s+/,"+vcs+lic+wait +cli -debug_access +define+VCS+1 -q -sverilog -CFLAGS '-DVCS' ")],
|
||||
vcs_flags2 => [], # Overridden in some sim files
|
||||
vcs_run_flags => [split(/\s+/,"+vcs+lic_wait")],
|
||||
# NC
|
||||
nc => 0,
|
||||
nc_define => 'NC',
|
||||
nc_flags => [split(/\s+/,("+licqueue +nowarn+LIBNOU +define+NC=1 -q +assert +sv -c "
|
||||
.($opt_trace ? " +access+r":"")))],
|
||||
nc_flags2 => [], # Overridden in some sim files
|
||||
nc_run_flags => [split(/\s+/,"+licqueue -q +assert +sv -R")],
|
||||
# ModelSim
|
||||
ms => 0,
|
||||
ms_define => 'MS',
|
||||
ms_flags => [split(/\s+/, ("-sv -work $self->{obj_dir}/work +define+MS=1 -ccflags \"-DMS=1\""))],
|
||||
ms_flags2 => [], # Overridden in some sim files
|
||||
ms_pli => 1, # need to use pli
|
||||
ms_run_flags => [split(/\s+/,"-lib $self->{obj_dir}/work -c -do 'run -all;quit' ")],
|
||||
# XSim
|
||||
xsim => 0,
|
||||
xsim_define => 'XSIM',
|
||||
xsim_flags => [split(/\s+/,("--nolog --sv --define XSIM --work $self->{name}=$self->{obj_dir}/xsim"))],
|
||||
xsim_flags2 => [], # Overridden in some sim files
|
||||
xsim_run_flags => [split(/\s+/,("--nolog --runall --lib $self->{name}=$self->{obj_dir}/xsim"
|
||||
|
|
@ -645,6 +654,7 @@ sub new {
|
|||
# Verilator
|
||||
vlt => 0,
|
||||
vltmt => 0,
|
||||
verilator_define => 'VERILATOR',
|
||||
verilator_flags => ["-cc",
|
||||
"-Mdir $self->{obj_dir}",
|
||||
"-OD", # As currently disabled unless -O3
|
||||
|
|
@ -886,6 +896,7 @@ sub compile_vlt_flags {
|
|||
unshift @verilator_flags, "--trace-threads 1" if $param{vltmt} && $checkflags =~ /-trace /;
|
||||
unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /;
|
||||
unshift @verilator_flags, "--debug-partition" if $param{vltmt};
|
||||
unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim;
|
||||
unshift @verilator_flags, "-CFLAGS -fsanitize=address -LDFLAGS -fsanitize=address" if $param{sanitize};
|
||||
unshift @verilator_flags, "--make gmake" if $param{verilator_make_gmake};
|
||||
unshift @verilator_flags, "--make cmake" if $param{verilator_make_cmake};
|
||||
|
|
@ -957,6 +968,7 @@ sub compile {
|
|||
}
|
||||
|
||||
if ($param{atsim}) {
|
||||
$param{tool_define} ||= $param{atsim_define};
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/atsim_compile.log",
|
||||
fails=>$param{fails},
|
||||
|
|
@ -971,6 +983,7 @@ sub compile {
|
|||
]);
|
||||
}
|
||||
elsif ($param{ghdl}) {
|
||||
$param{tool_define} ||= $param{ghdl_define};
|
||||
mkdir $self->{ghdl_work_dir};
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/ghdl_compile.log",
|
||||
|
|
@ -989,6 +1002,7 @@ sub compile {
|
|||
]);
|
||||
}
|
||||
elsif ($param{vcs}) {
|
||||
$param{tool_define} ||= $param{vcs_define};
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/vcs_compile.log",
|
||||
fails=>$param{fails},
|
||||
|
|
@ -1003,6 +1017,7 @@ sub compile {
|
|||
]);
|
||||
}
|
||||
elsif ($param{nc}) {
|
||||
$param{tool_define} ||= $param{nc_define};
|
||||
$self->_make_top();
|
||||
my @more_args;
|
||||
if ($self->vhdl) {
|
||||
|
|
@ -1024,6 +1039,7 @@ sub compile {
|
|||
]);
|
||||
}
|
||||
elsif ($param{ms}) {
|
||||
$param{tool_define} ||= $param{ms_define};
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/ms_compile.log",
|
||||
fails=>$param{fails},
|
||||
|
|
@ -1039,6 +1055,7 @@ sub compile {
|
|||
]);
|
||||
}
|
||||
elsif ($param{iv}) {
|
||||
$param{tool_define} ||= $param{iv_define};
|
||||
$self->_make_top();
|
||||
my @cmd = (($ENV{VERILATOR_IVERILOG}||"iverilog"),
|
||||
@{$param{iv_flags}},
|
||||
|
|
@ -1055,6 +1072,7 @@ sub compile {
|
|||
cmd=>\@cmd);
|
||||
}
|
||||
elsif ($param{xsim}) {
|
||||
$param{tool_define} ||= $param{xsim_define};
|
||||
$self->_make_top();
|
||||
$self->_run(logfile=>"$self->{obj_dir}/xsim_compile.log",
|
||||
fails=>$param{fails},
|
||||
|
|
@ -1069,6 +1087,7 @@ sub compile {
|
|||
]);
|
||||
}
|
||||
elsif ($param{vlt_all}) {
|
||||
$param{tool_define} ||= $param{verilator_define};
|
||||
|
||||
if ($self->sc && !$self->have_sc) {
|
||||
$self->skip("Test requires SystemC; ignore error since not installed\n");
|
||||
|
|
@ -1166,7 +1185,9 @@ sub compile {
|
|||
|
||||
if ($param{make_pli}) {
|
||||
$self->oprint("Compile vpi\n") if $self->{verbose};
|
||||
my @cmd = ($ENV{CXX}, @{$param{pli_flags}}, "-DIS_VPI", $ENV{CFLAGS},
|
||||
my @cmd = ($ENV{CXX}, @{$param{pli_flags}},
|
||||
"-D".$param{tool_define},
|
||||
"-DIS_VPI", ($ENV{CFLAGS}||''),
|
||||
"$self->{t_dir}/$self->{pli_filename}");
|
||||
|
||||
$self->_run(logfile=>"$self->{obj_dir}/pli_compile.log",
|
||||
|
|
@ -1219,7 +1240,7 @@ sub execute {
|
|||
@{$param{iv_run_flags}},
|
||||
@{$param{all_run_flags}},
|
||||
);
|
||||
if ($param{iv_pli}) {
|
||||
if ($param{use_libvpi}) {
|
||||
# don't enter command line on $stop, include vpi
|
||||
unshift @cmd, "vvp -n -m $self->{obj_dir}/libvpi.so";
|
||||
}
|
||||
|
|
@ -1233,7 +1254,7 @@ sub execute {
|
|||
}
|
||||
elsif ($param{ms}) {
|
||||
my @pli_opt=();
|
||||
if ($param{ms_pli}) {
|
||||
if ($param{use_libvpi}) {
|
||||
unshift @pli_opt, "-pli $self->{obj_dir}/libvpi.so";
|
||||
}
|
||||
$self->_run(logfile=>"$self->{obj_dir}/ms_sim.log",
|
||||
|
|
@ -1385,6 +1406,12 @@ sub errors {
|
|||
return $self->{errors};
|
||||
}
|
||||
|
||||
sub golden_filename {
|
||||
my $self = (ref $_[0]? shift : $Self);
|
||||
$self->{golden_filename} = shift if defined $_[0];
|
||||
return $self->{golden_filename};
|
||||
}
|
||||
|
||||
sub scenario_off {
|
||||
my $self = (ref $_[0]? shift : $Self);
|
||||
return $self->{scenario_off};
|
||||
|
|
@ -1711,7 +1738,7 @@ sub _make_main {
|
|||
if (!$self->sc) {
|
||||
if ($self->{vl_time_stamp64}) {
|
||||
print $fh "vluint64_t main_time = 0;\n";
|
||||
print $fh "vluint64_t vl_time_stamp() { return main_time; }\n";
|
||||
print $fh "vluint64_t vl_time_stamp64() { return main_time; }\n";
|
||||
} else {
|
||||
print $fh "double main_time = 0;\n";
|
||||
print $fh "double sc_time_stamp() { return main_time; }\n";
|
||||
|
|
@ -1818,7 +1845,7 @@ sub _make_main {
|
|||
$fh->print(" if (sc_time_stamp() == save_time && save_time) {\n");
|
||||
$fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n");
|
||||
$fh->print(" printf(\"Exiting after save_model\\n\");\n");
|
||||
$fh->print(" exit(0);\n");
|
||||
$fh->print(" return 0;\n");
|
||||
$fh->print(" }\n");
|
||||
}
|
||||
_print_advance_time($self, $fh, 1, $action);
|
||||
|
|
@ -1843,7 +1870,7 @@ sub _make_main {
|
|||
$fh->print("\n");
|
||||
|
||||
print $fh " topp.reset();\n";
|
||||
print $fh " exit(0L);\n";
|
||||
print $fh " return 0;\n";
|
||||
print $fh "}\n";
|
||||
$fh->close();
|
||||
}
|
||||
|
|
@ -2232,7 +2259,7 @@ sub _vcd_read {
|
|||
my @hier = ($data);
|
||||
my $lasthier;
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
if ($line =~ /\$scope module\s+(\S+)/) {
|
||||
if ($line =~ /\$scope (module|struct)\s+(\S+)/) {
|
||||
$hier[$#hier]->{$1} ||= {};
|
||||
push @hier, $hier[$#hier]->{$1};
|
||||
$lasthier = $hier[$#hier];
|
||||
|
|
|
|||
|
|
@ -11,17 +11,22 @@
|
|||
|
||||
#include "vpi_user.h"
|
||||
|
||||
// Avoid C++11 in this file as not all simulators allow it
|
||||
|
||||
//======================================================================
|
||||
|
||||
class TestVpiHandle {
|
||||
/// For testing, etc, wrap vpiHandle in an auto-releasing class
|
||||
vpiHandle m_handle = NULL;
|
||||
bool m_freeit = true;
|
||||
vpiHandle m_handle; // No = as no C++11
|
||||
bool m_freeit; // No = as no C++11
|
||||
|
||||
public:
|
||||
TestVpiHandle() {}
|
||||
TestVpiHandle()
|
||||
: m_handle(NULL)
|
||||
, m_freeit(true) {}
|
||||
TestVpiHandle(vpiHandle h)
|
||||
: m_handle(h) {}
|
||||
: m_handle(h)
|
||||
, m_freeit(true) {}
|
||||
~TestVpiHandle() { release(); }
|
||||
operator vpiHandle() const { return m_handle; }
|
||||
inline TestVpiHandle& operator=(vpiHandle h) {
|
||||
|
|
@ -32,7 +37,11 @@ public:
|
|||
void release() {
|
||||
if (m_handle && m_freeit) {
|
||||
// Below not VL_DO_DANGLING so is portable
|
||||
#ifdef IVERILOG
|
||||
vpi_free_object(m_handle);
|
||||
#else
|
||||
vpi_release_handle(m_handle);
|
||||
#endif
|
||||
m_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2019 by Wilson Snyder. This program is free software; you
|
||||
# Copyright 2021 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.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
// please note it here, otherwise:**
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by ____YOUR_NAME_HERE____.
|
||||
// any use, without warranty, 2021 by ____YOUR_NAME_HERE____.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@ typedef struct packed {
|
|||
// verilator lint_on LITENDIAN
|
||||
} t2;
|
||||
|
||||
logic [2:0][31:0] test2l;
|
||||
// verilator lint_off LITENDIAN
|
||||
logic [0:2][31:0] test2b;
|
||||
logic [0:2][31:0] test1b;
|
||||
// verilator lint_on LITENDIAN
|
||||
logic [2:0][31:0] test1l;
|
||||
|
||||
module t;
|
||||
t2 t;
|
||||
initial begin
|
||||
|
|
@ -65,6 +72,23 @@ module t;
|
|||
t.dl[7] = 1'b1;
|
||||
`checkh(t, 80'h80_0002040000100800_01);
|
||||
|
||||
test1b = '{0, 1, 2};
|
||||
test1l = test1b;
|
||||
test2l = '{2, 1, 0};
|
||||
test2b = test2l;
|
||||
`checkh(test2l[0], 0);
|
||||
`checkh(test2l[2], 2);
|
||||
`checkh(test2l, {32'h2, 32'h1, 32'h0});
|
||||
`checkh(test2b[0], 2);
|
||||
`checkh(test2b[2], 0);
|
||||
`checkh(test2b, {32'h2, 32'h1, 32'h0});
|
||||
`checkh(test1b[0], 0);
|
||||
`checkh(test1b[2], 2);
|
||||
`checkh(test1b, {32'h0, 32'h1, 32'h2});
|
||||
`checkh(test1l[0], 2);
|
||||
`checkh(test1l[2], 0);
|
||||
`checkh(test1l, {32'h0, 32'h1, 32'h2});
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ module t (/*AUTOARG*/
|
|||
.toggle (toggle),
|
||||
.cyc (cyc[31:0]));
|
||||
|
||||
Sub sub1 (.*);
|
||||
Sub sub2 (.*);
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
|
|
@ -142,3 +145,14 @@ module Test
|
|||
`endif
|
||||
|
||||
endmodule
|
||||
|
||||
module Sub
|
||||
(
|
||||
input clk,
|
||||
input integer cyc
|
||||
);
|
||||
|
||||
// Simple cover, per-instance
|
||||
pi_sub:
|
||||
cover property (@(posedge clk) cyc == 3);
|
||||
endmodule
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue