Merge from master for release.

This commit is contained in:
Wilson Snyder 2021-02-25 21:49:42 -05:00
commit 702140bf93
241 changed files with 3762 additions and 2200 deletions

View File

@ -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
View File

@ -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.

View File

@ -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:

View File

@ -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);
}

View File

@ -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"

View File

@ -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

View 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

View File

@ -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)

View File

@ -54,7 +54,7 @@ run:
@echo
@echo "-- BUILD -------------------"
cmake --build build
cmake --build build -j
@echo
@echo "-- RUN ---------------------"

View File

@ -90,7 +90,7 @@ run:
@echo
@echo "-- BUILD -------------------"
cmake --build build
cmake --build build -j
@echo
@echo "-- RUN ---------------------"

View File

@ -54,7 +54,7 @@ run:
@echo
@echo "-- BUILD -------------------"
cmake --build build
cmake --build build -j
@echo
@echo "-- RUN ---------------------"

View File

@ -54,7 +54,7 @@ run:
@echo
@echo "-- BUILD -------------------"
cmake --build build
cmake --build build -j
@echo
@echo "-- RUN ---------------------"

View File

@ -90,7 +90,7 @@ run:
@echo
@echo "-- BUILD -------------------"
cmake --build build
cmake --build build -j
@echo
@echo "-- RUN ---------------------"

View File

@ -38,5 +38,5 @@ int main(int argc, char** argv, char** env) {
delete top;
// Return good completion status
exit(0);
return 0;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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() {

View File

@ -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]);
}
}

View File

@ -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;

View File

@ -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; }

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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:

View File

@ -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););

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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; }

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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.
}

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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());

View File

@ -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");
}
};

View File

@ -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";
}

View File

@ -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();

View File

@ -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");

View File

@ -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;

View File

@ -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() << "\""

View File

@ -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) \

View File

@ -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;

View File

@ -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());
}

View File

@ -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()) {

View File

@ -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";
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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()) {

View File

@ -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";
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}
};

View File

@ -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);
}

View File

@ -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) {

View File

@ -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());

View File

@ -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");
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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); }

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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() {

View File

@ -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
//

View File

@ -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) {

View File

@ -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.

View File

@ -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");

View File

@ -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: ");

View File

@ -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 {

View File

@ -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]);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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),

View File

@ -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

View File

@ -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();

View File

@ -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); }

View File

@ -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;

1400
src/astgen Normal file → Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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];

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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*/

View File

@ -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

View File

@ -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