Compare commits
57 Commits
ccf42c78bc
...
fc0389f436
Author | SHA1 | Date |
---|---|---|
![]() |
fc0389f436 | |
![]() |
fa62cd3486 | |
![]() |
10ac99ac05 | |
![]() |
b408e097f6 | |
![]() |
94bebb2bcb | |
![]() |
2be257369a | |
![]() |
04c38d5b3b | |
![]() |
4882a3c827 | |
![]() |
e995646898 | |
![]() |
2287d420ee | |
![]() |
db5b2669fc | |
![]() |
460bfbf181 | |
![]() |
050e5ddb5b | |
![]() |
393f0e4acb | |
![]() |
7c5d462564 | |
![]() |
763183f067 | |
![]() |
2958a5aaae | |
![]() |
344fabf56a | |
![]() |
9f04ee68c8 | |
![]() |
b5126a6abe | |
![]() |
74d4b0c0ea | |
![]() |
7401a8a43a | |
![]() |
7646e7d89c | |
![]() |
a8dca71ed0 | |
![]() |
98b8d43a4a | |
![]() |
d419c49921 | |
![]() |
a50ea2a1a6 | |
![]() |
078bb21a89 | |
![]() |
b8b9478938 | |
![]() |
f535a73ea7 | |
![]() |
641e0e5672 | |
![]() |
9d146eae16 | |
![]() |
7d43a935bd | |
![]() |
9b99d9697f | |
![]() |
a21ecb2ab9 | |
![]() |
28808f38bb | |
![]() |
7a6775ca84 | |
![]() |
e527ff49a3 | |
![]() |
c1506deef9 | |
![]() |
87050670b4 | |
![]() |
fb1373b854 | |
![]() |
7f1011e5f7 | |
![]() |
7a32771c7e | |
![]() |
94b043d6c9 | |
![]() |
8c5ba3a0d7 | |
![]() |
826e5b0826 | |
![]() |
abd509ce53 | |
![]() |
1bf24c7eb4 | |
![]() |
1f0357ba93 | |
![]() |
db6b17fdb4 | |
![]() |
f3e109d8c5 | |
![]() |
371ac07c6f | |
![]() |
caf3522364 | |
![]() |
03e0d49d99 | |
![]() |
74d912e3fb | |
![]() |
1610cccbc2 | |
![]() |
3268bbe083 |
27
Changes
27
Changes
|
@ -14,19 +14,38 @@ Verilator 5.039 devel
|
|||
**Other:**
|
||||
|
||||
* Add ENUMITEMWIDTH error, and apply to X-extended and ranged values.
|
||||
* Add NOEFFECT warning, replacing previous `foreach` error.
|
||||
* Add SPECIFYIGN warning for specify constructs that were previously silently ignored.
|
||||
* Add enum base data type, and wire data type checking per IEEE.
|
||||
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
|
||||
* Support disabling a fork in additional contexts (#5432 partial) (#6174) (#6183). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Support disable dotted references (#6154). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Support randomize() on class member selects (#6161). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Support multiple variables on RHS of a `force` assignment (#6163). [Artur Bieniek, Antmicro Ltd.]]
|
||||
* Support randomize() on class member selects (#6161) (#6195). [Igor Zaworski, Ryszard Rozak, Antmicro Ltd.]
|
||||
* Support multiple variables on RHS of a `force` assignment (#6163). [Artur Bieniek, Antmicro Ltd.]
|
||||
* Support covergroup extends, etc., as unsupported (#6160). [Artur Bieniek, Antmicro Ltd.]
|
||||
* Change control file `public_flat_*` and other signal attributes to support __ in names (#6140).
|
||||
* Optimize to return memory when using -build (#6192) (#6226). [Michael B. Taylor]
|
||||
* Optimize 2 ** X to 1 << X if base is signed (#6203). [Max Wipfli]
|
||||
* Optimize more complex combinational assignments in DFG (#6205) (#6209). [Geza Lore]
|
||||
* Optimize combinational cycles through arrays in DFG (#6210). [Geza Lore]
|
||||
* Fix constructor parameters in inheritance hierarchies (#6036) (#6070). [Petr Nohavica]
|
||||
* Fix replicate of negative giving 'REPLICATE has no expected width' internal error (#6048) (#6229).
|
||||
* Fix cmake `-Wno` compiler flag testing (#6145). [Martin Stadler]
|
||||
* Fix class extends dotted error (#6162). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Fix genvar error with `-O0` (#6165). [Max Wipfli]
|
||||
* Fix uninitialized thread PGO counters (#6167). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Fix additional UNOPTFLAT combinational cycles automatically in DFG (#6168) (#6173). [Geza Lore]
|
||||
* Fix omitting error when assigning to an input (#6169). [Artur Bieniek, Antmicro Ltd.]]
|
||||
* Fix additional UNOPTFLAT combinational cycles automatically in DFG (#6168) (#6173) (#6176). [Geza Lore]
|
||||
* Fix omitting error when assigning to an input (#6169). [Artur Bieniek, Antmicro Ltd.]
|
||||
* Fix parameter-dependent type linking (#6170). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Fix param-dependent class typedef linking (#6171). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Fix virtual interface member propagation (#6175) (#6184). [Yilou Wang]
|
||||
* Fix `--coverage-expr` null pointer dereference (#6181). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Fix conflicting function/class name linking error (#6182). [Igor Zaworski, Antmicro Ltd.]
|
||||
* Fix automatic task variables in unrolled loops with forks (#6194) (#6201). [Danny Oler]
|
||||
* Fix VPI signal range order (#6189) (#6200). [Ibrahim Burak Yorulmaz]
|
||||
* Fix structure select causing 'Wide Op' error (#6191). [Danny Oler]
|
||||
* Fix 'driver same component' assertion (#6211) (#6215). [Geza Lore]
|
||||
* Fix `--stats` overridden by skipping identical build (#6220). [Geza Lore]
|
||||
|
||||
|
||||
Verilator 5.038 2025-07-08
|
||||
|
|
|
@ -470,6 +470,7 @@ CLANGFORMAT_FLAGS = -i
|
|||
CLANGFORMAT_FILES = $(CHECK_CPP) $(CHECK_H) $(CHECK_YL) test_regress/t/*.c* test_regress/t/*.h
|
||||
|
||||
format-c clang-format:
|
||||
$(CLANGFORMAT) --version
|
||||
@$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||
|
@ -538,6 +539,7 @@ YAPF = yapf3
|
|||
YAPF_FLAGS = -i --parallel
|
||||
|
||||
format-py yapf:
|
||||
$(YAPF) --version
|
||||
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
||||
|
||||
GERSEMI = gersemi
|
||||
|
|
|
@ -68,6 +68,7 @@ AC_ARG_ENABLE([tcmalloc],
|
|||
*) AC_MSG_ERROR([bad value '${enableval}' for --enable-tcmalloc]) ;;
|
||||
esac],
|
||||
[CFG_WITH_TCMALLOC=check;])
|
||||
AC_SUBST(CFG_WITH_TCMALLOC)
|
||||
AC_MSG_RESULT($CFG_WITH_TCMALLOC)
|
||||
|
||||
# Flag to enable coverage build
|
||||
|
@ -546,10 +547,12 @@ _MY_LDLIBS_CHECK_IFELSE(
|
|||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-free)
|
||||
AC_DEFINE([HAVE_TCMALLOC],[1],[Defined if have tcmalloc])
|
||||
fi],
|
||||
[if test "$CFG_WITH_TCMALLOC" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-tcmalloc was given but test for ${LTCMALLOC} failed])
|
||||
fi])
|
||||
AC_SUBST(HAVE_TCMALLOC)
|
||||
AC_SUBST(CFG_LIBS)
|
||||
|
||||
# Need C++14 at least
|
||||
|
|
|
@ -37,6 +37,7 @@ Chuxuan Wang
|
|||
Chykon
|
||||
Conor McCullough
|
||||
Dan Petrisko
|
||||
Danny Oler
|
||||
Daniel Bates
|
||||
Dave Sargeant
|
||||
David Horton
|
||||
|
@ -84,6 +85,7 @@ Huang Rui
|
|||
Huanghuang Zhou
|
||||
HungMingWu
|
||||
HyungKi Jeong
|
||||
Ibrahim Burak Yorulmaz
|
||||
Igor Zaworski
|
||||
Ilya Barkov
|
||||
Iru Cai
|
||||
|
@ -157,6 +159,7 @@ Martin Schmidt
|
|||
Martin Stadler
|
||||
Mateusz Gancarz
|
||||
Matthew Ballance
|
||||
Max Wipfli
|
||||
Michael Bikovitsky
|
||||
Michael Killough
|
||||
Michal Czyz
|
||||
|
|
|
@ -68,11 +68,16 @@ pdf:
|
|||
|
||||
######################################################################
|
||||
|
||||
html latex linkcheck spelling::
|
||||
html latex linkcheck::
|
||||
$(MAKE) vl-extract
|
||||
$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
||||
$(PYTHON3) bin/vl_sphinx_fix _build
|
||||
|
||||
spelling::
|
||||
$(MAKE) vl-extract
|
||||
$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
||||
sort -o guide/spelling.txt guide/spelling.txt
|
||||
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
:linenos:
|
||||
:emphasize-lines: 3
|
||||
|
||||
int array[5];
|
||||
bit [1:0] rd_addr;
|
||||
wire int rd_value = array[rd_addr]; //<--- Warning
|
||||
logic [31:0] array[5];
|
||||
bit [1:0] rd_addr;
|
||||
wire [31:0] rd_value = array[rd_addr]; //<--- Warning
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
.. code-block:: sv
|
||||
:emphasize-lines: 1
|
||||
|
||||
wire int rd_value = array[{1'b0, rd_addr}]; //<--- Fixed
|
||||
wire [31:0] rd_value = array[{1'b0, rd_addr}]; //<--- Fixed
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.. comment: generated by t_lint_widthexpand_docs_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-WIDTHEXPAND: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
|
||||
%Warning-WIDTHEXPAND: example.v:3:31 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
|
||||
|
|
|
@ -458,7 +458,7 @@ List Of Warnings
|
|||
|
||||
Warns that Verilator does not support certain forms of
|
||||
:code:`constraint`, :code:`constraint_mode`, or :code:`rand_mode`, and
|
||||
the construct was are ignored.
|
||||
the construct was ignored.
|
||||
|
||||
Ignoring this warning may make Verilator randomize() simulations differ
|
||||
from other simulators.
|
||||
|
@ -486,7 +486,7 @@ List Of Warnings
|
|||
|
||||
Warns that Verilator does not support certain forms of
|
||||
:code:`covergroup`, :code:`coverpoint`, and coverage options, and the
|
||||
construct was are ignored.
|
||||
construct was ignored.
|
||||
|
||||
Disabling the :option:`UNSUPPORTED` error also disables this warning.
|
||||
|
||||
|
@ -1308,6 +1308,21 @@ List Of Warnings
|
|||
simulate correctly.
|
||||
|
||||
|
||||
.. option:: NOEFFECT
|
||||
|
||||
Warns that the statement will have no effect and is roughly equivalent
|
||||
to not being present. This is only issued when it is "non-obvious",
|
||||
e.g. a :code:`if (0)` will not result in this warning.
|
||||
|
||||
Faulty example:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
foreach (array[]) begin ... end //<--- Warning
|
||||
|
||||
For a fix, remove the statement.
|
||||
|
||||
|
||||
.. option:: NOLATCH
|
||||
|
||||
.. TODO better example
|
||||
|
@ -1764,6 +1779,18 @@ List Of Warnings
|
|||
simulators.
|
||||
|
||||
|
||||
.. option:: SPECIFYIGN
|
||||
|
||||
Warns that Verilator does not support certain constructs in
|
||||
:code:`specify` blocks, nor :code:`$sdf_annotate`, and the construct was
|
||||
ignored.
|
||||
|
||||
Disabling the :option:`UNSUPPORTED` error also disables this warning.
|
||||
|
||||
Ignoring this warning may make Verilator ignore lint checking on the
|
||||
construct, and get different results from other simulators.
|
||||
|
||||
|
||||
.. option:: SPLITVAR
|
||||
|
||||
Warns that a variable with a :option:`/*verilator&32;split_var*/`
|
||||
|
|
|
@ -314,6 +314,7 @@ Noack
|
|||
Nodine
|
||||
Ober
|
||||
Oleg
|
||||
Oler
|
||||
Olof
|
||||
Olofsson
|
||||
Oron
|
||||
|
@ -601,6 +602,7 @@ coroutines
|
|||
countbits
|
||||
countones
|
||||
cout
|
||||
covergroup
|
||||
cpp
|
||||
cppstyle
|
||||
cpu
|
||||
|
|
|
@ -3061,7 +3061,9 @@ void VerilatedContext::statsPrintSummary() VL_MT_UNSAFE {
|
|||
= vl_timescaled_double((cputime != 0.0) ? (simtimeInUnits / cputime) : 0, "%0.3f %s");
|
||||
VL_PRINTF("- Verilator: %s at %s; walltime %0.3f s; speed %s/s\n", endwhy.c_str(),
|
||||
simtime.c_str(), walltime, simtimePerf.c_str());
|
||||
const double modelMB = VlOs::memUsageBytes() / 1024.0 / 1024.0;
|
||||
uint64_t memPeak, memCurrent;
|
||||
VlOs::memUsageBytes(memPeak /*ref*/, memCurrent /*ref*/);
|
||||
const double modelMB = memPeak / 1024.0 / 1024.0;
|
||||
VL_PRINTF("- Verilator: cpu %0.3f s on %u threads; alloced %0.0f MB\n", cputime,
|
||||
threadsInModels(), modelMB);
|
||||
}
|
||||
|
|
|
@ -580,4 +580,22 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlStdRandomizer provides a light wrapper for RNG used by std::randomize()
|
||||
// to support scope-level randomization.
|
||||
class VlStdRandomizer final {
|
||||
// MEMBERS
|
||||
VlRNG m_rng; // Random number generator
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlStdRandomizer() = default;
|
||||
~VlStdRandomizer() = default;
|
||||
|
||||
template <typename T>
|
||||
bool basicStdRandomization(T& value, size_t width) {
|
||||
value = VL_MASK_I(width) & VL_RANDOM_RNG_I(m_rng);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#endif // Guard
|
||||
|
|
|
@ -637,7 +637,7 @@ extern std::string getenvStr(const std::string& envvar,
|
|||
extern uint16_t getcpu() VL_MT_SAFE;
|
||||
|
||||
/// Return memory usage in bytes, or 0 if unknown
|
||||
extern uint64_t memUsageBytes() VL_MT_SAFE;
|
||||
extern void memUsageBytes(uint64_t& peakr, uint64_t& currentr) VL_MT_SAFE;
|
||||
|
||||
// Internal: Record CPU time, starting point on construction, and current delta from that
|
||||
class DeltaCpuTime final {
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// clang-format off
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <windows.h> // LONG for bcrypt.h on MINGW
|
||||
|
@ -102,29 +105,42 @@ uint16_t getcpu() VL_MT_SAFE {
|
|||
}
|
||||
|
||||
//=========================================================================
|
||||
// VlOs::memUsageBytes implementation
|
||||
// VlOs::memPeakUsageBytes implementation
|
||||
|
||||
uint64_t memUsageBytes() VL_MT_SAFE {
|
||||
void memUsageBytes(uint64_t& peakr, uint64_t& currentr) VL_MT_SAFE {
|
||||
peakr = 0;
|
||||
currentr = 0;
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
const HANDLE process = GetCurrentProcess();
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) {
|
||||
// The best we can do using simple Windows APIs is to get the size of the working set.
|
||||
return pmc.WorkingSetSize;
|
||||
peakr = pmc.PeakWorkingSetSize;
|
||||
currentr = pmc.WorkingSetSize;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
// Highly unportable. Sorry
|
||||
const char* const statmFilename = "/proc/self/statm";
|
||||
FILE* const fp = fopen(statmFilename, "r");
|
||||
if (!fp) return 0;
|
||||
uint64_t size, resident, share, text, lib, data, dt; // All in pages
|
||||
const int items = fscanf(
|
||||
fp, "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64,
|
||||
&size, &resident, &share, &text, &lib, &data, &dt);
|
||||
fclose(fp);
|
||||
if (VL_UNCOVERABLE(7 != items)) return 0;
|
||||
return (text + data) * getpagesize();
|
||||
std::ifstream is{"/proc/self/status"};
|
||||
if (!is) return;
|
||||
std::string line;
|
||||
uint64_t vmPeak = 0;
|
||||
uint64_t vmRss = 0;
|
||||
uint64_t vmSwap = 0;
|
||||
std::string field;
|
||||
while (std::getline(is, line)) {
|
||||
if (line.rfind("VmPeak:", 0) == 0) {
|
||||
std::stringstream ss{line};
|
||||
ss >> field >> vmPeak;
|
||||
} else if (line.rfind("VmRSS:", 0) == 0) {
|
||||
std::stringstream ss{line};
|
||||
ss >> field >> vmRss;
|
||||
} else if (line.rfind("VmSwap:", 0) == 0) {
|
||||
std::stringstream ss{line};
|
||||
ss >> field >> vmSwap;
|
||||
}
|
||||
}
|
||||
peakr = vmPeak * 1024;
|
||||
currentr = (vmRss + vmSwap) * 1024;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
28
src/V3Ast.h
28
src/V3Ast.h
|
@ -591,6 +591,7 @@ public:
|
|||
FORK_SYNC,
|
||||
PROCESS_REFERENCE,
|
||||
RANDOM_GENERATOR,
|
||||
RANDOM_STDGENERATOR,
|
||||
// Unsigned and two state; fundamental types
|
||||
UINT32,
|
||||
UINT64,
|
||||
|
@ -625,6 +626,7 @@ public:
|
|||
"VlFork",
|
||||
"VlProcessRef",
|
||||
"VlRandomizer",
|
||||
"VlStdRandomizer",
|
||||
"IData",
|
||||
"QData",
|
||||
"LOGIC_IMPLICIT",
|
||||
|
@ -632,13 +634,16 @@ public:
|
|||
return names[m_e];
|
||||
}
|
||||
const char* dpiType() const {
|
||||
static const char* const names[]
|
||||
= {"%E-unk", "svBit", "char", "void*", "char",
|
||||
"int", "%E-integer", "svLogic", "long long", "double",
|
||||
"short", "%E-time", "const char*", "%E-untyped", "dpiScope",
|
||||
"const char*", "%E-mtaskstate", "%E-triggervec", "%E-dly-sched", "%E-trig-sched",
|
||||
"%E-dyn-sched", "%E-fork", "%E-proc-ref", "%E-rand-gen", "IData",
|
||||
"QData", "%E-logic-implct", " MAX"};
|
||||
static const char* const names[] = {"%E-unk", "svBit", "char",
|
||||
"void*", "char", "int",
|
||||
"%E-integer", "svLogic", "long long",
|
||||
"double", "short", "%E-time",
|
||||
"const char*", "%E-untyped", "dpiScope",
|
||||
"const char*", "%E-mtaskstate", "%E-triggervec",
|
||||
"%E-dly-sched", "%E-trig-sched", "%E-dyn-sched",
|
||||
"%E-fork", "%E-proc-ref", "%E-rand-gen",
|
||||
"%E-stdrand-gen", "IData", "QData",
|
||||
"%E-logic-implct", " MAX"};
|
||||
return names[m_e];
|
||||
}
|
||||
static void selfTest() {
|
||||
|
@ -679,6 +684,7 @@ public:
|
|||
case FORK_SYNC: return 0; // opaque
|
||||
case PROCESS_REFERENCE: return 0; // opaque
|
||||
case RANDOM_GENERATOR: return 0; // opaque
|
||||
case RANDOM_STDGENERATOR: return 0; // opaque
|
||||
case UINT32: return 32;
|
||||
case UINT64: return 64;
|
||||
default: return 0;
|
||||
|
@ -718,8 +724,8 @@ public:
|
|||
return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|
||||
|| m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER
|
||||
|| m_e == TRIGGER_SCHEDULER || m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC
|
||||
|| m_e == PROCESS_REFERENCE || m_e == RANDOM_GENERATOR || m_e == DOUBLE
|
||||
|| m_e == UNTYPED);
|
||||
|| m_e == PROCESS_REFERENCE || m_e == RANDOM_GENERATOR
|
||||
|| m_e == RANDOM_STDGENERATOR || m_e == DOUBLE || m_e == UNTYPED);
|
||||
}
|
||||
bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; }
|
||||
bool isEvent() const { return m_e == EVENT; }
|
||||
|
@ -771,6 +777,8 @@ public:
|
|||
/* DYNAMIC_TRIGGER_SCHEDULER: */ "", // Should not be traced
|
||||
/* FORK_SYNC: */ "", // Should not be traced
|
||||
/* PROCESS_REFERENCE: */ "", // Should not be traced
|
||||
/* RANDOM_GENERATOR: */ "", // Should not be traced
|
||||
/* RANDOM_STD_GENERATOR: */ "", // Should not be traced
|
||||
/* UINT32: */ "BIT",
|
||||
/* UINT64: */ "BIT",
|
||||
/* LOGIC_IMPLICIT: */ "", // Should not be traced
|
||||
|
@ -2194,8 +2202,6 @@ public:
|
|||
// Used by AstNode::broken()
|
||||
bool brokeExists() const { return V3Broken::isLinkable(this); }
|
||||
bool brokeExistsAbove() const { return brokeExists() && (m_brokenState >> 7); }
|
||||
bool brokeExistsBelow() const { return brokeExists() && !(m_brokenState >> 7); }
|
||||
// Note: brokeExistsBelow is not quite precise, as it is true for sibling nodes as well
|
||||
|
||||
// CONSTRUCTORS
|
||||
virtual ~AstNode() = default;
|
||||
|
|
|
@ -473,6 +473,9 @@ public:
|
|||
bool isRandomGenerator() const VL_MT_SAFE {
|
||||
return keyword() == VBasicDTypeKwd::RANDOM_GENERATOR;
|
||||
}
|
||||
bool isStdRandomGenerator() const VL_MT_SAFE {
|
||||
return keyword() == VBasicDTypeKwd::RANDOM_STDGENERATOR;
|
||||
}
|
||||
bool isOpaque() const VL_MT_SAFE { return keyword().isOpaque(); }
|
||||
bool isString() const VL_MT_STABLE { return keyword().isString(); }
|
||||
bool isZeroInit() const { return keyword().isZeroInit(); }
|
||||
|
|
|
@ -561,6 +561,7 @@ public:
|
|||
|
||||
public:
|
||||
ASTGEN_MEMBERS_AstAddrOfCFunc;
|
||||
void dump(std::ostream& str) const override;
|
||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
|
@ -3366,7 +3367,11 @@ public:
|
|||
: ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) {
|
||||
if (lhsp) {
|
||||
if (const AstConst* const constp = VN_CAST(rhsp, Const)) {
|
||||
dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED);
|
||||
if (constp->num().isFourState() || constp->num().isNegative()) { // V3Width warns
|
||||
dtypeSetLogicSized(lhsp->width(), VSigning::UNSIGNED);
|
||||
} else {
|
||||
dtypeSetLogicSized(lhsp->width() * constp->toSInt(), VSigning::UNSIGNED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1406,6 +1406,7 @@ class AstNetlist final : public AstNode {
|
|||
public:
|
||||
AstNetlist();
|
||||
ASTGEN_MEMBERS_AstNetlist;
|
||||
void deleteContents();
|
||||
void cloneRelink() override { V3ERROR_NA; }
|
||||
string name() const override VL_MT_STABLE { return "$root"; }
|
||||
void dump(std::ostream& str) const override;
|
||||
|
@ -3279,14 +3280,13 @@ public:
|
|||
bool isDelayed() const { return m_delayed; }
|
||||
};
|
||||
class AstJumpBlock final : public AstNodeStmt {
|
||||
// Block of code including a single JumpLabel, and 0+ JumpGo's to that label
|
||||
// Block of code that might contain AstJumpGo statements as children,
|
||||
// which when exectued branch to right after the referenced AstJumpBlock.
|
||||
// AstJumpBlocks can nest, and an AstJumpGo can reference any of the
|
||||
// enclosing AstJumpBlocks (can break out of mulitple levels).
|
||||
// Parents: {statement list}
|
||||
// Children: {statement list, with JumpGo and JumpLabel below}
|
||||
// Children: {statement list, with JumpGo below}
|
||||
// @astgen op1 := stmtsp : List[AstNode]
|
||||
// @astgen op2 := endStmtsp : List[AstNode]
|
||||
//
|
||||
// @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration
|
||||
int m_labelNum = 0; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||
VIsCached m_purity; // Pure state
|
||||
public:
|
||||
// After construction must call ->labelp to associate with appropriate label
|
||||
|
@ -3295,66 +3295,35 @@ public:
|
|||
addStmtsp(stmtsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstJumpBlock;
|
||||
const char* broken() const override;
|
||||
int instrCount() const override { return 0; }
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
int labelNum() const { return m_labelNum; }
|
||||
void labelNum(int flag) { m_labelNum = flag; }
|
||||
AstJumpLabel* labelp() const { return m_labelp; }
|
||||
void labelp(AstJumpLabel* labelp) { m_labelp = labelp; }
|
||||
bool isPure() override;
|
||||
|
||||
private:
|
||||
bool getPurityRecurse() const;
|
||||
};
|
||||
class AstJumpGo final : public AstNodeStmt {
|
||||
// Jump point; branch down to a JumpLabel
|
||||
// No support for backward jumps at present
|
||||
// Parents: {statement list with JumpBlock above}
|
||||
// Branch to right after the referenced encloding AstJumpBlock
|
||||
// Parents: statement, including the referenced AstJumpBlock
|
||||
// Children: none
|
||||
//
|
||||
// @astgen ptr := m_labelp : AstJumpLabel // [After V3Jump] Pointer to declaration
|
||||
// @astgen ptr := m_blockp : AstJumpBlock // The AstJumpBlock we are branching after
|
||||
public:
|
||||
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
|
||||
AstJumpGo(FileLine* fl, AstJumpBlock* blockp)
|
||||
: ASTGEN_SUPER_JumpGo(fl)
|
||||
, m_labelp{labelp} {}
|
||||
, m_blockp{blockp} {}
|
||||
ASTGEN_MEMBERS_AstJumpGo;
|
||||
const char* broken() const override;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int instrCount() const override { return INSTR_COUNT_BRANCH; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
return labelp() == VN_DBG_AS(samep, JumpGo)->labelp();
|
||||
return blockp() == VN_DBG_AS(samep, JumpGo)->blockp();
|
||||
}
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isBrancher() const override {
|
||||
return true; // SPECIAL: We don't process code after breaks
|
||||
}
|
||||
AstJumpLabel* labelp() const { return m_labelp; }
|
||||
};
|
||||
class AstJumpLabel final : public AstNodeStmt {
|
||||
// Jump point declaration
|
||||
// Parents: {statement list with JumpBlock above}
|
||||
// Children: none
|
||||
// @astgen ptr := m_blockp : AstJumpBlock // [After V3Jump] Pointer to declaration
|
||||
public:
|
||||
AstJumpLabel(FileLine* fl, AstJumpBlock* blockp)
|
||||
: ASTGEN_SUPER_JumpLabel(fl)
|
||||
, m_blockp{blockp} {}
|
||||
ASTGEN_MEMBERS_AstJumpLabel;
|
||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!blockp()->brokeExistsAbove());
|
||||
BROKEN_RTN(blockp()->labelp() != this);
|
||||
return nullptr;
|
||||
}
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
int instrCount() const override { return 0; }
|
||||
bool sameNode(const AstNode* samep) const override {
|
||||
return blockp() == VN_DBG_AS(samep, JumpLabel)->blockp();
|
||||
}
|
||||
AstJumpBlock* blockp() const { return m_blockp; }
|
||||
};
|
||||
class AstMonitorOff final : public AstNodeStmt {
|
||||
|
@ -3737,10 +3706,9 @@ public:
|
|||
bool isTimingControl() const override { return true; }
|
||||
};
|
||||
class AstWhile final : public AstNodeStmt {
|
||||
// @astgen op1 := precondsp : List[AstNode]
|
||||
// @astgen op2 := condp : AstNodeExpr
|
||||
// @astgen op3 := stmtsp : List[AstNode]
|
||||
// @astgen op4 := incsp : List[AstNode]
|
||||
// @astgen op1 := condp : AstNodeExpr
|
||||
// @astgen op2 := stmtsp : List[AstNode]
|
||||
// @astgen op3 := incsp : List[AstNode]
|
||||
VOptionBool m_unrollFull; // Full, disable, or default unrolling
|
||||
public:
|
||||
AstWhile(FileLine* fl, AstNodeExpr* condp, AstNode* stmtsp = nullptr, AstNode* incsp = nullptr)
|
||||
|
|
|
@ -189,6 +189,12 @@ void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Numb
|
|||
}
|
||||
}
|
||||
|
||||
void AstAddrOfCFunc::dump(std::ostream& str) const {
|
||||
this->AstNodeExpr::dump(str);
|
||||
str << " -> ";
|
||||
funcp()->dump(str);
|
||||
}
|
||||
|
||||
void AstBasicDType::init(VBasicDTypeKwd kwd, VSigning numer, int wantwidth, int wantwidthmin,
|
||||
AstRange* rangep) {
|
||||
// wantwidth=0 means figure it out, but if a widthmin is >=0
|
||||
|
@ -1001,6 +1007,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
|
|||
info.m_type = "VlProcessRef";
|
||||
} else if (bdtypep->isRandomGenerator()) {
|
||||
info.m_type = "VlRandomizer";
|
||||
} else if (bdtypep->isStdRandomGenerator()) {
|
||||
info.m_type = "VlStdRandomizer";
|
||||
} else if (bdtypep->isEvent()) {
|
||||
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent";
|
||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||
|
@ -1110,6 +1118,9 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
|||
} else if (overMembers && VN_IS(nodep, MemberSel)) {
|
||||
nodep = VN_AS(nodep, MemberSel)->fromp();
|
||||
continue;
|
||||
} else if (overMembers && VN_IS(nodep, StructSel)) {
|
||||
nodep = VN_AS(nodep, StructSel)->fromp();
|
||||
continue;
|
||||
}
|
||||
// AstNodePreSel stashes the associated variable under an ATTROF
|
||||
// of VAttrType::VAR_BASE so it isn't constified
|
||||
|
@ -1130,10 +1141,6 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) {
|
|||
return nodep;
|
||||
}
|
||||
|
||||
const char* AstJumpBlock::broken() const {
|
||||
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
||||
return nullptr;
|
||||
}
|
||||
bool AstJumpBlock::isPure() {
|
||||
if (!m_purity.isCached()) m_purity.set(getPurityRecurse());
|
||||
return m_purity.get();
|
||||
|
@ -1509,12 +1516,7 @@ void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
|
|||
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
|
||||
// Special, as statements need to be put in different places
|
||||
// Belowp is how we came to recurse up to this point
|
||||
// Preconditions insert first just before themselves (the normal rule
|
||||
// for other statement types)
|
||||
if (belowp == precondsp()) {
|
||||
// Next in precond list
|
||||
belowp->addNextHere(newp);
|
||||
} else if (belowp == condp()) {
|
||||
if (belowp == condp()) {
|
||||
// Becomes first statement in body, body may have been empty
|
||||
if (stmtsp()) {
|
||||
stmtsp()->addHereThisAsNext(newp);
|
||||
|
@ -1973,21 +1975,6 @@ AstNodeExpr* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
|
|||
}
|
||||
|
||||
void AstJumpGo::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (labelp()) {
|
||||
labelp()->dump(str);
|
||||
} else {
|
||||
str << "%E:UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstJumpGo::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
const char* AstJumpGo::broken() const {
|
||||
BROKEN_RTN(!labelp()->brokeExistsBelow());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AstJumpLabel::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
if (blockp()) {
|
||||
|
@ -1996,7 +1983,11 @@ void AstJumpLabel::dump(std::ostream& str) const {
|
|||
str << "%E:UNLINKED";
|
||||
}
|
||||
}
|
||||
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
void AstJumpGo::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||
const char* AstJumpGo::broken() const {
|
||||
BROKEN_RTN(!blockp()->brokeExistsAbove());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AstMemberDType::dump(std::ostream& str) const {
|
||||
this->AstNodeDType::dump(str);
|
||||
|
@ -2307,6 +2298,25 @@ void AstNetlist::dumpJson(std::ostream& str) const {
|
|||
dumpJsonStr(str, "timeprecision", timeprecision().ascii());
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
void AstNetlist::deleteContents() {
|
||||
// Delete all netlist memory. Only for use by Verilator.cpp
|
||||
m_typeTablep = nullptr;
|
||||
m_constPoolp = nullptr;
|
||||
m_dollarUnitPkgp = nullptr;
|
||||
m_stdPackagep = nullptr;
|
||||
m_evalp = nullptr;
|
||||
m_evalNbap = nullptr;
|
||||
m_dpiExportTriggerp = nullptr;
|
||||
m_delaySchedulerp = nullptr;
|
||||
m_nbaEventp = nullptr;
|
||||
m_nbaEventTriggerp = nullptr;
|
||||
m_topScopep = nullptr;
|
||||
if (op1p()) op1p()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (op2p()) op2p()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (op3p()) op3p()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (op4p()) op4p()->unlinkFrBackWithNext()->deleteTree();
|
||||
#undef VN_DELETE_ONE
|
||||
}
|
||||
AstPackage* AstNetlist::dollarUnitPkgAddp() {
|
||||
if (!m_dollarUnitPkgp) {
|
||||
m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName(), "work"};
|
||||
|
@ -3090,7 +3100,8 @@ void AstCMethodHard::setPurity() {
|
|||
{"unique", true},
|
||||
{"unique_index", true},
|
||||
{"word", true},
|
||||
{"write_var", false}};
|
||||
{"write_var", false},
|
||||
{"basicStdRandomization", false}};
|
||||
|
||||
if (name() == "atWriteAppend" || name() == "atWriteAppendBack") {
|
||||
m_pure = false;
|
||||
|
|
|
@ -530,7 +530,11 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
|
|||
}
|
||||
// The parser validates we don't have "foreach (array[,,,])"
|
||||
AstNode* const bodyp = nodep->stmtsp();
|
||||
UASSERT_OBJ(newp, nodep, "foreach has no non-empty loop variable");
|
||||
if (!newp) {
|
||||
nodep->v3warn(NOEFFECT, "foreach with no loop variable has no effect");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return nullptr;
|
||||
}
|
||||
if (bodyp) {
|
||||
bodyPointp->replaceWith(bodyp->unlinkFrBackWithNext());
|
||||
} else {
|
||||
|
|
|
@ -166,7 +166,8 @@ private:
|
|||
nodep->brokenState(m_brokenCntCurrentUnder);
|
||||
const char* const whyp = nodep->brokenGen();
|
||||
UASSERT_OBJ(!whyp, nodep,
|
||||
"Broken link in node (or something without maybePointedTo): " << whyp);
|
||||
"Broken link in node (or something without maybePointedTo): " << whyp << " -- "
|
||||
<< nodep);
|
||||
if (!s_brokenAllowMidvisitorCheck) nodep->checkIter();
|
||||
if (nodep->dtypep()) {
|
||||
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
|
||||
|
|
|
@ -127,7 +127,8 @@ static void makeToStringMiddle(AstClass* nodep) {
|
|||
if (const auto* const varp = VN_CAST(itemp, Var)) {
|
||||
if (!varp->isParam() && !varp->isInternal()
|
||||
&& !(varp->dtypeSkipRefp()->basicp()
|
||||
&& varp->dtypeSkipRefp()->basicp()->isRandomGenerator())) {
|
||||
&& (varp->dtypeSkipRefp()->basicp()->isRandomGenerator()
|
||||
|| varp->dtypeSkipRefp()->basicp()->isStdRandomGenerator()))) {
|
||||
string stmt = "out += \"";
|
||||
stmt += comma;
|
||||
comma = ", ";
|
||||
|
|
100
src/V3Const.cpp
100
src/V3Const.cpp
|
@ -38,6 +38,7 @@
|
|||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <unordered_set>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
|
@ -912,7 +913,6 @@ class ConstVisitor final : public VNVisitor {
|
|||
// ** only when m_warn/m_doExpensive is set. If state is needed other times,
|
||||
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
||||
// AstVar::user4p -> Used by variable marking/finding
|
||||
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
|
||||
// AstEnum::user4 -> bool. Recursing.
|
||||
|
||||
// STATE
|
||||
|
@ -938,6 +938,7 @@ class ConstVisitor final : public VNVisitor {
|
|||
static uint32_t s_globalPassNum; // Counts number of times ConstVisitor invoked as global pass
|
||||
V3UniqueNames m_concswapNames; // For generating unique temporary variable names
|
||||
std::map<const AstNode*, bool> m_containsMemberAccess; // Caches results of matchBiopToBitwise
|
||||
std::unordered_set<AstJumpBlock*> m_usedJumpBlocks; // JumpBlocks used by some JumpGo
|
||||
|
||||
// METHODS
|
||||
|
||||
|
@ -1267,8 +1268,12 @@ class ConstVisitor final : public VNVisitor {
|
|||
&& nodep->lhsp()->isPure());
|
||||
}
|
||||
bool operandIsTwo(const AstNode* nodep) {
|
||||
return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState()
|
||||
&& nodep->width() <= VL_QUADSIZE && VN_AS(nodep, Const)->toUQuad() == 2);
|
||||
const AstConst* const constp = VN_CAST(nodep, Const);
|
||||
if (!constp) return false; // not constant
|
||||
if (constp->num().isFourState()) return false; // four-state
|
||||
if (nodep->width() > VL_QUADSIZE) return false; // too wide
|
||||
if (nodep->isSigned() && constp->num().isNegative()) return false; // signed and negative
|
||||
return constp->toUQuad() == 2;
|
||||
}
|
||||
bool operandIsTwostate(const AstNode* nodep) {
|
||||
return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState());
|
||||
|
@ -2299,19 +2304,6 @@ class ConstVisitor final : public VNVisitor {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
bool replaceJumpGoNext(AstJumpGo* nodep, AstNode* abovep) {
|
||||
// If JumpGo has an upper JumpBlock that is to same label, then
|
||||
// code will by normal sequential operation do the JUMPGO and it
|
||||
// can be removed.
|
||||
if (nodep->nextp()) return false; // Label jumps other statements
|
||||
AstJumpBlock* const aboveBlockp = VN_CAST(abovep, JumpBlock);
|
||||
if (!aboveBlockp) return false;
|
||||
if (aboveBlockp != nodep->labelp()->blockp()) return false;
|
||||
if (aboveBlockp->endStmtsp() != nodep->labelp()) return false;
|
||||
UINFO(4, "JUMPGO => last remove " << nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Boolean replacements
|
||||
bool operandBoolShift(const AstNode* nodep) {
|
||||
|
@ -3348,14 +3340,10 @@ class ConstVisitor final : public VNVisitor {
|
|||
if (m_doNConst) {
|
||||
if (nodep->condp()->isZero()) {
|
||||
UINFO(4, "WHILE(0) => nop " << nodep);
|
||||
if (nodep->precondsp()) {
|
||||
nodep->replaceWith(nodep->precondsp());
|
||||
} else {
|
||||
nodep->v3warn(UNUSEDLOOP,
|
||||
"Loop condition is always false; body will never execute");
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSEDLOOP, true);
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
nodep->v3warn(UNUSEDLOOP,
|
||||
"Loop condition is always false; body will never execute");
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSEDLOOP, true);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (nodep->condp()->isNeqZero()) {
|
||||
if (!thisWhileHasJumpDelay) {
|
||||
|
@ -3402,52 +3390,39 @@ class ConstVisitor final : public VNVisitor {
|
|||
// Jump elimination
|
||||
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Jump to label where label immediately follows this JumpGo is not useful
|
||||
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
// Keep the label, might be other jumps pointing to it, gets cleaned later
|
||||
return;
|
||||
}
|
||||
if (m_doExpensive) {
|
||||
// Any non-label statements (at this statement level) can never execute
|
||||
while (nodep->nextp() && !VN_IS(nodep->nextp(), JumpLabel)) {
|
||||
pushDeletep(nodep->nextp()->unlinkFrBack());
|
||||
// Any statements following the JumpGo (at this statement level) never execute, delete
|
||||
if (nodep->nextp()) pushDeletep(nodep->nextp()->unlinkFrBackWithNext());
|
||||
|
||||
// JumpGo as last statement in target JumpBlock (including last in a last sub-list),
|
||||
// is a no-op, remove it.
|
||||
for (AstNode* abovep = nodep->abovep(); abovep; abovep = abovep->abovep()) {
|
||||
if (abovep == nodep->blockp()) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
// If last statement in a jump label we have JumpLabel(...., JumpGo)
|
||||
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
|
||||
if (replaceJumpGoNext(nodep, nodep->abovep())) return;
|
||||
// Also optimize If with a then or else's final statement being this JumpGo
|
||||
// We only do single ifs... Ideally we'd look at control flow and delete any
|
||||
// Jumps where any following control flow point is the label
|
||||
if (!nodep->nextp()) {
|
||||
if (AstNodeIf* const aboveIfp = VN_CAST(nodep->abovep(), NodeIf)) {
|
||||
if (!aboveIfp->nextp()) {
|
||||
if (replaceJumpGoNext(nodep, aboveIfp->abovep())) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
nodep->labelp()->blockp()->user4(true);
|
||||
// Stop if not doing expensive, or if the above node is not the last in its list,
|
||||
// ... or if it's not an 'if' TODO: it would be enough if it was not a branch.
|
||||
if (!m_doExpensive || abovep->nextp() || !VN_IS(abovep, If)) break;
|
||||
}
|
||||
// Mark JumpBlock as used
|
||||
m_usedJumpBlocks.emplace(nodep->blockp());
|
||||
m_hasJumpDelay = true;
|
||||
}
|
||||
|
||||
void visit(AstJumpBlock* nodep) override {
|
||||
// Because JumpLabels disable many optimizations,
|
||||
// remove JumpLabels that are not pointed to by any AstJumpGos
|
||||
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
|
||||
iterateChildren(nodep);
|
||||
// AstJumpGo's below here that point to this node will set user4
|
||||
if (m_doExpensive && !nodep->user4()) {
|
||||
|
||||
// Remove if empty
|
||||
if (!nodep->stmtsp()) {
|
||||
UINFO(4, "JUMPLABEL => empty " << nodep);
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
// If no JumpGo points to this node, replace it with its body
|
||||
if (!m_usedJumpBlocks.count(nodep)) {
|
||||
UINFO(4, "JUMPLABEL => unused " << nodep);
|
||||
AstNode* underp = nullptr;
|
||||
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (underp) {
|
||||
nodep->replaceWith(underp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
pushDeletep(nodep->labelp()->unlinkFrBack());
|
||||
nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
@ -3550,6 +3525,7 @@ class ConstVisitor final : public VNVisitor {
|
|||
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
|
||||
TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
|
||||
TREEOP ("AstPow {operandIsTwo($lhsp), !$rhsp.isZero}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP ("AstPowSU {operandIsTwo($lhsp), !$rhsp.isZero}", "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
|
||||
|
|
|
@ -39,22 +39,33 @@ class ExprCoverageEligibleVisitor final : public VNVisitor {
|
|||
// STATE
|
||||
bool m_eligible = true;
|
||||
|
||||
static bool elemDTypeEligible(const AstNodeDType* dtypep) {
|
||||
dtypep = dtypep->skipRefp();
|
||||
if (AstNodeDType* const dtp = dtypep->virtRefDTypep()) {
|
||||
if (!elemDTypeEligible(dtp)) return false;
|
||||
}
|
||||
if (AstNodeDType* const dtp = dtypep->virtRefDType2p()) {
|
||||
if (!elemDTypeEligible(dtp)) return false;
|
||||
}
|
||||
return !VN_IS(dtypep, ClassRefDType);
|
||||
}
|
||||
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
AstNodeDType* dtypep = nodep->varp()->dtypep();
|
||||
// Class objecs and references not supported for expression coverage
|
||||
// Class objects and references not supported for expression coverage
|
||||
// because the object may not persist until the point at which
|
||||
// coverage data is gathered
|
||||
// This could be resolved in the future by protecting against dereferrencing
|
||||
// null pointers when cloning the expression for expression coverage
|
||||
if (VN_CAST(dtypep, ClassRefDType)) {
|
||||
m_eligible = false;
|
||||
} else {
|
||||
if (dtypep && elemDTypeEligible(dtypep)) {
|
||||
iterateChildren(nodep);
|
||||
} else {
|
||||
m_eligible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
if (!nodep->isExprCoverageEligible()) {
|
||||
if (!nodep->isExprCoverageEligible() || !nodep->isPure()) {
|
||||
m_eligible = false;
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
|
@ -63,7 +74,7 @@ class ExprCoverageEligibleVisitor final : public VNVisitor {
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ExprCoverageEligibleVisitor(AstNode* nodep) { iterateChildren(nodep); }
|
||||
explicit ExprCoverageEligibleVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
~ExprCoverageEligibleVisitor() override = default;
|
||||
|
||||
bool eligible() { return m_eligible; }
|
||||
|
@ -299,7 +310,6 @@ class CoverageVisitor final : public VNVisitor {
|
|||
{
|
||||
VL_RESTORER(m_inLoopNotBody);
|
||||
m_inLoopNotBody = true;
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateNull(nodep->condp());
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
}
|
||||
|
@ -858,7 +868,6 @@ class CoverageVisitor final : public VNVisitor {
|
|||
!= strs[!term.m_objective].end())
|
||||
impossible = true;
|
||||
}
|
||||
|
||||
if (!redundant) expr.push_back(term);
|
||||
}
|
||||
if (!impossible) m_exprs.push_back(std::move(expr));
|
||||
|
|
228
src/V3Dfg.cpp
228
src/V3Dfg.cpp
|
@ -97,6 +97,16 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
}
|
||||
case VDfgType::atSpliceArray: {
|
||||
DfgSpliceArray* const cp = new DfgSpliceArray{*clonep, vtx.fileline(), vtx.dtypep()};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
}
|
||||
case VDfgType::atSplicePacked: {
|
||||
DfgSplicePacked* const cp = new DfgSplicePacked{*clonep, vtx.fileline(), vtx.dtypep()};
|
||||
vtxp2clonep.emplace(&vtx, cp);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
vtx.v3fatalSrc("Unhandled operation vertex type: " + vtx.typeName());
|
||||
VL_UNREACHABLE;
|
||||
|
@ -109,49 +119,55 @@ std::unique_ptr<DfgGraph> DfgGraph::clone() const {
|
|||
// Constants have no inputs
|
||||
// Hook up inputs of cloned variables
|
||||
for (const DfgVertexVar& vtx : m_varVertices) {
|
||||
switch (vtx.type()) {
|
||||
case VDfgType::atVarArray: {
|
||||
const DfgVarArray* const vp = vtx.as<DfgVarArray>();
|
||||
DfgVarArray* const cp = vtxp2clonep.at(vp)->as<DfgVarArray>();
|
||||
vp->forEachSourceEdge([&](const DfgEdge& edge, size_t i) {
|
||||
if (DfgVertex* const srcp = edge.sourcep()) {
|
||||
cp->addDriver(vp->driverFileLine(i), //
|
||||
vp->driverIndex(i), //
|
||||
vtxp2clonep.at(srcp));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case VDfgType::atVarPacked: {
|
||||
const DfgVarPacked* const vp = vtx.as<DfgVarPacked>();
|
||||
DfgVarPacked* const cp = vtxp2clonep.at(vp)->as<DfgVarPacked>();
|
||||
vp->forEachSourceEdge([&](const DfgEdge& edge, size_t i) {
|
||||
if (DfgVertex* const srcp = edge.sourcep()) {
|
||||
cp->addDriver(vp->driverFileLine(i), //
|
||||
vp->driverLsb(i), //
|
||||
vtxp2clonep.at(srcp));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
vtx.v3fatalSrc("Unhandled variable vertex type: " + vtx.typeName());
|
||||
VL_UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
// All variable vertices are unary
|
||||
if (DfgVertex* const srcp = vtx.srcp()) {
|
||||
vtxp2clonep.at(&vtx)->as<DfgVertexVar>()->srcp(vtxp2clonep.at(srcp));
|
||||
}
|
||||
}
|
||||
// Hook up inputs of cloned operation vertices
|
||||
for (const DfgVertex& vtx : m_opVertices) {
|
||||
DfgVertex* const cp = vtxp2clonep.at(&vtx);
|
||||
// The code below doesn't work for DfgVertexVariadic, but none of the opVertices are such.
|
||||
UASSERT_OBJ(!vtx.is<DfgVertexVariadic>(), &vtx, "DfgVertexVariadic not handled");
|
||||
const auto oSourceEdges = vtx.sourceEdges();
|
||||
auto cSourceEdges = cp->sourceEdges();
|
||||
UASSERT_OBJ(oSourceEdges.second == cSourceEdges.second, &vtx, "Mismatched source count");
|
||||
for (size_t i = 0; i < oSourceEdges.second; ++i) {
|
||||
if (DfgVertex* const srcp = oSourceEdges.first[i].sourcep()) {
|
||||
cSourceEdges.first[i].relinkSource(vtxp2clonep.at(srcp));
|
||||
if (vtx.is<DfgVertexVariadic>()) {
|
||||
switch (vtx.type()) {
|
||||
case VDfgType::atSpliceArray: {
|
||||
const DfgSpliceArray* const vp = vtx.as<DfgSpliceArray>();
|
||||
DfgSpliceArray* const cp = vtxp2clonep.at(vp)->as<DfgSpliceArray>();
|
||||
vp->forEachSourceEdge([&](const DfgEdge& edge, size_t i) {
|
||||
if (DfgVertex* const srcp = edge.sourcep()) {
|
||||
cp->addDriver(vp->driverFileLine(i), //
|
||||
vp->driverIndex(i), //
|
||||
vtxp2clonep.at(srcp));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case VDfgType::atSplicePacked: {
|
||||
const DfgSplicePacked* const vp = vtx.as<DfgSplicePacked>();
|
||||
DfgSplicePacked* const cp = vtxp2clonep.at(vp)->as<DfgSplicePacked>();
|
||||
vp->forEachSourceEdge([&](const DfgEdge& edge, size_t i) {
|
||||
if (DfgVertex* const srcp = edge.sourcep()) {
|
||||
cp->addDriver(vp->driverFileLine(i), //
|
||||
vp->driverLsb(i), //
|
||||
vtxp2clonep.at(srcp));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
vtx.v3fatalSrc("Unhandled DfgVertexVariadic sub type: " + vtx.typeName());
|
||||
VL_UNREACHABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DfgVertex* const cp = vtxp2clonep.at(&vtx);
|
||||
const auto oSourceEdges = vtx.sourceEdges();
|
||||
auto cSourceEdges = cp->sourceEdges();
|
||||
UASSERT_OBJ(oSourceEdges.second == cSourceEdges.second, &vtx,
|
||||
"Mismatched source count");
|
||||
for (size_t i = 0; i < oSourceEdges.second; ++i) {
|
||||
if (DfgVertex* const srcp = oSourceEdges.first[i].sourcep()) {
|
||||
cSourceEdges.first[i].relinkSource(vtxp2clonep.at(srcp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,8 +246,9 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
|||
AstNode* const nodep = varVtxp->nodep();
|
||||
AstVar* const varp = varVtxp->varp();
|
||||
os << toDotId(vtx);
|
||||
os << " [label=\"" << nodep->name() << "\nW" << varVtxp->width() << " / F"
|
||||
<< varVtxp->fanout() << '"';
|
||||
os << " [label=\"" << nodep->name() << "\n";
|
||||
varVtxp->dtypep()->dumpSmall(os);
|
||||
os << " / F" << varVtxp->fanout() << '"';
|
||||
|
||||
if (varp->direction() == VDirection::INPUT) {
|
||||
os << ", shape=box, style=filled, fillcolor=chartreuse2"; // Green
|
||||
|
@ -257,9 +274,10 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
|||
if (const DfgVarArray* const arrVtxp = vtx.cast<DfgVarArray>()) {
|
||||
AstNode* const nodep = arrVtxp->nodep();
|
||||
AstVar* const varp = arrVtxp->varp();
|
||||
const int elements = VN_AS(arrVtxp->dtypep(), UnpackArrayDType)->elementsConst();
|
||||
os << toDotId(vtx);
|
||||
os << " [label=\"" << nodep->name() << "[" << elements << "]\"";
|
||||
os << " [label=\"" << nodep->name() << "\n";
|
||||
arrVtxp->dtypep()->dumpSmall(os);
|
||||
os << " / F" << arrVtxp->fanout() << '"';
|
||||
if (varp->direction() == VDirection::INPUT) {
|
||||
os << ", shape=box3d, style=filled, fillcolor=chartreuse2"; // Green
|
||||
} else if (varp->direction() == VDirection::OUTPUT) {
|
||||
|
@ -302,8 +320,9 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
|||
const uint32_t lsb = selVtxp->lsb();
|
||||
const uint32_t msb = lsb + selVtxp->width() - 1;
|
||||
os << toDotId(vtx);
|
||||
os << " [label=\"SEL\n_[" << msb << ":" << lsb << "]\nW" << vtx.width() << " / F"
|
||||
<< vtx.fanout() << '"';
|
||||
os << " [label=\"SEL\n_[" << msb << ":" << lsb << "]\n";
|
||||
vtx.dtypep()->dumpSmall(os);
|
||||
os << " / F" << vtx.fanout() << '"';
|
||||
if (vtx.hasMultipleSinks()) {
|
||||
os << ", shape=doublecircle";
|
||||
} else {
|
||||
|
@ -313,8 +332,24 @@ static void dumpDotVertex(std::ostream& os, const DfgVertex& vtx) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (vtx.is<DfgVertexSplice>()) {
|
||||
os << toDotId(vtx);
|
||||
os << " [label=\"" << vtx.typeName() << "\n";
|
||||
vtx.dtypep()->dumpSmall(os);
|
||||
os << " / F" << vtx.fanout() << '"';
|
||||
if (vtx.hasMultipleSinks()) {
|
||||
os << ", shape=doubleoctagon";
|
||||
} else {
|
||||
os << ", shape=octagon";
|
||||
}
|
||||
os << "]\n";
|
||||
return;
|
||||
}
|
||||
|
||||
os << toDotId(vtx);
|
||||
os << " [label=\"" << vtx.typeName() << "\nW" << vtx.width() << " / F" << vtx.fanout() << '"';
|
||||
os << " [label=\"" << vtx.typeName() << "\n";
|
||||
vtx.dtypep()->dumpSmall(os);
|
||||
os << " / F" << vtx.fanout() << '"';
|
||||
if (vtx.hasMultipleSinks()) {
|
||||
os << ", shape=doublecircle";
|
||||
} else {
|
||||
|
@ -336,7 +371,7 @@ static void dumpDotVertexAndSourceEdges(std::ostream& os, const DfgVertex& vtx)
|
|||
vtx.forEachSourceEdge([&](const DfgEdge& edge, size_t idx) { //
|
||||
if (edge.sourcep()) {
|
||||
string headLabel;
|
||||
if (vtx.arity() > 1 || vtx.is<DfgVertexVar>()) headLabel = vtx.srcName(idx);
|
||||
if (vtx.arity() > 1 || vtx.is<DfgVertexSplice>()) headLabel = vtx.srcName(idx);
|
||||
dumpDotEdge(os, edge, headLabel);
|
||||
}
|
||||
});
|
||||
|
@ -521,24 +556,34 @@ bool DfgVertex::selfEquals(const DfgVertex& that) const { return true; }
|
|||
V3Hash DfgVertex::selfHash() const { return V3Hash{}; }
|
||||
|
||||
bool DfgVertex::equals(const DfgVertex& that, EqualsCache& cache) const {
|
||||
// If same vertex, then equal
|
||||
if (this == &that) return true;
|
||||
|
||||
// If different type, then not equal
|
||||
if (this->type() != that.type()) return false;
|
||||
|
||||
// If different data type, then not equal
|
||||
if (this->dtypep() != that.dtypep()) return false;
|
||||
|
||||
// If different number of inputs, then not equal
|
||||
auto thisPair = this->sourceEdges();
|
||||
const DfgEdge* const thisSrcEdgesp = thisPair.first;
|
||||
const size_t thisArity = thisPair.second;
|
||||
auto thatPair = that.sourceEdges();
|
||||
const DfgEdge* const thatSrcEdgesp = thatPair.first;
|
||||
const size_t thatArity = thatPair.second;
|
||||
if (thisArity != thatArity) return false;
|
||||
|
||||
// Check vertex specifics
|
||||
if (!this->selfEquals(that)) return false;
|
||||
|
||||
// Check sources
|
||||
const auto key = (this < &that) ? EqualsCache::key_type{this, &that} //
|
||||
: EqualsCache::key_type{&that, this};
|
||||
// Note: the recursive invocation can cause a re-hash but that will not invalidate references
|
||||
uint8_t& result = cache[key];
|
||||
if (!result) {
|
||||
result = 2; // Assume equals
|
||||
auto thisPair = this->sourceEdges();
|
||||
const DfgEdge* const thisSrcEdgesp = thisPair.first;
|
||||
const size_t thisArity = thisPair.second;
|
||||
auto thatPair = that.sourceEdges();
|
||||
const DfgEdge* const thatSrcEdgesp = thatPair.first;
|
||||
const size_t thatArity = thatPair.second;
|
||||
UASSERT_OBJ(thisArity == thatArity, this, "Same type vertices must have same arity!");
|
||||
for (size_t i = 0; i < thisArity; ++i) {
|
||||
const DfgVertex* const thisSrcVtxp = thisSrcEdgesp[i].m_sourcep;
|
||||
const DfgVertex* const thatSrcVtxp = thatSrcEdgesp[i].m_sourcep;
|
||||
|
@ -561,7 +606,12 @@ V3Hash DfgVertex::hash() {
|
|||
// variables, which we rely on.
|
||||
if (!is<DfgVertexVar>()) {
|
||||
hash += m_type;
|
||||
hash += width(); // Currently all non-variable vertices are packed, so this is safe
|
||||
if (AstUnpackArrayDType* const adtypep = VN_CAST(dtypep(), UnpackArrayDType)) {
|
||||
hash += adtypep->elementsConst();
|
||||
// TODO: maybe include sub-dtype, but not hugely important at the moment
|
||||
} else {
|
||||
hash += width();
|
||||
}
|
||||
const auto pair = sourceEdges();
|
||||
const DfgEdge* const edgesp = pair.first;
|
||||
const size_t arity = pair.second;
|
||||
|
@ -579,22 +629,16 @@ uint32_t DfgVertex::fanout() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
DfgVarPacked* DfgVertex::getResultVar() {
|
||||
UASSERT_OBJ(!this->is<DfgVarArray>(), this, "Arrays are not supported by " << __FUNCTION__);
|
||||
|
||||
DfgVertexVar* DfgVertex::getResultVar() {
|
||||
// It's easy if the vertex is already a variable ...
|
||||
if (DfgVarPacked* const varp = this->cast<DfgVarPacked>()) return varp;
|
||||
if (DfgVertexVar* const varp = this->cast<DfgVertexVar>()) return varp;
|
||||
|
||||
// Inspect existing variables fully written by this vertex, and choose one
|
||||
DfgVarPacked* resp = nullptr;
|
||||
// Inspect existing variables written by this vertex, and choose one
|
||||
DfgVertexVar* resp = nullptr;
|
||||
// cppcheck-has-bug-suppress constParameter
|
||||
this->forEachSink([&resp](DfgVertex& sink) {
|
||||
DfgVarPacked* const varp = sink.cast<DfgVarPacked>();
|
||||
DfgVertexVar* const varp = sink.cast<DfgVertexVar>();
|
||||
if (!varp) return;
|
||||
if (!varp->isDrivenFullyByDfg()) return;
|
||||
// Ignore SystemC variables, they cannot participate in expressions or
|
||||
// be assigned rvalue expressions.
|
||||
if (varp->varp()->isSc()) return;
|
||||
// First variable found
|
||||
if (!resp) {
|
||||
resp = varp;
|
||||
|
@ -638,9 +682,11 @@ AstScope* DfgVertex::scopep(ScopeCache& cache, bool tryResultVar) VL_MT_DISABLED
|
|||
if (DfgVertexVar* const varp = this->getResultVar()) return varp->varScopep()->scopep();
|
||||
}
|
||||
|
||||
// Look up cache
|
||||
const auto pair = cache.emplace(this, nullptr);
|
||||
if (pair.second) {
|
||||
// Note: the recursive invocation can cause a re-hash but that will not invalidate references
|
||||
AstScope*& resultr = cache[this];
|
||||
if (!resultr) {
|
||||
// Mark to prevent infinite recursion on circular graphs - should never be called on such
|
||||
resultr = reinterpret_cast<AstScope*>(1);
|
||||
// Find scope based on sources, falling back on the root scope
|
||||
AstScope* const rootp = v3Global.rootp()->topScopep()->scopep();
|
||||
AstScope* foundp = rootp;
|
||||
|
@ -650,15 +696,15 @@ AstScope* DfgVertex::scopep(ScopeCache& cache, bool tryResultVar) VL_MT_DISABLED
|
|||
foundp = edge.sourcep()->scopep(cache, true);
|
||||
if (foundp != rootp) break;
|
||||
}
|
||||
pair.first->second = foundp;
|
||||
resultr = foundp;
|
||||
}
|
||||
|
||||
// If the cache entry exists, but have not set the mapping yet, then we have a circualr graph
|
||||
UASSERT_OBJ(pair.first->second, this,
|
||||
// Die on a graph circular through operation vertices
|
||||
UASSERT_OBJ(resultr != reinterpret_cast<AstScope*>(1), this,
|
||||
"DfgVertex::scopep called on graph with circular operations");
|
||||
|
||||
// Done
|
||||
return pair.first->second;
|
||||
return resultr;
|
||||
}
|
||||
|
||||
void DfgVertex::unlinkDelete(DfgGraph& dfg) {
|
||||
|
@ -694,6 +740,42 @@ bool DfgSel::selfEquals(const DfgVertex& that) const { return lsb() == that.as<D
|
|||
|
||||
V3Hash DfgSel::selfHash() const { return V3Hash{lsb()}; }
|
||||
|
||||
// DfgSpliceArray ----------
|
||||
|
||||
bool DfgSpliceArray::selfEquals(const DfgVertex& that) const {
|
||||
const DfgSpliceArray* const thatp = that.as<DfgSpliceArray>();
|
||||
const size_t arity = this->arity();
|
||||
for (size_t i = 0; i < arity; ++i) {
|
||||
if (driverIndex(i) != thatp->driverIndex(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
V3Hash DfgSpliceArray::selfHash() const {
|
||||
V3Hash hash;
|
||||
const size_t arity = this->arity();
|
||||
for (size_t i = 0; i < arity; ++i) hash += driverIndex(i);
|
||||
return hash;
|
||||
}
|
||||
|
||||
// DfgSplicePacked ----------
|
||||
|
||||
bool DfgSplicePacked::selfEquals(const DfgVertex& that) const {
|
||||
const DfgSplicePacked* const thatp = that.as<DfgSplicePacked>();
|
||||
const size_t arity = this->arity();
|
||||
for (size_t i = 0; i < arity; ++i) {
|
||||
if (driverLsb(i) != thatp->driverLsb(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
V3Hash DfgSplicePacked::selfHash() const {
|
||||
V3Hash hash;
|
||||
const size_t arity = this->arity();
|
||||
for (size_t i = 0; i < arity; ++i) hash += driverLsb(i);
|
||||
return hash;
|
||||
}
|
||||
|
||||
// DfgVertexVar ----------
|
||||
|
||||
bool DfgVertexVar::selfEquals(const DfgVertex& that) const {
|
||||
|
|
30
src/V3Dfg.h
30
src/V3Dfg.h
|
@ -230,7 +230,13 @@ public:
|
|||
|
||||
// Retrieve user data, must be current.
|
||||
template <typename T>
|
||||
inline T& getUser();
|
||||
inline const T& getUser() const;
|
||||
|
||||
// Retrieve user data, must be current.
|
||||
template <typename T>
|
||||
T& getUser() {
|
||||
return const_cast<T&>(const_cast<const DfgVertex*>(this)->getUser<T>());
|
||||
}
|
||||
|
||||
// Set user data, becomes current.
|
||||
template <typename T>
|
||||
|
@ -238,8 +244,7 @@ public:
|
|||
|
||||
// Width of result
|
||||
uint32_t width() const {
|
||||
// This is a hot enough function that this is an expensive check, so in debug build only.
|
||||
UDEBUGONLY(UASSERT_OBJ(VN_IS(dtypep(), BasicDType), this, "non-packed has no 'width()'"););
|
||||
UASSERT_OBJ(VN_IS(dtypep(), BasicDType), this, "non-packed has no 'width()'");
|
||||
return dtypep()->width();
|
||||
}
|
||||
|
||||
|
@ -283,7 +288,7 @@ public:
|
|||
|
||||
// Return a canonical variable vertex that holds the value of this vertex,
|
||||
// or nullptr if no such variable exists in the graph. This is O(fanout).
|
||||
DfgVarPacked* getResultVar() VL_MT_DISABLED;
|
||||
DfgVertexVar* getResultVar() VL_MT_DISABLED;
|
||||
|
||||
// Cache type for 'scopep' below
|
||||
using ScopeCache = std::unordered_map<const DfgVertex*, AstScope*>;
|
||||
|
@ -572,7 +577,7 @@ class DfgVertexVariadic VL_NOT_FINAL : public DfgVertex {
|
|||
|
||||
protected:
|
||||
DfgVertexVariadic(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep,
|
||||
uint32_t initialCapacity = 1)
|
||||
uint32_t initialCapacity)
|
||||
: DfgVertex{dfg, type, flp, dtypep}
|
||||
, m_srcsp{allocSources(initialCapacity)}
|
||||
, m_srcCap{initialCapacity} {}
|
||||
|
@ -784,12 +789,12 @@ T& DfgVertex::user() {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
T& DfgVertex::getUser() {
|
||||
const T& DfgVertex::getUser() const {
|
||||
static_assert(sizeof(T) <= sizeof(UserDataStorage),
|
||||
"Size of user data type 'T' is too large for allocated storage");
|
||||
static_assert(alignof(T) <= alignof(UserDataStorage),
|
||||
"Alignment of user data type 'T' is larger than allocated storage");
|
||||
T* const storagep = reinterpret_cast<T*>(&m_userDataStorage);
|
||||
const T* const storagep = reinterpret_cast<const T*>(&m_userDataStorage);
|
||||
#if VL_DEBUG
|
||||
const uint32_t userCurrent = m_graphp->m_userCurrent;
|
||||
UASSERT_OBJ(userCurrent, this, "DfgVertex user data used without reserving");
|
||||
|
@ -914,18 +919,19 @@ bool DfgVertex::isOnes() const {
|
|||
// Inline method definitions - for DfgVertexVar
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
DfgVertexVar::DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, uint32_t initialCapacity)
|
||||
: DfgVertexVariadic{dfg, type, varp->fileline(), dtypeFor(varp), initialCapacity}
|
||||
DfgVertexVar::DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp)
|
||||
: DfgVertexUnary{dfg, type, varp->fileline(), dtypeFor(varp)}
|
||||
, m_varp{varp}
|
||||
, m_varScopep{nullptr} {
|
||||
UASSERT_OBJ(dfg.modulep(), varp, "Un-scoped DfgVertexVar created in scoped DfgGraph");
|
||||
UASSERT_OBJ(!m_varp->isSc(), varp, "SystemC variable is not representable by DfgVertexVar");
|
||||
}
|
||||
DfgVertexVar::DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp,
|
||||
uint32_t initialCapacity)
|
||||
: DfgVertexVariadic{dfg, type, vscp->fileline(), dtypeFor(vscp), initialCapacity}
|
||||
DfgVertexVar::DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp)
|
||||
: DfgVertexUnary{dfg, type, vscp->fileline(), dtypeFor(vscp)}
|
||||
, m_varp{vscp->varp()}
|
||||
, m_varScopep{vscp} {
|
||||
UASSERT_OBJ(!dfg.modulep(), vscp, "Scoped DfgVertexVar created in un-scoped DfgGraph");
|
||||
UASSERT_OBJ(!m_varp->isSc(), vscp, "SystemC variable is not representable by DfgVertexVar");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
@ -28,9 +28,12 @@
|
|||
|
||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||
|
||||
#include "V3Const.h"
|
||||
#include "V3Dfg.h"
|
||||
#include "V3DfgPasses.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
||||
namespace {
|
||||
|
@ -42,6 +45,17 @@ T_Vertex* makeVertex(const T_Node* nodep, DfgGraph& dfg) {
|
|||
return new T_Vertex{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)};
|
||||
}
|
||||
|
||||
template <>
|
||||
DfgArraySel* makeVertex<DfgArraySel, AstArraySel>(const AstArraySel* nodep, DfgGraph& dfg) {
|
||||
// Some earlier passes create malformed ArraySels, just bail on those...
|
||||
// See t_bitsel_wire_array_bad
|
||||
if (VN_IS(nodep->fromp(), Const)) return nullptr;
|
||||
AstUnpackArrayDType* const fromDtypep
|
||||
= VN_CAST(nodep->fromp()->dtypep()->skipRefp(), UnpackArrayDType);
|
||||
if (!fromDtypep) return nullptr;
|
||||
return new DfgArraySel{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)};
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Currently unhandled nodes
|
||||
// LCOV_EXCL_START
|
||||
|
@ -77,17 +91,6 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
const VNUser1InUse m_user1InUse;
|
||||
|
||||
// TYPES
|
||||
// Represents a driver during canonicalization
|
||||
struct Driver final {
|
||||
FileLine* m_fileline;
|
||||
DfgVertex* m_vtxp;
|
||||
uint32_t m_lsb;
|
||||
Driver(FileLine* flp, uint32_t lsb, DfgVertex* vtxp)
|
||||
: m_fileline{flp}
|
||||
, m_vtxp{vtxp}
|
||||
, m_lsb{lsb} {}
|
||||
};
|
||||
|
||||
using RootType = std::conditional_t<T_Scoped, AstNetlist, AstModule>;
|
||||
using VariableType = std::conditional_t<T_Scoped, AstVarScope, AstVar>;
|
||||
|
||||
|
@ -122,8 +125,9 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
|
||||
void markReferenced(AstNode* nodep) {
|
||||
nodep->foreach([this](const AstVarRef* refp) {
|
||||
// No need to (and in fact cannot) mark variables with unsupported dtypes
|
||||
if (!DfgVertex::isSupportedDType(refp->varp()->dtypep())) return;
|
||||
// No need to (and in fact cannot) mark variables if:
|
||||
if (!DfgVertex::isSupportedDType(refp->varp()->dtypep())) return; // unsupported type
|
||||
if (refp->varp()->isSc()) return; // SystemC
|
||||
VariableType* const tgtp = getTarget(refp);
|
||||
// Mark vertex as having a module reference outside current DFG
|
||||
getNet(tgtp)->setHasModRefs();
|
||||
|
@ -183,75 +187,144 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
return m_foundUnhandled;
|
||||
}
|
||||
|
||||
// Build DfgEdge representing the LValue assignment. Returns false if unsuccessful.
|
||||
bool convertAssignment(FileLine* flp, AstNode* nodep, DfgVertex* vtxp) {
|
||||
std::pair<DfgVertexSplice*, uint32_t> convertLValue(AstNode* nodep) {
|
||||
if (AstVarRef* const vrefp = VN_CAST(nodep, VarRef)) {
|
||||
m_foundUnhandled = false;
|
||||
visit(vrefp);
|
||||
// cppcheck-has-bug-suppress knownConditionTrueFalse
|
||||
if (m_foundUnhandled) return false;
|
||||
getVertex(vrefp)->template as<DfgVarPacked>()->addDriver(flp, 0, vtxp);
|
||||
return true;
|
||||
if (m_foundUnhandled) return {nullptr, 0};
|
||||
|
||||
// Get the variable vertex
|
||||
DfgVertexVar* const vtxp = getVertex(vrefp)->template as<DfgVertexVar>();
|
||||
// Ensure the Splice driver exists for this variable
|
||||
if (!vtxp->srcp()) {
|
||||
FileLine* const flp = vtxp->fileline();
|
||||
AstNodeDType* const dtypep = vtxp->dtypep();
|
||||
if (vtxp->is<DfgVarPacked>()) {
|
||||
vtxp->srcp(new DfgSplicePacked{*m_dfgp, flp, dtypep});
|
||||
} else if (vtxp->is<DfgVarArray>()) {
|
||||
vtxp->srcp(new DfgSpliceArray{*m_dfgp, flp, dtypep});
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unhandled DfgVertexVar sub-type"); // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
// Return the Splice driver
|
||||
return {vtxp->srcp()->as<DfgVertexSplice>(), 0};
|
||||
}
|
||||
if (AstSel* const selp = VN_CAST(nodep, Sel)) {
|
||||
AstVarRef* const vrefp = VN_CAST(selp->fromp(), VarRef);
|
||||
|
||||
if (AstSel* selp = VN_CAST(nodep, Sel)) {
|
||||
// Only handle constant selects
|
||||
const AstConst* const lsbp = VN_CAST(selp->lsbp(), Const);
|
||||
if (!vrefp || !lsbp) {
|
||||
if (!lsbp) {
|
||||
++m_ctx.m_nonRepLhs;
|
||||
return false;
|
||||
return {nullptr, 0};
|
||||
}
|
||||
m_foundUnhandled = false;
|
||||
visit(vrefp);
|
||||
// cppcheck-has-bug-suppress knownConditionTrueFalse
|
||||
if (m_foundUnhandled) return false;
|
||||
getVertex(vrefp)->template as<DfgVarPacked>()->addDriver(flp, lsbp->toUInt(), vtxp);
|
||||
return true;
|
||||
}
|
||||
if (AstArraySel* const selp = VN_CAST(nodep, ArraySel)) {
|
||||
AstVarRef* const vrefp = VN_CAST(selp->fromp(), VarRef);
|
||||
const AstConst* const idxp = VN_CAST(selp->bitp(), Const);
|
||||
if (!vrefp || !idxp) {
|
||||
++m_ctx.m_nonRepLhs;
|
||||
return false;
|
||||
}
|
||||
m_foundUnhandled = false;
|
||||
visit(vrefp);
|
||||
// cppcheck-has-bug-suppress knownConditionTrueFalse
|
||||
if (m_foundUnhandled) return false;
|
||||
getVertex(vrefp)->template as<DfgVarArray>()->addDriver(flp, idxp->toUInt(), vtxp);
|
||||
return true;
|
||||
}
|
||||
if (AstConcat* const concatp = VN_CAST(nodep, Concat)) {
|
||||
AstNode* const lhsp = concatp->lhsp();
|
||||
AstNode* const rhsp = concatp->rhsp();
|
||||
uint32_t lsb = lsbp->toUInt();
|
||||
|
||||
{
|
||||
FileLine* const lFlp = lhsp->fileline();
|
||||
DfgSel* const lVtxp = new DfgSel{*m_dfgp, lFlp, DfgVertex::dtypeFor(lhsp)};
|
||||
// Convert the 'fromp' sub-expression
|
||||
const auto pair = convertLValue(selp->fromp());
|
||||
if (!pair.first) return {nullptr, 0};
|
||||
DfgSplicePacked* const splicep = pair.first->template as<DfgSplicePacked>();
|
||||
// Adjust index.
|
||||
lsb += pair.second;
|
||||
|
||||
// AstSel doesn't change type kind (array vs packed), so we can use
|
||||
// the existing splice driver with adjusted lsb
|
||||
return {splicep, lsb};
|
||||
}
|
||||
|
||||
if (AstArraySel* const aselp = VN_CAST(nodep, ArraySel)) {
|
||||
// Only handle constant selects
|
||||
const AstConst* const indexp = VN_CAST(aselp->bitp(), Const);
|
||||
if (!indexp) {
|
||||
++m_ctx.m_nonRepLhs;
|
||||
return {nullptr, 0};
|
||||
}
|
||||
uint32_t index = indexp->toUInt();
|
||||
|
||||
// Convert the 'fromp' sub-expression
|
||||
const auto pair = convertLValue(aselp->fromp());
|
||||
if (!pair.first) return {nullptr, 0};
|
||||
DfgSpliceArray* const splicep = pair.first->template as<DfgSpliceArray>();
|
||||
// Adjust index. Note pair.second is always 0, but we might handle array slices later..
|
||||
index += pair.second;
|
||||
|
||||
// Ensure the Splice driver exists for this element
|
||||
if (!splicep->driverAt(index)) {
|
||||
FileLine* const flp = nodep->fileline();
|
||||
AstNodeDType* const dtypep = DfgVertex::dtypeFor(nodep);
|
||||
if (VN_IS(dtypep, BasicDType)) {
|
||||
splicep->addDriver(flp, index, new DfgSplicePacked{*m_dfgp, flp, dtypep});
|
||||
} else if (VN_IS(dtypep, UnpackArrayDType)) {
|
||||
splicep->addDriver(flp, index, new DfgSpliceArray{*m_dfgp, flp, dtypep});
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unhandled AstNodeDType sub-type"); // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
// Return the splice driver
|
||||
return {splicep->driverAt(index)->as<DfgVertexSplice>(), 0};
|
||||
}
|
||||
|
||||
++m_ctx.m_nonRepLhs;
|
||||
return {nullptr, 0};
|
||||
}
|
||||
|
||||
// Build DfgEdge representing the LValue assignment. Returns false if unsuccessful.
|
||||
bool convertAssignment(FileLine* flp, AstNode* lhsp, DfgVertex* vtxp) {
|
||||
// Simplify the LHS, to get rid of things like SEL(CONCAT(_, _), _)
|
||||
lhsp = V3Const::constifyExpensiveEdit(lhsp);
|
||||
|
||||
// Concatenation on the LHS. Select parts of the driving 'vtxp' then convert each part
|
||||
if (AstConcat* const concatp = VN_CAST(lhsp, Concat)) {
|
||||
AstNode* const cLhsp = concatp->lhsp();
|
||||
AstNode* const cRhsp = concatp->rhsp();
|
||||
|
||||
{ // Convet LHS of concat
|
||||
FileLine* const lFlp = cLhsp->fileline();
|
||||
DfgSel* const lVtxp = new DfgSel{*m_dfgp, lFlp, DfgVertex::dtypeFor(cLhsp)};
|
||||
lVtxp->fromp(vtxp);
|
||||
lVtxp->lsb(rhsp->width());
|
||||
if (!convertAssignment(flp, lhsp, lVtxp)) return false;
|
||||
lVtxp->lsb(cRhsp->width());
|
||||
if (!convertAssignment(flp, cLhsp, lVtxp)) return false;
|
||||
}
|
||||
|
||||
{
|
||||
FileLine* const rFlp = rhsp->fileline();
|
||||
DfgSel* const rVtxp = new DfgSel{*m_dfgp, rFlp, DfgVertex::dtypeFor(rhsp)};
|
||||
{ // Convert RHS of concat
|
||||
FileLine* const rFlp = cRhsp->fileline();
|
||||
DfgSel* const rVtxp = new DfgSel{*m_dfgp, rFlp, DfgVertex::dtypeFor(cRhsp)};
|
||||
rVtxp->fromp(vtxp);
|
||||
rVtxp->lsb(0);
|
||||
return convertAssignment(flp, rhsp, rVtxp);
|
||||
return convertAssignment(flp, cRhsp, rVtxp);
|
||||
}
|
||||
}
|
||||
++m_ctx.m_nonRepLhs;
|
||||
return false;
|
||||
|
||||
// Construct LHS
|
||||
const auto pair = convertLValue(lhsp);
|
||||
if (!pair.first) return false;
|
||||
|
||||
// If successful connect the driver
|
||||
if (DfgSplicePacked* const sPackedp = pair.first->template cast<DfgSplicePacked>()) {
|
||||
sPackedp->addDriver(flp, pair.second, vtxp);
|
||||
} else if (DfgSpliceArray* const sArrayp = pair.first->template cast<DfgSpliceArray>()) {
|
||||
sArrayp->addDriver(flp, pair.second, vtxp);
|
||||
} else {
|
||||
lhsp->v3fatalSrc("Unhandled DfgVertexSplice sub-type"); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertEquation(AstNode* nodep, FileLine* flp, AstNode* lhsp, AstNode* rhsp) {
|
||||
UASSERT_OBJ(m_uncommittedVertices.empty(), nodep, "Should not nest");
|
||||
|
||||
// Currently cannot handle direct assignments between unpacked types. These arise e.g.
|
||||
// when passing an unpacked array through a module port.
|
||||
if (!DfgVertex::isSupportedPackedDType(lhsp->dtypep())
|
||||
|| !DfgVertex::isSupportedPackedDType(rhsp->dtypep())) {
|
||||
// Check data types are compatible.
|
||||
if (!DfgVertex::isSupportedDType(lhsp->dtypep())
|
||||
|| !DfgVertex::isSupportedDType(rhsp->dtypep())) {
|
||||
markReferenced(nodep);
|
||||
++m_ctx.m_nonRepDType;
|
||||
return false;
|
||||
}
|
||||
|
||||
// For now, only direct array assignment is supported (e.g. a = b, but not a = _ ? b : c)
|
||||
if (VN_IS(rhsp->dtypep()->skipRefp(), UnpackArrayDType) && !VN_IS(rhsp, VarRef)) {
|
||||
markReferenced(nodep);
|
||||
++m_ctx.m_nonRepDType;
|
||||
return false;
|
||||
|
@ -294,166 +367,310 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Sometime assignment ranges are coalesced by V3Const,
|
||||
// so we unpack concatenations for better error reporting.
|
||||
void addDriver(FileLine* flp, uint32_t lsb, DfgVertex* vtxp,
|
||||
std::vector<Driver>& drivers) const {
|
||||
if (DfgConcat* const concatp = vtxp->cast<DfgConcat>()) {
|
||||
DfgVertex* const rhsp = concatp->rhsp();
|
||||
auto const rhs_width = rhsp->width();
|
||||
addDriver(rhsp->fileline(), lsb, rhsp, drivers);
|
||||
DfgVertex* const lhsp = concatp->lhsp();
|
||||
addDriver(lhsp->fileline(), lsb + rhs_width, lhsp, drivers);
|
||||
concatp->unlinkDelete(*m_dfgp);
|
||||
} else {
|
||||
drivers.emplace_back(flp, lsb, vtxp);
|
||||
// Prune vertices potentially unused due to resolving multiple drivers.
|
||||
// Having multiple drivers is an error and is hence assumed to be rare,
|
||||
// so performance is not very important, set will suffice.
|
||||
void removeUnused(std::set<DfgVertex*>& prune) {
|
||||
while (!prune.empty()) {
|
||||
// Pop last vertex
|
||||
const auto it = prune.begin();
|
||||
DfgVertex* const vtxp = *it;
|
||||
prune.erase(it);
|
||||
// If used (or a variable), then done
|
||||
if (vtxp->hasSinks() || vtxp->is<DfgVertexVar>()) continue;
|
||||
// If unused, then add sources to work list and delete
|
||||
vtxp->forEachSource([&](DfgVertex& src) { prune.emplace(&src); });
|
||||
vtxp->unlinkDelete(*m_dfgp);
|
||||
}
|
||||
}
|
||||
|
||||
// Canonicalize packed variables
|
||||
void canonicalizePacked() {
|
||||
for (DfgVarPacked* const varp : m_varPackedps) {
|
||||
// Delete variables with no sinks nor sources (this can happen due to reverting
|
||||
// uncommitted vertices, which does not remove variables)
|
||||
if (!varp->hasSinks() && varp->arity() == 0) {
|
||||
VL_DO_DANGLING(varp->unlinkDelete(*m_dfgp), varp);
|
||||
// Normalize packed driver - return the normalized vertex and location for 'splicep'
|
||||
std::pair<DfgVertex*, FileLine*> //
|
||||
normalizePacked(DfgVertexVar* varp, const std::string& sub, DfgSplicePacked* const splicep) {
|
||||
// Represents a driver of 'splicep'
|
||||
struct Driver final {
|
||||
FileLine* m_fileline;
|
||||
DfgVertex* m_vtxp;
|
||||
uint32_t m_lsb;
|
||||
Driver() = delete;
|
||||
Driver(FileLine* flp, uint32_t lsb, DfgVertex* vtxp)
|
||||
: m_fileline{flp}
|
||||
, m_vtxp{vtxp}
|
||||
, m_lsb{lsb} {}
|
||||
};
|
||||
|
||||
// The drivers of 'splicep'
|
||||
std::vector<Driver> drivers;
|
||||
drivers.reserve(splicep->arity());
|
||||
|
||||
// Sometime assignment ranges are coalesced by V3Const,
|
||||
// so we unpack concatenations for better error reporting.
|
||||
const std::function<void(FileLine*, uint32_t, DfgVertex*)> gather
|
||||
= [&](FileLine* flp, uint32_t lsb, DfgVertex* vtxp) -> void {
|
||||
if (DfgConcat* const concatp = vtxp->cast<DfgConcat>()) {
|
||||
DfgVertex* const rhsp = concatp->rhsp();
|
||||
auto const rhs_width = rhsp->width();
|
||||
gather(rhsp->fileline(), lsb, rhsp);
|
||||
DfgVertex* const lhsp = concatp->lhsp();
|
||||
gather(lhsp->fileline(), lsb + rhs_width, lhsp);
|
||||
concatp->unlinkDelete(*m_dfgp);
|
||||
} else {
|
||||
drivers.emplace_back(flp, lsb, vtxp);
|
||||
}
|
||||
};
|
||||
|
||||
// Gather and unlink all drivers
|
||||
splicep->forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
DfgVertex* const driverp = edge.sourcep();
|
||||
UASSERT(driverp, "Should not have created undriven sources");
|
||||
UASSERT_OBJ(!driverp->is<DfgVertexSplice>(), splicep, "Should not be DfgVertexSplice");
|
||||
gather(splicep->driverFileLine(idx), splicep->driverLsb(idx), driverp);
|
||||
edge.unlinkSource();
|
||||
});
|
||||
|
||||
const auto cmp = [](const Driver& a, const Driver& b) {
|
||||
if (a.m_lsb != b.m_lsb) return a.m_lsb < b.m_lsb;
|
||||
return a.m_fileline->operatorCompare(*b.m_fileline) < 0;
|
||||
};
|
||||
|
||||
// Sort drivers by LSB
|
||||
std::stable_sort(drivers.begin(), drivers.end(), cmp);
|
||||
|
||||
// Vertices that might have become unused due to multiple driver resolution. Having
|
||||
// multiple drivers is an error and is hence assumed to be rare, so performance is
|
||||
// not very important, set will suffice.
|
||||
std::set<DfgVertex*> prune;
|
||||
|
||||
// Fix multiply driven ranges
|
||||
for (auto it = drivers.begin(); it != drivers.end();) {
|
||||
Driver& a = *it++;
|
||||
const uint32_t aWidth = a.m_vtxp->width();
|
||||
const uint32_t aEnd = a.m_lsb + aWidth;
|
||||
while (it != drivers.end()) {
|
||||
Driver& b = *it;
|
||||
// If no overlap, then nothing to do
|
||||
if (b.m_lsb >= aEnd) break;
|
||||
|
||||
const uint32_t bWidth = b.m_vtxp->width();
|
||||
const uint32_t bEnd = b.m_lsb + bWidth;
|
||||
const uint32_t overlapEnd = std::min(aEnd, bEnd) - 1;
|
||||
|
||||
if (a.m_fileline->operatorCompare(*b.m_fileline) != 0
|
||||
&& !varp->varp()->isUsedLoopIdx() // Loop index often abused, so suppress
|
||||
) {
|
||||
AstNode* const vp = varp->varScopep()
|
||||
? static_cast<AstNode*>(varp->varScopep())
|
||||
: static_cast<AstNode*>(varp->varp());
|
||||
|
||||
vp->v3warn( //
|
||||
MULTIDRIVEN,
|
||||
"Bits [" //
|
||||
<< overlapEnd << ":" << b.m_lsb << "] of signal '" << vp->prettyName()
|
||||
<< sub << "' have multiple combinational drivers\n"
|
||||
<< a.m_fileline->warnOther() << "... Location of first driver\n"
|
||||
<< a.m_fileline->warnContextPrimary() << '\n'
|
||||
<< b.m_fileline->warnOther() << "... Location of other driver\n"
|
||||
<< b.m_fileline->warnContextSecondary() << vp->warnOther()
|
||||
<< "... Only the first driver will be respected");
|
||||
}
|
||||
|
||||
// If the first driver completely covers the range of the second driver,
|
||||
// we can just delete the second driver completely, otherwise adjust the
|
||||
// second driver to apply from the end of the range of the first driver.
|
||||
if (aEnd >= bEnd) {
|
||||
prune.emplace(b.m_vtxp);
|
||||
it = drivers.erase(it);
|
||||
} else {
|
||||
const auto dtypep = DfgVertex::dtypeForWidth(bEnd - aEnd);
|
||||
DfgSel* const selp = new DfgSel{*m_dfgp, b.m_vtxp->fileline(), dtypep};
|
||||
selp->fromp(b.m_vtxp);
|
||||
selp->lsb(aEnd - b.m_lsb);
|
||||
b.m_lsb = aEnd;
|
||||
b.m_vtxp = selp;
|
||||
std::stable_sort(it, drivers.end(), cmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coalesce adjacent ranges
|
||||
for (size_t i = 0, j = 1; j < drivers.size(); ++j) {
|
||||
Driver& a = drivers[i];
|
||||
Driver& b = drivers[j];
|
||||
|
||||
// Coalesce adjacent range
|
||||
const uint32_t aWidth = a.m_vtxp->width();
|
||||
const uint32_t bWidth = b.m_vtxp->width();
|
||||
if (a.m_lsb + aWidth == b.m_lsb) {
|
||||
const auto dtypep = DfgVertex::dtypeForWidth(aWidth + bWidth);
|
||||
DfgConcat* const concatp = new DfgConcat{*m_dfgp, a.m_fileline, dtypep};
|
||||
concatp->rhsp(a.m_vtxp);
|
||||
concatp->lhsp(b.m_vtxp);
|
||||
a.m_vtxp = concatp;
|
||||
b.m_vtxp = nullptr; // Mark as moved
|
||||
++m_ctx.m_coalescedAssignments;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Gather (and unlink) all drivers
|
||||
std::vector<Driver> drivers;
|
||||
drivers.reserve(varp->arity());
|
||||
varp->forEachSourceEdge([this, varp, &drivers](DfgEdge& edge, size_t idx) {
|
||||
DfgVertex* const driverp = edge.sourcep();
|
||||
UASSERT(driverp, "Should not have created undriven sources");
|
||||
addDriver(varp->driverFileLine(idx), varp->driverLsb(idx), driverp, drivers);
|
||||
edge.unlinkSource();
|
||||
});
|
||||
++i;
|
||||
|
||||
const auto cmp = [](const Driver& a, const Driver& b) {
|
||||
if (a.m_lsb != b.m_lsb) return a.m_lsb < b.m_lsb;
|
||||
return a.m_fileline->operatorCompare(*b.m_fileline) < 0;
|
||||
};
|
||||
|
||||
// Sort drivers by LSB
|
||||
std::stable_sort(drivers.begin(), drivers.end(), cmp);
|
||||
|
||||
// Vertices that might have become unused due to multiple driver resolution. Having
|
||||
// multiple drivers is an error and is hence assumed to be rare, so performance is
|
||||
// not very important, set will suffice.
|
||||
std::set<DfgVertex*> prune;
|
||||
|
||||
// Fix multiply driven ranges
|
||||
for (auto it = drivers.begin(); it != drivers.end();) {
|
||||
Driver& a = *it++;
|
||||
const uint32_t aWidth = a.m_vtxp->width();
|
||||
const uint32_t aEnd = a.m_lsb + aWidth;
|
||||
while (it != drivers.end()) {
|
||||
Driver& b = *it;
|
||||
// If no overlap, then nothing to do
|
||||
if (b.m_lsb >= aEnd) break;
|
||||
|
||||
const uint32_t bWidth = b.m_vtxp->width();
|
||||
const uint32_t bEnd = b.m_lsb + bWidth;
|
||||
const uint32_t overlapEnd = std::min(aEnd, bEnd) - 1;
|
||||
|
||||
if (a.m_fileline->operatorCompare(*b.m_fileline) != 0
|
||||
&& !varp->varp()->isUsedLoopIdx() // Loop index often abused, so suppress
|
||||
) {
|
||||
AstNode* const vp = varp->varScopep()
|
||||
? static_cast<AstNode*>(varp->varScopep())
|
||||
: static_cast<AstNode*>(varp->varp());
|
||||
vp->v3warn( //
|
||||
MULTIDRIVEN,
|
||||
"Bits [" //
|
||||
<< overlapEnd << ":" << b.m_lsb << "] of signal "
|
||||
<< vp->prettyNameQ() << " have multiple combinational drivers\n"
|
||||
<< a.m_fileline->warnOther() << "... Location of first driver\n"
|
||||
<< a.m_fileline->warnContextPrimary() << '\n'
|
||||
<< b.m_fileline->warnOther() << "... Location of other driver\n"
|
||||
<< b.m_fileline->warnContextSecondary() << vp->warnOther()
|
||||
<< "... Only the first driver will be respected");
|
||||
}
|
||||
|
||||
// If the first driver completely covers the range of the second driver,
|
||||
// we can just delete the second driver completely, otherwise adjust the
|
||||
// second driver to apply from the end of the range of the first driver.
|
||||
if (aEnd >= bEnd) {
|
||||
prune.emplace(b.m_vtxp);
|
||||
it = drivers.erase(it);
|
||||
} else {
|
||||
const auto dtypep = DfgVertex::dtypeForWidth(bEnd - aEnd);
|
||||
DfgSel* const selp = new DfgSel{*m_dfgp, b.m_vtxp->fileline(), dtypep};
|
||||
selp->fromp(b.m_vtxp);
|
||||
selp->lsb(aEnd - b.m_lsb);
|
||||
b.m_lsb = aEnd;
|
||||
b.m_vtxp = selp;
|
||||
std::stable_sort(it, drivers.end(), cmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coalesce adjacent ranges
|
||||
for (size_t i = 0, j = 1; j < drivers.size(); ++j) {
|
||||
Driver& a = drivers[i];
|
||||
Driver& b = drivers[j];
|
||||
|
||||
// Coalesce adjacent range
|
||||
const uint32_t aWidth = a.m_vtxp->width();
|
||||
const uint32_t bWidth = b.m_vtxp->width();
|
||||
if (a.m_lsb + aWidth == b.m_lsb) {
|
||||
const auto dtypep = DfgVertex::dtypeForWidth(aWidth + bWidth);
|
||||
DfgConcat* const concatp = new DfgConcat{*m_dfgp, a.m_fileline, dtypep};
|
||||
concatp->rhsp(a.m_vtxp);
|
||||
concatp->lhsp(b.m_vtxp);
|
||||
a.m_vtxp = concatp;
|
||||
b.m_vtxp = nullptr; // Mark as moved
|
||||
++m_ctx.m_coalescedAssignments;
|
||||
continue;
|
||||
}
|
||||
|
||||
++i;
|
||||
|
||||
// Compact non-adjacent ranges within the vector
|
||||
if (j != i) {
|
||||
Driver& c = drivers[i];
|
||||
UASSERT_OBJ(!c.m_vtxp, c.m_fileline, "Should have been marked moved");
|
||||
c = b;
|
||||
b.m_vtxp = nullptr; // Mark as moved
|
||||
}
|
||||
}
|
||||
|
||||
// Reinsert drivers in order
|
||||
varp->resetSources();
|
||||
for (const Driver& driver : drivers) {
|
||||
if (!driver.m_vtxp) break; // Stop at end of compacted list
|
||||
varp->addDriver(driver.m_fileline, driver.m_lsb, driver.m_vtxp);
|
||||
}
|
||||
|
||||
// Prune vertices potentially unused due to resolving multiple drivers.
|
||||
while (!prune.empty()) {
|
||||
// Pop last vertex
|
||||
const auto it = prune.begin();
|
||||
DfgVertex* const vtxp = *it;
|
||||
prune.erase(it);
|
||||
// If used (or a variable), then done
|
||||
if (vtxp->hasSinks() || vtxp->is<DfgVertexVar>()) continue;
|
||||
// If unused, then add sources to work list and delete
|
||||
vtxp->forEachSource([&](DfgVertex& src) { prune.emplace(&src); });
|
||||
vtxp->unlinkDelete(*m_dfgp);
|
||||
// Compact non-adjacent ranges within the vector
|
||||
if (j != i) {
|
||||
Driver& c = drivers[i];
|
||||
UASSERT_OBJ(!c.m_vtxp, c.m_fileline, "Should have been marked moved");
|
||||
c = b;
|
||||
b.m_vtxp = nullptr; // Mark as moved
|
||||
}
|
||||
}
|
||||
|
||||
// Reinsert drivers in order
|
||||
splicep->resetSources();
|
||||
for (const Driver& driver : drivers) {
|
||||
if (!driver.m_vtxp) break; // Stop at end of compacted list
|
||||
splicep->addDriver(driver.m_fileline, driver.m_lsb, driver.m_vtxp);
|
||||
}
|
||||
|
||||
removeUnused(prune);
|
||||
|
||||
// If the whole variable is driven whole, we can just use that driver
|
||||
if (splicep->arity() == 1 //
|
||||
&& splicep->driverLsb(0) == 0 //
|
||||
&& splicep->source(0)->width() == splicep->width()) {
|
||||
const auto result = std::make_pair(splicep->source(0), splicep->driverFileLine(0));
|
||||
VL_DO_DANGLING(splicep->unlinkDelete(*m_dfgp), splicep);
|
||||
return result;
|
||||
}
|
||||
return {splicep, splicep->fileline()};
|
||||
}
|
||||
|
||||
// Canonicalize array variables
|
||||
void canonicalizeArray() {
|
||||
for (DfgVarArray* const varp : m_varArrayps) {
|
||||
// Delete variables with no sinks nor sources (this can happen due to reverting
|
||||
// uncommitted vertices, which does not remove variables)
|
||||
if (!varp->hasSinks() && varp->arity() == 0) {
|
||||
VL_DO_DANGLING(varp->unlinkDelete(*m_dfgp), varp);
|
||||
// Normalize array driver - return the normalized vertex and location for 'splicep'
|
||||
std::pair<DfgVertex*, FileLine*> //
|
||||
normalizeArray(DfgVertexVar* varp, const std::string& sub, DfgSpliceArray* const splicep) {
|
||||
// Represents a driver of 'splicep'
|
||||
struct Driver final {
|
||||
FileLine* m_fileline;
|
||||
DfgVertex* m_vtxp;
|
||||
uint32_t m_idx;
|
||||
Driver() = delete;
|
||||
Driver(FileLine* flp, uint32_t idx, DfgVertex* vtxp)
|
||||
: m_fileline{flp}
|
||||
, m_vtxp{vtxp}
|
||||
, m_idx{idx} {}
|
||||
};
|
||||
|
||||
// The drivers of 'splicep'
|
||||
std::vector<Driver> drivers;
|
||||
drivers.reserve(splicep->arity());
|
||||
|
||||
// Normalize, gather, and unlink all drivers
|
||||
splicep->forEachSourceEdge([&](DfgEdge& edge, size_t i) {
|
||||
DfgVertex* const driverp = edge.sourcep();
|
||||
UASSERT(driverp, "Should not have created undriven sources");
|
||||
const uint32_t idx = splicep->driverIndex(i);
|
||||
if (DfgSplicePacked* const spp = driverp->cast<DfgSplicePacked>()) {
|
||||
const auto pair
|
||||
= normalizePacked(varp, sub + "[" + std::to_string(idx) + "]", spp);
|
||||
drivers.emplace_back(pair.second, idx, pair.first);
|
||||
} else if (DfgSpliceArray* const sap = driverp->cast<DfgSpliceArray>()) {
|
||||
const auto pair = normalizeArray(varp, sub + "[" + std::to_string(idx) + "]", sap);
|
||||
drivers.emplace_back(pair.second, idx, pair.first);
|
||||
} else if (driverp->is<DfgVertexSplice>()) {
|
||||
driverp->v3fatalSrc("Unhandled DfgVertexSplice sub-type");
|
||||
} else {
|
||||
drivers.emplace_back(splicep->driverFileLine(i), idx, driverp);
|
||||
}
|
||||
edge.unlinkSource();
|
||||
});
|
||||
|
||||
const auto cmp = [](const Driver& a, const Driver& b) {
|
||||
if (a.m_idx != b.m_idx) return a.m_idx < b.m_idx;
|
||||
return a.m_fileline->operatorCompare(*b.m_fileline) < 0;
|
||||
};
|
||||
|
||||
// Sort drivers by index
|
||||
std::stable_sort(drivers.begin(), drivers.end(), cmp);
|
||||
|
||||
// Vertices that become unused due to multiple driver resolution
|
||||
std::set<DfgVertex*> prune;
|
||||
|
||||
// Fix multiply driven ranges
|
||||
for (auto it = drivers.begin(); it != drivers.end();) {
|
||||
Driver& a = *it++;
|
||||
AstUnpackArrayDType* aArrayDTypep = VN_CAST(a.m_vtxp->dtypep(), UnpackArrayDType);
|
||||
const uint32_t aElements = aArrayDTypep ? aArrayDTypep->elementsConst() : 1;
|
||||
const uint32_t aEnd = a.m_idx + aElements;
|
||||
while (it != drivers.end()) {
|
||||
Driver& b = *it;
|
||||
// If no overlap, then nothing to do
|
||||
if (b.m_idx >= aEnd) break;
|
||||
|
||||
AstUnpackArrayDType* bArrayDTypep = VN_CAST(b.m_vtxp->dtypep(), UnpackArrayDType);
|
||||
const uint32_t bElements = bArrayDTypep ? bArrayDTypep->elementsConst() : 1;
|
||||
const uint32_t bEnd = b.m_idx + bElements;
|
||||
const uint32_t overlapEnd = std::min(aEnd, bEnd) - 1;
|
||||
|
||||
if (a.m_fileline->operatorCompare(*b.m_fileline) != 0) {
|
||||
AstNode* const vp = varp->varScopep()
|
||||
? static_cast<AstNode*>(varp->varScopep())
|
||||
: static_cast<AstNode*>(varp->varp());
|
||||
|
||||
vp->v3warn( //
|
||||
MULTIDRIVEN,
|
||||
"Elements [" //
|
||||
<< overlapEnd << ":" << b.m_idx << "] of signal '" << vp->prettyName()
|
||||
<< sub << "' have multiple combinational drivers\n"
|
||||
<< a.m_fileline->warnOther() << "... Location of first driver\n"
|
||||
<< a.m_fileline->warnContextPrimary() << '\n'
|
||||
<< b.m_fileline->warnOther() << "... Location of other driver\n"
|
||||
<< b.m_fileline->warnContextSecondary() << vp->warnOther()
|
||||
<< "... Only the first driver will be respected");
|
||||
}
|
||||
|
||||
// If the first driver completely covers the range of the second driver,
|
||||
// we can just delete the second driver completely, otherwise adjust the
|
||||
// second driver to apply from the end of the range of the first driver.
|
||||
if (aEnd >= bEnd) {
|
||||
prune.emplace(b.m_vtxp);
|
||||
it = drivers.erase(it);
|
||||
} else {
|
||||
const auto distance = std::distance(drivers.begin(), it);
|
||||
DfgVertex* const bVtxp = b.m_vtxp;
|
||||
FileLine* const flp = b.m_vtxp->fileline();
|
||||
AstNodeDType* const elemDtypep = DfgVertex::dtypeFor(
|
||||
VN_AS(splicep->dtypep(), UnpackArrayDType)->subDTypep());
|
||||
// Remove this driver
|
||||
it = drivers.erase(it);
|
||||
// Add missing items element-wise
|
||||
for (uint32_t i = aEnd; i < bEnd; ++i) {
|
||||
DfgArraySel* const aselp = new DfgArraySel{*m_dfgp, flp, elemDtypep};
|
||||
aselp->fromp(bVtxp);
|
||||
aselp->bitp(new DfgConst{*m_dfgp, flp, 32, i});
|
||||
drivers.emplace_back(flp, i, aselp);
|
||||
}
|
||||
it = drivers.begin();
|
||||
std::advance(it, distance);
|
||||
std::stable_sort(it, drivers.end(), cmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reinsert drivers in order
|
||||
splicep->resetSources();
|
||||
for (const Driver& driver : drivers) {
|
||||
if (!driver.m_vtxp) break; // Stop at end of compacted list
|
||||
splicep->addDriver(driver.m_fileline, driver.m_idx, driver.m_vtxp);
|
||||
}
|
||||
|
||||
removeUnused(prune);
|
||||
|
||||
// If the whole variable is driven whole, we can just use that driver
|
||||
if (splicep->arity() == 1 //
|
||||
&& splicep->driverIndex(0) == 0 //
|
||||
&& splicep->source(0)->dtypep()->isSame(splicep->dtypep())) {
|
||||
const auto result = std::make_pair(splicep->source(0), splicep->driverFileLine(0));
|
||||
VL_DO_DANGLING(splicep->unlinkDelete(*m_dfgp), splicep);
|
||||
return result;
|
||||
}
|
||||
return {splicep, splicep->fileline()};
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
@ -593,6 +810,7 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
|| nodep->varp()->isIfaceRef() // Cannot handle interface references
|
||||
|| nodep->varp()->delayp() // Cannot handle delayed variables
|
||||
|| nodep->classOrPackagep() // Cannot represent cross module references
|
||||
|| nodep->varp()->isSc() // SystemC variables are special and rare, we can ignore
|
||||
) {
|
||||
markReferenced(nodep);
|
||||
m_foundUnhandled = true;
|
||||
|
@ -675,9 +893,32 @@ class AstToDfgVisitor final : public VNVisitor {
|
|||
iterate(&root);
|
||||
UASSERT_OBJ(m_uncommittedVertices.empty(), &root, "Uncommitted vertices remain");
|
||||
|
||||
// Canonicalize variables
|
||||
canonicalizePacked();
|
||||
canonicalizeArray();
|
||||
if (dumpDfgLevel() >= 8) m_dfgp->dumpDotFilePrefixed(ctx.prefix() + "ast2dfg");
|
||||
|
||||
// Normalize variable drivers (remove multiple drivers, remove unnecessary splice vertices)
|
||||
for (DfgVertexVar* const varp : m_dfgp->varVertices().unlinkable()) {
|
||||
// Delete variables with no sinks nor sources (this can happen due to reverting
|
||||
// uncommitted vertices, which does not remove variables)
|
||||
if (!varp->hasSinks() && !varp->srcp()) {
|
||||
VL_DO_DANGLING(varp->unlinkDelete(*m_dfgp), varp);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Nothing to do for un-driven (input) variables
|
||||
if (!varp->srcp()) continue;
|
||||
|
||||
// The driver of a variable must always be a splice vertex, normalize it
|
||||
std::pair<DfgVertex*, FileLine*> normalizedDriver;
|
||||
if (DfgSpliceArray* const sArrayp = varp->srcp()->cast<DfgSpliceArray>()) {
|
||||
normalizedDriver = normalizeArray(varp, "", sArrayp);
|
||||
} else if (DfgSplicePacked* const sPackedp = varp->srcp()->cast<DfgSplicePacked>()) {
|
||||
normalizedDriver = normalizePacked(varp, "", sPackedp);
|
||||
} else {
|
||||
varp->v3fatalSrc("Unhandled DfgSplicePacked sub-type"); // LCOV_EXCL_LINE
|
||||
}
|
||||
varp->srcp(normalizedDriver.first);
|
||||
varp->driverFileLine(normalizedDriver.second);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -210,7 +210,12 @@ class TraceDriver final : public DfgVisitor {
|
|||
// Create and return a new Vertex and add it to m_newVtxps. Fileline is
|
||||
// taken from 'refp', but 'refp' is otherwise not used. You should
|
||||
// always use this to create new vertices, so unused ones (if a trace
|
||||
// eventually fails) can be cleaned up at the end.
|
||||
// eventually fails) can be cleaned up at the end. This also sets the
|
||||
// vertex user<uint32_t> to 0, indicating the new vertex is not part of a
|
||||
// strongly connected component. This should always be true, as all the
|
||||
// vertices we create here are driven from outside the component we are
|
||||
// trying to escape, and will sink into that component. Given those are
|
||||
// separate SCCs, these new vertices must be acyclic.
|
||||
template <typename Vertex>
|
||||
Vertex* make(const DfgVertex* refp, uint32_t width) {
|
||||
static_assert(std::is_base_of<DfgVertex, Vertex>::value //
|
||||
|
@ -229,6 +234,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
|
||||
if VL_CONSTEXPR_CXX17 (std::is_same<DfgConst, Vertex>::value) {
|
||||
DfgConst* const vtxp = new DfgConst{m_dfg, refp->fileline(), width};
|
||||
vtxp->template setUser<uint32_t>(0);
|
||||
m_newVtxps.emplace_back(vtxp);
|
||||
return reinterpret_cast<Vertex*>(vtxp);
|
||||
} else {
|
||||
|
@ -239,6 +245,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
Vertex>::type;
|
||||
AstNodeDType* const dtypep = DfgVertex::dtypeForWidth(width);
|
||||
Vtx* const vtxp = new Vtx{m_dfg, refp->fileline(), dtypep};
|
||||
vtxp->template setUser<uint32_t>(0);
|
||||
m_newVtxps.emplace_back(vtxp);
|
||||
return reinterpret_cast<Vertex*>(vtxp);
|
||||
}
|
||||
|
@ -276,7 +283,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
// Trace the vertex
|
||||
onStackr = true;
|
||||
|
||||
if (vtxp->user<uint32_t>() != m_component) {
|
||||
if (vtxp->getUser<uint32_t>() != m_component) {
|
||||
// If the currently traced vertex is in a different component,
|
||||
// then we found what we were looking for.
|
||||
if (msb != vtxp->width() - 1 || lsb != 0) {
|
||||
|
@ -363,7 +370,7 @@ class TraceDriver final : public DfgVisitor {
|
|||
UINFO(9, "TraceDriver - Unhandled vertex type: " << vtxp->typeName());
|
||||
}
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
void visit(DfgSplicePacked* vtxp) override {
|
||||
// Proceed with the driver that wholly covers the searched bits
|
||||
const auto pair = vtxp->sourceEdges();
|
||||
for (size_t i = 0; i < pair.second; ++i) {
|
||||
|
@ -378,6 +385,34 @@ class TraceDriver final : public DfgVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
if (DfgVertex* const srcp = vtxp->srcp()) {
|
||||
SET_RESULT(trace(srcp, m_msb, m_lsb));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(DfgArraySel* vtxp) override {
|
||||
// Only constant select
|
||||
DfgConst* const idxp = vtxp->bitp()->cast<DfgConst>();
|
||||
if (!idxp) return;
|
||||
// From a variable
|
||||
DfgVarArray* varp = vtxp->fromp()->cast<DfgVarArray>();
|
||||
if (!varp) return;
|
||||
// Skip through intermediate variables
|
||||
while (varp->srcp() && varp->srcp()->is<DfgVarArray>()) {
|
||||
varp = varp->srcp()->as<DfgVarArray>();
|
||||
}
|
||||
// Find driver
|
||||
if (!varp->srcp()) return;
|
||||
DfgSpliceArray* const splicep = varp->srcp()->cast<DfgSpliceArray>();
|
||||
if (!splicep) return;
|
||||
DfgVertex* const driverp = splicep->driverAt(idxp->toSizeT());
|
||||
if (!driverp) return;
|
||||
// Trace the driver
|
||||
SET_RESULT(trace(driverp, m_msb, m_lsb));
|
||||
}
|
||||
|
||||
void visit(DfgConcat* vtxp) override {
|
||||
DfgVertex* const rhsp = vtxp->rhsp();
|
||||
DfgVertex* const lhsp = vtxp->lhsp();
|
||||
|
@ -551,7 +586,7 @@ public:
|
|||
// waste a lot of compute.
|
||||
static DfgVertex* apply(DfgGraph& dfg, DfgVertex* vtxp, uint32_t lsb, uint32_t width,
|
||||
bool aggressive) {
|
||||
TraceDriver traceDriver{dfg, vtxp->user<uint32_t>(), aggressive};
|
||||
TraceDriver traceDriver{dfg, vtxp->getUser<uint32_t>(), aggressive};
|
||||
// Find the out-of-component driver of the given vertex
|
||||
DfgVertex* const resultp = traceDriver.trace(vtxp, lsb + width - 1, lsb);
|
||||
// Delete unused newly created vertices (these can be created if a
|
||||
|
@ -573,22 +608,25 @@ public:
|
|||
|
||||
class IndependentBits final : public DfgVisitor {
|
||||
// STATE
|
||||
DfgVarPacked* const m_varp; // The variable we are computing dependencies for
|
||||
std::deque<DfgVertex*> m_workList; // Work list for traversal
|
||||
const uint32_t m_component; // The component the start vertex is part of
|
||||
// Vertex to current bit mask map. The mask is set for the bits that **depend** on 'm_varp'.
|
||||
std::unordered_map<const DfgVertex*, V3Number> m_vtxp2Mask;
|
||||
|
||||
std::ofstream m_lineCoverageFile; // Line coverage file, just for testing
|
||||
|
||||
// METHODS
|
||||
|
||||
// Retrieve the mask for the given vertex (create it with value 0 if needed)
|
||||
V3Number& mask(const DfgVertex* vtxp) {
|
||||
return m_vtxp2Mask
|
||||
.emplace(std::piecewise_construct, //
|
||||
std::forward_as_tuple(vtxp), //
|
||||
std::forward_as_tuple(vtxp->fileline(), static_cast<int>(vtxp->width()), 0))
|
||||
.first->second;
|
||||
// Look up (or create) mask for 'vtxp'
|
||||
auto pair = m_vtxp2Mask.emplace(
|
||||
std::piecewise_construct, //
|
||||
std::forward_as_tuple(vtxp), //
|
||||
std::forward_as_tuple(vtxp->fileline(), static_cast<int>(vtxp->width()), 0));
|
||||
// Initialize to all ones if the vertex is part of the same component, otherwise zeroes
|
||||
if (pair.second && vtxp->getUser<uint32_t>() == m_component) {
|
||||
pair.first->second.setAllBits1();
|
||||
}
|
||||
return pair.first->second;
|
||||
}
|
||||
|
||||
// Use this macro to call 'mask' in 'visit' methods. This also emits
|
||||
|
@ -603,14 +641,10 @@ class IndependentBits final : public DfgVisitor {
|
|||
// VISITORS
|
||||
void visit(DfgVertex* vtxp) override {
|
||||
UINFO(9, "Unhandled vertex type " << vtxp->typeName());
|
||||
// Conservatively assume it depends on the variable...
|
||||
mask(vtxp).setAllBits1(); // intentionally not using MASK here
|
||||
// Conservative assumption about all bits being dependent prevails
|
||||
}
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
// The mask of the traced variable is known to be all ones
|
||||
if (vtxp == m_varp) return;
|
||||
|
||||
void visit(DfgSplicePacked* vtxp) override {
|
||||
// Combine the masks of all drivers
|
||||
V3Number& m = MASK(vtxp);
|
||||
vtxp->forEachSourceEdge([&](DfgEdge& edge, size_t i) {
|
||||
|
@ -619,6 +653,31 @@ class IndependentBits final : public DfgVisitor {
|
|||
});
|
||||
}
|
||||
|
||||
void visit(DfgVarPacked* vtxp) override {
|
||||
if (DfgVertex* const srcp = vtxp->srcp()) MASK(vtxp) = MASK(srcp);
|
||||
}
|
||||
|
||||
void visit(DfgArraySel* vtxp) override {
|
||||
// Only constant select
|
||||
DfgConst* const idxp = vtxp->bitp()->cast<DfgConst>();
|
||||
if (!idxp) return;
|
||||
// From a variable
|
||||
DfgVarArray* varp = vtxp->fromp()->cast<DfgVarArray>();
|
||||
if (!varp) return;
|
||||
// Skip through intermediate variables
|
||||
while (varp->srcp() && varp->srcp()->is<DfgVarArray>()) {
|
||||
varp = varp->srcp()->as<DfgVarArray>();
|
||||
}
|
||||
// Find driver
|
||||
if (!varp->srcp()) return;
|
||||
DfgSpliceArray* const splicep = varp->srcp()->cast<DfgSpliceArray>();
|
||||
if (!splicep) return;
|
||||
DfgVertex* const driverp = splicep->driverAt(idxp->toSizeT());
|
||||
if (!driverp) return;
|
||||
// Update mask
|
||||
MASK(vtxp) = MASK(driverp);
|
||||
}
|
||||
|
||||
void visit(DfgConcat* vtxp) override {
|
||||
const DfgVertex* const rhsp = vtxp->rhsp();
|
||||
const DfgVertex* const lhsp = vtxp->lhsp();
|
||||
|
@ -644,7 +703,10 @@ class IndependentBits final : public DfgVisitor {
|
|||
|
||||
void visit(DfgExtend* vtxp) override {
|
||||
const DfgVertex* const srcp = vtxp->srcp();
|
||||
MASK(vtxp).opSelInto(MASK(srcp), 0, srcp->width());
|
||||
const uint32_t sWidth = srcp->width();
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opSelInto(MASK(srcp), 0, sWidth);
|
||||
m.opSetRange(sWidth, vtxp->width() - sWidth, '0');
|
||||
}
|
||||
|
||||
void visit(DfgNot* vtxp) override { //
|
||||
|
@ -672,7 +734,9 @@ class IndependentBits final : public DfgVisitor {
|
|||
if (shiftAmount >= width) return;
|
||||
V3Number shiftedMask{lhsp->fileline(), static_cast<int>(width), 0};
|
||||
shiftedMask.opShiftR(MASK(lhsp), rConstp->num());
|
||||
MASK(vtxp).opSelInto(shiftedMask, 0, width - shiftAmount);
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opSelInto(shiftedMask, 0, width - shiftAmount);
|
||||
m.opSetRange(width - shiftAmount, shiftAmount, '0');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -680,9 +744,9 @@ class IndependentBits final : public DfgVisitor {
|
|||
// the most significant dependent bit might be dependent
|
||||
V3Number& lMask = MASK(lhsp);
|
||||
V3Number& vMask = MASK(vtxp);
|
||||
int idx = width - 1;
|
||||
while (idx >= 0 && lMask.bitIs0(idx)) --idx;
|
||||
while (idx >= 0) vMask.setBit(idx--, '1');
|
||||
uint32_t lzc = 0; // Leading zero count
|
||||
while (lzc < width && lMask.bitIs0(width - 1 - lzc)) ++lzc;
|
||||
while (lzc > 0) vMask.setBit(width - 1 - (--lzc), '0');
|
||||
}
|
||||
|
||||
void visit(DfgShiftL* vtxp) override {
|
||||
|
@ -696,7 +760,9 @@ class IndependentBits final : public DfgVisitor {
|
|||
if (shiftAmount >= width) return;
|
||||
V3Number shiftedMask{lhsp->fileline(), static_cast<int>(width), 0};
|
||||
shiftedMask.opShiftL(MASK(lhsp), rConstp->num());
|
||||
MASK(vtxp).opSelInto(shiftedMask, shiftAmount, width - shiftAmount);
|
||||
V3Number& m = MASK(vtxp);
|
||||
m.opSelInto(shiftedMask, shiftAmount, width - shiftAmount);
|
||||
m.opSetRange(0, shiftAmount, '0');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -704,16 +770,16 @@ class IndependentBits final : public DfgVisitor {
|
|||
// the least significant dependent bit might be dependent
|
||||
V3Number& lMask = MASK(lhsp);
|
||||
V3Number& vMask = MASK(vtxp);
|
||||
uint32_t idx = 0;
|
||||
while (idx < width && lMask.bitIs0(idx)) ++idx;
|
||||
while (idx < width) vMask.setBit(idx++, '1');
|
||||
uint32_t tzc = 0; // Trailing zero count
|
||||
while (tzc < width && lMask.bitIs0(tzc)) ++tzc;
|
||||
while (tzc > 0) vMask.setBit(--tzc, '0');
|
||||
}
|
||||
|
||||
#undef MASK
|
||||
|
||||
// CONSTRUCTOR
|
||||
IndependentBits(DfgVarPacked* varp)
|
||||
: m_varp{varp} {
|
||||
IndependentBits(DfgGraph& dfg, DfgVertex* vtxp)
|
||||
: m_component{vtxp->getUser<uint32_t>()} {
|
||||
if (v3Global.opt.debugCheck()) {
|
||||
m_lineCoverageFile.open( //
|
||||
v3Global.opt.makeDir() + "/" + v3Global.opt.prefix()
|
||||
|
@ -721,16 +787,26 @@ class IndependentBits final : public DfgVisitor {
|
|||
std::ios_base::out | std::ios_base::app);
|
||||
}
|
||||
|
||||
// The starting vertex depends on it's own value, duuhh...
|
||||
mask(varp).setAllBits1();
|
||||
// Enqueue all sinks
|
||||
varp->forEachSink([&](DfgVertex& vtx) { m_workList.emplace_back(&vtx); });
|
||||
// Work list for the traversal
|
||||
std::deque<DfgVertex*> workList;
|
||||
|
||||
// While there is an item on the worklist ..
|
||||
while (!m_workList.empty()) {
|
||||
// Enqueue every operation vertex in the analysed component
|
||||
for (DfgVertex& vtx : dfg.opVertices()) {
|
||||
if (vtx.getUser<uint32_t>() == m_component) workList.emplace_back(&vtx);
|
||||
}
|
||||
|
||||
// While there is an item on the worklist ...
|
||||
while (!workList.empty()) {
|
||||
// Grab next item
|
||||
DfgVertex* const currp = m_workList.front();
|
||||
m_workList.pop_front();
|
||||
DfgVertex* const currp = workList.front();
|
||||
workList.pop_front();
|
||||
|
||||
if (VN_IS(currp->dtypep(), UnpackArrayDType)) {
|
||||
// For an unpacked array vertex, just enque it's sinks.
|
||||
// (There can be no loops through arrays directly)
|
||||
currp->forEachSink([&](DfgVertex& vtx) { workList.emplace_back(&vtx); });
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grab current mask of item
|
||||
const V3Number& maskCurr = mask(currp);
|
||||
|
@ -742,77 +818,110 @@ class IndependentBits final : public DfgVisitor {
|
|||
|
||||
// If mask changed, enqueue sinks
|
||||
if (!prevMask.isCaseEq(maskCurr)) {
|
||||
currp->forEachSink([&](DfgVertex& vtx) { m_workList.emplace_back(&vtx); });
|
||||
currp->forEachSink([&](DfgVertex& vtx) { workList.emplace_back(&vtx); });
|
||||
|
||||
// Check the mask only ever expands (no bit goes 1 -> 0)
|
||||
// Check the mask only ever contrects (no bit goes 0 -> 1)
|
||||
if (VL_UNLIKELY(v3Global.opt.debugCheck())) {
|
||||
V3Number notCurr{maskCurr};
|
||||
notCurr.opNot(maskCurr);
|
||||
V3Number prevAndNotCurr{maskCurr};
|
||||
prevAndNotCurr.opAnd(prevMask, notCurr);
|
||||
UASSERT_OBJ(prevAndNotCurr.isEqZero(), currp, "Mask should only expand");
|
||||
V3Number notPrev{prevMask};
|
||||
notPrev.opNot(prevMask);
|
||||
V3Number notPrevAndCurr{maskCurr};
|
||||
notPrevAndCurr.opAnd(notPrev, maskCurr);
|
||||
UASSERT_OBJ(notPrevAndCurr.isEqZero(), currp, "Mask should only contract");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// Given a variable, compute which bits in this variable are independent of
|
||||
// the variable itself (simple forward dataflow analysis). Returns a bit
|
||||
// mask where a set bit indicates that bit is independent of the variable
|
||||
// itself (logic is not circular). The result is a conservative estimate,
|
||||
// so bits reported dependent might not actually be, but all bits reported
|
||||
// independent are known to be so.
|
||||
static V3Number apply(DfgVarPacked* varp) {
|
||||
IndependentBits independentBits{varp};
|
||||
// Combine the masks of all drivers of the variable
|
||||
V3Number result{varp->fileline(), static_cast<int>(varp->width()), 0};
|
||||
varp->forEachSourceEdge([&](DfgEdge& edge, size_t i) {
|
||||
const DfgVertex* const srcp = edge.sourcep();
|
||||
// The mask represents the dependent bits, so invert it
|
||||
V3Number inverseMask{srcp->fileline(), static_cast<int>(srcp->width()), 0};
|
||||
inverseMask.opNot(independentBits.mask(srcp));
|
||||
result.opSelInto(inverseMask, varp->driverLsb(i), srcp->width());
|
||||
});
|
||||
// Given a Vertex that is part of an SCC denoted by vtxp->user<uint32_t>(),
|
||||
// compute which bits of this vertex have a value that is independent of
|
||||
// the current value of the Vertex itself (simple forward dataflow
|
||||
// analysis). Returns a bit mask where a set bit indicates that bit is
|
||||
// independent of the vertex itself (logic is not circular). The result is
|
||||
// a conservative estimate, so bits reported dependent might not actually
|
||||
// be, but all bits reported independent are known to be so.
|
||||
static V3Number apply(DfgGraph& dfg, DfgVertex* vtxp) {
|
||||
IndependentBits independentBits{dfg, vtxp};
|
||||
// The mask represents the dependent bits, so invert it
|
||||
V3Number result{vtxp->fileline(), static_cast<int>(vtxp->width()), 0};
|
||||
result.opNot(independentBits.mask(vtxp));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class FixUpSelDrivers final {
|
||||
public:
|
||||
// Attempt to push Sel form Var through to the driving
|
||||
// expression of the selected bits. This can fix things like
|
||||
// 'a[1:0] = foo', 'a[2] = a[1]', which are somewhat common.
|
||||
// Returns the number of drivers fixed up.
|
||||
static size_t apply(DfgGraph& dfg, DfgVarPacked* varp) {
|
||||
UINFO(9, "FixUpSelDrivers of " << varp->nodep()->name());
|
||||
const uint32_t component = varp->getUser<uint32_t>();
|
||||
static size_t fixUpSelSinks(DfgGraph& dfg, DfgVertex* vtxp) {
|
||||
size_t nImprovements = 0;
|
||||
varp->forEachSink([&](DfgVertex& sink) {
|
||||
// Ignore if sink is not part of cycle
|
||||
const uint32_t component = vtxp->getUser<uint32_t>();
|
||||
vtxp->forEachSink([&](DfgVertex& sink) {
|
||||
// Ignore if sink is not part of same cycle
|
||||
if (sink.getUser<uint32_t>() != component) return;
|
||||
// Only Handle Sels now
|
||||
// Only handle Sel
|
||||
DfgSel* const selp = sink.cast<DfgSel>();
|
||||
if (!selp) return;
|
||||
// Try to find of the driver of the selected bits outside the cycle
|
||||
// Try to find the driver of the selected bits outside the cycle
|
||||
DfgVertex* const fixp
|
||||
= TraceDriver::apply(dfg, varp, selp->lsb(), selp->width(), false);
|
||||
= TraceDriver::apply(dfg, vtxp, selp->lsb(), selp->width(), false);
|
||||
if (!fixp) return;
|
||||
// Found an out-of-cycle driver. We can replace this sel with that.
|
||||
selp->replaceWith(fixp);
|
||||
selp->unlinkDelete(dfg);
|
||||
++nImprovements;
|
||||
});
|
||||
return nImprovements;
|
||||
}
|
||||
|
||||
static size_t fixUpArraySelSinks(DfgGraph& dfg, DfgVertex* vtxp) {
|
||||
size_t nImprovements = 0;
|
||||
const uint32_t component = vtxp->getUser<uint32_t>();
|
||||
vtxp->forEachSink([&](DfgVertex& sink) {
|
||||
// Ignore if sink is not part of same cycle
|
||||
if (sink.getUser<uint32_t>() != component) return;
|
||||
// Only handle ArraySels
|
||||
DfgArraySel* const aselp = sink.cast<DfgArraySel>();
|
||||
if (!aselp) return;
|
||||
// First, try to fix up the whole word
|
||||
DfgVertex* const fixp = TraceDriver::apply(dfg, aselp, 0, aselp->width(), false);
|
||||
if (fixp) {
|
||||
// Found an out-of-cycle driver for the whole ArraySel
|
||||
aselp->replaceWith(fixp);
|
||||
aselp->unlinkDelete(dfg);
|
||||
++nImprovements;
|
||||
} else {
|
||||
// Attempt to fix up piece-wise at Sels applied to the ArraySel
|
||||
nImprovements += fixUpSelSinks(dfg, aselp);
|
||||
// Remove if became unused
|
||||
if (!aselp->hasSinks()) aselp->unlinkDelete(dfg);
|
||||
}
|
||||
});
|
||||
return nImprovements;
|
||||
}
|
||||
|
||||
public:
|
||||
// Attempt to push Sel form Var through to the driving
|
||||
// expression of the selected bits. This can fix things like
|
||||
// 'a[1:0] = foo', 'a[2] = a[1]', which are somewhat common.
|
||||
// Returns the number of drivers fixed up.
|
||||
static size_t apply(DfgGraph& dfg, DfgVertexVar* varp) {
|
||||
UINFO(9, "FixUpSelDrivers of " << varp->nodep()->name());
|
||||
size_t nImprovements = 0;
|
||||
if (varp->is<DfgVarPacked>()) {
|
||||
// For Packed variables, fix up all Sels applied to it
|
||||
nImprovements += fixUpSelSinks(dfg, varp);
|
||||
} else if (varp->is<DfgVarArray>()) {
|
||||
// For Array variables, fix up each ArraySel applied to it
|
||||
nImprovements += fixUpArraySelSinks(dfg, varp);
|
||||
}
|
||||
UINFO(9, "FixUpSelDrivers made " << nImprovements << " improvements");
|
||||
return nImprovements;
|
||||
}
|
||||
};
|
||||
|
||||
class FixUpIndependentRanges final {
|
||||
// Returns a bitmask set if that bit of 'varp' is used (has a sink)
|
||||
static V3Number computeUsedBits(DfgVarPacked* varp) {
|
||||
V3Number result{varp->fileline(), static_cast<int>(varp->width()), 0};
|
||||
varp->forEachSink([&](DfgVertex& sink) {
|
||||
// Returns a bitmask set if that bit of 'vtxp' is used (has a sink)
|
||||
static V3Number computeUsedBits(DfgVertex* vtxp) {
|
||||
V3Number result{vtxp->fileline(), static_cast<int>(vtxp->width()), 0};
|
||||
vtxp->forEachSink([&result](DfgVertex& sink) {
|
||||
// If used via a Sel, mark the selected bits used
|
||||
if (DfgSel* const selp = sink.cast<DfgSel>()) {
|
||||
uint32_t lsb = selp->lsb();
|
||||
|
@ -820,19 +929,29 @@ class FixUpIndependentRanges final {
|
|||
for (uint32_t i = lsb; i <= msb; ++i) result.setBit(i, '1');
|
||||
return;
|
||||
}
|
||||
|
||||
// Used without a Sel, so all bits are used
|
||||
result.setAllBits1();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Trace drivers of independent bits of 'varp' in the range '[hi:lo]'
|
||||
static std::string debugStr(DfgVertex* vtxp) {
|
||||
if (DfgArraySel* const aselp = vtxp->cast<DfgArraySel>()) {
|
||||
const size_t i = aselp->bitp()->as<DfgConst>()->toSizeT();
|
||||
return debugStr(aselp->fromp()) + "[" + std::to_string(i) + "]";
|
||||
}
|
||||
if (DfgVertexVar* const varp = vtxp->cast<DfgVertexVar>()) {
|
||||
return varp->nodep()->name();
|
||||
}
|
||||
vtxp->v3fatalSrc("Unhandled node type"); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// Trace drivers of independent bits of 'vtxp' in the range '[hi:lo]'
|
||||
// append replacement terms to 'termps'. Returns number of successful
|
||||
// replacements.
|
||||
static size_t gatherTerms(std::vector<DfgVertex*>& termps, DfgGraph& dfg,
|
||||
DfgVarPacked* const varp, const V3Number& indpBits,
|
||||
const uint32_t hi, const uint32_t lo) {
|
||||
DfgVertex* const vtxp, const V3Number& indpBits, const uint32_t hi,
|
||||
const uint32_t lo) {
|
||||
size_t nImprovements = 0;
|
||||
// Iterate through consecutive dependent/non-dependet ranges within [hi:lo]
|
||||
bool isIndependent = indpBits.bitIs1(lo);
|
||||
|
@ -844,19 +963,21 @@ class FixUpIndependentRanges final {
|
|||
DfgVertex* termp = nullptr;
|
||||
// If the range is not self-dependent, attempt to trace its driver
|
||||
if (isIndependent) {
|
||||
termp = TraceDriver::apply(dfg, varp, lsb, width, true);
|
||||
termp = TraceDriver::apply(dfg, vtxp, lsb, width, true);
|
||||
if (termp) {
|
||||
++nImprovements;
|
||||
} else {
|
||||
UINFO(5, "TraceDriver of independent range failed for "
|
||||
<< varp->nodep()->name() << "[" << msb << ":" << lsb << "]");
|
||||
<< debugStr(vtxp) << "[" << msb << ":" << lsb << "]");
|
||||
}
|
||||
}
|
||||
// Fall back on using the part of the variable (if dependent, or trace failed)
|
||||
if (!termp) {
|
||||
AstNodeDType* const dtypep = DfgVertex::dtypeForWidth(width);
|
||||
DfgSel* const selp = new DfgSel{dfg, varp->fileline(), dtypep};
|
||||
// Do not connect selp->fromp yet, need to do afer replacing 'varp'
|
||||
DfgSel* const selp = new DfgSel{dfg, vtxp->fileline(), dtypep};
|
||||
// Same component as 'vtxp', as reads 'vtxp' and will replace 'vtxp'
|
||||
selp->setUser<uint32_t>(vtxp->getUser<uint32_t>());
|
||||
// Do not connect selp->fromp yet, need to do afer replacing 'vtxp'
|
||||
selp->lsb(lsb);
|
||||
termp = selp;
|
||||
}
|
||||
|
@ -869,41 +990,37 @@ class FixUpIndependentRanges final {
|
|||
return nImprovements;
|
||||
}
|
||||
|
||||
public:
|
||||
// Similar to FixUpSelDrivers, but first comptute which bits of the
|
||||
// variable are self dependent, and fix up those that are independent
|
||||
// but used.
|
||||
static size_t apply(DfgGraph& dfg, DfgVarPacked* varp) {
|
||||
UINFO(9, "FixUpIndependentRanges of " << varp->nodep()->name());
|
||||
static size_t fixUpPacked(DfgGraph& dfg, DfgVertex* vtxp) {
|
||||
UASSERT_OBJ(VN_IS(vtxp->dtypep(), BasicDType), vtxp, "Should be a packed BasicDType");
|
||||
size_t nImprovements = 0;
|
||||
|
||||
// Figure out which bits of 'varp' are used
|
||||
const V3Number usedBits = computeUsedBits(varp);
|
||||
UINFO(9, "Used bits of '" << varp->nodep()->name() << "' are "
|
||||
<< usedBits.displayed(varp->nodep(), "%b"));
|
||||
// Figure out which bits of 'vtxp' are used
|
||||
const V3Number usedBits = computeUsedBits(vtxp);
|
||||
UINFO(9, "Used bits of '" << debugStr(vtxp) << "' are "
|
||||
<< usedBits.displayed(vtxp->fileline(), "%b"));
|
||||
// Nothing to do if no bits are used
|
||||
if (usedBits.isEqZero()) return 0;
|
||||
|
||||
// Figure out which bits of 'varp' are dependent on themselves
|
||||
const V3Number indpBits = IndependentBits::apply(varp);
|
||||
UINFO(9, "Independent bits of '" << varp->nodep()->name() << "' are "
|
||||
<< indpBits.displayed(varp->nodep(), "%b"));
|
||||
// Figure out which bits of 'vtxp' are dependent of themselves
|
||||
const V3Number indpBits = IndependentBits::apply(dfg, vtxp);
|
||||
UINFO(9, "Independent bits of '" << debugStr(vtxp) << "' are "
|
||||
<< indpBits.displayed(vtxp->fileline(), "%b"));
|
||||
// Can't do anything if all bits are dependent
|
||||
if (indpBits.isEqZero()) return 0;
|
||||
|
||||
{
|
||||
// Nothing to do if no used bits are independen (all used bits are dependent)
|
||||
V3Number usedAndIndependent{varp->fileline(), static_cast<int>(varp->width()), 0};
|
||||
V3Number usedAndIndependent{vtxp->fileline(), static_cast<int>(vtxp->width()), 0};
|
||||
usedAndIndependent.opAnd(usedBits, indpBits);
|
||||
if (usedAndIndependent.isEqZero()) return 0;
|
||||
}
|
||||
|
||||
// We are computing the terms to concatenate and replace 'varp' with
|
||||
// We are computing the terms to concatenate and replace 'vtxp' with
|
||||
std::vector<DfgVertex*> termps;
|
||||
|
||||
// Iterate through consecutive used/unused ranges
|
||||
FileLine* const flp = varp->fileline();
|
||||
const uint32_t width = varp->width();
|
||||
FileLine* const flp = vtxp->fileline();
|
||||
const uint32_t width = vtxp->width();
|
||||
bool isUsed = usedBits.bitIs1(0); // Is current range used
|
||||
uint32_t lsb = 0; // LSB of current range
|
||||
for (uint32_t msb = 0; msb < width; ++msb) {
|
||||
|
@ -911,10 +1028,12 @@ public:
|
|||
if (!endRange) continue;
|
||||
if (isUsed) {
|
||||
// The range is used, compute the replacement terms
|
||||
nImprovements += gatherTerms(termps, dfg, varp, indpBits, msb, lsb);
|
||||
nImprovements += gatherTerms(termps, dfg, vtxp, indpBits, msb, lsb);
|
||||
} else {
|
||||
// The range is not used, just use constant 0 as a placeholder
|
||||
termps.emplace_back(new DfgConst{dfg, flp, msb - lsb + 1});
|
||||
DfgConst* const constp = new DfgConst{dfg, flp, msb - lsb + 1};
|
||||
constp->setUser<uint32_t>(0);
|
||||
termps.emplace_back(constp);
|
||||
}
|
||||
// Next iteration
|
||||
isUsed = !isUsed;
|
||||
|
@ -925,6 +1044,7 @@ public:
|
|||
if (nImprovements) {
|
||||
// Concatenate all the terms to create the replacement
|
||||
DfgVertex* replacementp = termps.front();
|
||||
const uint32_t vComp = vtxp->getUser<uint32_t>();
|
||||
for (size_t i = 1; i < termps.size(); ++i) {
|
||||
DfgVertex* const termp = termps[i];
|
||||
const uint32_t catWidth = replacementp->width() + termp->width();
|
||||
|
@ -932,19 +1052,58 @@ public:
|
|||
DfgConcat* const catp = new DfgConcat{dfg, flp, dtypep};
|
||||
catp->rhsp(replacementp);
|
||||
catp->lhsp(termp);
|
||||
// Need to figure out which component the replacement vertex
|
||||
// belongs to. If any of the terms are of the original
|
||||
// component, it's part of that component, otherwise its not
|
||||
// cyclic (all terms are from outside the original component,
|
||||
// and feed into the original component).
|
||||
const uint32_t tComp = termp->getUser<uint32_t>();
|
||||
const uint32_t rComp = replacementp->getUser<uint32_t>();
|
||||
catp->setUser<uint32_t>(tComp == vComp || rComp == vComp ? vComp : 0);
|
||||
replacementp = catp;
|
||||
}
|
||||
|
||||
// Replace the variable
|
||||
varp->replaceWith(replacementp);
|
||||
// Replace the vertex
|
||||
vtxp->replaceWith(replacementp);
|
||||
// Connect the Sel nodes in the replacement
|
||||
for (DfgVertex* const termp : termps) {
|
||||
if (DfgSel* const selp = termp->cast<DfgSel>()) {
|
||||
if (!selp->fromp()) selp->fromp(varp);
|
||||
if (!selp->fromp()) selp->fromp(vtxp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nImprovements;
|
||||
}
|
||||
|
||||
public:
|
||||
// Similar to FixUpSelDrivers, but first comptute which bits of the
|
||||
// variable are self dependent, and fix up those that are independent
|
||||
// but used.
|
||||
static size_t apply(DfgGraph& dfg, DfgVertexVar* varp) {
|
||||
UINFO(9, "FixUpIndependentRanges of " << varp->nodep()->name());
|
||||
size_t nImprovements = 0;
|
||||
|
||||
if (varp->is<DfgVarPacked>()) {
|
||||
// For Packed variables, fix up as whole
|
||||
nImprovements += fixUpPacked(dfg, varp);
|
||||
} else if (varp->is<DfgVarArray>()) {
|
||||
// For array variables, fix up element-wise
|
||||
const uint32_t component = varp->getUser<uint32_t>();
|
||||
varp->forEachSink([&](DfgVertex& sink) {
|
||||
// Ignore if sink is not part of same cycle
|
||||
if (sink.getUser<uint32_t>() != component) return;
|
||||
// Only handle ArraySels with constant index
|
||||
DfgArraySel* const aselp = sink.cast<DfgArraySel>();
|
||||
if (!aselp) return;
|
||||
if (!aselp->bitp()->is<DfgConst>()) return;
|
||||
// Fix up the word
|
||||
nImprovements += fixUpPacked(dfg, aselp);
|
||||
// Remove if became unused
|
||||
if (!aselp->hasSinks()) aselp->unlinkDelete(dfg);
|
||||
});
|
||||
}
|
||||
|
||||
UINFO(9, "FixUpIndependentRanges made " << nImprovements << " improvements");
|
||||
return nImprovements;
|
||||
}
|
||||
|
@ -1000,14 +1159,11 @@ V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
|
|||
|
||||
// Method 1: FixUpSelDrivers
|
||||
for (DfgVertexVar& vtx : res.varVertices()) {
|
||||
// Only handle DfgVarPacked at this point
|
||||
DfgVarPacked* const varp = vtx.cast<DfgVarPacked>();
|
||||
if (!varp) continue;
|
||||
// If Variable is not part of a cycle, move on
|
||||
const uint32_t component = varp->getUser<uint32_t>();
|
||||
const uint32_t component = vtx.getUser<uint32_t>();
|
||||
if (!component) continue;
|
||||
|
||||
const size_t nFixed = FixUpSelDrivers::apply(res, varp);
|
||||
const size_t nFixed = FixUpSelDrivers::apply(res, &vtx);
|
||||
if (nFixed) {
|
||||
nImprovements += nFixed;
|
||||
ctx.m_breakCyclesContext.m_nImprovements += nFixed;
|
||||
|
@ -1020,14 +1176,11 @@ V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
|
|||
|
||||
// Method 2. FixUpIndependentRanges
|
||||
for (DfgVertexVar& vtx : res.varVertices()) {
|
||||
// Only handle DfgVarPacked at this point
|
||||
DfgVarPacked* const varp = vtx.cast<DfgVarPacked>();
|
||||
if (!varp) continue;
|
||||
// If Variable is not part of a cycle, move on
|
||||
const uint32_t component = varp->getUser<uint32_t>();
|
||||
const uint32_t component = vtx.getUser<uint32_t>();
|
||||
if (!component) continue;
|
||||
|
||||
const size_t nFixed = FixUpIndependentRanges::apply(res, varp);
|
||||
const size_t nFixed = FixUpIndependentRanges::apply(res, &vtx);
|
||||
if (nFixed) {
|
||||
nImprovements += nFixed;
|
||||
ctx.m_breakCyclesContext.m_nImprovements += nFixed;
|
||||
|
|
|
@ -341,32 +341,23 @@ class ExtractCyclicComponents final {
|
|||
return *clonep;
|
||||
}
|
||||
|
||||
// Fix up non-variable sources of a DfgVertexVar that are in a different component,
|
||||
// using the provided 'relink' callback
|
||||
template <typename T_Vertex>
|
||||
void fixSources(T_Vertex& vtx, std::function<void(T_Vertex&, DfgVertex&, size_t)> relink) {
|
||||
static_assert(std::is_base_of<DfgVertexVar, T_Vertex>::value,
|
||||
"'Vertex' must be a 'DfgVertexVar'");
|
||||
// Fix edges that cross components
|
||||
void fixEdges(DfgVertexVar& vtx) {
|
||||
const size_t component = state(vtx).component;
|
||||
vtx.forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
DfgVertex& source = *edge.sourcep();
|
||||
// DfgVertexVar sources are fixed up by `fixSinks` on those sources
|
||||
if (source.is<DfgVertexVar>()) return;
|
||||
const size_t sourceComponent = state(source).component;
|
||||
|
||||
// Fix up sources in a different component
|
||||
vtx.forEachSourceEdge([&](DfgEdge& edge, size_t) {
|
||||
DfgVertex* const srcp = edge.sourcep();
|
||||
if (!srcp) return;
|
||||
const size_t sourceComponent = state(*srcp).component;
|
||||
// Same component is OK
|
||||
if (sourceComponent == component) return;
|
||||
// Unlink the source edge (source is reconnected by 'relink'
|
||||
// Relink the source to write the clone
|
||||
edge.unlinkSource();
|
||||
// Apply the fixup
|
||||
// cppcheck-has-bug-suppress constVariable
|
||||
DfgVertexVar& clone = getClone(vtx, sourceComponent);
|
||||
relink(*(clone.as<T_Vertex>()), source, idx);
|
||||
getClone(vtx, sourceComponent).srcp(srcp);
|
||||
});
|
||||
}
|
||||
|
||||
// Fix up sinks of given variable vertex that are in a different component
|
||||
void fixSinks(DfgVertexVar& vtx) {
|
||||
const size_t component = state(vtx).component;
|
||||
// Fix up sinks in a different component
|
||||
vtx.forEachSinkEdge([&](DfgEdge& edge) {
|
||||
const size_t sinkComponent = state(*edge.sinkp()).component;
|
||||
// Same component is OK
|
||||
|
@ -376,49 +367,6 @@ class ExtractCyclicComponents final {
|
|||
});
|
||||
}
|
||||
|
||||
// Fix edges that cross components
|
||||
void fixEdges(DfgVertexVar& vtx) {
|
||||
if (DfgVarPacked* const vvtxp = vtx.cast<DfgVarPacked>()) {
|
||||
fixSources<DfgVarPacked>(
|
||||
*vvtxp, [&](DfgVarPacked& clone, DfgVertex& driver, size_t driverIdx) {
|
||||
clone.addDriver(vvtxp->driverFileLine(driverIdx), //
|
||||
vvtxp->driverLsb(driverIdx), &driver);
|
||||
});
|
||||
fixSinks(*vvtxp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DfgVarArray* const vvtxp = vtx.cast<DfgVarArray>()) {
|
||||
fixSources<DfgVarArray>( //
|
||||
*vvtxp, [&](DfgVarArray& clone, DfgVertex& driver, size_t driverIdx) {
|
||||
clone.addDriver(vvtxp->driverFileLine(driverIdx), //
|
||||
vvtxp->driverIndex(driverIdx), &driver);
|
||||
});
|
||||
fixSinks(*vvtxp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void packSources(DfgGraph& dfg) {
|
||||
// Remove undriven variable sources
|
||||
for (DfgVertexVar* const vtxp : dfg.varVertices().unlinkable()) {
|
||||
if (DfgVarPacked* const varp = vtxp->cast<DfgVarPacked>()) {
|
||||
varp->packSources();
|
||||
if (!varp->hasSinks() && varp->arity() == 0) {
|
||||
VL_DO_DANGLING(varp->unlinkDelete(dfg), varp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (DfgVarArray* const varp = vtxp->cast<DfgVarArray>()) {
|
||||
varp->packSources();
|
||||
if (!varp->hasSinks() && varp->arity() == 0) {
|
||||
VL_DO_DANGLING(varp->unlinkDelete(dfg), varp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Vertex>
|
||||
void moveVertices(DfgVertex::List<Vertex>& list) {
|
||||
for (DfgVertex* const vtxp : list.unlinkable()) {
|
||||
|
@ -446,11 +394,6 @@ class ExtractCyclicComponents final {
|
|||
UASSERT_OBJ(component == state(snk).component, &vtx,
|
||||
"Edge crossing components without variable involvement");
|
||||
});
|
||||
if (const DfgVertexVar* const vtxp = vtx.cast<DfgVertexVar>()) {
|
||||
vtxp->forEachSourceEdge([](const DfgEdge& edge, size_t) {
|
||||
UASSERT_OBJ(edge.sourcep(), edge.sinkp(), "Missing source on variable vertex");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -489,11 +432,6 @@ class ExtractCyclicComponents final {
|
|||
if (&vtx == lastp) break;
|
||||
}
|
||||
|
||||
// Pack sources of variables to remove the now undriven inputs
|
||||
// (cloning might have unlinked some of the inputs),
|
||||
packSources(m_dfg);
|
||||
for (const auto& dfgp : m_components) packSources(*dfgp);
|
||||
|
||||
// Check results for consistency
|
||||
if (VL_UNLIKELY(m_doExpensiveChecks)) {
|
||||
checkEdges(m_dfg);
|
||||
|
|
|
@ -188,58 +188,57 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
return resultp;
|
||||
}
|
||||
|
||||
void addResultEquation(const DfgVertexVar* vtxp, FileLine* flp, AstNodeExpr* lhsp,
|
||||
AstNodeExpr* rhsp) {
|
||||
AstAssignW* const assignp = new AstAssignW{flp, lhsp, rhsp};
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
// Add it to the scope holding the target variable
|
||||
getCombActive(vtxp->varScopep()->scopep())->addStmtsp(assignp);
|
||||
} else {
|
||||
// Add it to the parend module of the DfgGraph
|
||||
m_modp->addStmtsp(assignp);
|
||||
void convertDriver(AstScope* scopep, FileLine* flp, AstNodeExpr* lhsp, DfgVertex* driverp) {
|
||||
if (!driverp->is<DfgVertexSplice>()) {
|
||||
// Base case: assign vertex to current lhs
|
||||
AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(driverp);
|
||||
AstAssignW* const assignp = new AstAssignW{flp, lhsp, rhsp};
|
||||
lhsp->foreach([flp](AstNode* nodep) { nodep->fileline(flp); });
|
||||
if VL_CONSTEXPR_CXX17 (T_Scoped) {
|
||||
// Add it to the scope holding the target variable
|
||||
getCombActive(scopep)->addStmtsp(assignp);
|
||||
} else {
|
||||
// Add it to the parend module of the DfgGraph
|
||||
m_modp->addStmtsp(assignp);
|
||||
}
|
||||
++m_ctx.m_resultEquations;
|
||||
return;
|
||||
}
|
||||
++m_ctx.m_resultEquations;
|
||||
}
|
||||
|
||||
void convertVarDriver(const DfgVarPacked* dfgVarp) {
|
||||
if (dfgVarp->isDrivenFullyByDfg()) {
|
||||
// Whole variable is driven. Render driver and assign directly to whole variable.
|
||||
FileLine* const flp = dfgVarp->driverFileLine(0);
|
||||
AstVarRef* const lhsp = new AstVarRef{flp, getNode(dfgVarp), VAccess::WRITE};
|
||||
AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(dfgVarp->source(0));
|
||||
addResultEquation(dfgVarp, flp, lhsp, rhsp);
|
||||
} else {
|
||||
// Variable is driven partially. Render each driver as a separate assignment.
|
||||
dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) {
|
||||
UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources");
|
||||
// Render the rhs expression
|
||||
AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(edge.sourcep());
|
||||
// Create select LValue
|
||||
FileLine* const flp = dfgVarp->driverFileLine(idx);
|
||||
AstVarRef* const refp = new AstVarRef{flp, getNode(dfgVarp), VAccess::WRITE};
|
||||
AstConst* const lsbp = new AstConst{flp, dfgVarp->driverLsb(idx)};
|
||||
if (DfgSplicePacked* const sPackedp = driverp->cast<DfgSplicePacked>()) {
|
||||
// Partial assignment of packed value
|
||||
sPackedp->forEachSourceEdge([&](const DfgEdge& edge, size_t i) {
|
||||
UASSERT_OBJ(edge.sourcep(), sPackedp, "Should have removed undriven sources");
|
||||
// Create Sel
|
||||
FileLine* const dflp = sPackedp->driverFileLine(i);
|
||||
AstConst* const lsbp = new AstConst{dflp, sPackedp->driverLsb(i)};
|
||||
const int width = static_cast<int>(edge.sourcep()->width());
|
||||
AstSel* const lhsp = new AstSel{flp, refp, lsbp, width};
|
||||
// Add assignment of the value to the selected bits
|
||||
addResultEquation(dfgVarp, flp, lhsp, rhsp);
|
||||
AstSel* const nLhsp = new AstSel{dflp, lhsp->cloneTreePure(false), lsbp, width};
|
||||
// Convert source
|
||||
convertDriver(scopep, dflp, nLhsp, edge.sourcep());
|
||||
// Delete Sel if not consumed
|
||||
if (!nLhsp->backp()) VL_DO_DANGLING(nLhsp->deleteTree(), nLhsp);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void convertArrayDiver(const DfgVarArray* dfgVarp) {
|
||||
// Variable is driven partially. Assign from parts of the canonical var.
|
||||
dfgVarp->forEachSourceEdge([&](const DfgEdge& edge, size_t idx) {
|
||||
UASSERT_OBJ(edge.sourcep(), dfgVarp, "Should have removed undriven sources");
|
||||
// Render the rhs expression
|
||||
AstNodeExpr* const rhsp = convertDfgVertexToAstNodeExpr(edge.sourcep());
|
||||
// Create select LValue
|
||||
FileLine* const flp = dfgVarp->driverFileLine(idx);
|
||||
AstVarRef* const refp = new AstVarRef{flp, getNode(dfgVarp), VAccess::WRITE};
|
||||
AstConst* const idxp = new AstConst{flp, dfgVarp->driverIndex(idx)};
|
||||
AstArraySel* const lhsp = new AstArraySel{flp, refp, idxp};
|
||||
// Add assignment of the value to the selected bits
|
||||
addResultEquation(dfgVarp, flp, lhsp, rhsp);
|
||||
});
|
||||
if (DfgSpliceArray* const sArrayp = driverp->cast<DfgSpliceArray>()) {
|
||||
// Partial assignment of array variable
|
||||
sArrayp->forEachSourceEdge([&](const DfgEdge& edge, size_t i) {
|
||||
UASSERT_OBJ(edge.sourcep(), sArrayp, "Should have removed undriven sources");
|
||||
// Create ArraySel
|
||||
FileLine* const dflp = sArrayp->driverFileLine(i);
|
||||
AstConst* const idxp = new AstConst{dflp, sArrayp->driverIndex(i)};
|
||||
AstArraySel* const nLhsp = new AstArraySel{dflp, lhsp->cloneTreePure(false), idxp};
|
||||
// Convert source
|
||||
convertDriver(scopep, dflp, nLhsp, edge.sourcep());
|
||||
// Delete ArraySel if not consumed
|
||||
if (!nLhsp->backp()) VL_DO_DANGLING(nLhsp->deleteTree(), nLhsp);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
driverp->v3fatalSrc("Unhandled DfgVertexSplice sub-type"); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
@ -285,16 +284,15 @@ class DfgToAstVisitor final : DfgVisitor {
|
|||
// The graph must have been regularized, so we only need to render assignments
|
||||
for (DfgVertexVar& vtx : dfg.varVertices()) {
|
||||
// If there is no driver (this vertex is an input to the graph), then nothing to do.
|
||||
if (!vtx.isDrivenByDfg()) continue;
|
||||
if (!vtx.srcp()) continue;
|
||||
|
||||
// Render packed variable assignments
|
||||
if (const DfgVarPacked* const dfgVarp = vtx.cast<DfgVarPacked>()) {
|
||||
convertVarDriver(dfgVarp);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Render array variable assignments
|
||||
convertArrayDiver(vtx.as<DfgVarArray>());
|
||||
// Render variable assignments
|
||||
FileLine* const flp = vtx.driverFileLine() ? vtx.driverFileLine() : vtx.fileline();
|
||||
AstScope* const scopep = T_Scoped ? vtx.varScopep()->scopep() : nullptr;
|
||||
AstVarRef* const lhsp = new AstVarRef{flp, getNode(&vtx), VAccess::WRITE};
|
||||
convertDriver(scopep, flp, lhsp, vtx.srcp());
|
||||
// convetDriver clones and might not use up the original lhsp
|
||||
if (!lhsp->backp()) VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -169,18 +169,8 @@ void V3DfgPasses::cse(DfgGraph& dfg, V3DfgCseContext& ctx) {
|
|||
void V3DfgPasses::inlineVars(DfgGraph& dfg) {
|
||||
for (DfgVertexVar& vtx : dfg.varVertices()) {
|
||||
if (DfgVarPacked* const varp = vtx.cast<DfgVarPacked>()) {
|
||||
// Don't inline SystemC variables, as SystemC types are not interchangeable with
|
||||
// internal types, and hence the variables are not interchangeable either.
|
||||
if (varp->hasSinks() && varp->isDrivenFullyByDfg() && !varp->varp()->isSc()) {
|
||||
DfgVertex* const driverp = varp->source(0);
|
||||
|
||||
// We must keep the original driver in certain cases, when swapping them would
|
||||
// not be functionally or technically (implementation reasons) equivalent:
|
||||
// 1. If driven from a SystemC variable (assignment is non-trivial)
|
||||
if (DfgVertexVar* const driverVarp = driverp->cast<DfgVarPacked>()) {
|
||||
if (driverVarp->varp()->isSc()) continue;
|
||||
}
|
||||
|
||||
if (varp->hasSinks() && varp->isDrivenFullyByDfg()) {
|
||||
DfgVertex* const driverp = varp->srcp();
|
||||
varp->forEachSinkEdge([=](DfgEdge& edge) { edge.relinkSource(driverp); });
|
||||
}
|
||||
}
|
||||
|
@ -381,12 +371,14 @@ void V3DfgPasses::binToOneHot(DfgGraph& dfg, V3DfgBinToOneHotContext& ctx) {
|
|||
// The index variable
|
||||
DfgVarPacked* const idxVtxp = [&]() {
|
||||
// If there is an existing result variable, use that, otherwise create a new variable
|
||||
DfgVarPacked* varp = srcp->getResultVar();
|
||||
if (!varp) {
|
||||
DfgVarPacked* varp = nullptr;
|
||||
if (DfgVertexVar* const vp = srcp->getResultVar()) {
|
||||
varp = vp->as<DfgVarPacked>();
|
||||
} else {
|
||||
const std::string name = dfg.makeUniqueName("BinToOneHot_Idx", nTables);
|
||||
varp = dfg.makeNewVar(flp, name, idxDTypep, nullptr)->as<DfgVarPacked>();
|
||||
varp->varp()->isInternal(true);
|
||||
varp->addDriver(flp, 0, srcp);
|
||||
varp->srcp(srcp);
|
||||
}
|
||||
varp->setHasModRefs();
|
||||
return varp;
|
||||
|
@ -554,12 +546,10 @@ void V3DfgPasses::eliminateVars(DfgGraph& dfg, V3DfgEliminateVarsContext& ctx) {
|
|||
if (!varp->hasModRefs()) {
|
||||
// If it is only referenced in this DFG, it can be removed
|
||||
++ctx.m_varsRemoved;
|
||||
varp->replaceWith(varp->source(0));
|
||||
varp->replaceWith(varp->srcp());
|
||||
varp->nodep()->unlinkFrBack()->deleteTree();
|
||||
} else if (DfgVarPacked* const driverp = varp->source(0)->cast<DfgVarPacked>()) {
|
||||
// If it's driven from another variable, it can be replaced by that. However, we do not
|
||||
// want to propagate SystemC variables into the design.
|
||||
if (driverp->varp()->isSc()) continue;
|
||||
} else if (DfgVarPacked* const driverp = varp->srcp()->cast<DfgVarPacked>()) {
|
||||
// If it's driven from another variable, it can be replaced by that.
|
||||
// Mark it for replacement
|
||||
++ctx.m_varsReplaced;
|
||||
UASSERT_OBJ(!varp->hasSinks(), varp, "Variable inlining should make this impossible");
|
||||
|
|
|
@ -1202,11 +1202,16 @@ class V3DfgPeephole final : public DfgVisitor {
|
|||
void visit(DfgArraySel* vtxp) override {
|
||||
if (DfgConst* const idxp = vtxp->bitp()->cast<DfgConst>()) {
|
||||
if (DfgVarArray* const varp = vtxp->fromp()->cast<DfgVarArray>()) {
|
||||
const size_t idx = idxp->toSizeT();
|
||||
if (DfgVertex* const driverp = varp->driverAt(idx)) {
|
||||
APPLYING(INLINE_ARRAYSEL) {
|
||||
replace(vtxp, driverp);
|
||||
return;
|
||||
if (varp->srcp() && !varp->varp()->isForced()) {
|
||||
if (DfgSpliceArray* const splicep = varp->srcp()->cast<DfgSpliceArray>()) {
|
||||
if (DfgVertex* const driverp = splicep->driverAt(idxp->toSizeT())) {
|
||||
if (!driverp->is<DfgVertexSplice>()) {
|
||||
APPLYING(INLINE_ARRAYSEL) {
|
||||
replace(vtxp, driverp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,12 +45,15 @@ class DfgRegularize final {
|
|||
// Ensure intermediate values used multiple times are written to variables
|
||||
for (DfgVertex& vtx : m_dfg.opVertices()) {
|
||||
const bool needsIntermediateVariable = [&]() {
|
||||
// Anything that drives an SC variable needs an intermediate,
|
||||
// as we can only assign simple variables to SC variables at runtime.
|
||||
const bool hasScSink = vtx.findSink<DfgVertexVar>([](const DfgVertexVar& var) { //
|
||||
return var.varp()->isSc();
|
||||
});
|
||||
if (hasScSink) return true;
|
||||
// Splice vertices represent partial assignments, so they need a variable
|
||||
// iff and only if they have a non-variable sink.
|
||||
if (vtx.is<DfgVertexSplice>()) {
|
||||
const bool hasNonVarSink
|
||||
= vtx.findSink<DfgVertex>([](const DfgVertex& snk) { //
|
||||
return !snk.is<DfgVertexVar>() && !snk.is<DfgVertexSplice>();
|
||||
});
|
||||
return hasNonVarSink;
|
||||
}
|
||||
// Operations without multiple sinks need no variables
|
||||
if (!vtx.hasMultipleSinks()) return false;
|
||||
// Array selects need no variables, they are just memory references
|
||||
|
@ -63,26 +66,21 @@ class DfgRegularize final {
|
|||
|
||||
// This is an op that requires a result variable. Ensure it is
|
||||
// assigned to one, and redirect other sinks read that variable.
|
||||
if (DfgVarPacked* const varp = vtx.getResultVar()) {
|
||||
// A variable already exists
|
||||
UASSERT_OBJ(varp->arity() == 1, varp, "Result variable with multiple drivers");
|
||||
FileLine* const flp = varp->driverFileLine(0);
|
||||
varp->sourceEdge(0)->unlinkSource();
|
||||
varp->resetSources();
|
||||
if (DfgVertexVar* const varp = vtx.getResultVar()) {
|
||||
varp->sourceEdge<0>()->unlinkSource();
|
||||
vtx.replaceWith(varp);
|
||||
varp->addDriver(flp, 0, &vtx);
|
||||
varp->srcp(&vtx);
|
||||
} else {
|
||||
// Need to create an intermediate variable
|
||||
const std::string name = m_dfg.makeUniqueName("Regularize", m_nTmps);
|
||||
FileLine* const flp = vtx.fileline();
|
||||
AstScope* const scopep = scoped ? vtx.scopep(scopeCache) : nullptr;
|
||||
DfgVarPacked* const newp
|
||||
= m_dfg.makeNewVar(flp, name, vtx.dtypep(), scopep)->as<DfgVarPacked>();
|
||||
DfgVertexVar* const newp = m_dfg.makeNewVar(flp, name, vtx.dtypep(), scopep);
|
||||
++m_nTmps;
|
||||
++m_ctx.m_temporariesIntroduced;
|
||||
// Replace vertex with the variable and add back driver
|
||||
vtx.replaceWith(newp);
|
||||
newp->addDriver(vtx.fileline(), 0, &vtx);
|
||||
newp->srcp(&vtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,22 +38,24 @@
|
|||
|
||||
// === Abstract base node types (DfgVertex*) ===================================
|
||||
|
||||
class DfgVertexVar VL_NOT_FINAL : public DfgVertexVariadic {
|
||||
class DfgVertexVar VL_NOT_FINAL : public DfgVertexUnary {
|
||||
AstVar* const m_varp; // The AstVar associated with this vertex (not owned by this vertex)
|
||||
AstVarScope* const m_varScopep; // The AstVarScope associated with this vertex (not owned)
|
||||
bool m_hasDfgRefs = false; // This AstVar is referenced in a different DFG of the module
|
||||
bool m_hasModRefs = false; // This AstVar is referenced outside the DFG, but in the module
|
||||
bool m_hasExtRefs = false; // This AstVar is referenced from outside the module
|
||||
// Location of driver of this variable. Only used for converting back to Ast. Might be nullptr.
|
||||
FileLine* m_driverFileLine = nullptr;
|
||||
|
||||
bool selfEquals(const DfgVertex& that) const final VL_MT_DISABLED;
|
||||
V3Hash selfHash() const final VL_MT_DISABLED;
|
||||
|
||||
public:
|
||||
inline DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp, uint32_t initialCapacity);
|
||||
inline DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp, uint32_t initialCapacity);
|
||||
inline DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVar* varp);
|
||||
inline DfgVertexVar(DfgGraph& dfg, VDfgType type, AstVarScope* vscp);
|
||||
ASTGEN_MEMBERS_DfgVertexVar;
|
||||
|
||||
bool isDrivenByDfg() const { return arity() > 0; }
|
||||
const std::string srcName(size_t) const override { return ""; }
|
||||
|
||||
AstVar* varp() const { return m_varp; }
|
||||
AstVarScope* varScopep() const { return m_varScopep; }
|
||||
|
@ -68,6 +70,13 @@ public:
|
|||
void setHasExtRefs() { m_hasExtRefs = true; }
|
||||
bool hasNonLocalRefs() const { return hasDfgRefs() || hasModRefs() || hasExtRefs(); }
|
||||
|
||||
FileLine* driverFileLine() const { return m_driverFileLine; }
|
||||
void driverFileLine(FileLine* flp) { m_driverFileLine = flp; }
|
||||
|
||||
bool isDrivenFullyByDfg() const {
|
||||
return srcp() && !srcp()->is<DfgVertexSplice>() && !varp()->isForced();
|
||||
}
|
||||
|
||||
// Variable cannot be removed, even if redundant in the DfgGraph (might be used externally)
|
||||
bool keep() const {
|
||||
// Keep if referenced outside this module
|
||||
|
@ -82,6 +91,12 @@ public:
|
|||
return false;
|
||||
}
|
||||
};
|
||||
class DfgVertexSplice VL_NOT_FINAL : public DfgVertexVariadic {
|
||||
public:
|
||||
DfgVertexSplice(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertexVariadic{dfg, type, flp, dtypep, 1u} {}
|
||||
ASTGEN_MEMBERS_DfgVertexSplice;
|
||||
};
|
||||
|
||||
// === Concrete node types =====================================================
|
||||
|
||||
|
@ -178,20 +193,58 @@ class DfgVarArray final : public DfgVertexVar {
|
|||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
using DriverData = std::pair<FileLine*, uint32_t>;
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associate with each driver
|
||||
|
||||
public:
|
||||
DfgVarArray(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp, 4u} {
|
||||
: DfgVertexVar{dfg, dfgType(), varp} {
|
||||
UASSERT_OBJ(VN_IS(dtypep(), UnpackArrayDType), varp, "Non array DfgVarArray");
|
||||
}
|
||||
DfgVarArray(DfgGraph& dfg, AstVarScope* vscp)
|
||||
: DfgVertexVar{dfg, dfgType(), vscp, 4u} {
|
||||
: DfgVertexVar{dfg, dfgType(), vscp} {
|
||||
UASSERT_OBJ(VN_IS(dtypep(), UnpackArrayDType), vscp, "Non array DfgVarArray");
|
||||
}
|
||||
ASTGEN_MEMBERS_DfgVarArray;
|
||||
};
|
||||
class DfgVarPacked final : public DfgVertexVar {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
public:
|
||||
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp} {
|
||||
UASSERT_OBJ(!VN_IS(dtypep(), UnpackArrayDType), varp, "Array DfgVarPacked");
|
||||
}
|
||||
DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp)
|
||||
: DfgVertexVar{dfg, dfgType(), vscp} {
|
||||
UASSERT_OBJ(!VN_IS(dtypep(), UnpackArrayDType), vscp, "Array DfgVarPacked");
|
||||
}
|
||||
ASTGEN_MEMBERS_DfgVarPacked;
|
||||
};
|
||||
|
||||
// === DfgVertexSplice ===
|
||||
class DfgSpliceArray final : public DfgVertexSplice {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
struct DriverData final {
|
||||
FileLine* m_flp; // Location of this driver
|
||||
uint32_t m_index; // Array index driven by this driver (or low index of range)
|
||||
DriverData() = delete;
|
||||
DriverData(FileLine* flp, uint32_t index)
|
||||
: m_flp{flp}
|
||||
, m_index{index} {}
|
||||
};
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associated with each driver
|
||||
|
||||
bool selfEquals(const DfgVertex& that) const override VL_MT_DISABLED;
|
||||
V3Hash selfHash() const override VL_MT_DISABLED;
|
||||
|
||||
public:
|
||||
DfgSpliceArray(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertexSplice{dfg, dfgType(), flp, dtypep} {
|
||||
UASSERT_OBJ(VN_IS(dtypep, UnpackArrayDType), flp, "Non array DfgSpliceArray");
|
||||
}
|
||||
ASTGEN_MEMBERS_DfgSpliceArray;
|
||||
|
||||
void addDriver(FileLine* flp, uint32_t index, DfgVertex* vtxp) {
|
||||
m_driverData.emplace_back(flp, index);
|
||||
|
@ -203,29 +256,8 @@ public:
|
|||
DfgVertexVariadic::resetSources();
|
||||
}
|
||||
|
||||
// Remove undriven sources
|
||||
void packSources() {
|
||||
// Grab and reset the driver data
|
||||
std::vector<DriverData> driverData;
|
||||
driverData.swap(m_driverData);
|
||||
|
||||
// Grab and unlink the sources
|
||||
std::vector<DfgVertex*> sources{arity()};
|
||||
forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
sources[idx] = edge.sourcep();
|
||||
edge.unlinkSource();
|
||||
});
|
||||
DfgVertexVariadic::resetSources();
|
||||
|
||||
// Add back the driven sources
|
||||
for (size_t i = 0; i < sources.size(); ++i) {
|
||||
if (!sources[i]) continue;
|
||||
addDriver(driverData[i].first, driverData[i].second, sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; }
|
||||
uint32_t driverIndex(size_t idx) const { return m_driverData[idx].second; }
|
||||
FileLine* driverFileLine(size_t i) const { return m_driverData.at(i).m_flp; }
|
||||
uint32_t driverIndex(size_t i) const { return m_driverData.at(i).m_index; }
|
||||
|
||||
DfgVertex* driverAt(size_t idx) const {
|
||||
const DfgEdge* const edgep = findSourceEdge([this, idx](const DfgEdge&, size_t i) { //
|
||||
|
@ -234,26 +266,33 @@ public:
|
|||
return edgep ? edgep->sourcep() : nullptr;
|
||||
}
|
||||
|
||||
const string srcName(size_t idx) const override { return cvtToStr(driverIndex(idx)); }
|
||||
const std::string srcName(size_t idx) const override {
|
||||
return std::to_string(driverIndex(idx));
|
||||
}
|
||||
};
|
||||
class DfgVarPacked final : public DfgVertexVar {
|
||||
class DfgSplicePacked final : public DfgVertexSplice {
|
||||
friend class DfgVertex;
|
||||
friend class DfgVisitor;
|
||||
|
||||
using DriverData = std::pair<FileLine*, uint32_t>;
|
||||
struct DriverData final {
|
||||
FileLine* m_flp; // Location of this driver
|
||||
uint32_t m_lsb; // LSB of range driven by this driver
|
||||
DriverData() = delete;
|
||||
DriverData(FileLine* flp, uint32_t lsb)
|
||||
: m_flp{flp}
|
||||
, m_lsb{lsb} {}
|
||||
};
|
||||
std::vector<DriverData> m_driverData; // Additional data associated with each driver
|
||||
|
||||
std::vector<DriverData> m_driverData; // Additional data associate with each driver
|
||||
bool selfEquals(const DfgVertex& that) const override VL_MT_DISABLED;
|
||||
V3Hash selfHash() const override VL_MT_DISABLED;
|
||||
|
||||
public:
|
||||
DfgVarPacked(DfgGraph& dfg, AstVar* varp)
|
||||
: DfgVertexVar{dfg, dfgType(), varp, 1u} {}
|
||||
DfgVarPacked(DfgGraph& dfg, AstVarScope* vscp)
|
||||
: DfgVertexVar{dfg, dfgType(), vscp, 1u} {}
|
||||
ASTGEN_MEMBERS_DfgVarPacked;
|
||||
|
||||
bool isDrivenFullyByDfg() const {
|
||||
return arity() == 1 && source(0)->dtypep() == dtypep() && !varp()->isForced();
|
||||
DfgSplicePacked(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertexSplice{dfg, dfgType(), flp, dtypep} {
|
||||
UASSERT_OBJ(!VN_IS(dtypep, UnpackArrayDType), flp, "Array DfgSplicePacked");
|
||||
}
|
||||
ASTGEN_MEMBERS_DfgSplicePacked;
|
||||
|
||||
void addDriver(FileLine* flp, uint32_t lsb, DfgVertex* vtxp) {
|
||||
m_driverData.emplace_back(flp, lsb);
|
||||
|
@ -265,33 +304,10 @@ public:
|
|||
DfgVertexVariadic::resetSources();
|
||||
}
|
||||
|
||||
// Remove undriven sources
|
||||
void packSources() {
|
||||
// Grab and reset the driver data
|
||||
std::vector<DriverData> driverData;
|
||||
driverData.swap(m_driverData);
|
||||
FileLine* driverFileLine(size_t i) const { return m_driverData.at(i).m_flp; }
|
||||
uint32_t driverLsb(size_t i) const { return m_driverData.at(i).m_lsb; }
|
||||
|
||||
// Grab and unlink the sources
|
||||
std::vector<DfgVertex*> sources{arity()};
|
||||
forEachSourceEdge([&](DfgEdge& edge, size_t idx) {
|
||||
sources[idx] = edge.sourcep();
|
||||
edge.unlinkSource();
|
||||
});
|
||||
DfgVertexVariadic::resetSources();
|
||||
|
||||
// Add back the driven sources
|
||||
for (size_t i = 0; i < sources.size(); ++i) {
|
||||
if (!sources[i]) continue;
|
||||
addDriver(driverData[i].first, driverData[i].second, sources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FileLine* driverFileLine(size_t idx) const { return m_driverData[idx].first; }
|
||||
uint32_t driverLsb(size_t idx) const { return m_driverData[idx].second; }
|
||||
|
||||
const string srcName(size_t idx) const override {
|
||||
return isDrivenFullyByDfg() ? "" : cvtToStr(driverLsb(idx));
|
||||
}
|
||||
const std::string srcName(size_t idx) const override { return std::to_string(driverLsb(idx)); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -247,14 +247,14 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
|
|||
AstNode* argp = nullptr;
|
||||
if (!ignore) {
|
||||
argp = *elistp;
|
||||
// Prep for next parameter
|
||||
*elistp = (*elistp)->nextp();
|
||||
if (VL_UNCOVERABLE(!argp)) {
|
||||
// expectDisplay() checks this first, so internal error if found here
|
||||
dispp->v3error(
|
||||
"Internal: Missing arguments for $display-like format"); // LCOV_EXCL_LINE
|
||||
return; // LCOV_EXCL_LINE
|
||||
}
|
||||
// Prep for next parameter
|
||||
*elistp = (*elistp)->nextp();
|
||||
if (argp->widthMin() > VL_VALUE_STRING_MAX_WIDTH) {
|
||||
dispp->v3warn(E_UNSUPPORTED, "Unsupported: Exceeded limit of "
|
||||
+ cvtToStr(VL_VALUE_STRING_MAX_WIDTH)
|
||||
|
@ -745,7 +745,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
return "";
|
||||
} else if (basicp && basicp->isDynamicTriggerScheduler()) {
|
||||
return "";
|
||||
} else if (basicp && basicp->isRandomGenerator()) {
|
||||
} else if (basicp && (basicp->isRandomGenerator() || basicp->isStdRandomGenerator())) {
|
||||
return "";
|
||||
} else if (basicp) {
|
||||
const bool zeroit
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
|
@ -117,7 +118,7 @@ public:
|
|||
class EmitCFunc VL_NOT_FINAL : public EmitCConstInit {
|
||||
VMemberMap m_memberMap;
|
||||
AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting
|
||||
int m_labelNum = 0; // Next label number
|
||||
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for JumpBlocks
|
||||
bool m_inUC = false; // Inside an AstUCStmt or AstUCExpr
|
||||
bool m_emitConstInit = false; // Emitting constant initializer
|
||||
bool m_createdScopeHash = false; // Already created a scope hash
|
||||
|
@ -325,6 +326,7 @@ public:
|
|||
VL_RESTORER(m_createdScopeHash);
|
||||
m_cfuncp = nodep;
|
||||
m_instantiatesOwnProcess = false;
|
||||
m_labelNumbers.clear(); // No need to save/restore, all Jumps must be within the function
|
||||
|
||||
splitSizeInc(nodep);
|
||||
|
||||
|
@ -993,34 +995,36 @@ public:
|
|||
puts(";\n");
|
||||
}
|
||||
void visit(AstJumpBlock* nodep) override {
|
||||
nodep->labelNum(++m_labelNum);
|
||||
// Allocate label number
|
||||
const size_t n = m_labelNumbers.size();
|
||||
const bool newEntry = m_labelNumbers.emplace(nodep, n).second;
|
||||
UASSERT_OBJ(newEntry, nodep, "AstJumpBlock visited twide");
|
||||
// Emit
|
||||
putns(nodep, "{\n"); // Make it visually obvious label jumps outside these
|
||||
VL_RESTORER(m_createdScopeHash);
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->endStmtsp());
|
||||
puts("__Vlabel" + std::to_string(n) + ": ;\n");
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
// Retrieve target label number - must already exist (from enclosing AstJumpBlock)
|
||||
const size_t n = m_labelNumbers.at(nodep->blockp());
|
||||
// Emit
|
||||
putns(nodep, "goto __Vlabel" + std::to_string(n) + ";\n");
|
||||
}
|
||||
void visit(AstCLocalScope* nodep) override {
|
||||
putns(nodep, "{\n");
|
||||
VL_RESTORER(m_createdScopeHash);
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
putns(nodep, "goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
|
||||
}
|
||||
void visit(AstJumpLabel* nodep) override {
|
||||
putns(nodep, "__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n");
|
||||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
VL_RESTORER(m_createdScopeHash);
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
putns(nodep, "while (");
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
puts(") {\n");
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->incsp());
|
||||
iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
puts("}\n");
|
||||
}
|
||||
void visit(AstNodeIf* nodep) override {
|
||||
|
|
|
@ -964,9 +964,9 @@ void EmitCSyms::emitSymImp() {
|
|||
} else {
|
||||
if (basicp->isRanged()) {
|
||||
bounds += " ,";
|
||||
bounds += cvtToStr(basicp->hi());
|
||||
bounds += cvtToStr(basicp->left());
|
||||
bounds += ",";
|
||||
bounds += cvtToStr(basicp->lo());
|
||||
bounds += cvtToStr(basicp->right());
|
||||
pdim++;
|
||||
}
|
||||
break; // AstBasicDType - nothing below, 1
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||
|
@ -37,6 +38,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
|
||||
std::deque<AstNodeArrayDType*> m_packedps; // Packed arrays to print with BasicDType
|
||||
std::unordered_map<AstJumpBlock*, size_t> m_labelNumbers; // Label numbers for JumpBlocks
|
||||
|
||||
// METHODS
|
||||
virtual void puts(const string& str) = 0;
|
||||
|
@ -308,14 +310,23 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
puts(");\n");
|
||||
}
|
||||
void visit(AstJumpBlock* nodep) override {
|
||||
putbs("begin : label" + cvtToStr(nodep->labelNum()) + "\n");
|
||||
if (nodep->stmtsp()) iterateAndNextConstNull(nodep->stmtsp());
|
||||
// Allocate label number
|
||||
const size_t n = m_labelNumbers.size();
|
||||
const bool newEntry = m_labelNumbers.emplace(nodep, n).second;
|
||||
UASSERT_OBJ(newEntry, nodep, "AstJumpBlock visited twide");
|
||||
// Emit
|
||||
putbs("begin : label" + std::to_string(n) + "\n");
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
puts("end\n");
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
putbs("disable label" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n");
|
||||
// Retrieve target label number - Sometimes EmitV is used by debug code,
|
||||
// so allow printing with an unknown target
|
||||
const auto it = m_labelNumbers.find(nodep->blockp());
|
||||
const std::string label
|
||||
= it != m_labelNumbers.end() ? "label" + std::to_string(it->second) : "<UNKNOWN>";
|
||||
putbs("disable " + label + ";\n");
|
||||
}
|
||||
void visit(AstJumpLabel* nodep) override { putbs("// " + cvtToStr(nodep->blockp()) + ":\n"); }
|
||||
void visit(AstNodeReadWriteMem* nodep) override {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs("(");
|
||||
|
@ -365,13 +376,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
putfs(nodep, "end\n");
|
||||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
putfs(nodep, "while (");
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
puts(") begin\n");
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
iterateAndNextConstNull(nodep->incsp());
|
||||
iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop
|
||||
putfs(nodep, "end\n");
|
||||
}
|
||||
void visit(AstNodeIf* nodep) override {
|
||||
|
@ -922,6 +931,20 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||
m_sensesp = nodep->sensesp();
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
}
|
||||
void visit(AstDelay* nodep) override {
|
||||
puts(""); // this is for proper alignment
|
||||
puts("#");
|
||||
iterateConst(nodep->lhsp());
|
||||
puts(";\n");
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
}
|
||||
void visit(AstCAwait* nodep) override {
|
||||
AstCMethodHard* methodp = VN_CAST(nodep->exprp(), CMethodHard);
|
||||
UASSERT_OBJ(methodp, nodep, "AstCAwait expression must be an AstCMethodHard");
|
||||
puts(""); // this is for proper alignment
|
||||
puts("#");
|
||||
iterateConst(methodp->pinsp());
|
||||
}
|
||||
void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); }
|
||||
void visit(AstNodeText*) override {}
|
||||
void visit(AstVarScope*) override {}
|
||||
|
|
|
@ -129,9 +129,6 @@ class EmitXmlFileVisitor final : public VNVisitorConst {
|
|||
void visit(AstWhile* nodep) override {
|
||||
outputTag(nodep, "while");
|
||||
puts(">\n");
|
||||
puts("<begin>\n");
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
puts("</begin>\n");
|
||||
if (nodep->condp()) {
|
||||
puts("<begin>\n");
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
|
|
|
@ -125,6 +125,7 @@ public:
|
|||
MULTIDRIVEN, // Driven from multiple blocks
|
||||
MULTITOP, // Multiple top level modules
|
||||
NEWERSTD, // Newer language standard required
|
||||
NOEFFECT, // Statement has no effect
|
||||
NOLATCH, // No latch detected in always_latch block
|
||||
NONSTD, // Non-standard feature present in other sims
|
||||
NULLPORT, // Null port detected in module definition
|
||||
|
@ -145,6 +146,7 @@ public:
|
|||
SELRANGE, // Selection index out of range
|
||||
SHORTREAL, // Shortreal not supported
|
||||
SIDEEFFECT, // Sideeffect ignored
|
||||
SPECIFYIGN, // Specify construct ignored
|
||||
SPLITVAR, // Cannot split the variable
|
||||
STATICVAR, // Static variable declared in a loop with a declaration assignment
|
||||
STMTDLY, // Delayed statement
|
||||
|
@ -190,41 +192,33 @@ public:
|
|||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const VL_MT_SAFE { return m_e; }
|
||||
const char* ascii() const VL_MT_SAFE {
|
||||
// clang-format off
|
||||
static const char* const names[] = {
|
||||
// Leading spaces indicate it can't be disabled.
|
||||
" MIN", " INFO", " FATAL", " FATALMANY", " FATALSRC", " ERROR", " FIRST_NAMED",
|
||||
// Boolean
|
||||
" I_CELLDEFINE", " I_COVERAGE", " I_DEF_NETTYPE_WIRE", " I_LINT", " I_TIMING", " I_TRACING", " I_UNUSED",
|
||||
" I_CELLDEFINE", " I_COVERAGE", " I_DEF_NETTYPE_WIRE", " I_LINT", " I_TIMING",
|
||||
" I_TRACING", " I_UNUSED",
|
||||
// Errors
|
||||
"LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN",
|
||||
"ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", "BADVLTPRAGMA",
|
||||
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
|
||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN",
|
||||
"DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED",
|
||||
"ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE",
|
||||
"GENCLK", "GENUNNAMED", "HIERBLOCK",
|
||||
"IFDEPTH", "IGNOREDRETURN",
|
||||
"IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
|
||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
|
||||
"LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING",
|
||||
"MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOLATCH", "NONSTD", "NULLPORT", "PINCONNECTEMPTY",
|
||||
"PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE",
|
||||
"PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY",
|
||||
"SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPLITVAR",
|
||||
"STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"TICKCOUNT", "TIMESCALEMOD",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS",
|
||||
"UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP" ,"UNUSEDPARAM", "UNUSEDSIGNAL",
|
||||
"USERERROR", "USERFATAL", "USERINFO", "USERWARN",
|
||||
"VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND",
|
||||
"ZERODLY", "ZEROREPL",
|
||||
" MAX"
|
||||
};
|
||||
// clang-format on
|
||||
" EC_FIRST_WARN", "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
|
||||
"BADVLTPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE",
|
||||
"CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST",
|
||||
"COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN", "DECLFILENAME",
|
||||
"DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH",
|
||||
"ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED", "HIERBLOCK", "IFDEPTH",
|
||||
"IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE",
|
||||
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "LATCH", "LITENDIAN",
|
||||
"MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING", "MULTIDRIVEN", "MULTITOP",
|
||||
"NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT", "PINCONNECTEMPTY",
|
||||
"PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSINIT",
|
||||
"PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO",
|
||||
"RISEFALLDLY", "SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR",
|
||||
"STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED",
|
||||
"UNUSEDGENVAR", "UNUSEDLOOP", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL",
|
||||
"USERINFO", "USERWARN", "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT",
|
||||
"WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"};
|
||||
return names[m_e];
|
||||
}
|
||||
// Warnings that default to off
|
||||
|
|
|
@ -35,7 +35,7 @@ struct GraphPCNode final {
|
|||
//
|
||||
// Unlike the LogicMTasks's, we have no cost info for the generic graph
|
||||
// accepted by GraphPathChecker, so assume each node has unit cost.
|
||||
std::array<uint32_t, GraphWay::NUM_WAYS> m_cp;
|
||||
std::array<uint32_t, GraphWay::NUM_WAYS> m_cp = {};
|
||||
|
||||
// Detect if we've seen this node before in a given recursive
|
||||
// operation. We'll use this in pathExistsInternal() to avoid checking
|
||||
|
@ -44,9 +44,7 @@ struct GraphPCNode final {
|
|||
uint64_t m_seenAtGeneration = 0;
|
||||
|
||||
// CONSTRUCTORS
|
||||
GraphPCNode() {
|
||||
for (unsigned int& w : m_cp) w = 0;
|
||||
}
|
||||
GraphPCNode() {}
|
||||
~GraphPCNode() = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -320,9 +320,7 @@ class HasherVisitor final : public VNVisitorConst {
|
|||
});
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
|
||||
iterateConstNull(nodep->labelp());
|
||||
});
|
||||
m_hash += hashNodeAndIterate(nodep, false, false, []() {});
|
||||
}
|
||||
void visit(AstTraceInc* nodep) override {
|
||||
m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [this, nodep]() { //
|
||||
|
|
|
@ -401,7 +401,6 @@ class LifeVisitor final : public VNVisitor {
|
|||
LifeBlock* const bodyLifep = new LifeBlock{prevLifep, m_statep};
|
||||
{
|
||||
m_lifep = condLifep;
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextNull(nodep->condp());
|
||||
}
|
||||
{
|
||||
|
|
|
@ -779,14 +779,51 @@ public:
|
|||
if (!foundp) baddot = dotname;
|
||||
return foundp;
|
||||
}
|
||||
static bool checkIfClassOrPackage(const VSymEnt* const symp) {
|
||||
if (VN_IS(symp->nodep(), Class) || VN_IS(symp->nodep(), Package)) return true;
|
||||
const AstRefDType* refDTypep = nullptr;
|
||||
if (const AstTypedef* const typedefp = VN_CAST(symp->nodep(), Typedef)) {
|
||||
if (VN_IS(typedefp->childDTypep(), ClassRefDType)) return true;
|
||||
if (const AstRefDType* const refp = VN_CAST(typedefp->childDTypep(), RefDType)) {
|
||||
refDTypep = refp;
|
||||
}
|
||||
} else if (const AstParamTypeDType* const paramTypep
|
||||
= VN_CAST(symp->nodep(), ParamTypeDType)) {
|
||||
if (const AstRequireDType* const requireDTypep
|
||||
= VN_CAST(paramTypep->childDTypep(), RequireDType)) {
|
||||
if (const AstRefDType* const refp = VN_CAST(requireDTypep->lhsp(), RefDType)) {
|
||||
refDTypep = refp;
|
||||
} else if (VN_IS(requireDTypep->lhsp(), VoidDType)
|
||||
|| VN_IS(requireDTypep->lhsp(), BasicDType)
|
||||
|| VN_IS(requireDTypep->lhsp(), ClassRefDType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: this should be handled properly - case when it is known what type is
|
||||
// referenced by AstRefDType (refDTypep->typeofp() is null or
|
||||
// refDTypep->classOrPackageOpp() is null)
|
||||
if (refDTypep && !refDTypep->typeofp() && !refDTypep->classOrPackageOpp()) {
|
||||
// When still unknown - return because it may be a class, classes may not be
|
||||
// linked at this point. Return in case it gets resolved to a class in the future
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
VSymEnt* resolveClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool fallback,
|
||||
bool classOnly, const string& forWhat) {
|
||||
if (nodep->classOrPackageSkipp()) return getNodeSym(nodep->classOrPackageSkipp());
|
||||
VSymEnt* foundp;
|
||||
if (fallback) {
|
||||
foundp = lookSymp->findIdFallback(nodep->name());
|
||||
VSymEnt* currentLookSymp = lookSymp;
|
||||
do {
|
||||
foundp = currentLookSymp->findIdFlat(nodep->name());
|
||||
if (foundp && !checkIfClassOrPackage(foundp)) foundp = nullptr;
|
||||
if (!foundp) currentLookSymp = currentLookSymp->fallbackp();
|
||||
} while (!foundp && currentLookSymp);
|
||||
} else {
|
||||
foundp = lookSymp->findIdFlat(nodep->name());
|
||||
if (foundp && !checkIfClassOrPackage(foundp)) foundp = nullptr;
|
||||
}
|
||||
if (!foundp && v3Global.rootp()->stdPackagep()) { // Look under implied std::
|
||||
foundp = getNodeSym(v3Global.rootp()->stdPackagep())->findIdFlat(nodep->name());
|
||||
|
@ -3552,9 +3589,6 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
UINFO(9, indent() << m_ds.ascii());
|
||||
VL_RESTORER(m_usedPins);
|
||||
m_usedPins.clear();
|
||||
UASSERT_OBJ(m_statep->forPrimary() || VN_IS(nodep->classOrPackageNodep(), ParamTypeDType)
|
||||
|| nodep->classOrPackageSkipp(),
|
||||
nodep, "ClassRef has unlinked class");
|
||||
UASSERT_OBJ(m_statep->forPrimary() || !nodep->paramsp(), nodep,
|
||||
"class reference parameter not removed by V3Param");
|
||||
{
|
||||
|
@ -3565,6 +3599,10 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
m_statep->resolveClassOrPackage(m_ds.m_dotSymp, nodep, m_ds.m_dotPos != DP_PACKAGE,
|
||||
false, ":: reference");
|
||||
}
|
||||
UASSERT_OBJ(m_statep->forPrimary()
|
||||
|| VN_IS(nodep->classOrPackageNodep(), ParamTypeDType)
|
||||
|| nodep->classOrPackageSkipp(),
|
||||
nodep, "ClassRef has unlinked class");
|
||||
|
||||
// ClassRef's have pins, so track
|
||||
if (nodep->classOrPackageSkipp()) {
|
||||
|
|
|
@ -54,18 +54,11 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
//######################################################################
|
||||
|
||||
class LinkIncVisitor final : public VNVisitor {
|
||||
// TYPES
|
||||
enum InsertMode : uint8_t {
|
||||
IM_BEFORE, // Pointing at statement ref is in, insert before this
|
||||
IM_AFTER, // Pointing at last inserted stmt, insert after
|
||||
IM_WHILE_PRECOND // Pointing to for loop, add to body end
|
||||
};
|
||||
|
||||
// STATE
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside
|
||||
AstNodeModule* m_modp = nullptr; // Module we're inside
|
||||
int m_modIncrementsNum = 0; // Var name counter
|
||||
InsertMode m_insMode = IM_BEFORE; // How to insert
|
||||
AstWhile* m_inWhileCondp = nullptr; // Inside condition of this while loop
|
||||
AstNode* m_insStmtp = nullptr; // Where to insert statement
|
||||
bool m_unsupportedHere = false; // Used to detect where it's not supported yet
|
||||
|
||||
|
@ -86,23 +79,14 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
m_modp->addStmtsp(newp);
|
||||
}
|
||||
}
|
||||
void insertNextToStmt(AstNode* nodep, AstNode* newp) {
|
||||
void insertBeforeStmt(AstNode* nodep, AstNode* newp) {
|
||||
// Return node that must be visited, if any
|
||||
if (debug() >= 9) newp->dumpTree("- newstmt: ");
|
||||
UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement");
|
||||
if (m_insMode == IM_BEFORE) {
|
||||
// Add the whole thing before insertAt
|
||||
if (debug() >= 9) newp->dumpTree("- newfunc: ");
|
||||
m_insStmtp->addHereThisAsNext(newp);
|
||||
} else if (m_insMode == IM_AFTER) {
|
||||
m_insStmtp->addNextHere(newp);
|
||||
} else if (m_insMode == IM_WHILE_PRECOND) {
|
||||
AstWhile* const whilep = VN_AS(m_insStmtp, While);
|
||||
UASSERT_OBJ(whilep, nodep, "Insert should be under WHILE");
|
||||
whilep->addPrecondsp(newp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown InsertMode");
|
||||
}
|
||||
UASSERT_OBJ(m_insStmtp, nodep, "Expression not underneath a statement");
|
||||
// In a while condition, the statement also needs to go on the
|
||||
// back-edge to the loop header, 'incsp' is that place.
|
||||
if (m_inWhileCondp) m_inWhileCondp->addIncsp(newp->cloneTreePure(true));
|
||||
m_insStmtp->addHereThisAsNext(newp);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
@ -120,14 +104,13 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
// Special, as statements need to be put in different places
|
||||
// Preconditions insert first just before themselves (the normal
|
||||
// rule for other statement types)
|
||||
m_insStmtp = nullptr; // First thing should be new statement
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
// Conditions insert first at end of precondsp.
|
||||
m_insMode = IM_WHILE_PRECOND;
|
||||
m_insStmtp = nodep;
|
||||
iterateAndNextNull(nodep->condp());
|
||||
{
|
||||
// Conditions insert before the loop and into incsp
|
||||
VL_RESTORER(m_inWhileCondp);
|
||||
m_inWhileCondp = nodep;
|
||||
iterateAndNextNull(nodep->condp());
|
||||
}
|
||||
// Body insert just before themselves
|
||||
m_insStmtp = nullptr; // First thing should be new statement
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
|
@ -160,7 +143,6 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
m_insStmtp = nullptr;
|
||||
}
|
||||
void visit(AstCaseItem* nodep) override {
|
||||
m_insMode = IM_BEFORE;
|
||||
{
|
||||
VL_RESTORER(m_unsupportedHere);
|
||||
m_unsupportedHere = true;
|
||||
|
@ -193,7 +175,6 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
m_insStmtp = nullptr;
|
||||
}
|
||||
void visit(AstNodeStmt* nodep) override {
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_insStmtp = nullptr; // Next thing should be new statement
|
||||
|
@ -332,18 +313,17 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
// Immediately after declaration - increment it by one
|
||||
AstAssign* const assignp
|
||||
= new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, operp};
|
||||
insertNextToStmt(nodep, assignp);
|
||||
// Immediately after incrementing - assign it to the original variable
|
||||
assignp->addNextHere(
|
||||
new AstAssign{fl, writep, new AstVarRef{fl, varp, VAccess::READ}});
|
||||
assignp->addNext(new AstAssign{fl, writep, new AstVarRef{fl, varp, VAccess::READ}});
|
||||
insertBeforeStmt(nodep, assignp);
|
||||
} else {
|
||||
// PostAdd/PostSub operations
|
||||
// Assign the original variable to the temporary one
|
||||
AstAssign* const assignp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE},
|
||||
readp->cloneTreePure(true)};
|
||||
insertNextToStmt(nodep, assignp);
|
||||
// Increment the original variable by one
|
||||
assignp->addNextHere(new AstAssign{fl, writep, operp});
|
||||
assignp->addNext(new AstAssign{fl, writep, operp});
|
||||
insertBeforeStmt(nodep, assignp);
|
||||
}
|
||||
|
||||
// Replace the node with the temporary
|
||||
|
|
|
@ -45,8 +45,8 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
|
||||
class LinkJumpVisitor final : public VNVisitor {
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> AstJumpLabel*, for this block if endOfIter
|
||||
// AstNode::user2() -> AstJumpLabel*, for this block if !endOfIter
|
||||
// AstNode::user1() -> AstJumpBlock*, for body of this loop
|
||||
// AstNode::user2() -> AstJumpBlock*, for this block
|
||||
// AstNodeBlock::user3() -> bool, true if contains a fork
|
||||
const VNUser1InUse m_user1InUse;
|
||||
const VNUser2InUse m_user2InUse;
|
||||
|
@ -65,36 +65,34 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
"__VprocessQueue"}; // Names for queues needed for 'disable' handling
|
||||
|
||||
// METHODS
|
||||
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
|
||||
// Put label under given node, and if WHILE optionally at end of iteration
|
||||
UINFO(4, "Create label for " << nodep);
|
||||
if (VN_IS(nodep, JumpLabel)) return VN_AS(nodep, JumpLabel); // Done
|
||||
// Get (and create if necessary) the JumpBlock for this statement
|
||||
AstJumpBlock* getJumpBlock(AstNode* nodep, bool endOfIter) {
|
||||
// Wrap 'nodep' in JumpBlock. If loop, wrap the body instead if endOfIter is true
|
||||
UINFO(4, "Create JumpBlock for " << nodep);
|
||||
|
||||
// Made it previously? We always jump to the end, so this works out
|
||||
if (endOfIter) {
|
||||
if (nodep->user1p()) return VN_AS(nodep->user1p(), JumpLabel);
|
||||
if (nodep->user1p()) return VN_AS(nodep->user1p(), JumpBlock);
|
||||
} else {
|
||||
if (nodep->user2p()) return VN_AS(nodep->user2p(), JumpLabel);
|
||||
if (nodep->user2p()) return VN_AS(nodep->user2p(), JumpBlock);
|
||||
}
|
||||
|
||||
AstNode* underp = nullptr;
|
||||
bool under_and_next = true;
|
||||
if (VN_IS(nodep, NodeBlock)) {
|
||||
underp = VN_AS(nodep, NodeBlock)->stmtsp();
|
||||
} else if (VN_IS(nodep, NodeFTask)) {
|
||||
underp = VN_AS(nodep, NodeFTask)->stmtsp();
|
||||
} else if (VN_IS(nodep, Foreach)) {
|
||||
if (AstNodeBlock* const blockp = VN_CAST(nodep, NodeBlock)) {
|
||||
underp = blockp->stmtsp();
|
||||
} else if (AstNodeFTask* const fTaskp = VN_CAST(nodep, NodeFTask)) {
|
||||
underp = fTaskp->stmtsp();
|
||||
} else if (AstForeach* const foreachp = VN_CAST(nodep, Foreach)) {
|
||||
if (endOfIter) {
|
||||
underp = VN_AS(nodep, Foreach)->stmtsp();
|
||||
underp = foreachp->stmtsp();
|
||||
} else {
|
||||
underp = nodep;
|
||||
under_and_next = false; // IE we skip the entire foreach
|
||||
}
|
||||
} else if (VN_IS(nodep, While)) {
|
||||
} else if (AstWhile* const whilep = VN_CAST(nodep, While)) {
|
||||
if (endOfIter) {
|
||||
// Note we jump to end of bodysp; a FOR loop has its
|
||||
// increment under incsp() which we don't skip
|
||||
underp = VN_AS(nodep, While)->stmtsp();
|
||||
underp = whilep->stmtsp();
|
||||
} else {
|
||||
underp = nodep;
|
||||
under_and_next = false; // IE we skip the entire while
|
||||
|
@ -118,36 +116,32 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(underp, nodep, "Break/disable/continue not under expected statement");
|
||||
UINFO(5, " Underpoint is " << underp);
|
||||
|
||||
if (VN_IS(underp, JumpLabel)) {
|
||||
return VN_AS(underp, JumpLabel);
|
||||
} else { // Move underp stuff to be under a new label
|
||||
AstJumpBlock* const blockp = new AstJumpBlock{nodep->fileline(), nullptr};
|
||||
AstJumpLabel* const labelp = new AstJumpLabel{nodep->fileline(), blockp};
|
||||
blockp->labelp(labelp);
|
||||
|
||||
VNRelinker repHandle;
|
||||
if (under_and_next) {
|
||||
underp->unlinkFrBackWithNext(&repHandle);
|
||||
} else {
|
||||
underp->unlinkFrBack(&repHandle);
|
||||
}
|
||||
repHandle.relink(blockp);
|
||||
|
||||
blockp->addStmtsp(underp);
|
||||
// Keep any AstVars under the function not under the new JumpLabel
|
||||
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
||||
nextp = varp->nextp();
|
||||
if (VN_IS(varp, Var)) blockp->addHereThisAsNext(varp->unlinkFrBack());
|
||||
}
|
||||
// Label goes last
|
||||
blockp->addEndStmtsp(labelp);
|
||||
if (endOfIter) {
|
||||
nodep->user1p(labelp);
|
||||
} else {
|
||||
nodep->user2p(labelp);
|
||||
}
|
||||
return labelp;
|
||||
// If already wrapped, we are done ...
|
||||
if (!underp->nextp() || !under_and_next) {
|
||||
if (AstJumpBlock* const blockp = VN_CAST(underp, JumpBlock)) return blockp;
|
||||
}
|
||||
|
||||
// Move underp stuff to be under a new AstJumpBlock
|
||||
VNRelinker repHandle;
|
||||
if (under_and_next) {
|
||||
underp->unlinkFrBackWithNext(&repHandle);
|
||||
} else {
|
||||
underp->unlinkFrBack(&repHandle);
|
||||
}
|
||||
AstJumpBlock* const blockp = new AstJumpBlock{nodep->fileline(), underp};
|
||||
if (endOfIter) {
|
||||
nodep->user1p(blockp);
|
||||
} else {
|
||||
nodep->user2p(blockp);
|
||||
}
|
||||
repHandle.relink(blockp);
|
||||
|
||||
// Keep any AstVars under the function not under the new JumpLabel
|
||||
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
||||
nextp = varp->nextp();
|
||||
if (VN_IS(varp, Var)) blockp->addHereThisAsNext(varp->unlinkFrBack());
|
||||
}
|
||||
return blockp;
|
||||
}
|
||||
void addPrefixToBlocksRecurse(const std::string& prefix, AstNode* const nodep) {
|
||||
// Add a prefix to blocks
|
||||
|
@ -185,6 +179,56 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
return new AstStmtExpr{
|
||||
fl, new AstMethodCall{fl, queueRefp, "push_back", new AstArg{fl, "", processSelfp}}};
|
||||
}
|
||||
void handleDisableOnFork(AstDisable* const nodep, const std::vector<AstBegin*>& forks) {
|
||||
// The support is limited only to disabling a fork from outside that fork.
|
||||
// It utilizes the process::kill()` method. For each `disable` a queue of processes is
|
||||
// declared. At the beginning of each fork that can be disabled, its process handle is
|
||||
// pushed to the queue. `disable` statement is replaced with calling `kill()` method on
|
||||
// each element of the queue.
|
||||
FileLine* const fl = nodep->fileline();
|
||||
const std::string targetName = nodep->targetp()->name();
|
||||
if (existsBlockAbove(targetName)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from within same fork");
|
||||
}
|
||||
if (m_ftaskp) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from task / function");
|
||||
}
|
||||
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgAddp();
|
||||
AstClass* const processClassp
|
||||
= VN_AS(getMemberp(v3Global.rootp()->stdPackagep(), "process"), Class);
|
||||
// Declare queue of processes (as a global variable for simplicity)
|
||||
AstVar* const processQueuep = new AstVar{
|
||||
fl, VVarType::VAR, m_queueNames.get(targetName), VFlagChildDType{},
|
||||
new AstQueueDType{fl, VFlagChildDType{},
|
||||
new AstClassRefDType{fl, processClassp, nullptr}, nullptr}};
|
||||
processQueuep->lifetime(VLifetime::STATIC);
|
||||
topPkgp->addStmtsp(processQueuep);
|
||||
|
||||
AstVarRef* const queueWriteRefp
|
||||
= new AstVarRef{fl, topPkgp, processQueuep, VAccess::WRITE};
|
||||
AstStmtExpr* pushCurrentProcessp = getQueuePushProcessSelfp(queueWriteRefp);
|
||||
|
||||
for (AstBegin* const beginp : forks) {
|
||||
if (pushCurrentProcessp->backp()) {
|
||||
pushCurrentProcessp = pushCurrentProcessp->cloneTree(false);
|
||||
}
|
||||
if (beginp->stmtsp()) {
|
||||
// There is no need to add it to empty block
|
||||
beginp->stmtsp()->addHereThisAsNext(pushCurrentProcessp);
|
||||
}
|
||||
}
|
||||
AstVarRef* const queueRefp = new AstVarRef{fl, topPkgp, processQueuep, VAccess::READWRITE};
|
||||
AstTaskRef* const killQueueCall
|
||||
= new AstTaskRef{fl, VN_AS(getMemberp(processClassp, "killQueue"), Task),
|
||||
new AstArg{fl, "", queueRefp}};
|
||||
killQueueCall->classOrPackagep(processClassp);
|
||||
nodep->addNextHere(new AstStmtExpr{fl, killQueueCall});
|
||||
}
|
||||
static bool directlyUnderFork(const AstNode* const nodep) {
|
||||
if (nodep->backp()->nextp() == nodep) return directlyUnderFork(nodep->backp());
|
||||
if (VN_IS(nodep->backp(), Fork)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
|
@ -273,7 +317,6 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
VL_RESTORER(m_loopInc);
|
||||
m_loopp = nodep;
|
||||
m_loopInc = false;
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
iterateAndNextNull(nodep->condp());
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
m_loopInc = true;
|
||||
|
@ -330,8 +373,8 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
nodep->lhsp()->unlinkFrBackWithNext()});
|
||||
}
|
||||
// Jump to the end of the function call
|
||||
AstJumpLabel* const labelp = findAddLabel(m_ftaskp, false);
|
||||
nodep->addHereThisAsNext(new AstJumpGo{nodep->fileline(), labelp});
|
||||
AstJumpBlock* const blockp = getJumpBlock(m_ftaskp, false);
|
||||
nodep->addHereThisAsNext(new AstJumpGo{nodep->fileline(), blockp});
|
||||
}
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
@ -342,8 +385,8 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
nodep->v3error("break isn't underneath a loop");
|
||||
} else {
|
||||
// Jump to the end of the loop
|
||||
AstJumpLabel* const labelp = findAddLabel(m_loopp, false);
|
||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
||||
AstJumpBlock* const blockp = getJumpBlock(m_loopp, false);
|
||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});
|
||||
}
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
@ -355,8 +398,8 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
} else {
|
||||
// Jump to the end of this iteration
|
||||
// If a "for" loop then need to still do the post-loop increment
|
||||
AstJumpLabel* const labelp = findAddLabel(m_loopp, true);
|
||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
||||
AstJumpBlock* const blockp = getJumpBlock(m_loopp, true);
|
||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});
|
||||
}
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
@ -369,35 +412,9 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
if (VN_IS(targetp, Task)) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling task by name");
|
||||
} else if (AstFork* const forkp = VN_CAST(targetp, Fork)) {
|
||||
// The support is limited only to disabling a fork from outside that fork.
|
||||
// It utilizes the process::kill()` method. For each `disable` a queue of processes is
|
||||
// declared. At the beginning of each fork that can be disabled, its process handle is
|
||||
// pushed to the queue. `disable` statement is replaced with calling `kill()` method on
|
||||
// each element of the queue.
|
||||
if (existsBlockAbove(forkp->name())) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from within same fork");
|
||||
}
|
||||
if (m_ftaskp) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork from task / function");
|
||||
}
|
||||
AstPackage* const topPkgp = v3Global.rootp()->dollarUnitPkgAddp();
|
||||
AstClass* const processClassp
|
||||
= VN_AS(getMemberp(v3Global.rootp()->stdPackagep(), "process"), Class);
|
||||
// Declare queue of processes (as a global variable for simplicity)
|
||||
AstVar* const processQueuep = new AstVar{
|
||||
fl, VVarType::VAR, m_queueNames.get(forkp->name()), VFlagChildDType{},
|
||||
new AstQueueDType{fl, VFlagChildDType{},
|
||||
new AstClassRefDType{fl, processClassp, nullptr}, nullptr}};
|
||||
processQueuep->lifetime(VLifetime::STATIC);
|
||||
topPkgp->addStmtsp(processQueuep);
|
||||
|
||||
AstVarRef* const queueWriteRefp
|
||||
= new AstVarRef{fl, topPkgp, processQueuep, VAccess::WRITE};
|
||||
AstStmtExpr* const pushCurrentProcessp = getQueuePushProcessSelfp(queueWriteRefp);
|
||||
|
||||
std::vector<AstBegin*> forks;
|
||||
for (AstNode* forkItemp = forkp->stmtsp(); forkItemp; forkItemp = forkItemp->nextp()) {
|
||||
// Add push_back statement at the beginning of each fork.
|
||||
// Wrap into begin block if needed
|
||||
// Further handling of disable stmt requires all forks to be begin blocks
|
||||
AstBegin* beginp = VN_CAST(forkItemp, Begin);
|
||||
if (!beginp) {
|
||||
beginp = new AstBegin{fl, "", nullptr};
|
||||
|
@ -406,34 +423,28 @@ class LinkJumpVisitor final : public VNVisitor {
|
|||
// In order to continue the iteration
|
||||
forkItemp = beginp;
|
||||
}
|
||||
if (pushCurrentProcessp->backp()) {
|
||||
beginp->stmtsp()->addHereThisAsNext(pushCurrentProcessp->cloneTree(false));
|
||||
} else {
|
||||
beginp->stmtsp()->addHereThisAsNext(pushCurrentProcessp);
|
||||
}
|
||||
forks.push_back(beginp);
|
||||
}
|
||||
|
||||
AstVarRef* const queueRefp
|
||||
= new AstVarRef{fl, topPkgp, processQueuep, VAccess::READWRITE};
|
||||
AstTaskRef* const killQueueCall
|
||||
= new AstTaskRef{fl, VN_AS(getMemberp(processClassp, "killQueue"), Task),
|
||||
new AstArg{fl, "", queueRefp}};
|
||||
killQueueCall->classOrPackagep(processClassp);
|
||||
nodep->addNextHere(new AstStmtExpr{fl, killQueueCall});
|
||||
handleDisableOnFork(nodep, forks);
|
||||
} else if (AstBegin* const beginp = VN_CAST(targetp, Begin)) {
|
||||
const std::string targetName = beginp->name();
|
||||
if (existsBlockAbove(targetName)) {
|
||||
if (beginp->user3()) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: disabling block that contains a fork");
|
||||
} else {
|
||||
// Jump to the end of the named block
|
||||
AstJumpLabel* const labelp = findAddLabel(beginp, false);
|
||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
|
||||
}
|
||||
if (directlyUnderFork(beginp)) {
|
||||
std::vector<AstBegin*> forks{beginp};
|
||||
handleDisableOnFork(nodep, forks);
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '"
|
||||
<< targetName << "'");
|
||||
const std::string targetName = beginp->name();
|
||||
if (existsBlockAbove(targetName)) {
|
||||
if (beginp->user3()) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: disabling block that contains a fork");
|
||||
} else {
|
||||
// Jump to the end of the named block
|
||||
AstJumpBlock* const blockp = getJumpBlock(beginp, false);
|
||||
nodep->addNextHere(new AstJumpGo{nodep->fileline(), blockp});
|
||||
}
|
||||
} else {
|
||||
nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '"
|
||||
<< targetName << "'");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Disable linked with node of unhandled type "
|
||||
|
|
|
@ -578,7 +578,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
} else if (VN_IS(bracketp, SelLoopVars)) {
|
||||
// Ok
|
||||
} else {
|
||||
nodep->v3error("Syntax error; foreach missing bracketed loop variable"
|
||||
nodep->v3error("Foreach missing bracketed loop variable is no-operation"
|
||||
" (IEEE 1800-2023 12.7.3)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
|
|
|
@ -1471,11 +1471,7 @@ V3Number& V3Number::opRepl(const V3Number& lhs,
|
|||
// i op repl, L(i)*value(rhs) bit return
|
||||
NUM_ASSERT_OP_ARGS1(lhs);
|
||||
NUM_ASSERT_LOGIC_ARGS1(lhs);
|
||||
if (rhsval > (1UL << 24)) {
|
||||
v3error("More than a 16 Mbit replication, perhaps the replication factor"
|
||||
" was two's-complement negative: "
|
||||
<< rhsval << " (" << static_cast<int32_t>(rhsval) << ")");
|
||||
} else if (rhsval > 8192) {
|
||||
if (rhsval > 8192) {
|
||||
v3warn(WIDTHCONCAT, "More than a 8k bit replication is probably wrong: " << rhsval);
|
||||
}
|
||||
setZero();
|
||||
|
@ -2242,6 +2238,13 @@ V3Number& V3Number::opBufIf1(const V3Number& ens, const V3Number& if1s) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
// Sets all bits in range to the given value
|
||||
V3Number& V3Number::opSetRange(uint32_t lsb, uint32_t width, char bitValue) {
|
||||
const uint32_t msb = lsb + width - 1;
|
||||
for (uint32_t i = lsb; i <= msb; ++i) setBit(i, bitValue);
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opAssign(const V3Number& lhs) { return opAssignNonXZ(lhs, false); }
|
||||
V3Number& V3Number::opAssignNonXZ(const V3Number& lhs, bool ignoreXZ) {
|
||||
// Note may be a width change during the assign.
|
||||
|
|
|
@ -564,7 +564,6 @@ private:
|
|||
}
|
||||
}
|
||||
static string displayPad(size_t fmtsize, char pad, bool left, const string& in) VL_PURE;
|
||||
string displayed(FileLine* fl, const string& vformat) const VL_MT_STABLE;
|
||||
string displayed(const string& vformat) const VL_MT_STABLE {
|
||||
return displayed(m_fileline, vformat);
|
||||
}
|
||||
|
@ -592,6 +591,7 @@ public:
|
|||
// ACCESSORS
|
||||
string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_STABLE;
|
||||
string displayed(AstNode* nodep, const string& vformat) const VL_MT_STABLE;
|
||||
string displayed(FileLine* fl, const string& vformat) const VL_MT_STABLE;
|
||||
static bool displayedFmtLegal(char format, bool isScan); // Is this a valid format letter?
|
||||
int width() const VL_MT_SAFE { return m_data.width(); }
|
||||
int widthToFit() const; // Minimum width that can represent this number (~== log2(num)+1)
|
||||
|
@ -716,6 +716,7 @@ public:
|
|||
V3Number& opWildEq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildNeq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opBufIf1(const V3Number& ens, const V3Number& if1s);
|
||||
V3Number& opSetRange(uint32_t lsb, uint32_t width, char bitValue);
|
||||
// "standard" math
|
||||
V3Number& opNot(const V3Number& lhs);
|
||||
V3Number& opLogNot(const V3Number& lhs);
|
||||
|
|
|
@ -1803,8 +1803,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
DECL_OPTION("-Wwarn-UNSUPPORTED", CbCall, []() {
|
||||
FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, false);
|
||||
FileLine::globalWarnOff(V3ErrorCode::COVERIGN, false);
|
||||
FileLine::globalWarnOff(V3ErrorCode::SPECIFYIGN, false);
|
||||
V3Error::pretendError(V3ErrorCode::E_UNSUPPORTED, false);
|
||||
V3Error::pretendError(V3ErrorCode::COVERIGN, false);
|
||||
V3Error::pretendError(V3ErrorCode::SPECIFYIGN, false);
|
||||
});
|
||||
DECL_OPTION("-Wwarn-WIDTH", CbCall, []() {
|
||||
FileLine::globalWarnOff(V3ErrorCode::WIDTH, false);
|
||||
|
@ -2141,7 +2143,7 @@ void V3Options::setDebugMode(int level) {
|
|||
if (!m_dumpLevel.count("tree")) m_dumpLevel["tree"] = 3; // Don't override if already set.
|
||||
m_stats = true;
|
||||
m_debugCheck = true;
|
||||
cout << "Starting " << version() << "\n";
|
||||
if (level) cout << "Starting " << version() << "\n";
|
||||
}
|
||||
|
||||
unsigned V3Options::debugLevel(const string& tag) const VL_MT_SAFE {
|
||||
|
|
|
@ -332,7 +332,7 @@ private:
|
|||
// Cost of critical paths going FORWARD from graph-start to the start
|
||||
// of this vertex, and also going REVERSE from the end of the graph to
|
||||
// the end of the vertex. Same units as m_cost.
|
||||
std::array<uint64_t, GraphWay::NUM_WAYS> m_critPathCost;
|
||||
std::array<uint64_t, GraphWay::NUM_WAYS> m_critPathCost = {};
|
||||
|
||||
const uint32_t m_id; // Unique LogicMTask ID number
|
||||
static uint32_t s_nextId; // Next ID number to use
|
||||
|
@ -361,7 +361,6 @@ public:
|
|||
: V3GraphVertex{graphp}
|
||||
, m_id{s_nextId++} {
|
||||
UASSERT(s_nextId < 0xFFFFFFFFUL, "Too many mTaskGraphp");
|
||||
for (uint64_t& item : m_critPathCost) item = 0;
|
||||
if (mVtxp) {
|
||||
m_mVertices.linkBack(mVtxp);
|
||||
if (const OrderLogicVertex* const olvp = mVtxp->logicp()) {
|
||||
|
|
13
src/V3Os.cpp
13
src/V3Os.cpp
|
@ -54,6 +54,10 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_TCMALLOC
|
||||
#include <gperftools/malloc_extension.h>
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <windows.h> // LONG for bcrypt.h on MINGW
|
||||
|
@ -402,6 +406,15 @@ void V3Os::unlinkRegexp(const string& dir, const string& regexp) {
|
|||
#endif
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// METHODS (memory)
|
||||
|
||||
void V3Os::releaseMemory() {
|
||||
#ifdef HAVE_TCMALLOC
|
||||
MallocExtension::instance()->ReleaseFreeMemory();
|
||||
#endif
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// METHODS (random)
|
||||
|
||||
|
|
|
@ -71,6 +71,9 @@ public:
|
|||
static void filesystemFlushBuildDir(const string& dirname);
|
||||
static void unlinkRegexp(const string& dir, const string& regexp);
|
||||
|
||||
// METHODS (memory)
|
||||
static void releaseMemory();
|
||||
|
||||
// METHODS (random)
|
||||
static uint64_t rand64(std::array<uint64_t, 2>& stater);
|
||||
static string trueRandom(size_t size) VL_MT_SAFE;
|
||||
|
|
|
@ -1116,7 +1116,7 @@ class ParamVisitor final : public VNVisitor {
|
|||
} else {
|
||||
cellp->v3fatalSrc("Expected module parameterization");
|
||||
}
|
||||
UASSERT_OBJ(srcModp, cellp, "Unlinked class ref");
|
||||
if (!srcModp) continue;
|
||||
|
||||
// Update path
|
||||
string someInstanceName = modp->someInstanceName();
|
||||
|
|
|
@ -46,6 +46,7 @@ class PremitVisitor final : public VNVisitor {
|
|||
|
||||
// STATE - across all visitors
|
||||
VDouble0 m_extractedToConstPool; // Statistic tracking
|
||||
VDouble0 m_temporaryVarsCreated; // Statistic tracking
|
||||
|
||||
// STATE - for current visit position (use VL_RESTORER)
|
||||
AstCFunc* m_cfuncp = nullptr; // Current block
|
||||
|
@ -62,12 +63,12 @@ class PremitVisitor final : public VNVisitor {
|
|||
if (!nodep->isWide()) return; // Not wide
|
||||
if (m_assignLhs) return; // This is an lvalue!
|
||||
UASSERT_OBJ(!VN_IS(nodep->firstAbovep(), ArraySel), nodep, "Should have been ignored");
|
||||
createWideTemp(nodep);
|
||||
createTemp(nodep);
|
||||
}
|
||||
|
||||
AstVar* createWideTemp(AstNodeExpr* nodep) {
|
||||
AstVar* createTemp(AstNodeExpr* nodep) {
|
||||
UASSERT_OBJ(m_stmtp, nodep, "Attempting to create temporary with no insertion point");
|
||||
UINFO(4, "createWideTemp: " << nodep);
|
||||
UINFO(4, "createTemp: " << nodep);
|
||||
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
|
@ -80,7 +81,6 @@ class PremitVisitor final : public VNVisitor {
|
|||
&& !constp->num().isString(); // Not a string
|
||||
|
||||
AstVar* varp = nullptr;
|
||||
AstAssign* assignp = nullptr;
|
||||
|
||||
if (useConstPool) {
|
||||
// Extract into constant pool.
|
||||
|
@ -93,25 +93,22 @@ class PremitVisitor final : public VNVisitor {
|
|||
const std::string name = "__Vtemp_" + std::to_string(++m_tmpVarCnt);
|
||||
varp = new AstVar{flp, VVarType::STMTTEMP, name, nodep->dtypep()};
|
||||
m_cfuncp->addInitsp(varp);
|
||||
++m_temporaryVarsCreated;
|
||||
|
||||
// Put assignment before the referencing statement
|
||||
assignp = new AstAssign{flp, new AstVarRef{flp, varp, VAccess::WRITE}, nodep};
|
||||
if (m_inWhileCondp) {
|
||||
// Statements that are needed for the 'condition' in a while
|
||||
// actually have to be put before & after the loop, since we
|
||||
// can't do any statements in a while's (cond).
|
||||
m_inWhileCondp->addPrecondsp(assignp);
|
||||
} else {
|
||||
m_stmtp->addHereThisAsNext(assignp);
|
||||
}
|
||||
// Assignment to put before the referencing statement
|
||||
AstAssign* const assignp
|
||||
= new AstAssign{flp, new AstVarRef{flp, varp, VAccess::WRITE}, nodep};
|
||||
// Insert before the statement
|
||||
m_stmtp->addHereThisAsNext(assignp);
|
||||
// Statements that are needed for the 'condition' in a while also
|
||||
// need to be inserted on the back-edge to the loop header.
|
||||
// 'incsp' is just right palce to do this
|
||||
if (m_inWhileCondp) m_inWhileCondp->addIncsp(assignp->cloneTree(false));
|
||||
}
|
||||
|
||||
// Replace node with VarRef to new Var
|
||||
relinker.relink(new AstVarRef{flp, varp, VAccess::READ});
|
||||
|
||||
// Handle wide expressions inside the expression recursively
|
||||
if (assignp) iterate(assignp);
|
||||
|
||||
// Return the temporary variable
|
||||
return varp;
|
||||
}
|
||||
|
@ -184,7 +181,6 @@ class PremitVisitor final : public VNVisitor {
|
|||
UINFO(4, " WHILE " << nodep);
|
||||
// cppcheck-suppress shadowVariable // Also restored below
|
||||
START_STATEMENT_OR_RETURN(nodep);
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
{
|
||||
// cppcheck-suppress shadowVariable // Also restored above
|
||||
VL_RESTORER(m_inWhileCondp);
|
||||
|
@ -221,9 +217,10 @@ class PremitVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
if (rhsReadsLhs(nodep)) {
|
||||
// Need to do this even if not wide, as e.g. a select may be on a wide operator
|
||||
createWideTemp(nodep->rhsp());
|
||||
// If the RHS reads the LHS, we need a temporary unless the update is atomic
|
||||
const bool isAtomic = VN_IS(nodep->lhsp(), VarRef) && !nodep->lhsp()->isWide();
|
||||
if (!isAtomic && rhsReadsLhs(nodep)) {
|
||||
createTemp(nodep->rhsp());
|
||||
} else {
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
}
|
||||
|
@ -290,7 +287,7 @@ class PremitVisitor final : public VNVisitor {
|
|||
void visit(AstCvtPackedToArray* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
if (!VN_IS(nodep->backp(), NodeAssign)) createWideTemp(nodep);
|
||||
if (!VN_IS(nodep->backp(), NodeAssign)) createTemp(nodep);
|
||||
}
|
||||
void visit(AstCvtUnpackedToQueue* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
|
@ -330,7 +327,7 @@ class PremitVisitor final : public VNVisitor {
|
|||
&& !VN_IS(nodep->condp(), VarRef)) {
|
||||
// We're going to need the expression several times in the expanded code,
|
||||
// so might as well make it a common expression
|
||||
createWideTemp(nodep->condp());
|
||||
createTemp(nodep->condp());
|
||||
VIsCached::clearCacheTree();
|
||||
}
|
||||
checkNode(nodep);
|
||||
|
@ -342,7 +339,7 @@ class PremitVisitor final : public VNVisitor {
|
|||
for (AstNodeExpr *expp = nodep->exprsp(), *nextp; expp; expp = nextp) {
|
||||
nextp = VN_AS(expp->nextp(), NodeExpr);
|
||||
if (expp->isString() && !VN_IS(expp, VarRef)) {
|
||||
AstVar* const varp = createWideTemp(expp);
|
||||
AstVar* const varp = createTemp(expp);
|
||||
// Do not remove VarRefs to this in V3Const
|
||||
varp->noSubst(true);
|
||||
}
|
||||
|
@ -360,6 +357,8 @@ public:
|
|||
~PremitVisitor() override {
|
||||
V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool",
|
||||
m_extractedToConstPool);
|
||||
V3Stats::addStat("Optimizations, Prelim temporary variables created",
|
||||
m_temporaryVarsCreated);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ enum ClassRandom : uint8_t {
|
|||
NONE, // randomize() is not called
|
||||
IS_RANDOMIZED, // randomize() is called
|
||||
IS_RANDOMIZED_INLINE, // randomize() with args is called
|
||||
IS_STD_RANDOMIZED, // std::randomize() is called
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
|
@ -118,11 +119,13 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
|||
// NODE STATE
|
||||
// Cleared on Netlist
|
||||
// AstClass::user1() -> bool. Set true to indicate needs randomize processing
|
||||
// AstNodeModule::user1() -> bool. Set true to indicate needs std::randomize processing
|
||||
// AstNodeExpr::user1() -> bool. Set true to indicate constraint expression depending on a
|
||||
// randomized variable
|
||||
// AstVar::user1() -> bool. Set true to indicate needs rand_mode
|
||||
// AstVar::user2p() -> AstNodeModule*. Pointer to containing module
|
||||
// AstNodeFTask::user2p() -> AstNodeModule*. Pointer to containing module
|
||||
// AstMemberSel::user2p() -> AstNodeModule*. Pointer to containing module
|
||||
const VNUser1InUse m_inuser1;
|
||||
const VNUser2InUse m_inuser2;
|
||||
|
||||
|
@ -367,6 +370,33 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
|||
if (!classp->user1()) classp->user1(IS_RANDOMIZED);
|
||||
markMembers(classp);
|
||||
}
|
||||
if (nodep->classOrPackagep()->name() == "std") {
|
||||
for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) {
|
||||
AstArg* const argp = VN_CAST(pinp, Arg);
|
||||
if (!argp) continue;
|
||||
AstNodeExpr* exprp = argp->exprp();
|
||||
while (exprp) {
|
||||
AstVar* randVarp = nullptr;
|
||||
if (AstMemberSel* const memberSelp = VN_CAST(exprp, MemberSel)) {
|
||||
randVarp = memberSelp->varp();
|
||||
exprp = memberSelp->fromp();
|
||||
} else {
|
||||
AstVarRef* const varrefp = VN_AS(exprp, VarRef);
|
||||
randVarp = varrefp->varp();
|
||||
exprp = nullptr;
|
||||
}
|
||||
UASSERT_OBJ(randVarp, nodep, "No rand variable found");
|
||||
AstNode* backp = randVarp;
|
||||
while (backp && (!VN_IS(backp, Class) && !VN_IS(backp, NodeModule))) {
|
||||
backp = backp->backp();
|
||||
}
|
||||
UASSERT_OBJ(VN_IS(backp, NodeModule), randVarp,
|
||||
"No class or module found for rand variable");
|
||||
backp->user1(IS_STD_RANDOMIZED);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) {
|
||||
AstArg* const argp = VN_CAST(pinp, Arg);
|
||||
if (!argp) continue;
|
||||
|
@ -431,6 +461,7 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
|||
// of type AstLambdaArgRef. They are randomized too.
|
||||
const bool randObject = nodep->fromp()->user1() || VN_IS(nodep->fromp(), LambdaArgRef);
|
||||
nodep->user1(randObject && nodep->varp()->rand().isRandomizable());
|
||||
nodep->user2p(m_modp);
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
|
@ -472,7 +503,8 @@ public:
|
|||
class ConstraintExprVisitor final : public VNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::user3() -> bool. Handled in constraints
|
||||
// AstNodeExpr::user1() -> bool. Depending on a randomized variable
|
||||
// AstNodeExpr::user1() -> bool. Depending on a randomized variable
|
||||
// AstMemberSel::user2p() -> AstNodeModule*. Pointer to containing module
|
||||
// VNuser3InUse m_inuser3; (Allocated for use in RandomizeVisitor)
|
||||
|
||||
AstNodeFTask* const m_inlineInitTaskp; // Method to add write_var calls to
|
||||
|
@ -598,19 +630,25 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
|
||||
// VISITORS
|
||||
void visit(AstNodeVarRef* nodep) override {
|
||||
AstVar* const varp = nodep->varp();
|
||||
AstVar* varp = nodep->varp();
|
||||
if (varp->user4p()) {
|
||||
varp->user4p()->v3warn(
|
||||
CONSTRAINTIGN,
|
||||
"Size constraint combined with element constraint may not work correctly");
|
||||
}
|
||||
|
||||
AstMemberSel* membersel = VN_IS(nodep->backp(), MemberSel)
|
||||
? VN_AS(nodep->backp(), MemberSel)->cloneTree(false)
|
||||
: nullptr;
|
||||
if (membersel) varp = membersel->varp();
|
||||
AstNodeModule* const classOrPackagep = nodep->classOrPackagep();
|
||||
const RandomizeMode randMode = {.asInt = varp->user1()};
|
||||
if (!randMode.usesMode && editFormat(nodep)) return;
|
||||
|
||||
// In SMT just variable name, but we also ensure write_var for the variable
|
||||
const std::string smtName = nodep->name(); // Can be anything unique
|
||||
const std::string smtName = membersel
|
||||
? membersel->fromp()->name() + "." + membersel->name()
|
||||
: nodep->name(); // Can be anything unique
|
||||
|
||||
VNRelinker relinker;
|
||||
nodep->unlinkFrBack(&relinker);
|
||||
AstNodeExpr* exprp = new AstSFormatF{nodep->fileline(), smtName, false, nullptr};
|
||||
|
@ -648,11 +686,12 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
dimension = 1;
|
||||
}
|
||||
methodp->dtypeSetVoid();
|
||||
AstClass* const classp = VN_AS(varp->user2p(), Class);
|
||||
AstClass* const classp
|
||||
= membersel ? VN_AS(membersel->user2p(), Class) : VN_AS(varp->user2p(), Class);
|
||||
AstVarRef* const varRefp
|
||||
= new AstVarRef{varp->fileline(), classp, varp, VAccess::WRITE};
|
||||
varRefp->classOrPackagep(classOrPackagep);
|
||||
methodp->addPinsp(varRefp);
|
||||
membersel ? methodp->addPinsp(membersel) : methodp->addPinsp(varRefp);
|
||||
AstNodeDType* tmpDtypep = varp->dtypep();
|
||||
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|
||||
|| VN_IS(tmpDtypep, QueueDType) || VN_IS(tmpDtypep, AssocArrayDType))
|
||||
|
@ -838,6 +877,12 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
if (nodep->user1()) {
|
||||
nodep->v3warn(CONSTRAINTIGN, "Global constraints ignored (unsupported)");
|
||||
}
|
||||
if (VN_IS(nodep->fromp(), NodeVarRef) && nodep->varp()->isRand() && m_inlineInitTaskp) {
|
||||
iterateChildren(nodep);
|
||||
nodep->replaceWith(nodep->fromp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
editFormat(nodep);
|
||||
}
|
||||
void visit(AstSFormatF* nodep) override {}
|
||||
|
@ -1121,9 +1166,11 @@ class CaptureVisitor final : public VNVisitor {
|
|||
void captureRefByThis(AstNodeVarRef* nodep, CaptureMode capModeFlags) {
|
||||
AstVar* const thisp = importThisp(nodep->fileline());
|
||||
AstVarRef* const thisRefp = new AstVarRef{nodep->fileline(), thisp, nodep->access()};
|
||||
thisRefp->user1(true);
|
||||
m_ignore.emplace(thisRefp);
|
||||
AstMemberSel* const memberSelp
|
||||
= new AstMemberSel(nodep->fileline(), thisRefp, nodep->varp());
|
||||
memberSelp->user2p(m_targetp);
|
||||
nodep->replaceWith(memberSelp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
m_ignore.emplace(memberSelp);
|
||||
|
@ -1249,6 +1296,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
// AstConstraint::user3p() -> AstTask*. Pointer to resize procedure
|
||||
// AstClass::user4p() -> AstVar*. Constraint mode state variable
|
||||
// AstVar::user4p() -> AstVar*. Size variable for constrained queues
|
||||
// AstMemberSel::user2p() -> AstNodeModule*. Pointer to containing module
|
||||
// VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
|
||||
// VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor)
|
||||
const VNUser3InUse m_inuser3;
|
||||
|
@ -1258,8 +1306,10 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
V3UniqueNames m_inlineUniqueNames; // For generating unique function names
|
||||
V3UniqueNames m_modeUniqueNames{"__Vmode"}; // For generating unique rand/constraint
|
||||
// mode state var names
|
||||
V3UniqueNames m_inlineUniqueStdName{"__VStdrand"};
|
||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||
AstNodeModule* m_modp = nullptr; // Current module
|
||||
std::unordered_map<AstNodeModule*, AstVar*> m_stdMap; // Map from module/class to AST Var
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstNodeStmt* m_stmtp = nullptr; // Current statement
|
||||
AstDynArrayDType* m_dynarrayDtp = nullptr; // Dynamic array type (for rand mode)
|
||||
|
@ -1281,6 +1331,18 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
classp->addMembersp(genp);
|
||||
classp->user3p(genp);
|
||||
}
|
||||
AstVar* createStdRandomGenerator(AstNodeModule* const modp) {
|
||||
auto it = m_stdMap.find(modp);
|
||||
if (it == m_stdMap.end()) {
|
||||
AstVar* const stdgenp
|
||||
= new AstVar{modp->fileline(), VVarType::MEMBER, "stdrand",
|
||||
modp->findBasicDType(VBasicDTypeKwd::RANDOM_STDGENERATOR)};
|
||||
modp->addStmtsp(stdgenp);
|
||||
m_stdMap.emplace(modp, stdgenp);
|
||||
return stdgenp;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
AstVar* getRandomGenerator(AstClass* const classp) {
|
||||
if (classp->user3p()) return VN_AS(classp->user3p(), Var);
|
||||
if (classp->extendsp()) return getRandomGenerator(classp->extendsp()->classp());
|
||||
|
@ -2184,28 +2246,65 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
|
||||
if (nodep->name() != "randomize") return;
|
||||
|
||||
if (nodep->classOrPackagep() && nodep->classOrPackagep()->name() == "std") {
|
||||
AstVar* const stdrand = createStdRandomGenerator(m_modp);
|
||||
AstFunc* const randomizeFuncp = V3Randomize::newRandomizeStdFunc(
|
||||
m_memberMap, m_modp, m_inlineUniqueStdName.get(nodep));
|
||||
randomizeFuncp->addStmtsp(
|
||||
new AstAssign{nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
|
||||
VAccess::WRITE},
|
||||
new AstConst{nodep->fileline(), AstConst::WidthedValue{}, 32, 1}});
|
||||
for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) {
|
||||
AstArg* const argp = VN_CAST(pinp, Arg);
|
||||
if (!argp) continue;
|
||||
AstNodeExpr* exprp = argp->exprp();
|
||||
AstCMethodHard* const basicMethodp = new AstCMethodHard{
|
||||
nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), stdrand, VAccess::READWRITE},
|
||||
"basicStdRandomization"};
|
||||
const size_t width = exprp->width();
|
||||
basicMethodp->addPinsp(exprp->unlinkFrBack());
|
||||
basicMethodp->addPinsp(
|
||||
new AstConst{nodep->fileline(), AstConst::Unsized64{}, width});
|
||||
basicMethodp->dtypeSetBit();
|
||||
randomizeFuncp->addStmtsp(new AstAssign{
|
||||
nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
|
||||
VAccess::WRITE},
|
||||
new AstAnd{nodep->fileline(),
|
||||
new AstVarRef{nodep->fileline(),
|
||||
VN_AS(randomizeFuncp->fvarp(), Var), VAccess::READ},
|
||||
basicMethodp}});
|
||||
}
|
||||
// Replace the node with a call to that function
|
||||
nodep->name(randomizeFuncp->name());
|
||||
nodep->taskp(randomizeFuncp);
|
||||
nodep->dtypeFrom(randomizeFuncp->dtypep());
|
||||
if (VN_IS(m_modp, Class)) nodep->classOrPackagep(m_modp);
|
||||
if (nodep->pinsp()) pushDeletep(nodep->pinsp()->unlinkFrBackWithNext());
|
||||
return;
|
||||
}
|
||||
handleRandomizeArgs(nodep);
|
||||
|
||||
AstWith* const withp = VN_CAST(nodep->pinsp(), With);
|
||||
|
||||
if (!withp) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
withp->unlinkFrBack();
|
||||
|
||||
iterateChildren(nodep);
|
||||
|
||||
AstClass* classp = nullptr;
|
||||
if (AstMethodCall* const callp = VN_CAST(nodep, MethodCall)) {
|
||||
UASSERT_OBJ(callp->fromp()->dtypep(), callp->fromp(), "Object dtype is not linked");
|
||||
AstClassRefDType* const classrefdtypep
|
||||
= VN_CAST(callp->fromp()->dtypep(), ClassRefDType);
|
||||
if (!classrefdtypep) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Inline constraints are not supported for this node type");
|
||||
return;
|
||||
}
|
||||
const AstNodeDType* const fromDTypep = callp->fromp()->dtypep();
|
||||
UASSERT_OBJ(fromDTypep, callp->fromp(), "Object dtype is not linked");
|
||||
const AstClassRefDType* const classrefdtypep
|
||||
= VN_CAST(fromDTypep->skipRefp(), ClassRefDType);
|
||||
UASSERT_OBJ(classrefdtypep, callp->fromp(),
|
||||
"Randomize called on expression of non-class type "
|
||||
<< fromDTypep->skipRefp()->prettyDTypeNameQ()
|
||||
<< " (it should be detected earlier)");
|
||||
classp = classrefdtypep->classp();
|
||||
UASSERT_OBJ(classp, classrefdtypep, "Class type is unlinked to its ref type");
|
||||
} else {
|
||||
|
@ -2232,7 +2331,6 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
|
||||
// Detach the expression and prepare variable copies
|
||||
const CaptureVisitor captured{withp->exprp(), m_modp, classp};
|
||||
|
||||
// Add function arguments
|
||||
captured.addFunctionArguments(randomizeFuncp);
|
||||
|
||||
|
@ -2406,6 +2504,28 @@ AstFunc* V3Randomize::newRandomizeFunc(VMemberMap& memberMap, AstClass* nodep,
|
|||
return funcp;
|
||||
}
|
||||
|
||||
AstFunc* V3Randomize::newRandomizeStdFunc(VMemberMap& memberMap, AstNodeModule* nodep,
|
||||
const std::string& name) {
|
||||
AstFunc* funcp = nullptr;
|
||||
v3Global.useRandomizeMethods(true);
|
||||
AstNodeDType* const dtypep = nodep->findBitDType(32, 32, VSigning::SIGNED);
|
||||
AstVar* const fvarp = new AstVar{nodep->fileline(), VVarType::MEMBER, name, dtypep};
|
||||
fvarp->lifetime(VLifetime::AUTOMATIC);
|
||||
fvarp->funcLocal(true);
|
||||
fvarp->funcReturn(true);
|
||||
fvarp->direction(VDirection::OUTPUT);
|
||||
funcp = new AstFunc{nodep->fileline(), name, nullptr, fvarp};
|
||||
funcp->dtypep(dtypep);
|
||||
if (VN_IS(nodep, Class)) {
|
||||
funcp->classMethod(true);
|
||||
} else {
|
||||
funcp->classMethod(false);
|
||||
funcp->isStatic(true);
|
||||
}
|
||||
nodep->addStmtsp(funcp);
|
||||
return funcp;
|
||||
}
|
||||
|
||||
AstFunc* V3Randomize::newSRandomFunc(VMemberMap& memberMap, AstClass* nodep) {
|
||||
AstClass* const basep = nodep->baseMostClassp();
|
||||
AstFunc* funcp = VN_AS(memberMap.findMember(basep, "srandom"), Func);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
class AstClass;
|
||||
class AstFunc;
|
||||
class AstNetlist;
|
||||
class AstNodeModule;
|
||||
|
||||
class VMemberMap;
|
||||
|
||||
|
@ -34,6 +35,8 @@ public:
|
|||
const std::string& name = "randomize",
|
||||
bool allowVirtual = true,
|
||||
bool childDType = false) VL_MT_DISABLED;
|
||||
static AstFunc* newRandomizeStdFunc(VMemberMap& memberMap, AstNodeModule* nodep,
|
||||
const std::string& name) VL_MT_DISABLED;
|
||||
static AstFunc* newSRandomFunc(VMemberMap& memberMap, AstClass* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
|
|
|
@ -104,6 +104,17 @@ void invertAndMergeSenTreeMap(
|
|||
for (const auto& pair : senTreeMap) result.emplace(pair.second, pair.first);
|
||||
}
|
||||
|
||||
AstSenTree* findTriggeredIface(const AstVarScope* vscp,
|
||||
const VirtIfaceTriggers::IfaceSensMap& vifTrigged,
|
||||
const VirtIfaceTriggers::IfaceMemberSensMap& vifMemberTriggered) {
|
||||
const auto ifaceIt = vifTrigged.find(vscp->varp()->sensIfacep());
|
||||
if (ifaceIt != vifTrigged.end()) return ifaceIt->second;
|
||||
for (const auto& memberIt : vifMemberTriggered) {
|
||||
if (memberIt.first.m_ifacep == vscp->varp()->sensIfacep()) { return memberIt.second; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Code generation utility functions
|
||||
|
||||
|
@ -955,8 +966,10 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
AstSenTree* const dpiExportTriggered
|
||||
= dpiExportTriggerVscp ? createTriggerSenTree(netlistp, trig.m_vscp, dpiExportTriggerIndex)
|
||||
: nullptr;
|
||||
const auto& vifTriggered
|
||||
const auto& vifTriggeredIco
|
||||
= virtIfaceTriggers.makeIfaceToSensMap(netlistp, firstVifTriggerIndex, trig.m_vscp);
|
||||
const auto& vifMemberTriggeredIco
|
||||
= virtIfaceTriggers.makeMemberToSensMap(netlistp, firstVifTriggerIndex, trig.m_vscp);
|
||||
|
||||
// Create and Order the body function
|
||||
AstCFunc* const icoFuncp
|
||||
|
@ -968,8 +981,9 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||
}
|
||||
if (varp->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
||||
if (vscp->varp()->sensIfacep()) {
|
||||
const auto it = vifTriggered.find(vscp->varp()->sensIfacep());
|
||||
if (it != vifTriggered.end()) out.push_back(it->second);
|
||||
AstSenTree* ifaceTriggered = findTriggeredIface(
|
||||
vscp, vifTriggeredIco, vifMemberTriggeredIco);
|
||||
out.push_back(ifaceTriggered);
|
||||
}
|
||||
});
|
||||
splitCheck(icoFuncp);
|
||||
|
@ -1371,6 +1385,8 @@ void schedule(AstNetlist* netlistp) {
|
|||
|
||||
const auto& vifTriggeredAct
|
||||
= virtIfaceTriggers.makeIfaceToSensMap(netlistp, firstVifTriggerIndex, actTrig.m_vscp);
|
||||
const auto& vifMemberTriggeredAct
|
||||
= virtIfaceTriggers.makeMemberToSensMap(netlistp, firstVifTriggerIndex, actTrig.m_vscp);
|
||||
|
||||
AstCFunc* const actFuncp = V3Order::order(
|
||||
netlistp, {&logicRegions.m_pre, &logicRegions.m_act, &logicReplicas.m_act}, trigToSenAct,
|
||||
|
@ -1379,8 +1395,9 @@ void schedule(AstNetlist* netlistp) {
|
|||
if (it != actTimingDomains.end()) out = it->second;
|
||||
if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredAct);
|
||||
if (vscp->varp()->sensIfacep()) {
|
||||
const auto sit = vifTriggeredAct.find(vscp->varp()->sensIfacep());
|
||||
if (sit != vifTriggeredAct.end()) out.push_back(sit->second);
|
||||
AstSenTree* ifaceTriggered
|
||||
= findTriggeredIface(vscp, vifTriggeredAct, vifMemberTriggeredAct);
|
||||
out.push_back(ifaceTriggered);
|
||||
}
|
||||
});
|
||||
splitCheck(actFuncp);
|
||||
|
@ -1408,6 +1425,8 @@ void schedule(AstNetlist* netlistp) {
|
|||
: nullptr;
|
||||
const auto& vifTriggered
|
||||
= virtIfaceTriggers.makeIfaceToSensMap(netlistp, firstVifTriggerIndex, trigVscp);
|
||||
const auto& vifMemberTriggered
|
||||
= virtIfaceTriggers.makeMemberToSensMap(netlistp, firstVifTriggerIndex, trigVscp);
|
||||
|
||||
const auto& timingDomains = timingKit.remapDomains(trigMap);
|
||||
AstCFunc* const funcp = V3Order::order(
|
||||
|
@ -1417,8 +1436,9 @@ void schedule(AstNetlist* netlistp) {
|
|||
if (it != timingDomains.end()) out = it->second;
|
||||
if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggered);
|
||||
if (vscp->varp()->sensIfacep()) {
|
||||
const auto sit = vifTriggered.find(vscp->varp()->sensIfacep());
|
||||
if (sit != vifTriggered.end()) out.push_back(sit->second);
|
||||
AstSenTree* ifaceTriggered
|
||||
= findTriggeredIface(vscp, vifTriggered, vifMemberTriggered);
|
||||
out.push_back(ifaceTriggered);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -168,6 +168,7 @@ class VirtIfaceTriggers final {
|
|||
}
|
||||
};
|
||||
|
||||
public:
|
||||
using IfaceMemberTrigger = std::pair<IfaceMember, AstVarScope*>;
|
||||
using IfaceMemberTriggerVec = std::vector<IfaceMemberTrigger>;
|
||||
using IfaceMemberSensMap = std::map<IfaceMember, AstSenTree*>;
|
||||
|
@ -179,7 +180,6 @@ class VirtIfaceTriggers final {
|
|||
IfaceMemberTriggerVec m_memberTriggers;
|
||||
IfaceTriggerVec m_ifaceTriggers;
|
||||
|
||||
public:
|
||||
void addMemberTrigger(const AstIface* ifacep, const AstVar* memberVarp,
|
||||
AstVarScope* triggerVscp) {
|
||||
m_memberTriggers.emplace_back(IfaceMember(ifacep, memberVarp), triggerVscp);
|
||||
|
|
|
@ -201,7 +201,6 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
unsupportedWriteToVirtIface(nodep->precondsp(), "loop condition");
|
||||
unsupportedWriteToVirtIface(nodep->condp(), "loop condition");
|
||||
unsupportedWriteToVirtIface(nodep->incsp(), "loop increment statement");
|
||||
{
|
||||
|
|
|
@ -397,10 +397,9 @@ private:
|
|||
UASSERT_OBJ(vscp, nodep, "Not linked");
|
||||
return vscp;
|
||||
}
|
||||
bool jumpingOver(const AstNode* nodep) const {
|
||||
// True to jump over this node - all visitors must call this up front
|
||||
return (m_jumpp && m_jumpp->labelp() != nodep);
|
||||
}
|
||||
|
||||
// True if current node might be jumped over - all visitors must call this up front
|
||||
bool jumpingOver() const { return m_jumpp; }
|
||||
void assignOutValue(AstNodeAssign* nodep, AstNode* vscp, const AstNodeExpr* valuep) {
|
||||
if (VN_IS(nodep, AssignDly)) {
|
||||
// Don't do setValue, as value isn't yet visible to following statements
|
||||
|
@ -413,7 +412,7 @@ private:
|
|||
|
||||
// VISITORS
|
||||
void visit(AstAlways* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
@ -421,7 +420,7 @@ private:
|
|||
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
|
||||
}
|
||||
void visit(AstVarRef* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
UASSERT_OBJ(nodep->varp(), nodep, "Unlinked");
|
||||
iterateChildrenConst(nodep->varp());
|
||||
|
@ -490,7 +489,7 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstVarXRef* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (m_scoped) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
|
@ -500,7 +499,7 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstNodeFTask* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
|
@ -520,7 +519,7 @@ private:
|
|||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstInitialStatic* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
|
@ -529,7 +528,7 @@ private:
|
|||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeIf* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
UINFO(5, " IF " << nodep);
|
||||
checkNodeInfo(nodep);
|
||||
if (m_checkOnly) {
|
||||
|
@ -856,7 +855,7 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstNodeAssign* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
checkNodeInfo(nodep);
|
||||
|
||||
|
@ -900,7 +899,7 @@ private:
|
|||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstNodeCase* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
UINFO(5, " CASE " << nodep);
|
||||
checkNodeInfo(nodep);
|
||||
if (m_checkOnly) {
|
||||
|
@ -939,7 +938,7 @@ private:
|
|||
|
||||
void visit(AstCaseItem* nodep) override {
|
||||
// Real handling is in AstNodeCase
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
@ -947,12 +946,12 @@ private:
|
|||
void visit(AstComment*) override {}
|
||||
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstExprStmt* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
checkNodeInfo(nodep);
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
if (!optimizable()) return;
|
||||
|
@ -962,30 +961,24 @@ private:
|
|||
}
|
||||
|
||||
void visit(AstJumpBlock* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_jumpp && m_jumpp->blockp() == nodep) {
|
||||
UINFO(5, " JUMP DONE " << nodep);
|
||||
m_jumpp = nullptr;
|
||||
}
|
||||
}
|
||||
void visit(AstJumpGo* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_checkOnly) {
|
||||
UINFO(5, " JUMP GO " << nodep);
|
||||
m_jumpp = nodep;
|
||||
}
|
||||
}
|
||||
void visit(AstJumpLabel* nodep) override {
|
||||
// This only supports forward jumps. That's all we make at present,
|
||||
// AstJumpGo::broken uses brokeExistsBelow() to check this.
|
||||
if (jumpingOver(nodep)) return;
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
if (m_jumpp && m_jumpp->labelp() == nodep) {
|
||||
UINFO(5, " JUMP DONE " << nodep);
|
||||
m_jumpp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstStop* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (m_params) { // This message seems better than an obscure $stop
|
||||
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
||||
clearOptimizable(
|
||||
|
@ -1030,7 +1023,7 @@ private:
|
|||
|
||||
void visit(AstWhile* nodep) override {
|
||||
// Doing lots of Whiles is slow, so only for parameters
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
UINFO(5, " WHILE " << nodep);
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
|
@ -1043,18 +1036,16 @@ private:
|
|||
int loops = 0;
|
||||
while (true) {
|
||||
UINFO(5, " WHILE-ITER " << nodep);
|
||||
iterateAndNextConstNull(nodep->precondsp());
|
||||
if (jumpingOver(nodep)) break;
|
||||
iterateAndNextConstNull(nodep->condp());
|
||||
if (jumpingOver(nodep)) break;
|
||||
if (jumpingOver()) break;
|
||||
if (!optimizable()) break;
|
||||
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
|
||||
break;
|
||||
}
|
||||
iterateAndNextConstNull(nodep->stmtsp());
|
||||
if (jumpingOver(nodep)) break;
|
||||
if (jumpingOver()) break;
|
||||
iterateAndNextConstNull(nodep->incsp());
|
||||
if (jumpingOver(nodep)) break;
|
||||
if (jumpingOver()) break;
|
||||
|
||||
// Prep for next loop
|
||||
if (loops++
|
||||
|
@ -1070,7 +1061,7 @@ private:
|
|||
}
|
||||
|
||||
void visit(AstFuncRef* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
UINFO(5, " FUNCREF " << nodep);
|
||||
checkNodeInfo(nodep);
|
||||
|
@ -1142,7 +1133,7 @@ private:
|
|||
}
|
||||
|
||||
void visit(AstVar* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
|
@ -1150,12 +1141,12 @@ private:
|
|||
}
|
||||
|
||||
void visit(AstScopeName* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
// Ignore
|
||||
}
|
||||
|
||||
void visit(AstSFormatF* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
checkNodeInfo(nodep);
|
||||
iterateChildrenConst(nodep);
|
||||
|
@ -1216,7 +1207,7 @@ private:
|
|||
}
|
||||
|
||||
void visit(AstDisplay* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
// We ignore isPredictOptimizable as $display is often in constant
|
||||
// functions and we want them to work if used with parameters
|
||||
|
@ -1244,11 +1235,11 @@ private:
|
|||
// Some CMethods such as size() on queues could be supported, but
|
||||
// instead we should change those methods to new Ast types so we can
|
||||
// properly dispatch them
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
knownBadNodeType(nodep);
|
||||
}
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
knownBadNodeType(nodep);
|
||||
}
|
||||
// ====
|
||||
|
@ -1257,7 +1248,7 @@ private:
|
|||
// AstCoverInc, AstFinish,
|
||||
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
||||
void visit(AstNode* nodep) override {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (jumpingOver()) return;
|
||||
badNodeType(nodep);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,11 +34,11 @@ V3Mutex V3Stats::s_mutex;
|
|||
class StatsVisitor final : public VNVisitorConst {
|
||||
struct Counters final {
|
||||
// Nodes of given type
|
||||
uint64_t m_statTypeCount[VNType::_ENUM_END];
|
||||
std::array<uint64_t, VNType::_ENUM_END> m_statTypeCount = {};
|
||||
// Nodes of given type with given type immediate child
|
||||
uint64_t m_statAbove[VNType::_ENUM_END][VNType::_ENUM_END];
|
||||
std::array<std::array<uint64_t, VNType::_ENUM_END>, VNType::_ENUM_END> m_statAbove = {};
|
||||
// Prediction of given type
|
||||
uint64_t m_statPred[VBranchPred::_ENUM_END];
|
||||
std::array<uint64_t, VBranchPred::_ENUM_END> m_statPred = {};
|
||||
};
|
||||
|
||||
// STATE
|
||||
|
@ -103,9 +103,6 @@ public:
|
|||
: m_fastOnly{fastOnly}
|
||||
, m_accump{fastOnly ? &m_dumpster : &m_counters} {
|
||||
UINFO(9, "Starting stats, fastOnly=" << fastOnly);
|
||||
memset(&m_counters, 0, sizeof(m_counters));
|
||||
memset(&m_dumpster, 0, sizeof(m_dumpster));
|
||||
|
||||
iterateConst(nodep);
|
||||
|
||||
// Shorthand
|
||||
|
@ -179,7 +176,4 @@ void V3Stats::statsStageAll(AstNetlist* nodep, const std::string& stage, bool fa
|
|||
StatsVisitor{nodep, stage, fastOnly};
|
||||
}
|
||||
|
||||
void V3Stats::statsFinalAll(AstNetlist* nodep) {
|
||||
statsStageAll(nodep, "Final all");
|
||||
statsStageAll(nodep, "Final fast", true);
|
||||
}
|
||||
void V3Stats::statsFinalAll(AstNetlist* nodep) { statsStageAll(nodep, "Final"); }
|
||||
|
|
|
@ -215,8 +215,10 @@ void V3Stats::statsStage(const string& name) {
|
|||
V3Stats::addStatPerf("Stage, Elapsed time (sec), " + digitName, wallTimeDelta);
|
||||
V3Stats::addStatPerf("Stage, Elapsed time (sec), TOTAL", wallTimeDelta);
|
||||
|
||||
const double memory = VlOs::memUsageBytes() / 1024.0 / 1024.0;
|
||||
V3Stats::addStatPerf("Stage, Memory (MB), " + digitName, memory);
|
||||
uint64_t memPeak, memCurrent;
|
||||
VlOs::memUsageBytes(memPeak /*ref*/, memCurrent /*ref*/);
|
||||
V3Stats::addStatPerf("Stage, Memory current (MB), " + digitName, memCurrent / 1024.0 / 1024.0);
|
||||
V3Stats::addStatPerf("Stage, Memory peak (MB), " + digitName, memPeak / 1024.0 / 1024.0);
|
||||
}
|
||||
|
||||
void V3Stats::infoHeader(std::ofstream& os, const string& prefix) {
|
||||
|
@ -266,7 +268,9 @@ void V3Stats::summaryReport() {
|
|||
<< ", cvt=" << walltimeCvt << ", bld=" << walltimeBuild << "); cpu " << cputime
|
||||
<< " s on " << std::max(v3Global.opt.verilateJobs(), v3Global.opt.buildJobs())
|
||||
<< " threads";
|
||||
const double memory = VlOs::memUsageBytes() / 1024.0 / 1024.0;
|
||||
uint64_t memPeak, memCurrent;
|
||||
VlOs::memUsageBytes(memPeak /*ref*/, memCurrent /*ref*/);
|
||||
const double memory = memPeak / 1024.0 / 1024.0;
|
||||
if (VL_UNCOVERABLE(memory != 0.0)) std::cout << "; alloced " << memory << " MB";
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
|
|
@ -1588,11 +1588,8 @@ class TaskVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
// Special, as statements need to be put in different places
|
||||
// Preconditions insert first just before themselves (the normal
|
||||
// rule for other statement types)
|
||||
m_insStmtp = nullptr; // First thing should be new statement
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
// Conditions insert first at end of precondsp.
|
||||
// TODO: is this right? This is how it used to be.
|
||||
m_insStmtp = nodep;
|
||||
iterateAndNextNull(nodep->condp());
|
||||
// Body insert just before themselves
|
||||
|
|
|
@ -266,7 +266,7 @@ class TimingSuspendableVisitor final : public VNVisitor {
|
|||
getNeedsProcDepVtx(nodep);
|
||||
addFlags(nodep, T_ALLOCS_PROC);
|
||||
if (VN_IS(nodep, Always)) {
|
||||
UINFO(1, "Always does " << (nodep->needProcess() ? "" : "NOT ") << "need process");
|
||||
UINFO(9, "Always does " << (nodep->needProcess() ? "" : "NOT ") << "need process");
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
|
@ -293,7 +293,7 @@ class UndrivenVisitor final : public VNVisitorConst {
|
|||
const VNUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
std::array<std::vector<UndrivenVarEntry*>, 3> m_entryps; // Nodes to delete when finished
|
||||
std::array<std::vector<UndrivenVarEntry*>, 3> m_entryps = {}; // Nodes to delete when finished
|
||||
bool m_inBBox = false; // In black box; mark as driven+used
|
||||
bool m_inContAssign = false; // In continuous assignment
|
||||
bool m_inInitialStatic = false; // In InitialStatic
|
||||
|
|
|
@ -46,6 +46,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
bool m_varModeCheck; // Just checking RHS assignments
|
||||
bool m_varModeReplace; // Replacing varrefs
|
||||
bool m_varAssignHit; // Assign var hit
|
||||
bool m_forkHit; // Fork hit
|
||||
bool m_generate; // Expand single generate For loop
|
||||
string m_beginName; // What name to give begin iterations
|
||||
VDouble0 m_statLoops; // Statistic tracking
|
||||
|
@ -81,13 +82,12 @@ class UnrollVisitor final : public VNVisitor {
|
|||
AstNode* const nodep,
|
||||
const VOptionBool& unrollFull, // Pragma unroll_full, unroll_disable
|
||||
AstNode* const initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
||||
AstNode* const precondsp, AstNode* condp,
|
||||
AstNode* condp,
|
||||
AstNode* const incp, // Maybe under nodep or in bodysp
|
||||
AstNode* bodysp) {
|
||||
// To keep the IF levels low, we return as each test fails.
|
||||
UINFO(4, " FOR Check " << nodep);
|
||||
if (initp) UINFO(6, " Init " << initp);
|
||||
if (precondsp) UINFO(6, " Pcon " << precondsp);
|
||||
if (condp) UINFO(6, " Cond " << condp);
|
||||
if (incp) UINFO(6, " Inc " << incp);
|
||||
|
||||
|
@ -133,14 +133,16 @@ class UnrollVisitor final : public VNVisitor {
|
|||
// Now, make sure there's no assignment to this variable in the loop
|
||||
m_varModeCheck = true;
|
||||
m_varAssignHit = false;
|
||||
m_forkHit = false;
|
||||
m_ignoreIncp = incp;
|
||||
iterateAndNextNull(precondsp);
|
||||
iterateAndNextNull(bodysp);
|
||||
iterateAndNextNull(incp);
|
||||
m_varModeCheck = false;
|
||||
m_ignoreIncp = nullptr;
|
||||
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
||||
|
||||
if (m_forkHit) return cantUnroll(nodep, "fork inside loop");
|
||||
|
||||
//
|
||||
if (m_forVscp) {
|
||||
UINFO(8, " Loop Variable: " << m_forVscp);
|
||||
|
@ -168,15 +170,14 @@ class UnrollVisitor final : public VNVisitor {
|
|||
int bodySize = 0;
|
||||
int bodyLimit = v3Global.opt.unrollStmts();
|
||||
if (loops > 0) bodyLimit = v3Global.opt.unrollStmts() / loops;
|
||||
if (bodySizeOverRecurse(precondsp, bodySize /*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(bodysp, bodySize /*ref*/, bodyLimit)
|
||||
if (bodySizeOverRecurse(bodysp, bodySize /*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(incp, bodySize /*ref*/, bodyLimit)) {
|
||||
return cantUnroll(nodep, "too many statements");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Finally, we can do it
|
||||
if (!forUnroller(nodep, unrollFull, initAssp, condp, precondsp, incp, bodysp)) {
|
||||
if (!forUnroller(nodep, unrollFull, initAssp, condp, incp, bodysp)) {
|
||||
return cantUnroll(nodep, "Unable to unroll loop");
|
||||
}
|
||||
VL_DANGLING(nodep);
|
||||
|
@ -264,7 +265,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
bool forUnroller(AstNode* nodep, const VOptionBool& unrollFull, AstAssign* initp,
|
||||
AstNode* condp, AstNode* precondsp, AstNode* incp, AstNode* bodysp) {
|
||||
AstNode* condp, AstNode* incp, AstNode* bodysp) {
|
||||
UINFO(9, "forUnroller " << nodep);
|
||||
V3Number loopValue{nodep};
|
||||
if (!simulateTree(initp->rhsp(), nullptr, initp, loopValue)) { //
|
||||
|
@ -276,10 +277,6 @@ class UnrollVisitor final : public VNVisitor {
|
|||
// Don't add to list, we do it once, and setting loop index isn't
|
||||
// needed if we have > 1 loop, as we're constant propagating it
|
||||
}
|
||||
if (precondsp) {
|
||||
precondsp->unlinkFrBackWithNext();
|
||||
stmtsp = AstNode::addNext(stmtsp, precondsp);
|
||||
}
|
||||
if (bodysp) {
|
||||
bodysp->unlinkFrBackWithNext();
|
||||
stmtsp = AstNode::addNext(stmtsp, bodysp); // Maybe null if no body
|
||||
|
@ -370,7 +367,6 @@ class UnrollVisitor final : public VNVisitor {
|
|||
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 (debug() >= 9 && newbodysp) newbodysp->dumpTree("- _new: ");
|
||||
|
@ -382,9 +378,6 @@ class UnrollVisitor final : public VNVisitor {
|
|||
if (m_varModeCheck || m_varModeReplace) {
|
||||
} else {
|
||||
// Constify before unroll call, as it may change what is underneath.
|
||||
if (nodep->precondsp()) {
|
||||
V3Const::constifyEdit(nodep->precondsp()); // precondsp may change
|
||||
}
|
||||
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
|
||||
// Grab initial value
|
||||
AstNode* initp = nullptr; // Should be statement before the while.
|
||||
|
@ -407,8 +400,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||
if (incp == stmtsp) stmtsp = nullptr;
|
||||
}
|
||||
// And check it
|
||||
if (forUnrollCheck(nodep, nodep->unrollFull(), initp, nodep->precondsp(),
|
||||
nodep->condp(), incp, stmtsp)) {
|
||||
if (forUnrollCheck(nodep, nodep->unrollFull(), initp, nodep->condp(), incp, stmtsp)) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
|
||||
}
|
||||
}
|
||||
|
@ -432,8 +424,8 @@ class UnrollVisitor final : public VNVisitor {
|
|||
// condition, but they'll become while's which can be
|
||||
// deleted by V3Const.
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
} else if (forUnrollCheck(nodep, VOptionBool{}, nodep->initsp(), nullptr,
|
||||
nodep->condp(), nodep->incsp(), nodep->stmtsp())) {
|
||||
} else if (forUnrollCheck(nodep, VOptionBool{}, nodep->initsp(), nodep->condp(),
|
||||
nodep->incsp(), nodep->stmtsp())) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
|
||||
} else {
|
||||
nodep->v3error("For loop doesn't have genvar index, or is malformed");
|
||||
|
@ -463,6 +455,17 @@ class UnrollVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
void visit(AstFork* nodep) override {
|
||||
if (m_varModeCheck) {
|
||||
if (nodep->joinType().joinNone() || nodep->joinType().joinAny()) {
|
||||
// Forks are not allowed to unroll for loops, so we just set a flag
|
||||
m_forkHit = true;
|
||||
}
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
void visit(AstNode* nodep) override {
|
||||
|
@ -489,6 +492,7 @@ public:
|
|||
m_varModeCheck = false;
|
||||
m_varModeReplace = false;
|
||||
m_varAssignHit = false;
|
||||
m_forkHit = false;
|
||||
m_generate = generate;
|
||||
m_beginName = beginName;
|
||||
}
|
||||
|
|
168
src/V3Width.cpp
168
src/V3Width.cpp
|
@ -629,8 +629,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheckString(nodep, "RHS", nodep->rhsp(), BOTH);
|
||||
nodep->dtypeSetString();
|
||||
} else {
|
||||
iterateCheckSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
iterateCheckSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
iterateCheckIntegralSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
iterateCheckIntegralSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
|
||||
if (m_streamConcat) {
|
||||
packIfUnpacked(nodep->lhsp());
|
||||
|
@ -798,10 +798,19 @@ class WidthVisitor final : public VNVisitor {
|
|||
iterateCheckSizedSelf(nodep, "RHS", nodep->countp(), SELF, BOTH);
|
||||
V3Const::constifyParamsNoWarnEdit(nodep->countp()); // rhsp may change
|
||||
|
||||
uint32_t times = 1;
|
||||
int32_t times = 1; // IEEE replicate value is integral
|
||||
|
||||
const AstConst* const constp = VN_CAST(nodep->countp(), Const);
|
||||
if (constp) times = constp->toUInt();
|
||||
if (constp) {
|
||||
if (constp->num().isFourState()
|
||||
|| (constp->dtypep()->isSigned() && constp->num().isNegative())) {
|
||||
nodep->v3error("Replication value of < 0 or X/Z not legal"
|
||||
" (IEEE 1800-2023 11.4.12.1): "
|
||||
<< constp->prettyNameQ());
|
||||
} else {
|
||||
times = constp->toSInt();
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp();
|
||||
if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType)
|
||||
|
@ -837,7 +846,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (vdtypep && vdtypep->isString()) {
|
||||
iterateCheckString(nodep, "LHS", nodep->srcp(), BOTH);
|
||||
} else {
|
||||
iterateCheckSelf(nodep, "LHS", nodep->srcp(), SELF, BOTH);
|
||||
iterateCheckIntegralSelf(nodep, "LHS", nodep->srcp(), SELF, BOTH);
|
||||
}
|
||||
|
||||
if ((vdtypep && vdtypep->isString()) || nodep->srcp()->isString()) {
|
||||
|
@ -971,7 +980,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (debug() >= 9) nodep->dumpTree("- selWidth: ");
|
||||
userIterateAndNext(nodep->fromp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
userIterateAndNext(nodep->lsbp(), WidthVP{SELF, PRELIM}.p());
|
||||
checkCvtUS(nodep->fromp());
|
||||
checkCvtUS(nodep->fromp(), false);
|
||||
iterateCheckSizedSelf(nodep, "Select LHS", nodep->fromp(), SELF, BOTH);
|
||||
int width = nodep->widthConst();
|
||||
if (width <= 0) {
|
||||
|
@ -1510,7 +1519,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
return;
|
||||
}
|
||||
|
||||
checkCvtUS(nodep->lhsp());
|
||||
checkCvtUS(nodep->lhsp(), false);
|
||||
iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
nodep->dtypeFrom(nodep->lhsp());
|
||||
}
|
||||
|
@ -2422,6 +2431,18 @@ class WidthVisitor final : public VNVisitor {
|
|||
nodep->dtypeSetLogicSized(1, bdtypep->numeric());
|
||||
VL_DANGLING(bdtypep);
|
||||
}
|
||||
if (nodep->isNet()) {
|
||||
AstNodeDType* const badDtp = dtypeNot4StateIntegralRecurse(nodep->dtypep());
|
||||
if (badDtp)
|
||||
nodep->v3error(
|
||||
"Net " << nodep->prettyNameQ()
|
||||
<< " data type must be 4-state integral or array/union/struct of such"
|
||||
<< " (IEEE 1800-2023 6.7.1)\n"
|
||||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< badDtp->warnOther() << "... Location of failing data type "
|
||||
<< badDtp->prettyDTypeNameQ() << '\n'
|
||||
<< badDtp->warnContextSecondary());
|
||||
}
|
||||
if (nodep->valuep() && !didchk) {
|
||||
// if (debug()) nodep->dumpTree("- final: ");
|
||||
// AstPattern requires assignments to pass datatype on PRELIM
|
||||
|
@ -2483,10 +2504,15 @@ class WidthVisitor final : public VNVisitor {
|
|||
UINFO(5, " ENUMDTYPE " << nodep);
|
||||
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
||||
nodep->dtypep(nodep);
|
||||
AstBasicDType* basicp = nodep->dtypep()->skipRefp()->basicp();
|
||||
if (!basicp || !basicp->keyword().isIntNumeric()) {
|
||||
AstNodeDType* basicp = nodep->dtypep()->skipRefp()->basicp();
|
||||
AstNodeDType* const badDtp = dtypeNotIntAtomOrVecRecurse(nodep->subDTypep());
|
||||
if (badDtp) {
|
||||
nodep->v3error(
|
||||
"Enum type must be an integer atom or vector type (IEEE 1800-2023 6.19)");
|
||||
"Enum data type must be an integer atom or vector type (IEEE 1800-2023 6.19)\n"
|
||||
<< nodep->warnContextPrimary() << '\n'
|
||||
<< badDtp->warnOther() << "... Location of failing data type "
|
||||
<< badDtp->prettyDTypeNameQ() << '\n'
|
||||
<< badDtp->warnContextSecondary());
|
||||
basicp = nodep->findSigned32DType()->basicp();
|
||||
nodep->refDTypep(basicp);
|
||||
}
|
||||
|
@ -3323,7 +3349,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
<< nodep->fromp()->prettyTypeName()
|
||||
<< "' which is a '"
|
||||
<< nodep->fromp()->dtypep()->prettyTypeName() << "'");
|
||||
nodep->dtypep(m_vup->dtypeNullp());
|
||||
nodep->dtypeSetVoid();
|
||||
}
|
||||
}
|
||||
AstWith* methodWithArgument(AstNodeFTaskRef* nodep, bool required, bool arbReturn,
|
||||
|
@ -5172,7 +5198,6 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstWhile* nodep) override {
|
||||
assertAtStatement(nodep);
|
||||
userIterateAndNext(nodep->precondsp(), nullptr);
|
||||
iterateCheckBool(nodep, "For Test Condition", nodep->condp(),
|
||||
BOTH); // it's like an if() condition.
|
||||
userIterateAndNext(nodep->stmtsp(), nullptr);
|
||||
|
@ -6257,9 +6282,39 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleStdRandomizeArgs(AstNodeFTaskRef* const nodep) {
|
||||
AstConst* nullp = nullptr;
|
||||
for (AstNode *pinp = nodep->pinsp(), *nextp = nullptr; pinp; pinp = nextp) {
|
||||
nextp = pinp->nextp();
|
||||
AstArg* const argp = VN_CAST(pinp, Arg);
|
||||
if (!argp) continue;
|
||||
AstNodeExpr* const exprp = argp->exprp();
|
||||
if (AstConst* const constp = VN_CAST(exprp, Const)) {
|
||||
if (constp->num().isNull()) {
|
||||
nullp = constp;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (VN_IS(exprp, MemberSel)) {
|
||||
// Non-standard usage: std::randomize() with class-scoped member
|
||||
// IEEE 1800-2023 (18.12) limits args to current scope variables.
|
||||
// Verilator accepts this for compatibility with other simulators.
|
||||
continue;
|
||||
} else if (VN_IS(exprp, VarRef)) {
|
||||
// Valid usage
|
||||
continue;
|
||||
} else {
|
||||
argp->v3error("Non-variable arguments for 'std::randomize()'.");
|
||||
}
|
||||
if (!argp) continue;
|
||||
}
|
||||
if (nullp) { nullp->v3error("'std::randomize()' does not accept 'null' as arguments."); }
|
||||
}
|
||||
void visit(AstNodeFTaskRef* nodep) override {
|
||||
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
|
||||
// Function hasn't been widthed, so make it so.
|
||||
if (nodep->didWidth()) return;
|
||||
UINFO(5, " FTASKREF " << nodep);
|
||||
AstWith* withp = nullptr;
|
||||
if (nodep->name() == "rand_mode" || nodep->name() == "constraint_mode") {
|
||||
|
@ -6272,16 +6327,23 @@ class WidthVisitor final : public VNVisitor {
|
|||
|| nodep->name() == "set_randstate"))) {
|
||||
// TODO perhaps this should move to V3LinkDot
|
||||
AstClass* const classp = VN_CAST(nodep->classOrPackagep(), Class);
|
||||
if (!classp) {
|
||||
if (nodep->classOrPackagep()->name() == "std") {
|
||||
v3Global.useRandomizeMethods(true);
|
||||
AstNodeDType* const adtypep = nodep->findBitDType();
|
||||
withp = methodWithArgument(nodep, false, false, adtypep->findVoidDType(),
|
||||
adtypep->findBitDType(), adtypep);
|
||||
for (const AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp())
|
||||
userIterateAndNext(VN_AS(argp, Arg)->exprp(), WidthVP{SELF, BOTH}.p());
|
||||
handleStdRandomizeArgs(nodep); // Provided args should be in current scope
|
||||
if (withp) {
|
||||
nodep->v3warn(CONSTRAINTIGN, "Unsupported: std::randomize()'s 'with'");
|
||||
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
return;
|
||||
}
|
||||
processFTaskRefArgs(nodep);
|
||||
nodep->addPinsp(withp);
|
||||
nodep->v3warn(CONSTRAINTIGN, "std::randomize ignored (unsupported)");
|
||||
nodep->replaceWith(new AstConst{nodep->fileline(), 0});
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->didWidth(true);
|
||||
return;
|
||||
}
|
||||
UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot");
|
||||
|
@ -6826,7 +6888,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(!nodep->op2p(), nodep, "For unary ops only!");
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
if (!real_ok) checkCvtUS(nodep->lhsp());
|
||||
if (!real_ok) checkCvtUS(nodep->lhsp(), false);
|
||||
}
|
||||
if (real_ok && nodep->lhsp()->isDouble()) {
|
||||
spliceCvtD(nodep->lhsp());
|
||||
|
@ -6867,7 +6929,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
UASSERT_OBJ(!nodep->op2p(), nodep, "For unary ops only!");
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, PRELIM}.p());
|
||||
checkCvtUS(nodep->lhsp());
|
||||
checkCvtUS(nodep->lhsp(), true);
|
||||
const int width = nodep->lhsp()->width();
|
||||
AstNodeDType* const expDTypep = nodep->findLogicDType(width, width, rs_out);
|
||||
nodep->dtypep(expDTypep);
|
||||
|
@ -6895,7 +6957,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
// RHS is self-determined. RHS is always treated as unsigned, has no effect on result.
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, PRELIM}.p());
|
||||
checkCvtUS(nodep->lhsp());
|
||||
checkCvtUS(nodep->lhsp(), false);
|
||||
iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
|
||||
nodep->dtypeFrom(nodep->lhsp());
|
||||
}
|
||||
|
@ -6955,8 +7017,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
// Determine expression widths only relying on what's in the subops
|
||||
userIterateAndNext(nodep->lhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
checkCvtUS(nodep->lhsp());
|
||||
checkCvtUS(nodep->rhsp());
|
||||
checkCvtUS(nodep->lhsp(), false);
|
||||
checkCvtUS(nodep->rhsp(), false);
|
||||
const int width = std::max(nodep->lhsp()->width(), nodep->rhsp()->width());
|
||||
const int mwidth = std::max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin());
|
||||
const bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
|
||||
|
@ -6990,8 +7052,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
userIterateAndNext(nodep->lhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
userIterateAndNext(nodep->rhsp(), WidthVP{CONTEXT_DET, PRELIM}.p());
|
||||
if (!real_ok) {
|
||||
checkCvtUS(nodep->lhsp());
|
||||
checkCvtUS(nodep->rhsp());
|
||||
checkCvtUS(nodep->lhsp(), false);
|
||||
checkCvtUS(nodep->rhsp(), false);
|
||||
}
|
||||
if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
|
||||
spliceCvtD(nodep->lhsp());
|
||||
|
@ -7330,8 +7392,12 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
(void)underp; // cppcheck
|
||||
}
|
||||
void iterateCheckIntegralSelf(AstNode* nodep, const char* side, AstNode* underp, Determ determ,
|
||||
Stage stage) {
|
||||
iterateCheckSelf(nodep, side, underp, determ, stage, true);
|
||||
}
|
||||
void iterateCheckSelf(AstNode* nodep, const char* side, AstNode* underp, Determ determ,
|
||||
Stage stage) {
|
||||
Stage stage, bool integralOnly = false) {
|
||||
// Coerce child to any data type; child is self-determined
|
||||
// i.e. isolated from expected type.
|
||||
// e.g. nodep=CONCAT, underp=lhs in CONCAT(lhs,rhs)
|
||||
|
@ -7341,7 +7407,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (stage & PRELIM) {
|
||||
underp = userIterateSubtreeReturnEdits(underp, WidthVP{SELF, PRELIM}.p());
|
||||
}
|
||||
underp = VN_IS(underp, NodeExpr) ? checkCvtUS(VN_AS(underp, NodeExpr)) : underp;
|
||||
underp
|
||||
= VN_IS(underp, NodeExpr) ? checkCvtUS(VN_AS(underp, NodeExpr), integralOnly) : underp;
|
||||
AstNodeDType* const expDTypep = underp->dtypep();
|
||||
underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
|
||||
(void)underp; // cppcheck
|
||||
|
@ -7357,7 +7424,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (stage & PRELIM) {
|
||||
underp = userIterateSubtreeReturnEdits(underp, WidthVP{SELF, PRELIM}.p());
|
||||
}
|
||||
underp = VN_IS(underp, NodeExpr) ? checkCvtUS(VN_AS(underp, NodeExpr)) : underp;
|
||||
underp = VN_IS(underp, NodeExpr) ? checkCvtUS(VN_AS(underp, NodeExpr), false) : underp;
|
||||
AstNodeDType* const expDTypep = underp->dtypep();
|
||||
underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP);
|
||||
AstNodeDType* const checkDtp = expDTypep->skipRefToEnump();
|
||||
|
@ -7674,12 +7741,16 @@ class WidthVisitor final : public VNVisitor {
|
|||
//----------------------------------------------------------------------
|
||||
// SIGNED/DOUBLE METHODS
|
||||
|
||||
AstNodeExpr* checkCvtUS(AstNodeExpr* nodep) {
|
||||
if (nodep && nodep->isDouble()) {
|
||||
nodep->v3error("Expected integral (non-" << nodep->dtypep()->prettyDTypeNameQ()
|
||||
<< ") input to "
|
||||
<< nodep->backp()->prettyTypeName());
|
||||
nodep = spliceCvtS(nodep, true, 32);
|
||||
AstNodeExpr* checkCvtUS(AstNodeExpr* nodep, bool fatal) {
|
||||
if (nodep && nodep->dtypep()->skipRefp()->isDouble()) {
|
||||
if (fatal) {
|
||||
nodep->v3error("Expected integral input to " << nodep->backp()->prettyTypeName());
|
||||
} else {
|
||||
nodep->v3warn(REALCVT,
|
||||
"Implicit conversion of real to integer; expected integral input to "
|
||||
<< nodep->backp()->prettyTypeName());
|
||||
}
|
||||
nodep = spliceCvtS(nodep, false, 32);
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
|
@ -8300,6 +8371,39 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp());
|
||||
return false;
|
||||
}
|
||||
AstNodeDType* dtypeNotIntAtomOrVecRecurse(AstNodeDType* nodep, bool ranged = false) {
|
||||
// If node is _not_ integer or atomic, return node that makes it fail
|
||||
nodep = nodep->skipRefToEnump();
|
||||
if (AstBasicDType* const dtp = VN_CAST(nodep, BasicDType)) {
|
||||
if (ranged && (!dtp->isBitLogic() || dtp->isRanged()))
|
||||
return dtp; // Packed when already packed
|
||||
if (dtp->keyword().isIntNumeric()) return nullptr;
|
||||
return dtp;
|
||||
} else if (AstPackArrayDType* const dtp = VN_CAST(nodep, PackArrayDType)) {
|
||||
if (ranged) return dtp; // Packed when already packed
|
||||
return dtypeNotIntAtomOrVecRecurse(nodep->subDTypep(), true);
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
AstNodeDType* dtypeNot4StateIntegralRecurse(AstNodeDType* nodep) {
|
||||
// If node is _not_ inet valid data type, 4-state integral packed or union, return node
|
||||
// that makes it fail
|
||||
nodep = nodep->skipRefp();
|
||||
if (AstBasicDType* const dtp = VN_CAST(nodep, BasicDType)) {
|
||||
if (!dtp->keyword().isFourstate()) return dtp;
|
||||
return nullptr;
|
||||
} else if (AstNodeArrayDType* const dtp = VN_CAST(nodep, NodeArrayDType)) {
|
||||
return dtypeNot4StateIntegralRecurse(dtp->subDTypep());
|
||||
} else if (AstNodeUOrStructDType* const dtp = VN_CAST(nodep, NodeUOrStructDType)) {
|
||||
for (AstMemberDType* itemp = dtp->membersp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||
AstNodeDType* const badDtp = dtypeNot4StateIntegralRecurse(itemp->dtypep());
|
||||
if (badDtp) return badDtp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// METHODS - special type detection
|
||||
|
|
|
@ -649,10 +649,10 @@ static void process() {
|
|||
|
||||
// Final statistics
|
||||
if (v3Global.opt.stats()) V3Stats::statsStage("emit");
|
||||
reportStatsIfEnabled();
|
||||
}
|
||||
|
||||
static void verilate(const string& argString) {
|
||||
static bool verilate(const string& argString) {
|
||||
// Run verilation, and return false if skipped
|
||||
UINFO(1, "Option --verilate: Start Verilation");
|
||||
|
||||
// Can we skip doing everything if times are ok?
|
||||
|
@ -662,7 +662,7 @@ static void verilate(const string& argString) {
|
|||
+ "__verFiles.dat",
|
||||
argString)) {
|
||||
UINFO(1, "--skip-identical: No change to any source files, exiting");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Undocumented debugging - cannot be a switch as then command line
|
||||
// would mismatch forcing non-identicalness when we set it
|
||||
|
@ -769,9 +769,19 @@ static void verilate(const string& argString) {
|
|||
|
||||
V3Os::filesystemFlushBuildDir(v3Global.opt.makeDir());
|
||||
if (v3Global.opt.hierTop()) V3Os::filesystemFlushBuildDir(v3Global.opt.hierTopDataDir());
|
||||
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "WroteAll");
|
||||
if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "WroteFast");
|
||||
|
||||
// Final writing shouldn't throw warnings, but...
|
||||
V3Error::abortIfWarnings();
|
||||
|
||||
// Free memory so compiler has more for --build
|
||||
// No need to do this if skipped (above) as didn't alloc much
|
||||
UINFO(1, "Releasing netlist memory");
|
||||
v3Global.rootp()->deleteContents();
|
||||
V3Os::releaseMemory();
|
||||
if (v3Global.opt.stats()) V3Stats::statsStage("released");
|
||||
return true;
|
||||
}
|
||||
|
||||
static string buildMakeCmd(const string& makefile, const string& target) {
|
||||
|
@ -855,8 +865,9 @@ int main(int argc, char** argv) {
|
|||
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
bool didVerilate = false;
|
||||
if (v3Global.opt.verilate()) {
|
||||
verilate(argString);
|
||||
didVerilate = verilate(argString);
|
||||
} else {
|
||||
UINFO(1, "Option --no-verilate: Skip Verilation");
|
||||
}
|
||||
|
@ -867,6 +878,7 @@ int main(int argc, char** argv) {
|
|||
execBuildJob();
|
||||
}
|
||||
|
||||
if (didVerilate) reportStatsIfEnabled();
|
||||
V3DiagSarif::output(true);
|
||||
|
||||
// Explicitly release resources
|
||||
|
|
|
@ -41,6 +41,9 @@ PACKAGE_VERSION_STRING_CHAR
|
|||
// Define if coroutines are supported on this platform
|
||||
#undef HAVE_COROUTINES
|
||||
|
||||
// Define if compiled with tcmalloc
|
||||
#undef HAVE_TCMALLOC
|
||||
|
||||
//**********************************************************************
|
||||
//**** This file sometimes gets truncated, so check in consumers
|
||||
#define HAVE_CONFIG_PACKAGE
|
||||
|
|
|
@ -270,6 +270,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$rewind" { FL; return yD_REWIND; }
|
||||
"$rtoi" { FL; return yD_RTOI; }
|
||||
"$sampled" { FL; return yD_SAMPLED; }
|
||||
"$sdf_annotate" { FL; return yD_SDF_ANNOTATE; }
|
||||
"$setup" { FL; return yaTIMINGSPEC; }
|
||||
"$setuphold" { FL; return yD_SETUPHOLD; }
|
||||
"$sformat" { FL; return yD_SFORMAT; }
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
bool m_tracingParse = true; // Tracing disable for parser
|
||||
bool m_inImplements = false; // Is inside class implements list
|
||||
bool m_insideProperty = false; // Is inside property declaration
|
||||
bool m_specifyignWarned = false; // Issued a SPECIFYIGN warning
|
||||
bool m_typedPropertyPort = false; // Typed property port occurred on port lists
|
||||
bool m_modportImpExpActive
|
||||
= false; // Standalone ID is a tf_identifier instead of port_identifier
|
||||
|
@ -926,6 +927,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_ROSE_GCLK "$rose_gclk"
|
||||
%token<fl> yD_RTOI "$rtoi"
|
||||
%token<fl> yD_SAMPLED "$sampled"
|
||||
%token<fl> yD_SDF_ANNOTATE "$sdf_annotate"
|
||||
%token<fl> yD_SETUPHOLD "$setuphold"
|
||||
%token<fl> yD_SFORMAT "$sformat"
|
||||
%token<fl> yD_SFORMATF "$sformatf"
|
||||
|
@ -2226,10 +2228,11 @@ data_typeNoRef<nodeDTypep>: // ==IEEE: data_type, excluding class_ty
|
|||
new AstDefImplicitDType{$1->fileline(),
|
||||
"__typeimpsu" + cvtToStr(GRAMMARP->s_typeImpNum++),
|
||||
VFlagChildDType{}, $1}, $2, true); }
|
||||
| enumDecl
|
||||
{ $$ = new AstDefImplicitDType{$1->fileline(),
|
||||
"__typeimpenum" + cvtToStr(GRAMMARP->s_typeImpNum++),
|
||||
VFlagChildDType{}, $1}; }
|
||||
| enumDecl packed_dimensionListE
|
||||
{ $$ = GRAMMARP->createArray(
|
||||
new AstDefImplicitDType{$1->fileline(),
|
||||
"__typeimpenum" + cvtToStr(GRAMMARP->s_typeImpNum++),
|
||||
VFlagChildDType{}, $1}, $2, true); }
|
||||
| ySTRING
|
||||
{ $$ = new AstBasicDType{$1, VBasicDTypeKwd::STRING}; }
|
||||
| yCHANDLE
|
||||
|
@ -3058,7 +3061,6 @@ genvar_iteration<nodep>: // ==IEEE: genvar_iteration
|
|||
| varRefBase yP_SSRIGHTEQ expr
|
||||
{ $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTreePure(true), $3}}; }
|
||||
// // inc_or_dec_operator
|
||||
// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstNodeExprStmt?
|
||||
| yP_PLUSPLUS varRefBase
|
||||
{ $$ = new AstAssign{$1, $2, new AstAdd{$1, $2->cloneTreePure(true),
|
||||
new AstConst{$1, AstConst::StringToParse{}, "'b1"}}}; }
|
||||
|
@ -4180,6 +4182,7 @@ loop_variables<nodep>: // IEEE: loop_variables
|
|||
parseRefBase { $$ = $1; }
|
||||
| loop_variables ',' parseRefBase { $$ = $1->addNext($3); }
|
||||
| ',' parseRefBase { $$ = new AstEmpty{$1}; $$->addNext($2); }
|
||||
| ',' { $$ = new AstEmpty{$1}; }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
|
@ -4282,6 +4285,7 @@ system_t_call<nodeStmtp>: // IEEE: system_tf_call (as task)
|
|||
| yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl{$<fl>1, VDumpCtlType::ON}; DEL($3); }
|
||||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCStmt{$1, $3}); }
|
||||
| yD_SDF_ANNOTATE '(' exprEListE ')' { $$ = nullptr; $1->v3warn(SPECIFYIGN, "Ignoring unsupported: $sdf_annotate"); }
|
||||
| yD_STACKTRACE parenE { $$ = new AstStackTraceT{$1}; }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT{$1, $3}; }
|
||||
//
|
||||
|
@ -5351,6 +5355,11 @@ exprList<nodeExprp>:
|
|||
| exprList ',' expr { $$ = $1->addNext($3); }
|
||||
;
|
||||
|
||||
exprEListE<nodep>: // expression list with empty commas allowed
|
||||
exprE { $$ = $1; }
|
||||
| exprEListE ',' exprE { $$ = addNextNull($1, $3); }
|
||||
;
|
||||
|
||||
exprDispList<nodeExprp>: // exprList for within $display
|
||||
expr { $$ = $1; }
|
||||
| exprDispList ',' expr { $$ = $1->addNext($3); }
|
||||
|
@ -5823,8 +5832,12 @@ tablelVal<udpTableLineValp>:
|
|||
// Specify
|
||||
|
||||
specify_block<nodep>: // ==IEEE: specify_block
|
||||
ySPECIFY specify_itemList yENDSPECIFY { $$ = $2; }
|
||||
| ySPECIFY yENDSPECIFY { $$ = nullptr; }
|
||||
specifyFront specify_itemList yENDSPECIFY { $$ = $2; }
|
||||
| specifyFront yENDSPECIFY { $$ = nullptr; }
|
||||
;
|
||||
|
||||
specifyFront: // IEEE: specify_block front
|
||||
ySPECIFY { GRAMMARP->m_specifyignWarned = false; }
|
||||
;
|
||||
|
||||
specify_itemList<nodep>: // IEEE: { specify_item }
|
||||
|
@ -5835,7 +5848,13 @@ specify_itemList<nodep>: // IEEE: { specify_item }
|
|||
specify_item<nodep>: // ==IEEE: specify_item
|
||||
specparam_declaration { $$ = $1; }
|
||||
| system_timing_check { $$ = $1; }
|
||||
| junkToSemiList ';' { $$ = nullptr; }
|
||||
| junkToSemiList ';'
|
||||
{ $$ = nullptr;
|
||||
if (!GRAMMARP->m_specifyignWarned) {
|
||||
GRAMMARP->m_specifyignWarned = true;
|
||||
$1->v3warn(SPECIFYIGN, "Ignoring unsupported: specify block construct");
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
|
||||
|
@ -5924,9 +5943,9 @@ idAnyE<strp>:
|
|||
| idAny { $$ = $1; }
|
||||
;
|
||||
|
||||
junkToSemiList:
|
||||
junkToSemi { } /* ignored */
|
||||
| junkToSemiList junkToSemi { } /* ignored */
|
||||
junkToSemiList<fl>:
|
||||
junkToSemi { $$ = CRELINE(); }
|
||||
| junkToSemiList junkToSemi { $$ = CRELINE(); }
|
||||
;
|
||||
|
||||
junkToSemi:
|
||||
|
@ -6118,6 +6137,8 @@ idArrayedForeach<nodeExprp>: // IEEE: id + select (under foreach expression)
|
|||
| idArrayed '[' expr yP_MINUSCOLON constExpr ']' { $$ = new AstSelMinus{$2, $1, $3, $5}; }
|
||||
// // IEEE: loop_variables (under foreach expression)
|
||||
// // To avoid conflicts we allow expr as first element, must post-check
|
||||
| idArrayed '[' ']'
|
||||
{ $$ = new AstSelLoopVars{$2, $1, new AstEmpty{$3}}; }
|
||||
| idArrayed '[' expr ',' loop_variables ']'
|
||||
{ $$ = new AstSelLoopVars{$2, $1, addNextNull(static_cast<AstNode*>($3), $5)}; }
|
||||
| idArrayed '[' ',' loop_variables ']'
|
||||
|
@ -6821,21 +6842,38 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
|
|||
| covergroup_declarationFront '(' tf_port_listE ')'
|
||||
/*cont*/ coverage_eventE ';' coverage_spec_or_optionListE
|
||||
/*cont*/ yENDGROUP endLabelE
|
||||
{ $$ = $1;
|
||||
{ AstFunc* const newp = new AstFunc{$<fl>1, "new", nullptr, nullptr};
|
||||
newp->classMethod(true);
|
||||
newp->isConstructor(true);
|
||||
newp->dtypep($1->dtypep());
|
||||
newp->addStmtsp($3);
|
||||
$1->addMembersp(newp);
|
||||
$$ = $1;
|
||||
GRAMMARP->endLabel($<fl>9, $1, $9); }
|
||||
// // IEEE 1800-2023 added:
|
||||
| covergroup_declarationFront yEXTENDS idAny/*covergroup_identifier*/
|
||||
/*cont*/ ';' coverage_spec_or_optionListE
|
||||
/*cont*/ yENDGROUP endLabelE
|
||||
{ $$ = $1;
|
||||
GRAMMARP->endLabel($<fl>7, $1, $7); }
|
||||
;
|
||||
|
||||
covergroup_extendsE<fl>: // IEEE: Part of covergroup_declaration
|
||||
/* empty */ { $$ = nullptr; }
|
||||
| yEXTENDS { $$ = $1; }
|
||||
;
|
||||
|
||||
covergroup_declarationFront<classp>: // IEEE: part of covergroup_declaration
|
||||
yCOVERGROUP idAny
|
||||
{ $$ = new AstClass{$<fl>2, *$2, PARSEP->libname()};
|
||||
yCOVERGROUP covergroup_extendsE idAny
|
||||
{
|
||||
$$ = new AstClass{$<fl>3, *$3, PARSEP->libname()};
|
||||
|
||||
AstFunc* const sample = new AstFunc{$<fl>1, "sample", nullptr, nullptr};
|
||||
sample->classMethod(true);
|
||||
sample->dtypep(sample->findVoidDType());
|
||||
$$->addMembersp(sample);
|
||||
|
||||
AstFunc* const getCoverage = new AstFunc{$<fl>1, "get_coverage", nullptr, nullptr};
|
||||
getCoverage->classMethod(true);
|
||||
getCoverage->dtypep(getCoverage->findVoidDType());
|
||||
$$->addMembersp(getCoverage);
|
||||
|
||||
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup"); }
|
||||
;
|
||||
;
|
||||
|
||||
cgexpr<nodeExprp>: // IEEE-2012: covergroup_expression, before that just expression
|
||||
expr { $$ = $1; }
|
||||
|
@ -7005,7 +7043,7 @@ cross_itemList<nodep>: // IEEE: part of list_of_cross_items
|
|||
;
|
||||
|
||||
cross_item<nodep>: // ==IEEE: cross_item
|
||||
idAny/*cover_point_identifier or variable_identifier*/ { $$ = nullptr; /*UNSUP*/ }
|
||||
idDotted/*cover_point_identifier or variable_identifier*/ { $1->deleteTree(); $$ = nullptr; /*UNSUP*/ }
|
||||
;
|
||||
|
||||
cross_body<nodep>: // ==IEEE: cross_body
|
||||
|
@ -7551,7 +7589,12 @@ class_item<nodep>: // ==IEEE: class_item
|
|||
| class_declaration { $$ = $1; }
|
||||
| timeunits_declaration { $$ = $1; }
|
||||
| covergroup_declaration
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup within class"); }
|
||||
{
|
||||
const string cgName = $1->name();
|
||||
$1->name("__vlAnonCG_" + cgName);
|
||||
AstVar* const newp = new AstVar{$<fl>1, VVarType::VAR, cgName, VFlagChildDType{}, new AstRefDType($<fl>1, $1->name())};
|
||||
$$ = addNextNull($1, newp);
|
||||
}
|
||||
// // local_parameter_declaration under parameter_declaration
|
||||
| parameter_declaration ';' { $$ = $1; }
|
||||
| ';' { $$ = nullptr; }
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import argparse
|
||||
import collections
|
||||
import ctypes
|
||||
import glob
|
||||
import hashlib
|
||||
import json
|
||||
|
@ -14,6 +15,7 @@ import pickle
|
|||
import platform
|
||||
import pty
|
||||
import re
|
||||
import resource
|
||||
import runpy
|
||||
import shutil
|
||||
import signal
|
||||
|
@ -1366,6 +1368,19 @@ class VlTest:
|
|||
]
|
||||
self.run(logfile=self.obj_dir + "/pli_compile.log", fails=param['fails'], cmd=cmd)
|
||||
|
||||
def timeout(self, seconds):
|
||||
"""Limit the CPU time of the test - this limit is inherited
|
||||
by all of the spawned child processess"""
|
||||
# An unprivileged process may set only its soft limit
|
||||
# to a value in the range from 0 up to the hard limit
|
||||
_, hardlimit = resource.getrlimit(resource.RLIMIT_CPU)
|
||||
softlimit = ctypes.c_long(min(seconds, ctypes.c_ulong(hardlimit).value)).value
|
||||
# Casting is required due to a quirk in Python,
|
||||
# rlimit values are interpreted as LONG, instead of ULONG
|
||||
# https://github.com/python/cpython/issues/137044
|
||||
rlimit = (softlimit, hardlimit)
|
||||
resource.setrlimit(resource.RLIMIT_CPU, rlimit)
|
||||
|
||||
def execute(self, **kwargs) -> None:
|
||||
"""Run simulation executable.
|
||||
Arguments similar to run(); default arguments are from self"""
|
||||
|
|
|
@ -16,19 +16,21 @@
|
|||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
module t ( /*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
int cyc;
|
||||
reg [63:0] crc;
|
||||
reg [63:0] sum;
|
||||
int cyc;
|
||||
reg [63:0] crc;
|
||||
reg [63:0] sum;
|
||||
|
||||
// Take CRC data and apply to testblock inputs
|
||||
wire [31:0] in = crc[31:0];
|
||||
|
@ -38,12 +40,12 @@ module t(/*AUTOARG*/
|
|||
wire [31:0] out; // From test of Test.v
|
||||
// End of automatics
|
||||
|
||||
Test test(/*AUTOINST*/
|
||||
// Outputs
|
||||
.out (out[31:0]),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.in (in[31:0]));
|
||||
Test test ( /*AUTOINST*/
|
||||
// Outputs
|
||||
.out (out[31:0]),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.in (in[31:0]));
|
||||
|
||||
// Aggregate outputs into a single result vector
|
||||
wire [63:0] result = {32'h0, out};
|
||||
|
@ -78,7 +80,7 @@ module t(/*AUTOARG*/
|
|||
|
||||
endmodule
|
||||
|
||||
module Test(/*AUTOARG*/
|
||||
module Test ( /*AUTOARG*/
|
||||
// Outputs
|
||||
out,
|
||||
// Inputs
|
||||
|
|
|
@ -5,290 +5,284 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t_case_huge_sub (/*AUTOARG*/
|
||||
// Outputs
|
||||
outa, outb, outc,
|
||||
// Inputs
|
||||
index
|
||||
);
|
||||
// Outputs
|
||||
outa, outb, outc,
|
||||
// Inputs
|
||||
index
|
||||
);
|
||||
|
||||
input [7:0] index;
|
||||
output [9:0] outa;
|
||||
output [1:0] outb;
|
||||
output outc;
|
||||
input [7:0] index;
|
||||
output logic [9:0] outa;
|
||||
output logic [1:0] outb;
|
||||
output logic outc;
|
||||
|
||||
// =============================
|
||||
/*AUTOREG*/
|
||||
// Beginning of automatic regs (for this module's undeclared outputs)
|
||||
reg [9:0] outa;
|
||||
reg [1:0] outb;
|
||||
reg outc;
|
||||
// End of automatics
|
||||
// =============================
|
||||
// Created from Python3:
|
||||
// for i in range(1024):
|
||||
// print(" 10'h%03x: begin outa = 10'h%03x; outb = 2'b%d%d; outc = 1'b%d; end"
|
||||
// % (i, random.randint(0,1024), random.randint(0,1),
|
||||
// random.randint(0,1), random.randint(0,1)))
|
||||
|
||||
// =============================
|
||||
// Created from Python3:
|
||||
// for i in range(1024):
|
||||
// print(" 10'h%03x: begin outa = 10'h%03x; outb = 2'b%d%d; outc = 1'b%d; end"
|
||||
// % (i, random.randint(0,1024), random.randint(0,1),
|
||||
// random.randint(0,1), random.randint(0,1)))
|
||||
|
||||
always @(/*AS*/index) begin
|
||||
case (index)
|
||||
8'h00: begin outa = 10'h152; outb = 2'b00; outc = 1'b1; end
|
||||
8'h01: begin outa = 10'h318; outb = 2'b11; outc = 1'b1; end
|
||||
8'h02: begin outa = 10'h29f; outb = 2'b11; outc = 1'b0; end
|
||||
8'h03: begin outa = 10'h392; outb = 2'b01; outc = 1'b1; end
|
||||
8'h04: begin outa = 10'h1ef; outb = 2'b00; outc = 1'b0; end
|
||||
8'h05: begin outa = 10'h06c; outb = 2'b10; outc = 1'b1; end
|
||||
8'h06: begin outa = 10'h29f; outb = 2'b11; outc = 1'b0; end
|
||||
8'h07: begin outa = 10'h29a; outb = 2'b10; outc = 1'b0; end
|
||||
8'h08: begin outa = 10'h3ce; outb = 2'b01; outc = 1'b0; end
|
||||
8'h09: begin outa = 10'h37c; outb = 2'b01; outc = 1'b0; end
|
||||
8'h0a: begin outa = 10'h058; outb = 2'b10; outc = 1'b0; end
|
||||
8'h0b: begin outa = 10'h3b2; outb = 2'b01; outc = 1'b1; end
|
||||
8'h0c: begin outa = 10'h36f; outb = 2'b11; outc = 1'b0; end
|
||||
8'h0d: begin outa = 10'h2c5; outb = 2'b11; outc = 1'b0; end
|
||||
8'h0e: begin outa = 10'h23a; outb = 2'b00; outc = 1'b0; end
|
||||
8'h0f: begin outa = 10'h222; outb = 2'b01; outc = 1'b1; end
|
||||
8'h10: begin outa = 10'h328; outb = 2'b00; outc = 1'b1; end
|
||||
8'h11: begin outa = 10'h3c3; outb = 2'b00; outc = 1'b1; end
|
||||
8'h12: begin outa = 10'h12c; outb = 2'b01; outc = 1'b0; end
|
||||
8'h13: begin outa = 10'h1d0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h14: begin outa = 10'h3ff; outb = 2'b01; outc = 1'b1; end
|
||||
8'h15: begin outa = 10'h115; outb = 2'b11; outc = 1'b1; end
|
||||
8'h16: begin outa = 10'h3ba; outb = 2'b10; outc = 1'b0; end
|
||||
8'h17: begin outa = 10'h3ba; outb = 2'b00; outc = 1'b0; end
|
||||
8'h18: begin outa = 10'h10d; outb = 2'b00; outc = 1'b1; end
|
||||
8'h19: begin outa = 10'h13b; outb = 2'b01; outc = 1'b1; end
|
||||
8'h1a: begin outa = 10'h0a0; outb = 2'b10; outc = 1'b1; end
|
||||
8'h1b: begin outa = 10'h264; outb = 2'b11; outc = 1'b0; end
|
||||
8'h1c: begin outa = 10'h3a2; outb = 2'b10; outc = 1'b0; end
|
||||
8'h1d: begin outa = 10'h07c; outb = 2'b00; outc = 1'b1; end
|
||||
8'h1e: begin outa = 10'h291; outb = 2'b00; outc = 1'b0; end
|
||||
8'h1f: begin outa = 10'h1d1; outb = 2'b10; outc = 1'b0; end
|
||||
8'h20: begin outa = 10'h354; outb = 2'b11; outc = 1'b1; end
|
||||
8'h21: begin outa = 10'h0c0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h22: begin outa = 10'h191; outb = 2'b00; outc = 1'b0; end
|
||||
8'h23: begin outa = 10'h379; outb = 2'b01; outc = 1'b0; end
|
||||
8'h24: begin outa = 10'h073; outb = 2'b00; outc = 1'b0; end
|
||||
8'h25: begin outa = 10'h2fd; outb = 2'b11; outc = 1'b1; end
|
||||
8'h26: begin outa = 10'h2e0; outb = 2'b11; outc = 1'b1; end
|
||||
8'h27: begin outa = 10'h337; outb = 2'b01; outc = 1'b1; end
|
||||
8'h28: begin outa = 10'h2c7; outb = 2'b11; outc = 1'b1; end
|
||||
8'h29: begin outa = 10'h19e; outb = 2'b11; outc = 1'b0; end
|
||||
8'h2a: begin outa = 10'h107; outb = 2'b10; outc = 1'b0; end
|
||||
8'h2b: begin outa = 10'h06a; outb = 2'b01; outc = 1'b1; end
|
||||
8'h2c: begin outa = 10'h1c7; outb = 2'b01; outc = 1'b1; end
|
||||
8'h2d: begin outa = 10'h107; outb = 2'b10; outc = 1'b0; end
|
||||
8'h2e: begin outa = 10'h0cf; outb = 2'b01; outc = 1'b1; end
|
||||
8'h2f: begin outa = 10'h009; outb = 2'b11; outc = 1'b1; end
|
||||
8'h30: begin outa = 10'h09d; outb = 2'b00; outc = 1'b1; end
|
||||
8'h31: begin outa = 10'h28e; outb = 2'b00; outc = 1'b0; end
|
||||
8'h32: begin outa = 10'h010; outb = 2'b01; outc = 1'b0; end
|
||||
8'h33: begin outa = 10'h1e0; outb = 2'b10; outc = 1'b0; end
|
||||
8'h34: begin outa = 10'h079; outb = 2'b01; outc = 1'b1; end
|
||||
8'h35: begin outa = 10'h13e; outb = 2'b10; outc = 1'b1; end
|
||||
8'h36: begin outa = 10'h282; outb = 2'b11; outc = 1'b0; end
|
||||
8'h37: begin outa = 10'h21c; outb = 2'b11; outc = 1'b1; end
|
||||
8'h38: begin outa = 10'h148; outb = 2'b00; outc = 1'b1; end
|
||||
8'h39: begin outa = 10'h3c0; outb = 2'b10; outc = 1'b0; end
|
||||
8'h3a: begin outa = 10'h176; outb = 2'b01; outc = 1'b1; end
|
||||
8'h3b: begin outa = 10'h3fc; outb = 2'b10; outc = 1'b1; end
|
||||
8'h3c: begin outa = 10'h295; outb = 2'b11; outc = 1'b1; end
|
||||
8'h3d: begin outa = 10'h113; outb = 2'b10; outc = 1'b1; end
|
||||
8'h3e: begin outa = 10'h354; outb = 2'b01; outc = 1'b1; end
|
||||
8'h3f: begin outa = 10'h0db; outb = 2'b11; outc = 1'b0; end
|
||||
8'h40: begin outa = 10'h238; outb = 2'b01; outc = 1'b0; end
|
||||
8'h41: begin outa = 10'h12b; outb = 2'b01; outc = 1'b1; end
|
||||
8'h42: begin outa = 10'h1dc; outb = 2'b10; outc = 1'b0; end
|
||||
8'h43: begin outa = 10'h137; outb = 2'b01; outc = 1'b1; end
|
||||
8'h44: begin outa = 10'h1e2; outb = 2'b01; outc = 1'b1; end
|
||||
8'h45: begin outa = 10'h3d5; outb = 2'b11; outc = 1'b1; end
|
||||
8'h46: begin outa = 10'h30c; outb = 2'b11; outc = 1'b0; end
|
||||
8'h47: begin outa = 10'h298; outb = 2'b11; outc = 1'b0; end
|
||||
8'h48: begin outa = 10'h080; outb = 2'b00; outc = 1'b1; end
|
||||
8'h49: begin outa = 10'h35a; outb = 2'b11; outc = 1'b1; end
|
||||
8'h4a: begin outa = 10'h01b; outb = 2'b00; outc = 1'b0; end
|
||||
8'h4b: begin outa = 10'h0a3; outb = 2'b11; outc = 1'b0; end
|
||||
8'h4c: begin outa = 10'h0b3; outb = 2'b11; outc = 1'b1; end
|
||||
8'h4d: begin outa = 10'h17a; outb = 2'b00; outc = 1'b0; end
|
||||
8'h4e: begin outa = 10'h3ae; outb = 2'b11; outc = 1'b0; end
|
||||
8'h4f: begin outa = 10'h078; outb = 2'b11; outc = 1'b0; end
|
||||
8'h50: begin outa = 10'h322; outb = 2'b00; outc = 1'b1; end
|
||||
8'h51: begin outa = 10'h213; outb = 2'b11; outc = 1'b0; end
|
||||
8'h52: begin outa = 10'h11a; outb = 2'b11; outc = 1'b0; end
|
||||
8'h53: begin outa = 10'h1a7; outb = 2'b00; outc = 1'b0; end
|
||||
8'h54: begin outa = 10'h35a; outb = 2'b00; outc = 1'b1; end
|
||||
8'h55: begin outa = 10'h233; outb = 2'b00; outc = 1'b0; end
|
||||
8'h56: begin outa = 10'h01d; outb = 2'b01; outc = 1'b1; end
|
||||
8'h57: begin outa = 10'h2d5; outb = 2'b00; outc = 1'b0; end
|
||||
8'h58: begin outa = 10'h1a0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h59: begin outa = 10'h3d0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h5a: begin outa = 10'h181; outb = 2'b01; outc = 1'b1; end
|
||||
8'h5b: begin outa = 10'h219; outb = 2'b01; outc = 1'b1; end
|
||||
8'h5c: begin outa = 10'h26a; outb = 2'b01; outc = 1'b1; end
|
||||
8'h5d: begin outa = 10'h050; outb = 2'b10; outc = 1'b0; end
|
||||
8'h5e: begin outa = 10'h189; outb = 2'b10; outc = 1'b0; end
|
||||
8'h5f: begin outa = 10'h1eb; outb = 2'b01; outc = 1'b1; end
|
||||
8'h60: begin outa = 10'h224; outb = 2'b00; outc = 1'b1; end
|
||||
8'h61: begin outa = 10'h2fe; outb = 2'b00; outc = 1'b0; end
|
||||
8'h62: begin outa = 10'h0ae; outb = 2'b00; outc = 1'b1; end
|
||||
8'h63: begin outa = 10'h1cd; outb = 2'b00; outc = 1'b0; end
|
||||
8'h64: begin outa = 10'h273; outb = 2'b10; outc = 1'b1; end
|
||||
8'h65: begin outa = 10'h268; outb = 2'b10; outc = 1'b0; end
|
||||
8'h66: begin outa = 10'h111; outb = 2'b01; outc = 1'b0; end
|
||||
8'h67: begin outa = 10'h1f9; outb = 2'b00; outc = 1'b0; end
|
||||
8'h68: begin outa = 10'h232; outb = 2'b00; outc = 1'b1; end
|
||||
8'h69: begin outa = 10'h255; outb = 2'b11; outc = 1'b0; end
|
||||
8'h6a: begin outa = 10'h34c; outb = 2'b01; outc = 1'b1; end
|
||||
8'h6b: begin outa = 10'h049; outb = 2'b01; outc = 1'b1; end
|
||||
8'h6c: begin outa = 10'h197; outb = 2'b11; outc = 1'b0; end
|
||||
8'h6d: begin outa = 10'h0fe; outb = 2'b11; outc = 1'b0; end
|
||||
8'h6e: begin outa = 10'h253; outb = 2'b01; outc = 1'b1; end
|
||||
8'h6f: begin outa = 10'h2de; outb = 2'b11; outc = 1'b0; end
|
||||
8'h70: begin outa = 10'h13b; outb = 2'b10; outc = 1'b1; end
|
||||
8'h71: begin outa = 10'h040; outb = 2'b10; outc = 1'b0; end
|
||||
8'h72: begin outa = 10'h0b4; outb = 2'b00; outc = 1'b1; end
|
||||
8'h73: begin outa = 10'h233; outb = 2'b11; outc = 1'b1; end
|
||||
8'h74: begin outa = 10'h198; outb = 2'b00; outc = 1'b1; end
|
||||
8'h75: begin outa = 10'h018; outb = 2'b00; outc = 1'b1; end
|
||||
8'h76: begin outa = 10'h2f7; outb = 2'b00; outc = 1'b1; end
|
||||
8'h77: begin outa = 10'h134; outb = 2'b11; outc = 1'b0; end
|
||||
8'h78: begin outa = 10'h1ca; outb = 2'b10; outc = 1'b0; end
|
||||
8'h79: begin outa = 10'h286; outb = 2'b10; outc = 1'b1; end
|
||||
8'h7a: begin outa = 10'h0e6; outb = 2'b11; outc = 1'b1; end
|
||||
8'h7b: begin outa = 10'h064; outb = 2'b10; outc = 1'b1; end
|
||||
8'h7c: begin outa = 10'h257; outb = 2'b00; outc = 1'b1; end
|
||||
8'h7d: begin outa = 10'h31a; outb = 2'b10; outc = 1'b1; end
|
||||
8'h7e: begin outa = 10'h247; outb = 2'b01; outc = 1'b0; end
|
||||
8'h7f: begin outa = 10'h299; outb = 2'b00; outc = 1'b0; end
|
||||
8'h80: begin outa = 10'h02c; outb = 2'b00; outc = 1'b0; end
|
||||
8'h81: begin outa = 10'h2bb; outb = 2'b11; outc = 1'b0; end
|
||||
8'h82: begin outa = 10'h180; outb = 2'b10; outc = 1'b0; end
|
||||
8'h83: begin outa = 10'h245; outb = 2'b01; outc = 1'b1; end
|
||||
8'h84: begin outa = 10'h0da; outb = 2'b10; outc = 1'b0; end
|
||||
8'h85: begin outa = 10'h367; outb = 2'b10; outc = 1'b0; end
|
||||
8'h86: begin outa = 10'h304; outb = 2'b01; outc = 1'b0; end
|
||||
8'h87: begin outa = 10'h38b; outb = 2'b11; outc = 1'b0; end
|
||||
8'h88: begin outa = 10'h09f; outb = 2'b01; outc = 1'b0; end
|
||||
8'h89: begin outa = 10'h1f0; outb = 2'b10; outc = 1'b1; end
|
||||
8'h8a: begin outa = 10'h281; outb = 2'b10; outc = 1'b1; end
|
||||
8'h8b: begin outa = 10'h019; outb = 2'b00; outc = 1'b0; end
|
||||
8'h8c: begin outa = 10'h1f2; outb = 2'b10; outc = 1'b0; end
|
||||
8'h8d: begin outa = 10'h0b1; outb = 2'b01; outc = 1'b1; end
|
||||
8'h8e: begin outa = 10'h058; outb = 2'b01; outc = 1'b1; end
|
||||
8'h8f: begin outa = 10'h39b; outb = 2'b00; outc = 1'b1; end
|
||||
8'h90: begin outa = 10'h2ec; outb = 2'b10; outc = 1'b1; end
|
||||
8'h91: begin outa = 10'h250; outb = 2'b00; outc = 1'b1; end
|
||||
8'h92: begin outa = 10'h3f4; outb = 2'b10; outc = 1'b1; end
|
||||
8'h93: begin outa = 10'h057; outb = 2'b10; outc = 1'b1; end
|
||||
8'h94: begin outa = 10'h18f; outb = 2'b01; outc = 1'b1; end
|
||||
8'h95: begin outa = 10'h105; outb = 2'b01; outc = 1'b1; end
|
||||
8'h96: begin outa = 10'h1ae; outb = 2'b00; outc = 1'b1; end
|
||||
8'h97: begin outa = 10'h04e; outb = 2'b10; outc = 1'b0; end
|
||||
8'h98: begin outa = 10'h240; outb = 2'b11; outc = 1'b0; end
|
||||
8'h99: begin outa = 10'h3e4; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9a: begin outa = 10'h3c6; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9b: begin outa = 10'h109; outb = 2'b00; outc = 1'b1; end
|
||||
8'h9c: begin outa = 10'h073; outb = 2'b10; outc = 1'b1; end
|
||||
8'h9d: begin outa = 10'h19f; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9e: begin outa = 10'h3b8; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9f: begin outa = 10'h00e; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha0: begin outa = 10'h1b3; outb = 2'b11; outc = 1'b1; end
|
||||
8'ha1: begin outa = 10'h2bd; outb = 2'b11; outc = 1'b0; end
|
||||
8'ha2: begin outa = 10'h324; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha3: begin outa = 10'h343; outb = 2'b10; outc = 1'b0; end
|
||||
8'ha4: begin outa = 10'h1c9; outb = 2'b01; outc = 1'b0; end
|
||||
8'ha5: begin outa = 10'h185; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha6: begin outa = 10'h37a; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha7: begin outa = 10'h0e0; outb = 2'b01; outc = 1'b1; end
|
||||
8'ha8: begin outa = 10'h0a3; outb = 2'b10; outc = 1'b0; end
|
||||
8'ha9: begin outa = 10'h019; outb = 2'b11; outc = 1'b0; end
|
||||
8'haa: begin outa = 10'h099; outb = 2'b00; outc = 1'b1; end
|
||||
8'hab: begin outa = 10'h376; outb = 2'b01; outc = 1'b1; end
|
||||
8'hac: begin outa = 10'h077; outb = 2'b00; outc = 1'b1; end
|
||||
8'had: begin outa = 10'h2b1; outb = 2'b11; outc = 1'b1; end
|
||||
8'hae: begin outa = 10'h27f; outb = 2'b00; outc = 1'b0; end
|
||||
8'haf: begin outa = 10'h265; outb = 2'b11; outc = 1'b0; end
|
||||
8'hb0: begin outa = 10'h156; outb = 2'b10; outc = 1'b1; end
|
||||
8'hb1: begin outa = 10'h1ce; outb = 2'b00; outc = 1'b0; end
|
||||
8'hb2: begin outa = 10'h008; outb = 2'b01; outc = 1'b0; end
|
||||
8'hb3: begin outa = 10'h12e; outb = 2'b11; outc = 1'b1; end
|
||||
8'hb4: begin outa = 10'h199; outb = 2'b11; outc = 1'b0; end
|
||||
8'hb5: begin outa = 10'h330; outb = 2'b10; outc = 1'b0; end
|
||||
8'hb6: begin outa = 10'h1ab; outb = 2'b01; outc = 1'b1; end
|
||||
8'hb7: begin outa = 10'h3bd; outb = 2'b00; outc = 1'b0; end
|
||||
8'hb8: begin outa = 10'h0ca; outb = 2'b10; outc = 1'b0; end
|
||||
8'hb9: begin outa = 10'h367; outb = 2'b00; outc = 1'b0; end
|
||||
8'hba: begin outa = 10'h334; outb = 2'b00; outc = 1'b0; end
|
||||
8'hbb: begin outa = 10'h040; outb = 2'b00; outc = 1'b1; end
|
||||
8'hbc: begin outa = 10'h1a7; outb = 2'b10; outc = 1'b1; end
|
||||
8'hbd: begin outa = 10'h036; outb = 2'b11; outc = 1'b1; end
|
||||
8'hbe: begin outa = 10'h223; outb = 2'b11; outc = 1'b1; end
|
||||
8'hbf: begin outa = 10'h075; outb = 2'b01; outc = 1'b0; end
|
||||
8'hc0: begin outa = 10'h3c4; outb = 2'b00; outc = 1'b1; end
|
||||
8'hc1: begin outa = 10'h2cc; outb = 2'b01; outc = 1'b0; end
|
||||
8'hc2: begin outa = 10'h123; outb = 2'b01; outc = 1'b0; end
|
||||
8'hc3: begin outa = 10'h3fd; outb = 2'b01; outc = 1'b1; end
|
||||
8'hc4: begin outa = 10'h11e; outb = 2'b00; outc = 1'b0; end
|
||||
8'hc5: begin outa = 10'h27c; outb = 2'b11; outc = 1'b1; end
|
||||
8'hc6: begin outa = 10'h1e2; outb = 2'b11; outc = 1'b0; end
|
||||
8'hc7: begin outa = 10'h377; outb = 2'b11; outc = 1'b0; end
|
||||
8'hc8: begin outa = 10'h33a; outb = 2'b11; outc = 1'b0; end
|
||||
8'hc9: begin outa = 10'h32d; outb = 2'b11; outc = 1'b1; end
|
||||
8'hca: begin outa = 10'h014; outb = 2'b11; outc = 1'b0; end
|
||||
8'hcb: begin outa = 10'h332; outb = 2'b10; outc = 1'b0; end
|
||||
8'hcc: begin outa = 10'h359; outb = 2'b00; outc = 1'b0; end
|
||||
8'hcd: begin outa = 10'h0a4; outb = 2'b10; outc = 1'b1; end
|
||||
8'hce: begin outa = 10'h348; outb = 2'b00; outc = 1'b1; end
|
||||
8'hcf: begin outa = 10'h04b; outb = 2'b11; outc = 1'b1; end
|
||||
8'hd0: begin outa = 10'h147; outb = 2'b10; outc = 1'b1; end
|
||||
8'hd1: begin outa = 10'h026; outb = 2'b00; outc = 1'b1; end
|
||||
8'hd2: begin outa = 10'h103; outb = 2'b00; outc = 1'b0; end
|
||||
8'hd3: begin outa = 10'h106; outb = 2'b00; outc = 1'b1; end
|
||||
8'hd4: begin outa = 10'h35a; outb = 2'b00; outc = 1'b0; end
|
||||
8'hd5: begin outa = 10'h254; outb = 2'b01; outc = 1'b0; end
|
||||
8'hd6: begin outa = 10'h0cd; outb = 2'b01; outc = 1'b0; end
|
||||
8'hd7: begin outa = 10'h17c; outb = 2'b11; outc = 1'b1; end
|
||||
8'hd8: begin outa = 10'h37e; outb = 2'b10; outc = 1'b1; end
|
||||
8'hd9: begin outa = 10'h0a9; outb = 2'b11; outc = 1'b1; end
|
||||
8'hda: begin outa = 10'h0fe; outb = 2'b01; outc = 1'b0; end
|
||||
8'hdb: begin outa = 10'h3c0; outb = 2'b11; outc = 1'b1; end
|
||||
8'hdc: begin outa = 10'h1d9; outb = 2'b10; outc = 1'b1; end
|
||||
8'hdd: begin outa = 10'h10e; outb = 2'b00; outc = 1'b1; end
|
||||
8'hde: begin outa = 10'h394; outb = 2'b01; outc = 1'b0; end
|
||||
8'hdf: begin outa = 10'h316; outb = 2'b01; outc = 1'b0; end
|
||||
8'he0: begin outa = 10'h05b; outb = 2'b11; outc = 1'b0; end
|
||||
8'he1: begin outa = 10'h126; outb = 2'b01; outc = 1'b1; end
|
||||
8'he2: begin outa = 10'h369; outb = 2'b11; outc = 1'b0; end
|
||||
8'he3: begin outa = 10'h291; outb = 2'b10; outc = 1'b1; end
|
||||
8'he4: begin outa = 10'h2ca; outb = 2'b00; outc = 1'b1; end
|
||||
8'he5: begin outa = 10'h25b; outb = 2'b01; outc = 1'b1; end
|
||||
8'he6: begin outa = 10'h106; outb = 2'b00; outc = 1'b0; end
|
||||
8'he7: begin outa = 10'h172; outb = 2'b11; outc = 1'b1; end
|
||||
8'he8: begin outa = 10'h2f7; outb = 2'b00; outc = 1'b1; end
|
||||
8'he9: begin outa = 10'h2d3; outb = 2'b11; outc = 1'b1; end
|
||||
8'hea: begin outa = 10'h182; outb = 2'b00; outc = 1'b0; end
|
||||
8'heb: begin outa = 10'h327; outb = 2'b00; outc = 1'b1; end
|
||||
8'hec: begin outa = 10'h1d0; outb = 2'b10; outc = 1'b0; end
|
||||
8'hed: begin outa = 10'h204; outb = 2'b00; outc = 1'b1; end
|
||||
8'hee: begin outa = 10'h11f; outb = 2'b00; outc = 1'b1; end
|
||||
8'hef: begin outa = 10'h365; outb = 2'b11; outc = 1'b1; end
|
||||
8'hf0: begin outa = 10'h2c2; outb = 2'b01; outc = 1'b1; end
|
||||
8'hf1: begin outa = 10'h2b5; outb = 2'b10; outc = 1'b0; end
|
||||
8'hf2: begin outa = 10'h1f8; outb = 2'b10; outc = 1'b1; end
|
||||
8'hf3: begin outa = 10'h2a7; outb = 2'b01; outc = 1'b1; end
|
||||
8'hf4: begin outa = 10'h1be; outb = 2'b10; outc = 1'b1; end
|
||||
8'hf5: begin outa = 10'h25e; outb = 2'b10; outc = 1'b1; end
|
||||
8'hf6: begin outa = 10'h032; outb = 2'b10; outc = 1'b0; end
|
||||
8'hf7: begin outa = 10'h2ef; outb = 2'b00; outc = 1'b0; end
|
||||
8'hf8: begin outa = 10'h02f; outb = 2'b00; outc = 1'b1; end
|
||||
8'hf9: begin outa = 10'h201; outb = 2'b10; outc = 1'b0; end
|
||||
8'hfa: begin outa = 10'h054; outb = 2'b01; outc = 1'b1; end
|
||||
8'hfb: begin outa = 10'h013; outb = 2'b10; outc = 1'b0; end
|
||||
8'hfc: begin outa = 10'h249; outb = 2'b01; outc = 1'b0; end
|
||||
8'hfd: begin outa = 10'h09a; outb = 2'b10; outc = 1'b0; end
|
||||
8'hfe: begin outa = 10'h012; outb = 2'b00; outc = 1'b0; end
|
||||
8'hff: begin outa = 10'h114; outb = 2'b10; outc = 1'b1; end
|
||||
endcase
|
||||
end
|
||||
always @* begin
|
||||
// verilog_format: off
|
||||
case (index)
|
||||
8'h00: begin outa = 10'h152; outb = 2'b00; outc = 1'b1; end
|
||||
8'h01: begin outa = 10'h318; outb = 2'b11; outc = 1'b1; end
|
||||
8'h02: begin outa = 10'h29f; outb = 2'b11; outc = 1'b0; end
|
||||
8'h03: begin outa = 10'h392; outb = 2'b01; outc = 1'b1; end
|
||||
8'h04: begin outa = 10'h1ef; outb = 2'b00; outc = 1'b0; end
|
||||
8'h05: begin outa = 10'h06c; outb = 2'b10; outc = 1'b1; end
|
||||
8'h06: begin outa = 10'h29f; outb = 2'b11; outc = 1'b0; end
|
||||
8'h07: begin outa = 10'h29a; outb = 2'b10; outc = 1'b0; end
|
||||
8'h08: begin outa = 10'h3ce; outb = 2'b01; outc = 1'b0; end
|
||||
8'h09: begin outa = 10'h37c; outb = 2'b01; outc = 1'b0; end
|
||||
8'h0a: begin outa = 10'h058; outb = 2'b10; outc = 1'b0; end
|
||||
8'h0b: begin outa = 10'h3b2; outb = 2'b01; outc = 1'b1; end
|
||||
8'h0c: begin outa = 10'h36f; outb = 2'b11; outc = 1'b0; end
|
||||
8'h0d: begin outa = 10'h2c5; outb = 2'b11; outc = 1'b0; end
|
||||
8'h0e: begin outa = 10'h23a; outb = 2'b00; outc = 1'b0; end
|
||||
8'h0f: begin outa = 10'h222; outb = 2'b01; outc = 1'b1; end
|
||||
8'h10: begin outa = 10'h328; outb = 2'b00; outc = 1'b1; end
|
||||
8'h11: begin outa = 10'h3c3; outb = 2'b00; outc = 1'b1; end
|
||||
8'h12: begin outa = 10'h12c; outb = 2'b01; outc = 1'b0; end
|
||||
8'h13: begin outa = 10'h1d0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h14: begin outa = 10'h3ff; outb = 2'b01; outc = 1'b1; end
|
||||
8'h15: begin outa = 10'h115; outb = 2'b11; outc = 1'b1; end
|
||||
8'h16: begin outa = 10'h3ba; outb = 2'b10; outc = 1'b0; end
|
||||
8'h17: begin outa = 10'h3ba; outb = 2'b00; outc = 1'b0; end
|
||||
8'h18: begin outa = 10'h10d; outb = 2'b00; outc = 1'b1; end
|
||||
8'h19: begin outa = 10'h13b; outb = 2'b01; outc = 1'b1; end
|
||||
8'h1a: begin outa = 10'h0a0; outb = 2'b10; outc = 1'b1; end
|
||||
8'h1b: begin outa = 10'h264; outb = 2'b11; outc = 1'b0; end
|
||||
8'h1c: begin outa = 10'h3a2; outb = 2'b10; outc = 1'b0; end
|
||||
8'h1d: begin outa = 10'h07c; outb = 2'b00; outc = 1'b1; end
|
||||
8'h1e: begin outa = 10'h291; outb = 2'b00; outc = 1'b0; end
|
||||
8'h1f: begin outa = 10'h1d1; outb = 2'b10; outc = 1'b0; end
|
||||
8'h20: begin outa = 10'h354; outb = 2'b11; outc = 1'b1; end
|
||||
8'h21: begin outa = 10'h0c0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h22: begin outa = 10'h191; outb = 2'b00; outc = 1'b0; end
|
||||
8'h23: begin outa = 10'h379; outb = 2'b01; outc = 1'b0; end
|
||||
8'h24: begin outa = 10'h073; outb = 2'b00; outc = 1'b0; end
|
||||
8'h25: begin outa = 10'h2fd; outb = 2'b11; outc = 1'b1; end
|
||||
8'h26: begin outa = 10'h2e0; outb = 2'b11; outc = 1'b1; end
|
||||
8'h27: begin outa = 10'h337; outb = 2'b01; outc = 1'b1; end
|
||||
8'h28: begin outa = 10'h2c7; outb = 2'b11; outc = 1'b1; end
|
||||
8'h29: begin outa = 10'h19e; outb = 2'b11; outc = 1'b0; end
|
||||
8'h2a: begin outa = 10'h107; outb = 2'b10; outc = 1'b0; end
|
||||
8'h2b: begin outa = 10'h06a; outb = 2'b01; outc = 1'b1; end
|
||||
8'h2c: begin outa = 10'h1c7; outb = 2'b01; outc = 1'b1; end
|
||||
8'h2d: begin outa = 10'h107; outb = 2'b10; outc = 1'b0; end
|
||||
8'h2e: begin outa = 10'h0cf; outb = 2'b01; outc = 1'b1; end
|
||||
8'h2f: begin outa = 10'h009; outb = 2'b11; outc = 1'b1; end
|
||||
8'h30: begin outa = 10'h09d; outb = 2'b00; outc = 1'b1; end
|
||||
8'h31: begin outa = 10'h28e; outb = 2'b00; outc = 1'b0; end
|
||||
8'h32: begin outa = 10'h010; outb = 2'b01; outc = 1'b0; end
|
||||
8'h33: begin outa = 10'h1e0; outb = 2'b10; outc = 1'b0; end
|
||||
8'h34: begin outa = 10'h079; outb = 2'b01; outc = 1'b1; end
|
||||
8'h35: begin outa = 10'h13e; outb = 2'b10; outc = 1'b1; end
|
||||
8'h36: begin outa = 10'h282; outb = 2'b11; outc = 1'b0; end
|
||||
8'h37: begin outa = 10'h21c; outb = 2'b11; outc = 1'b1; end
|
||||
8'h38: begin outa = 10'h148; outb = 2'b00; outc = 1'b1; end
|
||||
8'h39: begin outa = 10'h3c0; outb = 2'b10; outc = 1'b0; end
|
||||
8'h3a: begin outa = 10'h176; outb = 2'b01; outc = 1'b1; end
|
||||
8'h3b: begin outa = 10'h3fc; outb = 2'b10; outc = 1'b1; end
|
||||
8'h3c: begin outa = 10'h295; outb = 2'b11; outc = 1'b1; end
|
||||
8'h3d: begin outa = 10'h113; outb = 2'b10; outc = 1'b1; end
|
||||
8'h3e: begin outa = 10'h354; outb = 2'b01; outc = 1'b1; end
|
||||
8'h3f: begin outa = 10'h0db; outb = 2'b11; outc = 1'b0; end
|
||||
8'h40: begin outa = 10'h238; outb = 2'b01; outc = 1'b0; end
|
||||
8'h41: begin outa = 10'h12b; outb = 2'b01; outc = 1'b1; end
|
||||
8'h42: begin outa = 10'h1dc; outb = 2'b10; outc = 1'b0; end
|
||||
8'h43: begin outa = 10'h137; outb = 2'b01; outc = 1'b1; end
|
||||
8'h44: begin outa = 10'h1e2; outb = 2'b01; outc = 1'b1; end
|
||||
8'h45: begin outa = 10'h3d5; outb = 2'b11; outc = 1'b1; end
|
||||
8'h46: begin outa = 10'h30c; outb = 2'b11; outc = 1'b0; end
|
||||
8'h47: begin outa = 10'h298; outb = 2'b11; outc = 1'b0; end
|
||||
8'h48: begin outa = 10'h080; outb = 2'b00; outc = 1'b1; end
|
||||
8'h49: begin outa = 10'h35a; outb = 2'b11; outc = 1'b1; end
|
||||
8'h4a: begin outa = 10'h01b; outb = 2'b00; outc = 1'b0; end
|
||||
8'h4b: begin outa = 10'h0a3; outb = 2'b11; outc = 1'b0; end
|
||||
8'h4c: begin outa = 10'h0b3; outb = 2'b11; outc = 1'b1; end
|
||||
8'h4d: begin outa = 10'h17a; outb = 2'b00; outc = 1'b0; end
|
||||
8'h4e: begin outa = 10'h3ae; outb = 2'b11; outc = 1'b0; end
|
||||
8'h4f: begin outa = 10'h078; outb = 2'b11; outc = 1'b0; end
|
||||
8'h50: begin outa = 10'h322; outb = 2'b00; outc = 1'b1; end
|
||||
8'h51: begin outa = 10'h213; outb = 2'b11; outc = 1'b0; end
|
||||
8'h52: begin outa = 10'h11a; outb = 2'b11; outc = 1'b0; end
|
||||
8'h53: begin outa = 10'h1a7; outb = 2'b00; outc = 1'b0; end
|
||||
8'h54: begin outa = 10'h35a; outb = 2'b00; outc = 1'b1; end
|
||||
8'h55: begin outa = 10'h233; outb = 2'b00; outc = 1'b0; end
|
||||
8'h56: begin outa = 10'h01d; outb = 2'b01; outc = 1'b1; end
|
||||
8'h57: begin outa = 10'h2d5; outb = 2'b00; outc = 1'b0; end
|
||||
8'h58: begin outa = 10'h1a0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h59: begin outa = 10'h3d0; outb = 2'b00; outc = 1'b1; end
|
||||
8'h5a: begin outa = 10'h181; outb = 2'b01; outc = 1'b1; end
|
||||
8'h5b: begin outa = 10'h219; outb = 2'b01; outc = 1'b1; end
|
||||
8'h5c: begin outa = 10'h26a; outb = 2'b01; outc = 1'b1; end
|
||||
8'h5d: begin outa = 10'h050; outb = 2'b10; outc = 1'b0; end
|
||||
8'h5e: begin outa = 10'h189; outb = 2'b10; outc = 1'b0; end
|
||||
8'h5f: begin outa = 10'h1eb; outb = 2'b01; outc = 1'b1; end
|
||||
8'h60: begin outa = 10'h224; outb = 2'b00; outc = 1'b1; end
|
||||
8'h61: begin outa = 10'h2fe; outb = 2'b00; outc = 1'b0; end
|
||||
8'h62: begin outa = 10'h0ae; outb = 2'b00; outc = 1'b1; end
|
||||
8'h63: begin outa = 10'h1cd; outb = 2'b00; outc = 1'b0; end
|
||||
8'h64: begin outa = 10'h273; outb = 2'b10; outc = 1'b1; end
|
||||
8'h65: begin outa = 10'h268; outb = 2'b10; outc = 1'b0; end
|
||||
8'h66: begin outa = 10'h111; outb = 2'b01; outc = 1'b0; end
|
||||
8'h67: begin outa = 10'h1f9; outb = 2'b00; outc = 1'b0; end
|
||||
8'h68: begin outa = 10'h232; outb = 2'b00; outc = 1'b1; end
|
||||
8'h69: begin outa = 10'h255; outb = 2'b11; outc = 1'b0; end
|
||||
8'h6a: begin outa = 10'h34c; outb = 2'b01; outc = 1'b1; end
|
||||
8'h6b: begin outa = 10'h049; outb = 2'b01; outc = 1'b1; end
|
||||
8'h6c: begin outa = 10'h197; outb = 2'b11; outc = 1'b0; end
|
||||
8'h6d: begin outa = 10'h0fe; outb = 2'b11; outc = 1'b0; end
|
||||
8'h6e: begin outa = 10'h253; outb = 2'b01; outc = 1'b1; end
|
||||
8'h6f: begin outa = 10'h2de; outb = 2'b11; outc = 1'b0; end
|
||||
8'h70: begin outa = 10'h13b; outb = 2'b10; outc = 1'b1; end
|
||||
8'h71: begin outa = 10'h040; outb = 2'b10; outc = 1'b0; end
|
||||
8'h72: begin outa = 10'h0b4; outb = 2'b00; outc = 1'b1; end
|
||||
8'h73: begin outa = 10'h233; outb = 2'b11; outc = 1'b1; end
|
||||
8'h74: begin outa = 10'h198; outb = 2'b00; outc = 1'b1; end
|
||||
8'h75: begin outa = 10'h018; outb = 2'b00; outc = 1'b1; end
|
||||
8'h76: begin outa = 10'h2f7; outb = 2'b00; outc = 1'b1; end
|
||||
8'h77: begin outa = 10'h134; outb = 2'b11; outc = 1'b0; end
|
||||
8'h78: begin outa = 10'h1ca; outb = 2'b10; outc = 1'b0; end
|
||||
8'h79: begin outa = 10'h286; outb = 2'b10; outc = 1'b1; end
|
||||
8'h7a: begin outa = 10'h0e6; outb = 2'b11; outc = 1'b1; end
|
||||
8'h7b: begin outa = 10'h064; outb = 2'b10; outc = 1'b1; end
|
||||
8'h7c: begin outa = 10'h257; outb = 2'b00; outc = 1'b1; end
|
||||
8'h7d: begin outa = 10'h31a; outb = 2'b10; outc = 1'b1; end
|
||||
8'h7e: begin outa = 10'h247; outb = 2'b01; outc = 1'b0; end
|
||||
8'h7f: begin outa = 10'h299; outb = 2'b00; outc = 1'b0; end
|
||||
8'h80: begin outa = 10'h02c; outb = 2'b00; outc = 1'b0; end
|
||||
8'h81: begin outa = 10'h2bb; outb = 2'b11; outc = 1'b0; end
|
||||
8'h82: begin outa = 10'h180; outb = 2'b10; outc = 1'b0; end
|
||||
8'h83: begin outa = 10'h245; outb = 2'b01; outc = 1'b1; end
|
||||
8'h84: begin outa = 10'h0da; outb = 2'b10; outc = 1'b0; end
|
||||
8'h85: begin outa = 10'h367; outb = 2'b10; outc = 1'b0; end
|
||||
8'h86: begin outa = 10'h304; outb = 2'b01; outc = 1'b0; end
|
||||
8'h87: begin outa = 10'h38b; outb = 2'b11; outc = 1'b0; end
|
||||
8'h88: begin outa = 10'h09f; outb = 2'b01; outc = 1'b0; end
|
||||
8'h89: begin outa = 10'h1f0; outb = 2'b10; outc = 1'b1; end
|
||||
8'h8a: begin outa = 10'h281; outb = 2'b10; outc = 1'b1; end
|
||||
8'h8b: begin outa = 10'h019; outb = 2'b00; outc = 1'b0; end
|
||||
8'h8c: begin outa = 10'h1f2; outb = 2'b10; outc = 1'b0; end
|
||||
8'h8d: begin outa = 10'h0b1; outb = 2'b01; outc = 1'b1; end
|
||||
8'h8e: begin outa = 10'h058; outb = 2'b01; outc = 1'b1; end
|
||||
8'h8f: begin outa = 10'h39b; outb = 2'b00; outc = 1'b1; end
|
||||
8'h90: begin outa = 10'h2ec; outb = 2'b10; outc = 1'b1; end
|
||||
8'h91: begin outa = 10'h250; outb = 2'b00; outc = 1'b1; end
|
||||
8'h92: begin outa = 10'h3f4; outb = 2'b10; outc = 1'b1; end
|
||||
8'h93: begin outa = 10'h057; outb = 2'b10; outc = 1'b1; end
|
||||
8'h94: begin outa = 10'h18f; outb = 2'b01; outc = 1'b1; end
|
||||
8'h95: begin outa = 10'h105; outb = 2'b01; outc = 1'b1; end
|
||||
8'h96: begin outa = 10'h1ae; outb = 2'b00; outc = 1'b1; end
|
||||
8'h97: begin outa = 10'h04e; outb = 2'b10; outc = 1'b0; end
|
||||
8'h98: begin outa = 10'h240; outb = 2'b11; outc = 1'b0; end
|
||||
8'h99: begin outa = 10'h3e4; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9a: begin outa = 10'h3c6; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9b: begin outa = 10'h109; outb = 2'b00; outc = 1'b1; end
|
||||
8'h9c: begin outa = 10'h073; outb = 2'b10; outc = 1'b1; end
|
||||
8'h9d: begin outa = 10'h19f; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9e: begin outa = 10'h3b8; outb = 2'b01; outc = 1'b0; end
|
||||
8'h9f: begin outa = 10'h00e; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha0: begin outa = 10'h1b3; outb = 2'b11; outc = 1'b1; end
|
||||
8'ha1: begin outa = 10'h2bd; outb = 2'b11; outc = 1'b0; end
|
||||
8'ha2: begin outa = 10'h324; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha3: begin outa = 10'h343; outb = 2'b10; outc = 1'b0; end
|
||||
8'ha4: begin outa = 10'h1c9; outb = 2'b01; outc = 1'b0; end
|
||||
8'ha5: begin outa = 10'h185; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha6: begin outa = 10'h37a; outb = 2'b00; outc = 1'b1; end
|
||||
8'ha7: begin outa = 10'h0e0; outb = 2'b01; outc = 1'b1; end
|
||||
8'ha8: begin outa = 10'h0a3; outb = 2'b10; outc = 1'b0; end
|
||||
8'ha9: begin outa = 10'h019; outb = 2'b11; outc = 1'b0; end
|
||||
8'haa: begin outa = 10'h099; outb = 2'b00; outc = 1'b1; end
|
||||
8'hab: begin outa = 10'h376; outb = 2'b01; outc = 1'b1; end
|
||||
8'hac: begin outa = 10'h077; outb = 2'b00; outc = 1'b1; end
|
||||
8'had: begin outa = 10'h2b1; outb = 2'b11; outc = 1'b1; end
|
||||
8'hae: begin outa = 10'h27f; outb = 2'b00; outc = 1'b0; end
|
||||
8'haf: begin outa = 10'h265; outb = 2'b11; outc = 1'b0; end
|
||||
8'hb0: begin outa = 10'h156; outb = 2'b10; outc = 1'b1; end
|
||||
8'hb1: begin outa = 10'h1ce; outb = 2'b00; outc = 1'b0; end
|
||||
8'hb2: begin outa = 10'h008; outb = 2'b01; outc = 1'b0; end
|
||||
8'hb3: begin outa = 10'h12e; outb = 2'b11; outc = 1'b1; end
|
||||
8'hb4: begin outa = 10'h199; outb = 2'b11; outc = 1'b0; end
|
||||
8'hb5: begin outa = 10'h330; outb = 2'b10; outc = 1'b0; end
|
||||
8'hb6: begin outa = 10'h1ab; outb = 2'b01; outc = 1'b1; end
|
||||
8'hb7: begin outa = 10'h3bd; outb = 2'b00; outc = 1'b0; end
|
||||
8'hb8: begin outa = 10'h0ca; outb = 2'b10; outc = 1'b0; end
|
||||
8'hb9: begin outa = 10'h367; outb = 2'b00; outc = 1'b0; end
|
||||
8'hba: begin outa = 10'h334; outb = 2'b00; outc = 1'b0; end
|
||||
8'hbb: begin outa = 10'h040; outb = 2'b00; outc = 1'b1; end
|
||||
8'hbc: begin outa = 10'h1a7; outb = 2'b10; outc = 1'b1; end
|
||||
8'hbd: begin outa = 10'h036; outb = 2'b11; outc = 1'b1; end
|
||||
8'hbe: begin outa = 10'h223; outb = 2'b11; outc = 1'b1; end
|
||||
8'hbf: begin outa = 10'h075; outb = 2'b01; outc = 1'b0; end
|
||||
8'hc0: begin outa = 10'h3c4; outb = 2'b00; outc = 1'b1; end
|
||||
8'hc1: begin outa = 10'h2cc; outb = 2'b01; outc = 1'b0; end
|
||||
8'hc2: begin outa = 10'h123; outb = 2'b01; outc = 1'b0; end
|
||||
8'hc3: begin outa = 10'h3fd; outb = 2'b01; outc = 1'b1; end
|
||||
8'hc4: begin outa = 10'h11e; outb = 2'b00; outc = 1'b0; end
|
||||
8'hc5: begin outa = 10'h27c; outb = 2'b11; outc = 1'b1; end
|
||||
8'hc6: begin outa = 10'h1e2; outb = 2'b11; outc = 1'b0; end
|
||||
8'hc7: begin outa = 10'h377; outb = 2'b11; outc = 1'b0; end
|
||||
8'hc8: begin outa = 10'h33a; outb = 2'b11; outc = 1'b0; end
|
||||
8'hc9: begin outa = 10'h32d; outb = 2'b11; outc = 1'b1; end
|
||||
8'hca: begin outa = 10'h014; outb = 2'b11; outc = 1'b0; end
|
||||
8'hcb: begin outa = 10'h332; outb = 2'b10; outc = 1'b0; end
|
||||
8'hcc: begin outa = 10'h359; outb = 2'b00; outc = 1'b0; end
|
||||
8'hcd: begin outa = 10'h0a4; outb = 2'b10; outc = 1'b1; end
|
||||
8'hce: begin outa = 10'h348; outb = 2'b00; outc = 1'b1; end
|
||||
8'hcf: begin outa = 10'h04b; outb = 2'b11; outc = 1'b1; end
|
||||
8'hd0: begin outa = 10'h147; outb = 2'b10; outc = 1'b1; end
|
||||
8'hd1: begin outa = 10'h026; outb = 2'b00; outc = 1'b1; end
|
||||
8'hd2: begin outa = 10'h103; outb = 2'b00; outc = 1'b0; end
|
||||
8'hd3: begin outa = 10'h106; outb = 2'b00; outc = 1'b1; end
|
||||
8'hd4: begin outa = 10'h35a; outb = 2'b00; outc = 1'b0; end
|
||||
8'hd5: begin outa = 10'h254; outb = 2'b01; outc = 1'b0; end
|
||||
8'hd6: begin outa = 10'h0cd; outb = 2'b01; outc = 1'b0; end
|
||||
8'hd7: begin outa = 10'h17c; outb = 2'b11; outc = 1'b1; end
|
||||
8'hd8: begin outa = 10'h37e; outb = 2'b10; outc = 1'b1; end
|
||||
8'hd9: begin outa = 10'h0a9; outb = 2'b11; outc = 1'b1; end
|
||||
8'hda: begin outa = 10'h0fe; outb = 2'b01; outc = 1'b0; end
|
||||
8'hdb: begin outa = 10'h3c0; outb = 2'b11; outc = 1'b1; end
|
||||
8'hdc: begin outa = 10'h1d9; outb = 2'b10; outc = 1'b1; end
|
||||
8'hdd: begin outa = 10'h10e; outb = 2'b00; outc = 1'b1; end
|
||||
8'hde: begin outa = 10'h394; outb = 2'b01; outc = 1'b0; end
|
||||
8'hdf: begin outa = 10'h316; outb = 2'b01; outc = 1'b0; end
|
||||
8'he0: begin outa = 10'h05b; outb = 2'b11; outc = 1'b0; end
|
||||
8'he1: begin outa = 10'h126; outb = 2'b01; outc = 1'b1; end
|
||||
8'he2: begin outa = 10'h369; outb = 2'b11; outc = 1'b0; end
|
||||
8'he3: begin outa = 10'h291; outb = 2'b10; outc = 1'b1; end
|
||||
8'he4: begin outa = 10'h2ca; outb = 2'b00; outc = 1'b1; end
|
||||
8'he5: begin outa = 10'h25b; outb = 2'b01; outc = 1'b1; end
|
||||
8'he6: begin outa = 10'h106; outb = 2'b00; outc = 1'b0; end
|
||||
8'he7: begin outa = 10'h172; outb = 2'b11; outc = 1'b1; end
|
||||
8'he8: begin outa = 10'h2f7; outb = 2'b00; outc = 1'b1; end
|
||||
8'he9: begin outa = 10'h2d3; outb = 2'b11; outc = 1'b1; end
|
||||
8'hea: begin outa = 10'h182; outb = 2'b00; outc = 1'b0; end
|
||||
8'heb: begin outa = 10'h327; outb = 2'b00; outc = 1'b1; end
|
||||
8'hec: begin outa = 10'h1d0; outb = 2'b10; outc = 1'b0; end
|
||||
8'hed: begin outa = 10'h204; outb = 2'b00; outc = 1'b1; end
|
||||
8'hee: begin outa = 10'h11f; outb = 2'b00; outc = 1'b1; end
|
||||
8'hef: begin outa = 10'h365; outb = 2'b11; outc = 1'b1; end
|
||||
8'hf0: begin outa = 10'h2c2; outb = 2'b01; outc = 1'b1; end
|
||||
8'hf1: begin outa = 10'h2b5; outb = 2'b10; outc = 1'b0; end
|
||||
8'hf2: begin outa = 10'h1f8; outb = 2'b10; outc = 1'b1; end
|
||||
8'hf3: begin outa = 10'h2a7; outb = 2'b01; outc = 1'b1; end
|
||||
8'hf4: begin outa = 10'h1be; outb = 2'b10; outc = 1'b1; end
|
||||
8'hf5: begin outa = 10'h25e; outb = 2'b10; outc = 1'b1; end
|
||||
8'hf6: begin outa = 10'h032; outb = 2'b10; outc = 1'b0; end
|
||||
8'hf7: begin outa = 10'h2ef; outb = 2'b00; outc = 1'b0; end
|
||||
8'hf8: begin outa = 10'h02f; outb = 2'b00; outc = 1'b1; end
|
||||
8'hf9: begin outa = 10'h201; outb = 2'b10; outc = 1'b0; end
|
||||
8'hfa: begin outa = 10'h054; outb = 2'b01; outc = 1'b1; end
|
||||
8'hfb: begin outa = 10'h013; outb = 2'b10; outc = 1'b0; end
|
||||
8'hfc: begin outa = 10'h249; outb = 2'b01; outc = 1'b0; end
|
||||
8'hfd: begin outa = 10'h09a; outb = 2'b10; outc = 1'b0; end
|
||||
8'hfe: begin outa = 10'h012; outb = 2'b00; outc = 1'b0; end
|
||||
8'hff: begin outa = 10'h114; outb = 2'b10; outc = 1'b1; end
|
||||
endcase
|
||||
// verilog_format: on
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -5,290 +5,286 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t_case_huge_sub2 (/*AUTOARG*/
|
||||
// Outputs
|
||||
outa,
|
||||
// Inputs
|
||||
index
|
||||
);
|
||||
// Outputs
|
||||
outa,
|
||||
// Inputs
|
||||
index
|
||||
);
|
||||
|
||||
input [9:0] index;
|
||||
output [9:0] outa;
|
||||
input [9:0] index;
|
||||
output logic [9:0] outa;
|
||||
|
||||
// =============================
|
||||
/*AUTOREG*/
|
||||
// Beginning of automatic regs (for this module's undeclared outputs)
|
||||
reg [9:0] outa;
|
||||
// End of automatics
|
||||
// =============================
|
||||
// Created from Python3:
|
||||
// for i in range(1024):
|
||||
// print(" 10'h%03x: begin outa = 10'h%03x; outb = 2'b%d%d; outc = 1'b%d; end"
|
||||
// % (i, random.randint(0,1024), random.randint(0,1),
|
||||
// random.randint(0,1), random.randint(0,1)))
|
||||
|
||||
// =============================
|
||||
// Created from Python3:
|
||||
// for i in range(1024):
|
||||
// print(" 10'h%03x: begin outa = 10'h%03x; outb = 2'b%d%d; outc = 1'b%d; end"
|
||||
// % (i, random.randint(0,1024), random.randint(0,1),
|
||||
// random.randint(0,1), random.randint(0,1)))
|
||||
|
||||
always @(/*AS*/index) begin
|
||||
case (index[7:0])
|
||||
`ifdef VERILATOR // Harder test
|
||||
8'h00: begin outa = $c("0"); end // Makes whole table non-optimizable
|
||||
always @(/*AS*/index) begin
|
||||
case (index[7:0])
|
||||
`ifdef VERILATOR // Harder test
|
||||
8'h00: begin
|
||||
outa = $c("0");
|
||||
end // Makes whole table non-optimizable
|
||||
`else
|
||||
8'h00: begin outa = 10'h0; end
|
||||
8'h00: outa = 10'h0;
|
||||
`endif
|
||||
8'h01: begin outa = 10'h318; end
|
||||
8'h02: begin outa = 10'h29f; end
|
||||
8'h03: begin outa = 10'h392; end
|
||||
8'h04: begin outa = 10'h1ef; end
|
||||
8'h05: begin outa = 10'h06c; end
|
||||
8'h06: begin outa = 10'h29f; end
|
||||
8'h07: begin outa = 10'h29a; end
|
||||
8'h08: begin outa = 10'h3ce; end
|
||||
8'h09: begin outa = 10'h37c; end
|
||||
8'h0a: begin outa = 10'h058; end
|
||||
8'h0b: begin outa = 10'h3b2; end
|
||||
8'h0c: begin outa = 10'h36f; end
|
||||
8'h0d: begin outa = 10'h2c5; end
|
||||
8'h0e: begin outa = 10'h23a; end
|
||||
8'h0f: begin outa = 10'h222; end
|
||||
8'h10: begin outa = 10'h328; end
|
||||
8'h11: begin outa = 10'h3c3; end
|
||||
8'h12: begin outa = 10'h12c; end
|
||||
8'h13: begin outa = 10'h1d0; end
|
||||
8'h14: begin outa = 10'h3ff; end
|
||||
8'h15: begin outa = 10'h115; end
|
||||
8'h16: begin outa = 10'h3ba; end
|
||||
8'h17: begin outa = 10'h3ba; end
|
||||
8'h18: begin outa = 10'h10d; end
|
||||
8'h19: begin outa = 10'h13b; end
|
||||
8'h1a: begin outa = 10'h0a0; end
|
||||
8'h1b: begin outa = 10'h264; end
|
||||
8'h1c: begin outa = 10'h3a2; end
|
||||
8'h1d: begin outa = 10'h07c; end
|
||||
8'h1e: begin outa = 10'h291; end
|
||||
8'h1f: begin outa = 10'h1d1; end
|
||||
8'h20: begin outa = 10'h354; end
|
||||
8'h21: begin outa = 10'h0c0; end
|
||||
8'h22: begin outa = 10'h191; end
|
||||
8'h23: begin outa = 10'h379; end
|
||||
8'h24: begin outa = 10'h073; end
|
||||
8'h25: begin outa = 10'h2fd; end
|
||||
8'h26: begin outa = 10'h2e0; end
|
||||
8'h27: begin outa = 10'h337; end
|
||||
8'h28: begin outa = 10'h2c7; end
|
||||
8'h29: begin outa = 10'h19e; end
|
||||
8'h2a: begin outa = 10'h107; end
|
||||
8'h2b: begin outa = 10'h06a; end
|
||||
8'h2c: begin outa = 10'h1c7; end
|
||||
8'h2d: begin outa = 10'h107; end
|
||||
8'h2e: begin outa = 10'h0cf; end
|
||||
8'h2f: begin outa = 10'h009; end
|
||||
8'h30: begin outa = 10'h09d; end
|
||||
8'h31: begin outa = 10'h28e; end
|
||||
8'h32: begin outa = 10'h010; end
|
||||
8'h33: begin outa = 10'h1e0; end
|
||||
8'h34: begin outa = 10'h079; end
|
||||
8'h35: begin outa = 10'h13e; end
|
||||
8'h36: begin outa = 10'h282; end
|
||||
8'h37: begin outa = 10'h21c; end
|
||||
8'h38: begin outa = 10'h148; end
|
||||
8'h39: begin outa = 10'h3c0; end
|
||||
8'h3a: begin outa = 10'h176; end
|
||||
8'h3b: begin outa = 10'h3fc; end
|
||||
8'h3c: begin outa = 10'h295; end
|
||||
8'h3d: begin outa = 10'h113; end
|
||||
8'h3e: begin outa = 10'h354; end
|
||||
8'h3f: begin outa = 10'h0db; end
|
||||
8'h40: begin outa = 10'h238; end
|
||||
8'h41: begin outa = 10'h12b; end
|
||||
8'h42: begin outa = 10'h1dc; end
|
||||
8'h43: begin outa = 10'h137; end
|
||||
8'h44: begin outa = 10'h1e2; end
|
||||
8'h45: begin outa = 10'h3d5; end
|
||||
8'h46: begin outa = 10'h30c; end
|
||||
8'h47: begin outa = 10'h298; end
|
||||
8'h48: begin outa = 10'h080; end
|
||||
8'h49: begin outa = 10'h35a; end
|
||||
8'h4a: begin outa = 10'h01b; end
|
||||
8'h4b: begin outa = 10'h0a3; end
|
||||
8'h4c: begin outa = 10'h0b3; end
|
||||
8'h4d: begin outa = 10'h17a; end
|
||||
8'h4e: begin outa = 10'h3ae; end
|
||||
8'h4f: begin outa = 10'h078; end
|
||||
8'h50: begin outa = 10'h322; end
|
||||
8'h51: begin outa = 10'h213; end
|
||||
8'h52: begin outa = 10'h11a; end
|
||||
8'h53: begin outa = 10'h1a7; end
|
||||
8'h54: begin outa = 10'h35a; end
|
||||
8'h55: begin outa = 10'h233; end
|
||||
8'h56: begin outa = 10'h01d; end
|
||||
8'h57: begin outa = 10'h2d5; end
|
||||
8'h58: begin outa = 10'h1a0; end
|
||||
8'h59: begin outa = 10'h3d0; end
|
||||
8'h5a: begin outa = 10'h181; end
|
||||
8'h5b: begin outa = 10'h219; end
|
||||
8'h5c: begin outa = 10'h26a; end
|
||||
8'h5d: begin outa = 10'h050; end
|
||||
8'h5e: begin outa = 10'h189; end
|
||||
8'h5f: begin outa = 10'h1eb; end
|
||||
8'h60: begin outa = 10'h224; end
|
||||
8'h61: begin outa = 10'h2fe; end
|
||||
8'h62: begin outa = 10'h0ae; end
|
||||
8'h63: begin outa = 10'h1cd; end
|
||||
8'h64: begin outa = 10'h273; end
|
||||
8'h65: begin outa = 10'h268; end
|
||||
8'h66: begin outa = 10'h111; end
|
||||
8'h67: begin outa = 10'h1f9; end
|
||||
8'h68: begin outa = 10'h232; end
|
||||
8'h69: begin outa = 10'h255; end
|
||||
8'h6a: begin outa = 10'h34c; end
|
||||
8'h6b: begin outa = 10'h049; end
|
||||
8'h6c: begin outa = 10'h197; end
|
||||
8'h6d: begin outa = 10'h0fe; end
|
||||
8'h6e: begin outa = 10'h253; end
|
||||
8'h6f: begin outa = 10'h2de; end
|
||||
8'h70: begin outa = 10'h13b; end
|
||||
8'h71: begin outa = 10'h040; end
|
||||
8'h72: begin outa = 10'h0b4; end
|
||||
8'h73: begin outa = 10'h233; end
|
||||
8'h74: begin outa = 10'h198; end
|
||||
8'h75: begin outa = 10'h018; end
|
||||
8'h76: begin outa = 10'h2f7; end
|
||||
8'h77: begin outa = 10'h134; end
|
||||
8'h78: begin outa = 10'h1ca; end
|
||||
8'h79: begin outa = 10'h286; end
|
||||
8'h7a: begin outa = 10'h0e6; end
|
||||
8'h7b: begin outa = 10'h064; end
|
||||
8'h7c: begin outa = 10'h257; end
|
||||
8'h7d: begin outa = 10'h31a; end
|
||||
8'h7e: begin outa = 10'h247; end
|
||||
8'h7f: begin outa = 10'h299; end
|
||||
8'h80: begin outa = 10'h02c; end
|
||||
8'h81: begin outa = 10'h2bb; end
|
||||
8'h82: begin outa = 10'h180; end
|
||||
8'h83: begin outa = 10'h245; end
|
||||
8'h84: begin outa = 10'h0da; end
|
||||
8'h85: begin outa = 10'h367; end
|
||||
8'h86: begin outa = 10'h304; end
|
||||
8'h87: begin outa = 10'h38b; end
|
||||
8'h88: begin outa = 10'h09f; end
|
||||
8'h89: begin outa = 10'h1f0; end
|
||||
8'h8a: begin outa = 10'h281; end
|
||||
8'h8b: begin outa = 10'h019; end
|
||||
8'h8c: begin outa = 10'h1f2; end
|
||||
8'h8d: begin outa = 10'h0b1; end
|
||||
8'h8e: begin outa = 10'h058; end
|
||||
8'h8f: begin outa = 10'h39b; end
|
||||
8'h90: begin outa = 10'h2ec; end
|
||||
8'h91: begin outa = 10'h250; end
|
||||
8'h92: begin outa = 10'h3f4; end
|
||||
8'h93: begin outa = 10'h057; end
|
||||
8'h94: begin outa = 10'h18f; end
|
||||
8'h95: begin outa = 10'h105; end
|
||||
8'h96: begin outa = 10'h1ae; end
|
||||
8'h97: begin outa = 10'h04e; end
|
||||
8'h98: begin outa = 10'h240; end
|
||||
8'h99: begin outa = 10'h3e4; end
|
||||
8'h9a: begin outa = 10'h3c6; end
|
||||
8'h9b: begin outa = 10'h109; end
|
||||
8'h9c: begin outa = 10'h073; end
|
||||
8'h9d: begin outa = 10'h19f; end
|
||||
8'h9e: begin outa = 10'h3b8; end
|
||||
8'h9f: begin outa = 10'h00e; end
|
||||
8'ha0: begin outa = 10'h1b3; end
|
||||
8'ha1: begin outa = 10'h2bd; end
|
||||
8'ha2: begin outa = 10'h324; end
|
||||
8'ha3: begin outa = 10'h343; end
|
||||
8'ha4: begin outa = 10'h1c9; end
|
||||
8'ha5: begin outa = 10'h185; end
|
||||
8'ha6: begin outa = 10'h37a; end
|
||||
8'ha7: begin outa = 10'h0e0; end
|
||||
8'ha8: begin outa = 10'h0a3; end
|
||||
8'ha9: begin outa = 10'h019; end
|
||||
8'haa: begin outa = 10'h099; end
|
||||
8'hab: begin outa = 10'h376; end
|
||||
8'hac: begin outa = 10'h077; end
|
||||
8'had: begin outa = 10'h2b1; end
|
||||
8'hae: begin outa = 10'h27f; end
|
||||
8'haf: begin outa = 10'h265; end
|
||||
8'hb0: begin outa = 10'h156; end
|
||||
8'hb1: begin outa = 10'h1ce; end
|
||||
8'hb2: begin outa = 10'h008; end
|
||||
8'hb3: begin outa = 10'h12e; end
|
||||
8'hb4: begin outa = 10'h199; end
|
||||
8'hb5: begin outa = 10'h330; end
|
||||
8'hb6: begin outa = 10'h1ab; end
|
||||
8'hb7: begin outa = 10'h3bd; end
|
||||
8'hb8: begin outa = 10'h0ca; end
|
||||
8'hb9: begin outa = 10'h367; end
|
||||
8'hba: begin outa = 10'h334; end
|
||||
8'hbb: begin outa = 10'h040; end
|
||||
8'hbc: begin outa = 10'h1a7; end
|
||||
8'hbd: begin outa = 10'h036; end
|
||||
8'hbe: begin outa = 10'h223; end
|
||||
8'hbf: begin outa = 10'h075; end
|
||||
8'hc0: begin outa = 10'h3c4; end
|
||||
8'hc1: begin outa = 10'h2cc; end
|
||||
8'hc2: begin outa = 10'h123; end
|
||||
8'hc3: begin outa = 10'h3fd; end
|
||||
8'hc4: begin outa = 10'h11e; end
|
||||
8'hc5: begin outa = 10'h27c; end
|
||||
8'hc6: begin outa = 10'h1e2; end
|
||||
8'hc7: begin outa = 10'h377; end
|
||||
8'hc8: begin outa = 10'h33a; end
|
||||
8'hc9: begin outa = 10'h32d; end
|
||||
8'hca: begin outa = 10'h014; end
|
||||
8'hcb: begin outa = 10'h332; end
|
||||
8'hcc: begin outa = 10'h359; end
|
||||
8'hcd: begin outa = 10'h0a4; end
|
||||
8'hce: begin outa = 10'h348; end
|
||||
8'hcf: begin outa = 10'h04b; end
|
||||
8'hd0: begin outa = 10'h147; end
|
||||
8'hd1: begin outa = 10'h026; end
|
||||
8'hd2: begin outa = 10'h103; end
|
||||
8'hd3: begin outa = 10'h106; end
|
||||
8'hd4: begin outa = 10'h35a; end
|
||||
8'hd5: begin outa = 10'h254; end
|
||||
8'hd6: begin outa = 10'h0cd; end
|
||||
8'hd7: begin outa = 10'h17c; end
|
||||
8'hd8: begin outa = 10'h37e; end
|
||||
8'hd9: begin outa = 10'h0a9; end
|
||||
8'hda: begin outa = 10'h0fe; end
|
||||
8'hdb: begin outa = 10'h3c0; end
|
||||
8'hdc: begin outa = 10'h1d9; end
|
||||
8'hdd: begin outa = 10'h10e; end
|
||||
8'hde: begin outa = 10'h394; end
|
||||
8'hdf: begin outa = 10'h316; end
|
||||
8'he0: begin outa = 10'h05b; end
|
||||
8'he1: begin outa = 10'h126; end
|
||||
8'he2: begin outa = 10'h369; end
|
||||
8'he3: begin outa = 10'h291; end
|
||||
8'he4: begin outa = 10'h2ca; end
|
||||
8'he5: begin outa = 10'h25b; end
|
||||
8'he6: begin outa = 10'h106; end
|
||||
8'he7: begin outa = 10'h172; end
|
||||
8'he8: begin outa = 10'h2f7; end
|
||||
8'he9: begin outa = 10'h2d3; end
|
||||
8'hea: begin outa = 10'h182; end
|
||||
8'heb: begin outa = 10'h327; end
|
||||
8'hec: begin outa = 10'h1d0; end
|
||||
8'hed: begin outa = 10'h204; end
|
||||
8'hee: begin outa = 10'h11f; end
|
||||
8'hef: begin outa = 10'h365; end
|
||||
8'hf0: begin outa = 10'h2c2; end
|
||||
8'hf1: begin outa = 10'h2b5; end
|
||||
8'hf2: begin outa = 10'h1f8; end
|
||||
8'hf3: begin outa = 10'h2a7; end
|
||||
8'hf4: begin outa = 10'h1be; end
|
||||
8'hf5: begin outa = 10'h25e; end
|
||||
8'hf6: begin outa = 10'h032; end
|
||||
8'hf7: begin outa = 10'h2ef; end
|
||||
8'hf8: begin outa = 10'h02f; end
|
||||
8'hf9: begin outa = 10'h201; end
|
||||
8'hfa: begin outa = 10'h054; end
|
||||
8'hfb: begin outa = 10'h013; end
|
||||
8'hfc: begin outa = 10'h249; end
|
||||
8'hfd: begin outa = 10'h09a; end
|
||||
8'hfe: begin outa = 10'h012; end
|
||||
8'hff: begin outa = 10'h114; end
|
||||
endcase
|
||||
end
|
||||
8'h01: outa = 10'h318;
|
||||
8'h02: outa = 10'h29f;
|
||||
8'h03: outa = 10'h392;
|
||||
8'h04: outa = 10'h1ef;
|
||||
8'h05: outa = 10'h06c;
|
||||
8'h06: outa = 10'h29f;
|
||||
8'h07: outa = 10'h29a;
|
||||
8'h08: outa = 10'h3ce;
|
||||
8'h09: outa = 10'h37c;
|
||||
8'h0a: outa = 10'h058;
|
||||
8'h0b: outa = 10'h3b2;
|
||||
8'h0c: outa = 10'h36f;
|
||||
8'h0d: outa = 10'h2c5;
|
||||
8'h0e: outa = 10'h23a;
|
||||
8'h0f: outa = 10'h222;
|
||||
8'h10: outa = 10'h328;
|
||||
8'h11: outa = 10'h3c3;
|
||||
8'h12: outa = 10'h12c;
|
||||
8'h13: outa = 10'h1d0;
|
||||
8'h14: outa = 10'h3ff;
|
||||
8'h15: outa = 10'h115;
|
||||
8'h16: outa = 10'h3ba;
|
||||
8'h17: outa = 10'h3ba;
|
||||
8'h18: outa = 10'h10d;
|
||||
8'h19: outa = 10'h13b;
|
||||
8'h1a: outa = 10'h0a0;
|
||||
8'h1b: outa = 10'h264;
|
||||
8'h1c: outa = 10'h3a2;
|
||||
8'h1d: outa = 10'h07c;
|
||||
8'h1e: outa = 10'h291;
|
||||
8'h1f: outa = 10'h1d1;
|
||||
8'h20: outa = 10'h354;
|
||||
8'h21: outa = 10'h0c0;
|
||||
8'h22: outa = 10'h191;
|
||||
8'h23: outa = 10'h379;
|
||||
8'h24: outa = 10'h073;
|
||||
8'h25: outa = 10'h2fd;
|
||||
8'h26: outa = 10'h2e0;
|
||||
8'h27: outa = 10'h337;
|
||||
8'h28: outa = 10'h2c7;
|
||||
8'h29: outa = 10'h19e;
|
||||
8'h2a: outa = 10'h107;
|
||||
8'h2b: outa = 10'h06a;
|
||||
8'h2c: outa = 10'h1c7;
|
||||
8'h2d: outa = 10'h107;
|
||||
8'h2e: outa = 10'h0cf;
|
||||
8'h2f: outa = 10'h009;
|
||||
8'h30: outa = 10'h09d;
|
||||
8'h31: outa = 10'h28e;
|
||||
8'h32: outa = 10'h010;
|
||||
8'h33: outa = 10'h1e0;
|
||||
8'h34: outa = 10'h079;
|
||||
8'h35: outa = 10'h13e;
|
||||
8'h36: outa = 10'h282;
|
||||
8'h37: outa = 10'h21c;
|
||||
8'h38: outa = 10'h148;
|
||||
8'h39: outa = 10'h3c0;
|
||||
8'h3a: outa = 10'h176;
|
||||
8'h3b: outa = 10'h3fc;
|
||||
8'h3c: outa = 10'h295;
|
||||
8'h3d: outa = 10'h113;
|
||||
8'h3e: outa = 10'h354;
|
||||
8'h3f: outa = 10'h0db;
|
||||
8'h40: outa = 10'h238;
|
||||
8'h41: outa = 10'h12b;
|
||||
8'h42: outa = 10'h1dc;
|
||||
8'h43: outa = 10'h137;
|
||||
8'h44: outa = 10'h1e2;
|
||||
8'h45: outa = 10'h3d5;
|
||||
8'h46: outa = 10'h30c;
|
||||
8'h47: outa = 10'h298;
|
||||
8'h48: outa = 10'h080;
|
||||
8'h49: outa = 10'h35a;
|
||||
8'h4a: outa = 10'h01b;
|
||||
8'h4b: outa = 10'h0a3;
|
||||
8'h4c: outa = 10'h0b3;
|
||||
8'h4d: outa = 10'h17a;
|
||||
8'h4e: outa = 10'h3ae;
|
||||
8'h4f: outa = 10'h078;
|
||||
8'h50: outa = 10'h322;
|
||||
8'h51: outa = 10'h213;
|
||||
8'h52: outa = 10'h11a;
|
||||
8'h53: outa = 10'h1a7;
|
||||
8'h54: outa = 10'h35a;
|
||||
8'h55: outa = 10'h233;
|
||||
8'h56: outa = 10'h01d;
|
||||
8'h57: outa = 10'h2d5;
|
||||
8'h58: outa = 10'h1a0;
|
||||
8'h59: outa = 10'h3d0;
|
||||
8'h5a: outa = 10'h181;
|
||||
8'h5b: outa = 10'h219;
|
||||
8'h5c: outa = 10'h26a;
|
||||
8'h5d: outa = 10'h050;
|
||||
8'h5e: outa = 10'h189;
|
||||
8'h5f: outa = 10'h1eb;
|
||||
8'h60: outa = 10'h224;
|
||||
8'h61: outa = 10'h2fe;
|
||||
8'h62: outa = 10'h0ae;
|
||||
8'h63: outa = 10'h1cd;
|
||||
8'h64: outa = 10'h273;
|
||||
8'h65: outa = 10'h268;
|
||||
8'h66: outa = 10'h111;
|
||||
8'h67: outa = 10'h1f9;
|
||||
8'h68: outa = 10'h232;
|
||||
8'h69: outa = 10'h255;
|
||||
8'h6a: outa = 10'h34c;
|
||||
8'h6b: outa = 10'h049;
|
||||
8'h6c: outa = 10'h197;
|
||||
8'h6d: outa = 10'h0fe;
|
||||
8'h6e: outa = 10'h253;
|
||||
8'h6f: outa = 10'h2de;
|
||||
8'h70: outa = 10'h13b;
|
||||
8'h71: outa = 10'h040;
|
||||
8'h72: outa = 10'h0b4;
|
||||
8'h73: outa = 10'h233;
|
||||
8'h74: outa = 10'h198;
|
||||
8'h75: outa = 10'h018;
|
||||
8'h76: outa = 10'h2f7;
|
||||
8'h77: outa = 10'h134;
|
||||
8'h78: outa = 10'h1ca;
|
||||
8'h79: outa = 10'h286;
|
||||
8'h7a: outa = 10'h0e6;
|
||||
8'h7b: outa = 10'h064;
|
||||
8'h7c: outa = 10'h257;
|
||||
8'h7d: outa = 10'h31a;
|
||||
8'h7e: outa = 10'h247;
|
||||
8'h7f: outa = 10'h299;
|
||||
8'h80: outa = 10'h02c;
|
||||
8'h81: outa = 10'h2bb;
|
||||
8'h82: outa = 10'h180;
|
||||
8'h83: outa = 10'h245;
|
||||
8'h84: outa = 10'h0da;
|
||||
8'h85: outa = 10'h367;
|
||||
8'h86: outa = 10'h304;
|
||||
8'h87: outa = 10'h38b;
|
||||
8'h88: outa = 10'h09f;
|
||||
8'h89: outa = 10'h1f0;
|
||||
8'h8a: outa = 10'h281;
|
||||
8'h8b: outa = 10'h019;
|
||||
8'h8c: outa = 10'h1f2;
|
||||
8'h8d: outa = 10'h0b1;
|
||||
8'h8e: outa = 10'h058;
|
||||
8'h8f: outa = 10'h39b;
|
||||
8'h90: outa = 10'h2ec;
|
||||
8'h91: outa = 10'h250;
|
||||
8'h92: outa = 10'h3f4;
|
||||
8'h93: outa = 10'h057;
|
||||
8'h94: outa = 10'h18f;
|
||||
8'h95: outa = 10'h105;
|
||||
8'h96: outa = 10'h1ae;
|
||||
8'h97: outa = 10'h04e;
|
||||
8'h98: outa = 10'h240;
|
||||
8'h99: outa = 10'h3e4;
|
||||
8'h9a: outa = 10'h3c6;
|
||||
8'h9b: outa = 10'h109;
|
||||
8'h9c: outa = 10'h073;
|
||||
8'h9d: outa = 10'h19f;
|
||||
8'h9e: outa = 10'h3b8;
|
||||
8'h9f: outa = 10'h00e;
|
||||
8'ha0: outa = 10'h1b3;
|
||||
8'ha1: outa = 10'h2bd;
|
||||
8'ha2: outa = 10'h324;
|
||||
8'ha3: outa = 10'h343;
|
||||
8'ha4: outa = 10'h1c9;
|
||||
8'ha5: outa = 10'h185;
|
||||
8'ha6: outa = 10'h37a;
|
||||
8'ha7: outa = 10'h0e0;
|
||||
8'ha8: outa = 10'h0a3;
|
||||
8'ha9: outa = 10'h019;
|
||||
8'haa: outa = 10'h099;
|
||||
8'hab: outa = 10'h376;
|
||||
8'hac: outa = 10'h077;
|
||||
8'had: outa = 10'h2b1;
|
||||
8'hae: outa = 10'h27f;
|
||||
8'haf: outa = 10'h265;
|
||||
8'hb0: outa = 10'h156;
|
||||
8'hb1: outa = 10'h1ce;
|
||||
8'hb2: outa = 10'h008;
|
||||
8'hb3: outa = 10'h12e;
|
||||
8'hb4: outa = 10'h199;
|
||||
8'hb5: outa = 10'h330;
|
||||
8'hb6: outa = 10'h1ab;
|
||||
8'hb7: outa = 10'h3bd;
|
||||
8'hb8: outa = 10'h0ca;
|
||||
8'hb9: outa = 10'h367;
|
||||
8'hba: outa = 10'h334;
|
||||
8'hbb: outa = 10'h040;
|
||||
8'hbc: outa = 10'h1a7;
|
||||
8'hbd: outa = 10'h036;
|
||||
8'hbe: outa = 10'h223;
|
||||
8'hbf: outa = 10'h075;
|
||||
8'hc0: outa = 10'h3c4;
|
||||
8'hc1: outa = 10'h2cc;
|
||||
8'hc2: outa = 10'h123;
|
||||
8'hc3: outa = 10'h3fd;
|
||||
8'hc4: outa = 10'h11e;
|
||||
8'hc5: outa = 10'h27c;
|
||||
8'hc6: outa = 10'h1e2;
|
||||
8'hc7: outa = 10'h377;
|
||||
8'hc8: outa = 10'h33a;
|
||||
8'hc9: outa = 10'h32d;
|
||||
8'hca: outa = 10'h014;
|
||||
8'hcb: outa = 10'h332;
|
||||
8'hcc: outa = 10'h359;
|
||||
8'hcd: outa = 10'h0a4;
|
||||
8'hce: outa = 10'h348;
|
||||
8'hcf: outa = 10'h04b;
|
||||
8'hd0: outa = 10'h147;
|
||||
8'hd1: outa = 10'h026;
|
||||
8'hd2: outa = 10'h103;
|
||||
8'hd3: outa = 10'h106;
|
||||
8'hd4: outa = 10'h35a;
|
||||
8'hd5: outa = 10'h254;
|
||||
8'hd6: outa = 10'h0cd;
|
||||
8'hd7: outa = 10'h17c;
|
||||
8'hd8: outa = 10'h37e;
|
||||
8'hd9: outa = 10'h0a9;
|
||||
8'hda: outa = 10'h0fe;
|
||||
8'hdb: outa = 10'h3c0;
|
||||
8'hdc: outa = 10'h1d9;
|
||||
8'hdd: outa = 10'h10e;
|
||||
8'hde: outa = 10'h394;
|
||||
8'hdf: outa = 10'h316;
|
||||
8'he0: outa = 10'h05b;
|
||||
8'he1: outa = 10'h126;
|
||||
8'he2: outa = 10'h369;
|
||||
8'he3: outa = 10'h291;
|
||||
8'he4: outa = 10'h2ca;
|
||||
8'he5: outa = 10'h25b;
|
||||
8'he6: outa = 10'h106;
|
||||
8'he7: outa = 10'h172;
|
||||
8'he8: outa = 10'h2f7;
|
||||
8'he9: outa = 10'h2d3;
|
||||
8'hea: outa = 10'h182;
|
||||
8'heb: outa = 10'h327;
|
||||
8'hec: outa = 10'h1d0;
|
||||
8'hed: outa = 10'h204;
|
||||
8'hee: outa = 10'h11f;
|
||||
8'hef: outa = 10'h365;
|
||||
8'hf0: outa = 10'h2c2;
|
||||
8'hf1: outa = 10'h2b5;
|
||||
8'hf2: outa = 10'h1f8;
|
||||
8'hf3: outa = 10'h2a7;
|
||||
8'hf4: outa = 10'h1be;
|
||||
8'hf5: outa = 10'h25e;
|
||||
8'hf6: outa = 10'h032;
|
||||
8'hf7: outa = 10'h2ef;
|
||||
8'hf8: outa = 10'h02f;
|
||||
8'hf9: outa = 10'h201;
|
||||
8'hfa: outa = 10'h054;
|
||||
8'hfb: outa = 10'h013;
|
||||
8'hfc: outa = 10'h249;
|
||||
8'hfd: outa = 10'h09a;
|
||||
8'hfe: outa = 10'h012;
|
||||
8'hff: outa = 10'h114;
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -5,289 +5,285 @@
|
|||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t_case_huge_sub3 (/*AUTOARG*/
|
||||
// Outputs
|
||||
outr,
|
||||
// Inputs
|
||||
clk, index
|
||||
);
|
||||
// Outputs
|
||||
outr,
|
||||
// Inputs
|
||||
clk, index
|
||||
);
|
||||
|
||||
input clk;
|
||||
input [9:0] index;
|
||||
output [3:0] outr;
|
||||
input clk;
|
||||
input [9:0] index;
|
||||
output logic [3:0] outr;
|
||||
|
||||
// =============================
|
||||
/*AUTOREG*/
|
||||
// Beginning of automatic regs (for this module's undeclared outputs)
|
||||
reg [3:0] outr;
|
||||
// End of automatics
|
||||
// =============================
|
||||
// Created from Pthon3:
|
||||
// for i in range(256):
|
||||
// print(" 8'h%02x: begin outr <= outr^index[8:5]^4'h%01x; end"
|
||||
// % (i, random.randint(0,15)))
|
||||
|
||||
// =============================
|
||||
// Created from Pthon3:
|
||||
// for i in range(256):
|
||||
// print(" 8'h%02x: begin outr <= outr^index[8:5]^4'h%01x; end"
|
||||
// % (i, random.randint(0,15)))
|
||||
// Reset cheating
|
||||
initial outr = 4'b0;
|
||||
|
||||
// Reset cheating
|
||||
initial outr = 4'b0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
case (index[7:0])
|
||||
8'h00: begin outr <= 4'h0; end
|
||||
8'h01: begin /*No Change*/ end
|
||||
8'h02: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h03: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h04: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h05: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h06: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h07: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h08: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h09: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h0a: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h0b: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h0c: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h0d: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h0e: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h0f: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h10: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h11: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h12: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h13: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h14: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h15: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h16: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h17: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h18: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h19: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h1a: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h1b: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h1c: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h1d: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h1e: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h1f: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h20: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h21: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h22: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h23: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h24: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h25: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h26: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h27: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h28: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h29: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h2a: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h2b: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h2c: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h2d: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h2e: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h2f: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h30: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h31: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h32: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h33: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h34: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h35: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h36: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h37: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h38: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h39: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h3a: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h3b: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h3c: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h3d: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h3e: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h3f: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h40: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h41: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h42: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h43: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h44: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h45: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h46: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h47: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h48: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h49: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h4a: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h4b: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h4c: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h4d: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h4e: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h4f: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h50: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h51: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h52: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h53: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h54: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h55: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h56: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h57: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h58: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h59: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h5a: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h5b: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h5c: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h5d: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h5e: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h5f: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h60: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h61: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h62: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h63: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h64: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h65: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h66: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h67: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h68: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h69: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h6a: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h6b: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h6c: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h6d: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h6e: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h6f: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h70: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h71: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h72: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h73: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h74: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h75: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h76: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h77: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h78: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h79: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h7a: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h7b: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h7c: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h7d: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h7e: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h7f: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h80: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h81: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h82: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h83: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h84: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h85: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h86: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h87: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h88: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h89: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h8a: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h8b: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h8c: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h8d: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h8e: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h8f: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h90: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h91: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h92: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h93: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h94: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h95: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h96: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h97: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h98: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h99: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h9a: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h9b: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h9c: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h9d: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h9e: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h9f: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'ha0: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'ha1: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'ha2: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'ha3: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'ha4: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'ha5: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'ha6: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'ha7: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'ha8: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'ha9: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'haa: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hab: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hac: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'had: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hae: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'haf: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hb0: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hb1: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'hb2: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hb3: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hb4: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hb5: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'hb6: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hb7: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hb8: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hb9: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hba: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'hbb: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hbc: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hbd: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hbe: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'hbf: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hc0: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hc1: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hc2: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hc3: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hc4: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hc5: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hc6: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hc7: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hc8: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hc9: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hca: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'hcb: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hcc: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hcd: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hce: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hcf: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hd0: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hd1: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hd2: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hd3: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hd4: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hd5: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hd6: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hd7: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hd8: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hd9: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hda: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hdb: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'hdc: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hdd: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hde: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hdf: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'he0: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'he1: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'he2: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'he3: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'he4: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'he5: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'he6: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'he7: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'he8: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'he9: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hea: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'heb: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hec: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'hed: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hee: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hef: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hf0: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hf1: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hf2: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'hf3: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hf4: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hf5: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hf6: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hf7: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'hf8: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hf9: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hfa: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hfb: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'hfc: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hfd: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hfe: begin outr <= outr^index[8:5]^4'h1; end
|
||||
default: begin outr <= outr^index[8:5]^4'h6; end
|
||||
endcase
|
||||
end
|
||||
always @(posedge clk) begin
|
||||
// verilog_format: off
|
||||
case (index[7:0])
|
||||
8'h00: begin outr <= 4'h0; end
|
||||
8'h01: begin /*No Change*/ end
|
||||
8'h02: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h03: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h04: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h05: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h06: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h07: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h08: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h09: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h0a: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h0b: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h0c: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h0d: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h0e: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h0f: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h10: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h11: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h12: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h13: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h14: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h15: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h16: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h17: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h18: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h19: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h1a: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h1b: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h1c: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h1d: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h1e: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h1f: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h20: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h21: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h22: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h23: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h24: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h25: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h26: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h27: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h28: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h29: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h2a: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h2b: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h2c: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h2d: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h2e: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h2f: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h30: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h31: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h32: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h33: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h34: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h35: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h36: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h37: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h38: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h39: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h3a: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h3b: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h3c: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h3d: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h3e: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h3f: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h40: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h41: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h42: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h43: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h44: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h45: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h46: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h47: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h48: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h49: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h4a: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h4b: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h4c: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h4d: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h4e: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h4f: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h50: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h51: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h52: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h53: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h54: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h55: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h56: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h57: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h58: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h59: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h5a: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h5b: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h5c: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h5d: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h5e: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h5f: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h60: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h61: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h62: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h63: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h64: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h65: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h66: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h67: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h68: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h69: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h6a: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h6b: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h6c: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h6d: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h6e: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h6f: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h70: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h71: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h72: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h73: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h74: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h75: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h76: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h77: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h78: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h79: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h7a: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'h7b: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h7c: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h7d: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h7e: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h7f: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h80: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h81: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h82: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h83: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h84: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h85: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'h86: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h87: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'h88: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'h89: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'h8a: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h8b: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'h8c: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h8d: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h8e: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'h8f: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'h90: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h91: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h92: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h93: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h94: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h95: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'h96: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'h97: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h98: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'h99: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'h9a: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'h9b: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h9c: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'h9d: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'h9e: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'h9f: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'ha0: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'ha1: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'ha2: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'ha3: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'ha4: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'ha5: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'ha6: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'ha7: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'ha8: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'ha9: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'haa: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hab: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hac: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'had: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hae: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'haf: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hb0: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hb1: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'hb2: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hb3: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hb4: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hb5: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'hb6: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hb7: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hb8: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hb9: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hba: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'hbb: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hbc: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hbd: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hbe: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'hbf: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hc0: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hc1: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hc2: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hc3: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hc4: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hc5: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hc6: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hc7: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hc8: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hc9: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hca: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'hcb: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hcc: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hcd: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hce: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hcf: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hd0: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hd1: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hd2: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hd3: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hd4: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hd5: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hd6: begin outr <= outr^index[8:5]^4'hb; end
|
||||
8'hd7: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'hd8: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hd9: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hda: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hdb: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'hdc: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hdd: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hde: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hdf: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'he0: begin outr <= outr^index[8:5]^4'h7; end
|
||||
8'he1: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'he2: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'he3: begin outr <= outr^index[8:5]^4'h3; end
|
||||
8'he4: begin outr <= outr^index[8:5]^4'h2; end
|
||||
8'he5: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'he6: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'he7: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'he8: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'he9: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hea: begin outr <= outr^index[8:5]^4'hc; end
|
||||
8'heb: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hec: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'hed: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hee: begin outr <= outr^index[8:5]^4'h9; end
|
||||
8'hef: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hf0: begin outr <= outr^index[8:5]^4'hd; end
|
||||
8'hf1: begin outr <= outr^index[8:5]^4'hf; end
|
||||
8'hf2: begin outr <= outr^index[8:5]^4'h4; end
|
||||
8'hf3: begin outr <= outr^index[8:5]^4'ha; end
|
||||
8'hf4: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hf5: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hf6: begin outr <= outr^index[8:5]^4'he; end
|
||||
8'hf7: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'hf8: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hf9: begin outr <= outr^index[8:5]^4'h0; end
|
||||
8'hfa: begin outr <= outr^index[8:5]^4'h5; end
|
||||
8'hfb: begin outr <= outr^index[8:5]^4'h1; end
|
||||
8'hfc: begin outr <= outr^index[8:5]^4'h8; end
|
||||
8'hfd: begin outr <= outr^index[8:5]^4'h6; end
|
||||
8'hfe: begin outr <= outr^index[8:5]^4'h1; end
|
||||
default: begin outr <= outr^index[8:5]^4'h6; end
|
||||
endcase
|
||||
// verilog_format: on
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -7,59 +7,56 @@
|
|||
// verilator lint_off LATCH
|
||||
|
||||
module t_case_huge_sub4 (/*AUTOARG*/
|
||||
// Outputs
|
||||
outq,
|
||||
// Inputs
|
||||
index
|
||||
);
|
||||
// Outputs
|
||||
outq,
|
||||
// Inputs
|
||||
index
|
||||
);
|
||||
|
||||
input [7:0] index;
|
||||
output [9:0] outq;
|
||||
input [7:0] index;
|
||||
output logic [9:0] outq;
|
||||
|
||||
// =============================
|
||||
/*AUTOREG*/
|
||||
// Beginning of automatic regs (for this module's undeclared outputs)
|
||||
reg [9:0] outq;
|
||||
// End of automatics
|
||||
// =============================
|
||||
|
||||
// =============================
|
||||
always @(/*AS*/index) begin
|
||||
case (index)
|
||||
// default below: no change
|
||||
8'h00: begin outq = 10'h001; end
|
||||
8'he0: begin outq = 10'h05b; end
|
||||
8'he1: begin outq = 10'h126; end
|
||||
8'he2: begin outq = 10'h369; end
|
||||
8'he3: begin outq = 10'h291; end
|
||||
8'he4: begin outq = 10'h2ca; end
|
||||
8'he5: begin outq = 10'h25b; end
|
||||
8'he6: begin outq = 10'h106; end
|
||||
8'he7: begin outq = 10'h172; end
|
||||
8'he8: begin outq = 10'h2f7; end
|
||||
8'he9: begin outq = 10'h2d3; end
|
||||
8'hea: begin outq = 10'h182; end
|
||||
8'heb: begin outq = 10'h327; end
|
||||
8'hec: begin outq = 10'h1d0; end
|
||||
8'hed: begin outq = 10'h204; end
|
||||
8'hee: begin outq = 10'h11f; end
|
||||
8'hef: begin outq = 10'h365; end
|
||||
8'hf0: begin outq = 10'h2c2; end
|
||||
8'hf1: begin outq = 10'h2b5; end
|
||||
8'hf2: begin outq = 10'h1f8; end
|
||||
8'hf3: begin outq = 10'h2a7; end
|
||||
8'hf4: begin outq = 10'h1be; end
|
||||
8'hf5: begin outq = 10'h25e; end
|
||||
8'hf6: begin outq = 10'h032; end
|
||||
8'hf7: begin outq = 10'h2ef; end
|
||||
8'hf8: begin outq = 10'h02f; end
|
||||
8'hf9: begin outq = 10'h201; end
|
||||
8'hfa: begin outq = 10'h054; end
|
||||
8'hfb: begin outq = 10'h013; end
|
||||
8'hfc: begin outq = 10'h249; end
|
||||
8'hfd: begin outq = 10'h09a; end
|
||||
8'hfe: begin outq = 10'h012; end
|
||||
8'hff: begin outq = 10'h114; end
|
||||
default: ; // No change
|
||||
endcase
|
||||
end
|
||||
always @* begin
|
||||
// verilog_format: off
|
||||
case (index)
|
||||
// default below: no change
|
||||
8'h00: begin outq = 10'h001; end
|
||||
8'he0: begin outq = 10'h05b; end
|
||||
8'he1: begin outq = 10'h126; end
|
||||
8'he2: begin outq = 10'h369; end
|
||||
8'he3: begin outq = 10'h291; end
|
||||
8'he4: begin outq = 10'h2ca; end
|
||||
8'he5: begin outq = 10'h25b; end
|
||||
8'he6: begin outq = 10'h106; end
|
||||
8'he7: begin outq = 10'h172; end
|
||||
8'he8: begin outq = 10'h2f7; end
|
||||
8'he9: begin outq = 10'h2d3; end
|
||||
8'hea: begin outq = 10'h182; end
|
||||
8'heb: begin outq = 10'h327; end
|
||||
8'hec: begin outq = 10'h1d0; end
|
||||
8'hed: begin outq = 10'h204; end
|
||||
8'hee: begin outq = 10'h11f; end
|
||||
8'hef: begin outq = 10'h365; end
|
||||
8'hf0: begin outq = 10'h2c2; end
|
||||
8'hf1: begin outq = 10'h2b5; end
|
||||
8'hf2: begin outq = 10'h1f8; end
|
||||
8'hf3: begin outq = 10'h2a7; end
|
||||
8'hf4: begin outq = 10'h1be; end
|
||||
8'hf5: begin outq = 10'h25e; end
|
||||
8'hf6: begin outq = 10'h032; end
|
||||
8'hf7: begin outq = 10'h2ef; end
|
||||
8'hf8: begin outq = 10'h02f; end
|
||||
8'hf9: begin outq = 10'h201; end
|
||||
8'hfa: begin outq = 10'h054; end
|
||||
8'hfb: begin outq = 10'h013; end
|
||||
8'hfc: begin outq = 10'h249; end
|
||||
8'hfd: begin outq = 10'h09a; end
|
||||
8'hfe: begin outq = 10'h012; end
|
||||
8'hff: begin outq = 10'h114; end
|
||||
default: ; // No change
|
||||
endcase
|
||||
// verilog_format: on
|
||||
end
|
||||
endmodule
|
||||
|
|
|
@ -4,326 +4,326 @@
|
|||
// any use, without warranty, 2024 by Varun Koyyalagunta, Tenstorrent.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
module t;
|
||||
|
||||
localparam W = 23;
|
||||
localparam W = 23;
|
||||
|
||||
localparam [W-1:0] R0 = W'('h200000 + 0);
|
||||
localparam [W-1:0] R1 = W'('h200000 + 1);
|
||||
localparam [W-1:0] R2 = W'('h200000 + 2);
|
||||
localparam [W-1:0] R3 = W'('h200000 + 3);
|
||||
localparam [W-1:0] R4 = W'('h200000 + 4);
|
||||
localparam [W-1:0] R5 = W'('h200000 + 5);
|
||||
localparam [W-1:0] R6 = W'('h200000 + 6);
|
||||
localparam [W-1:0] R7 = W'('h200000 + 7);
|
||||
localparam [W-1:0] R8 = W'('h200000 + 8);
|
||||
localparam [W-1:0] R9 = W'('h200000 + 9);
|
||||
localparam [W-1:0] R10 = W'('h200000 + 10);
|
||||
localparam [W-1:0] R11 = W'('h200000 + 11);
|
||||
localparam [W-1:0] R12 = W'('h200000 + 12);
|
||||
localparam [W-1:0] R13 = W'('h200000 + 13);
|
||||
localparam [W-1:0] R14 = W'('h200000 + 14);
|
||||
localparam [W-1:0] R15 = W'('h200000 + 15);
|
||||
localparam [W-1:0] R16 = W'('h200000 + 16);
|
||||
localparam [W-1:0] R17 = W'('h200000 + 17);
|
||||
localparam [W-1:0] R18 = W'('h200000 + 18);
|
||||
localparam [W-1:0] R19 = W'('h200000 + 19);
|
||||
localparam [W-1:0] R20 = W'('h200000 + 20);
|
||||
localparam [W-1:0] R21 = W'('h200000 + 21);
|
||||
localparam [W-1:0] R22 = W'('h200000 + 22);
|
||||
localparam [W-1:0] R23 = W'('h200000 + 23);
|
||||
localparam [W-1:0] R24 = W'('h200000 + 24);
|
||||
localparam [W-1:0] R25 = W'('h200000 + 25);
|
||||
localparam [W-1:0] R26 = W'('h200000 + 26);
|
||||
localparam [W-1:0] R27 = W'('h200000 + 27);
|
||||
localparam [W-1:0] R28 = W'('h200000 + 28);
|
||||
localparam [W-1:0] R29 = W'('h200000 + 29);
|
||||
localparam [W-1:0] R30 = W'('h200000 + 30);
|
||||
localparam [W-1:0] R31 = W'('h200000 + 31);
|
||||
localparam [W-1:0] R32 = W'('h200000 + 32);
|
||||
localparam [W-1:0] R33 = W'('h200000 + 33);
|
||||
localparam [W-1:0] R34 = W'('h200000 + 34);
|
||||
localparam [W-1:0] R35 = W'('h200000 + 35);
|
||||
localparam [W-1:0] R36 = W'('h200000 + 36);
|
||||
localparam [W-1:0] R37 = W'('h200000 + 37);
|
||||
localparam [W-1:0] R38 = W'('h200000 + 38);
|
||||
localparam [W-1:0] R39 = W'('h200000 + 39);
|
||||
localparam [W-1:0] R40 = W'('h200000 + 40);
|
||||
localparam [W-1:0] R41 = W'('h200000 + 41);
|
||||
localparam [W-1:0] R42 = W'('h200000 + 42);
|
||||
localparam [W-1:0] R43 = W'('h200000 + 43);
|
||||
localparam [W-1:0] R44 = W'('h200000 + 44);
|
||||
localparam [W-1:0] R45 = W'('h200000 + 45);
|
||||
localparam [W-1:0] R46 = W'('h200000 + 46);
|
||||
localparam [W-1:0] R47 = W'('h200000 + 47);
|
||||
localparam [W-1:0] R48 = W'('h200000 + 48);
|
||||
localparam [W-1:0] R49 = W'('h200000 + 49);
|
||||
localparam [W-1:0] R50 = W'('h200000 + 50);
|
||||
localparam [W-1:0] R51 = W'('h200000 + 51);
|
||||
localparam [W-1:0] R52 = W'('h200000 + 52);
|
||||
localparam [W-1:0] R53 = W'('h200000 + 53);
|
||||
localparam [W-1:0] R54 = W'('h200000 + 54);
|
||||
localparam [W-1:0] R55 = W'('h200000 + 55);
|
||||
localparam [W-1:0] R56 = W'('h200000 + 56);
|
||||
localparam [W-1:0] R57 = W'('h200000 + 57);
|
||||
localparam [W-1:0] R58 = W'('h200000 + 58);
|
||||
localparam [W-1:0] R59 = W'('h200000 + 59);
|
||||
localparam [W-1:0] R60 = W'('h200000 + 60);
|
||||
localparam [W-1:0] R61 = W'('h200000 + 61);
|
||||
localparam [W-1:0] R62 = W'('h200000 + 62);
|
||||
localparam [W-1:0] R63 = W'('h200000 + 63);
|
||||
localparam [W-1:0] R64 = W'('h200000 + 64);
|
||||
localparam [W-1:0] R65 = W'('h200000 + 65);
|
||||
localparam [W-1:0] R66 = W'('h200000 + 66);
|
||||
localparam [W-1:0] R67 = W'('h200000 + 67);
|
||||
localparam [W-1:0] R68 = W'('h200000 + 68);
|
||||
localparam [W-1:0] R69 = W'('h200000 + 69);
|
||||
localparam [W-1:0] R70 = W'('h200000 + 70);
|
||||
localparam [W-1:0] R71 = W'('h200000 + 71);
|
||||
localparam [W-1:0] R72 = W'('h200000 + 72);
|
||||
localparam [W-1:0] R73 = W'('h200000 + 73);
|
||||
localparam [W-1:0] R74 = W'('h200000 + 74);
|
||||
localparam [W-1:0] R75 = W'('h200000 + 75);
|
||||
localparam [W-1:0] R76 = W'('h200000 + 76);
|
||||
localparam [W-1:0] R77 = W'('h200000 + 77);
|
||||
localparam [W-1:0] R78 = W'('h200000 + 78);
|
||||
localparam [W-1:0] R79 = W'('h200000 + 79);
|
||||
localparam [W-1:0] R80 = W'('h200000 + 80);
|
||||
localparam [W-1:0] R81 = W'('h200000 + 81);
|
||||
localparam [W-1:0] R82 = W'('h200000 + 82);
|
||||
localparam [W-1:0] R83 = W'('h200000 + 83);
|
||||
localparam [W-1:0] R84 = W'('h200000 + 84);
|
||||
localparam [W-1:0] R85 = W'('h200000 + 85);
|
||||
localparam [W-1:0] R86 = W'('h200000 + 86);
|
||||
localparam [W-1:0] R87 = W'('h200000 + 87);
|
||||
localparam [W-1:0] R88 = W'('h200000 + 88);
|
||||
localparam [W-1:0] R89 = W'('h200000 + 89);
|
||||
localparam [W-1:0] R90 = W'('h200000 + 90);
|
||||
localparam [W-1:0] R91 = W'('h200000 + 91);
|
||||
localparam [W-1:0] R92 = W'('h200000 + 92);
|
||||
localparam [W-1:0] R93 = W'('h200000 + 93);
|
||||
localparam [W-1:0] R94 = W'('h200000 + 94);
|
||||
localparam [W-1:0] R95 = W'('h200000 + 95);
|
||||
localparam [W-1:0] R96 = W'('h200000 + 96);
|
||||
localparam [W-1:0] R97 = W'('h200000 + 97);
|
||||
localparam [W-1:0] R98 = W'('h200000 + 98);
|
||||
localparam [W-1:0] R99 = W'('h200000 + 99);
|
||||
typedef struct packed {
|
||||
logic r0;
|
||||
logic r1;
|
||||
logic r2;
|
||||
logic r3;
|
||||
logic r4;
|
||||
logic r5;
|
||||
logic r6;
|
||||
logic r7;
|
||||
logic r8;
|
||||
logic r9;
|
||||
logic r10;
|
||||
logic r11;
|
||||
logic r12;
|
||||
logic r13;
|
||||
logic r14;
|
||||
logic r15;
|
||||
logic r16;
|
||||
logic r17;
|
||||
logic r18;
|
||||
logic r19;
|
||||
logic r20;
|
||||
logic r21;
|
||||
logic r22;
|
||||
logic r23;
|
||||
logic r24;
|
||||
logic r25;
|
||||
logic r26;
|
||||
logic r27;
|
||||
logic r28;
|
||||
logic r29;
|
||||
logic r30;
|
||||
logic r31;
|
||||
logic r32;
|
||||
logic r33;
|
||||
logic r34;
|
||||
logic r35;
|
||||
logic r36;
|
||||
logic r37;
|
||||
logic r38;
|
||||
logic r39;
|
||||
logic r40;
|
||||
logic r41;
|
||||
logic r42;
|
||||
logic r43;
|
||||
logic r44;
|
||||
logic r45;
|
||||
logic r46;
|
||||
logic r47;
|
||||
logic r48;
|
||||
logic r49;
|
||||
logic r50;
|
||||
logic r51;
|
||||
logic r52;
|
||||
logic r53;
|
||||
logic r54;
|
||||
logic r55;
|
||||
logic r56;
|
||||
logic r57;
|
||||
logic r58;
|
||||
logic r59;
|
||||
logic r60;
|
||||
logic r61;
|
||||
logic r62;
|
||||
logic r63;
|
||||
logic r64;
|
||||
logic r65;
|
||||
logic r66;
|
||||
logic r67;
|
||||
logic r68;
|
||||
logic r69;
|
||||
logic r70;
|
||||
logic r71;
|
||||
logic r72;
|
||||
logic r73;
|
||||
logic r74;
|
||||
logic r75;
|
||||
logic r76;
|
||||
logic r77;
|
||||
logic r78;
|
||||
logic r79;
|
||||
logic r80;
|
||||
logic r81;
|
||||
logic r82;
|
||||
logic r83;
|
||||
logic r84;
|
||||
logic r85;
|
||||
logic r86;
|
||||
logic r87;
|
||||
logic r88;
|
||||
logic r89;
|
||||
logic r90;
|
||||
logic r91;
|
||||
logic r92;
|
||||
logic r93;
|
||||
logic r94;
|
||||
logic r95;
|
||||
logic r96;
|
||||
logic r97;
|
||||
logic r98;
|
||||
logic r99;
|
||||
} hit_t;
|
||||
function automatic hit_t get_hit(input logic [22:0] a);
|
||||
hit_t hit = '0;
|
||||
unique case (a)
|
||||
R0 : begin hit.r0 = 1'b1; end
|
||||
R1 : begin hit.r1 = 1'b1; end
|
||||
R2 : begin hit.r2 = 1'b1; end
|
||||
R3 : begin hit.r3 = 1'b1; end
|
||||
R4 : begin hit.r4 = 1'b1; end
|
||||
R5 : begin hit.r5 = 1'b1; end
|
||||
R6 : begin hit.r6 = 1'b1; end
|
||||
R7 : begin hit.r7 = 1'b1; end
|
||||
R8 : begin hit.r8 = 1'b1; end
|
||||
R9 : begin hit.r9 = 1'b1; end
|
||||
R10 : begin hit.r10 = 1'b1; end
|
||||
R11 : begin hit.r11 = 1'b1; end
|
||||
R12 : begin hit.r12 = 1'b1; end
|
||||
R13 : begin hit.r13 = 1'b1; end
|
||||
R14 : begin hit.r14 = 1'b1; end
|
||||
R15 : begin hit.r15 = 1'b1; end
|
||||
R16 : begin hit.r16 = 1'b1; end
|
||||
R17 : begin hit.r17 = 1'b1; end
|
||||
R18 : begin hit.r18 = 1'b1; end
|
||||
R19 : begin hit.r19 = 1'b1; end
|
||||
R20 : begin hit.r20 = 1'b1; end
|
||||
R21 : begin hit.r21 = 1'b1; end
|
||||
R22 : begin hit.r22 = 1'b1; end
|
||||
R23 : begin hit.r23 = 1'b1; end
|
||||
R24 : begin hit.r24 = 1'b1; end
|
||||
R25 : begin hit.r25 = 1'b1; end
|
||||
R26 : begin hit.r26 = 1'b1; end
|
||||
R27 : begin hit.r27 = 1'b1; end
|
||||
R28 : begin hit.r28 = 1'b1; end
|
||||
R29 : begin hit.r29 = 1'b1; end
|
||||
R30 : begin hit.r30 = 1'b1; end
|
||||
R31 : begin hit.r31 = 1'b1; end
|
||||
R32 : begin hit.r32 = 1'b1; end
|
||||
R33 : begin hit.r33 = 1'b1; end
|
||||
R34 : begin hit.r34 = 1'b1; end
|
||||
R35 : begin hit.r35 = 1'b1; end
|
||||
R36 : begin hit.r36 = 1'b1; end
|
||||
R37 : begin hit.r37 = 1'b1; end
|
||||
R38 : begin hit.r38 = 1'b1; end
|
||||
R39 : begin hit.r39 = 1'b1; end
|
||||
R40 : begin hit.r40 = 1'b1; end
|
||||
R41 : begin hit.r41 = 1'b1; end
|
||||
R42 : begin hit.r42 = 1'b1; end
|
||||
R43 : begin hit.r43 = 1'b1; end
|
||||
R44 : begin hit.r44 = 1'b1; end
|
||||
R45 : begin hit.r45 = 1'b1; end
|
||||
R46 : begin hit.r46 = 1'b1; end
|
||||
R47 : begin hit.r47 = 1'b1; end
|
||||
R48 : begin hit.r48 = 1'b1; end
|
||||
R49 : begin hit.r49 = 1'b1; end
|
||||
R50 : begin hit.r50 = 1'b1; end
|
||||
R51 : begin hit.r51 = 1'b1; end
|
||||
R52 : begin hit.r52 = 1'b1; end
|
||||
R53 : begin hit.r53 = 1'b1; end
|
||||
R54 : begin hit.r54 = 1'b1; end
|
||||
R55 : begin hit.r55 = 1'b1; end
|
||||
R56 : begin hit.r56 = 1'b1; end
|
||||
R57 : begin hit.r57 = 1'b1; end
|
||||
R58 : begin hit.r58 = 1'b1; end
|
||||
R59 : begin hit.r59 = 1'b1; end
|
||||
R60 : begin hit.r60 = 1'b1; end
|
||||
R61 : begin hit.r61 = 1'b1; end
|
||||
R62 : begin hit.r62 = 1'b1; end
|
||||
R63 : begin hit.r63 = 1'b1; end
|
||||
R64 : begin hit.r64 = 1'b1; end
|
||||
R65 : begin hit.r65 = 1'b1; end
|
||||
R66 : begin hit.r66 = 1'b1; end
|
||||
R67 : begin hit.r67 = 1'b1; end
|
||||
R68 : begin hit.r68 = 1'b1; end
|
||||
R69 : begin hit.r69 = 1'b1; end
|
||||
R70 : begin hit.r70 = 1'b1; end
|
||||
R71 : begin hit.r71 = 1'b1; end
|
||||
R72 : begin hit.r72 = 1'b1; end
|
||||
R73 : begin hit.r73 = 1'b1; end
|
||||
R74 : begin hit.r74 = 1'b1; end
|
||||
R75 : begin hit.r75 = 1'b1; end
|
||||
R76 : begin hit.r76 = 1'b1; end
|
||||
R77 : begin hit.r77 = 1'b1; end
|
||||
R78 : begin hit.r78 = 1'b1; end
|
||||
R79 : begin hit.r79 = 1'b1; end
|
||||
R80 : begin hit.r80 = 1'b1; end
|
||||
R81 : begin hit.r81 = 1'b1; end
|
||||
R82 : begin hit.r82 = 1'b1; end
|
||||
R83 : begin hit.r83 = 1'b1; end
|
||||
R84 : begin hit.r84 = 1'b1; end
|
||||
R85 : begin hit.r85 = 1'b1; end
|
||||
R86 : begin hit.r86 = 1'b1; end
|
||||
R87 : begin hit.r87 = 1'b1; end
|
||||
R88 : begin hit.r88 = 1'b1; end
|
||||
R89 : begin hit.r89 = 1'b1; end
|
||||
R90 : begin hit.r90 = 1'b1; end
|
||||
R91 : begin hit.r91 = 1'b1; end
|
||||
R92 : begin hit.r92 = 1'b1; end
|
||||
R93 : begin hit.r93 = 1'b1; end
|
||||
R94 : begin hit.r94 = 1'b1; end
|
||||
R95 : begin hit.r95 = 1'b1; end
|
||||
R96 : begin hit.r96 = 1'b1; end
|
||||
R97 : begin hit.r97 = 1'b1; end
|
||||
R98 : begin hit.r98 = 1'b1; end
|
||||
R99 : begin hit.r99 = 1'b1; end
|
||||
default: begin hit = '0; end
|
||||
endcase
|
||||
return hit;
|
||||
endfunction
|
||||
localparam [W-1:0] R0 = W'('h200000 + 0);
|
||||
localparam [W-1:0] R1 = W'('h200000 + 1);
|
||||
localparam [W-1:0] R2 = W'('h200000 + 2);
|
||||
localparam [W-1:0] R3 = W'('h200000 + 3);
|
||||
localparam [W-1:0] R4 = W'('h200000 + 4);
|
||||
localparam [W-1:0] R5 = W'('h200000 + 5);
|
||||
localparam [W-1:0] R6 = W'('h200000 + 6);
|
||||
localparam [W-1:0] R7 = W'('h200000 + 7);
|
||||
localparam [W-1:0] R8 = W'('h200000 + 8);
|
||||
localparam [W-1:0] R9 = W'('h200000 + 9);
|
||||
localparam [W-1:0] R10 = W'('h200000 + 10);
|
||||
localparam [W-1:0] R11 = W'('h200000 + 11);
|
||||
localparam [W-1:0] R12 = W'('h200000 + 12);
|
||||
localparam [W-1:0] R13 = W'('h200000 + 13);
|
||||
localparam [W-1:0] R14 = W'('h200000 + 14);
|
||||
localparam [W-1:0] R15 = W'('h200000 + 15);
|
||||
localparam [W-1:0] R16 = W'('h200000 + 16);
|
||||
localparam [W-1:0] R17 = W'('h200000 + 17);
|
||||
localparam [W-1:0] R18 = W'('h200000 + 18);
|
||||
localparam [W-1:0] R19 = W'('h200000 + 19);
|
||||
localparam [W-1:0] R20 = W'('h200000 + 20);
|
||||
localparam [W-1:0] R21 = W'('h200000 + 21);
|
||||
localparam [W-1:0] R22 = W'('h200000 + 22);
|
||||
localparam [W-1:0] R23 = W'('h200000 + 23);
|
||||
localparam [W-1:0] R24 = W'('h200000 + 24);
|
||||
localparam [W-1:0] R25 = W'('h200000 + 25);
|
||||
localparam [W-1:0] R26 = W'('h200000 + 26);
|
||||
localparam [W-1:0] R27 = W'('h200000 + 27);
|
||||
localparam [W-1:0] R28 = W'('h200000 + 28);
|
||||
localparam [W-1:0] R29 = W'('h200000 + 29);
|
||||
localparam [W-1:0] R30 = W'('h200000 + 30);
|
||||
localparam [W-1:0] R31 = W'('h200000 + 31);
|
||||
localparam [W-1:0] R32 = W'('h200000 + 32);
|
||||
localparam [W-1:0] R33 = W'('h200000 + 33);
|
||||
localparam [W-1:0] R34 = W'('h200000 + 34);
|
||||
localparam [W-1:0] R35 = W'('h200000 + 35);
|
||||
localparam [W-1:0] R36 = W'('h200000 + 36);
|
||||
localparam [W-1:0] R37 = W'('h200000 + 37);
|
||||
localparam [W-1:0] R38 = W'('h200000 + 38);
|
||||
localparam [W-1:0] R39 = W'('h200000 + 39);
|
||||
localparam [W-1:0] R40 = W'('h200000 + 40);
|
||||
localparam [W-1:0] R41 = W'('h200000 + 41);
|
||||
localparam [W-1:0] R42 = W'('h200000 + 42);
|
||||
localparam [W-1:0] R43 = W'('h200000 + 43);
|
||||
localparam [W-1:0] R44 = W'('h200000 + 44);
|
||||
localparam [W-1:0] R45 = W'('h200000 + 45);
|
||||
localparam [W-1:0] R46 = W'('h200000 + 46);
|
||||
localparam [W-1:0] R47 = W'('h200000 + 47);
|
||||
localparam [W-1:0] R48 = W'('h200000 + 48);
|
||||
localparam [W-1:0] R49 = W'('h200000 + 49);
|
||||
localparam [W-1:0] R50 = W'('h200000 + 50);
|
||||
localparam [W-1:0] R51 = W'('h200000 + 51);
|
||||
localparam [W-1:0] R52 = W'('h200000 + 52);
|
||||
localparam [W-1:0] R53 = W'('h200000 + 53);
|
||||
localparam [W-1:0] R54 = W'('h200000 + 54);
|
||||
localparam [W-1:0] R55 = W'('h200000 + 55);
|
||||
localparam [W-1:0] R56 = W'('h200000 + 56);
|
||||
localparam [W-1:0] R57 = W'('h200000 + 57);
|
||||
localparam [W-1:0] R58 = W'('h200000 + 58);
|
||||
localparam [W-1:0] R59 = W'('h200000 + 59);
|
||||
localparam [W-1:0] R60 = W'('h200000 + 60);
|
||||
localparam [W-1:0] R61 = W'('h200000 + 61);
|
||||
localparam [W-1:0] R62 = W'('h200000 + 62);
|
||||
localparam [W-1:0] R63 = W'('h200000 + 63);
|
||||
localparam [W-1:0] R64 = W'('h200000 + 64);
|
||||
localparam [W-1:0] R65 = W'('h200000 + 65);
|
||||
localparam [W-1:0] R66 = W'('h200000 + 66);
|
||||
localparam [W-1:0] R67 = W'('h200000 + 67);
|
||||
localparam [W-1:0] R68 = W'('h200000 + 68);
|
||||
localparam [W-1:0] R69 = W'('h200000 + 69);
|
||||
localparam [W-1:0] R70 = W'('h200000 + 70);
|
||||
localparam [W-1:0] R71 = W'('h200000 + 71);
|
||||
localparam [W-1:0] R72 = W'('h200000 + 72);
|
||||
localparam [W-1:0] R73 = W'('h200000 + 73);
|
||||
localparam [W-1:0] R74 = W'('h200000 + 74);
|
||||
localparam [W-1:0] R75 = W'('h200000 + 75);
|
||||
localparam [W-1:0] R76 = W'('h200000 + 76);
|
||||
localparam [W-1:0] R77 = W'('h200000 + 77);
|
||||
localparam [W-1:0] R78 = W'('h200000 + 78);
|
||||
localparam [W-1:0] R79 = W'('h200000 + 79);
|
||||
localparam [W-1:0] R80 = W'('h200000 + 80);
|
||||
localparam [W-1:0] R81 = W'('h200000 + 81);
|
||||
localparam [W-1:0] R82 = W'('h200000 + 82);
|
||||
localparam [W-1:0] R83 = W'('h200000 + 83);
|
||||
localparam [W-1:0] R84 = W'('h200000 + 84);
|
||||
localparam [W-1:0] R85 = W'('h200000 + 85);
|
||||
localparam [W-1:0] R86 = W'('h200000 + 86);
|
||||
localparam [W-1:0] R87 = W'('h200000 + 87);
|
||||
localparam [W-1:0] R88 = W'('h200000 + 88);
|
||||
localparam [W-1:0] R89 = W'('h200000 + 89);
|
||||
localparam [W-1:0] R90 = W'('h200000 + 90);
|
||||
localparam [W-1:0] R91 = W'('h200000 + 91);
|
||||
localparam [W-1:0] R92 = W'('h200000 + 92);
|
||||
localparam [W-1:0] R93 = W'('h200000 + 93);
|
||||
localparam [W-1:0] R94 = W'('h200000 + 94);
|
||||
localparam [W-1:0] R95 = W'('h200000 + 95);
|
||||
localparam [W-1:0] R96 = W'('h200000 + 96);
|
||||
localparam [W-1:0] R97 = W'('h200000 + 97);
|
||||
localparam [W-1:0] R98 = W'('h200000 + 98);
|
||||
localparam [W-1:0] R99 = W'('h200000 + 99);
|
||||
typedef struct packed {
|
||||
logic r0;
|
||||
logic r1;
|
||||
logic r2;
|
||||
logic r3;
|
||||
logic r4;
|
||||
logic r5;
|
||||
logic r6;
|
||||
logic r7;
|
||||
logic r8;
|
||||
logic r9;
|
||||
logic r10;
|
||||
logic r11;
|
||||
logic r12;
|
||||
logic r13;
|
||||
logic r14;
|
||||
logic r15;
|
||||
logic r16;
|
||||
logic r17;
|
||||
logic r18;
|
||||
logic r19;
|
||||
logic r20;
|
||||
logic r21;
|
||||
logic r22;
|
||||
logic r23;
|
||||
logic r24;
|
||||
logic r25;
|
||||
logic r26;
|
||||
logic r27;
|
||||
logic r28;
|
||||
logic r29;
|
||||
logic r30;
|
||||
logic r31;
|
||||
logic r32;
|
||||
logic r33;
|
||||
logic r34;
|
||||
logic r35;
|
||||
logic r36;
|
||||
logic r37;
|
||||
logic r38;
|
||||
logic r39;
|
||||
logic r40;
|
||||
logic r41;
|
||||
logic r42;
|
||||
logic r43;
|
||||
logic r44;
|
||||
logic r45;
|
||||
logic r46;
|
||||
logic r47;
|
||||
logic r48;
|
||||
logic r49;
|
||||
logic r50;
|
||||
logic r51;
|
||||
logic r52;
|
||||
logic r53;
|
||||
logic r54;
|
||||
logic r55;
|
||||
logic r56;
|
||||
logic r57;
|
||||
logic r58;
|
||||
logic r59;
|
||||
logic r60;
|
||||
logic r61;
|
||||
logic r62;
|
||||
logic r63;
|
||||
logic r64;
|
||||
logic r65;
|
||||
logic r66;
|
||||
logic r67;
|
||||
logic r68;
|
||||
logic r69;
|
||||
logic r70;
|
||||
logic r71;
|
||||
logic r72;
|
||||
logic r73;
|
||||
logic r74;
|
||||
logic r75;
|
||||
logic r76;
|
||||
logic r77;
|
||||
logic r78;
|
||||
logic r79;
|
||||
logic r80;
|
||||
logic r81;
|
||||
logic r82;
|
||||
logic r83;
|
||||
logic r84;
|
||||
logic r85;
|
||||
logic r86;
|
||||
logic r87;
|
||||
logic r88;
|
||||
logic r89;
|
||||
logic r90;
|
||||
logic r91;
|
||||
logic r92;
|
||||
logic r93;
|
||||
logic r94;
|
||||
logic r95;
|
||||
logic r96;
|
||||
logic r97;
|
||||
logic r98;
|
||||
logic r99;
|
||||
} hit_t;
|
||||
function automatic hit_t get_hit(input logic [22:0] a);
|
||||
hit_t hit = '0;
|
||||
unique case (a)
|
||||
R0: hit.r0 = 1'b1;
|
||||
R1: hit.r1 = 1'b1;
|
||||
R2: hit.r2 = 1'b1;
|
||||
R3: hit.r3 = 1'b1;
|
||||
R4: hit.r4 = 1'b1;
|
||||
R5: hit.r5 = 1'b1;
|
||||
R6: hit.r6 = 1'b1;
|
||||
R7: hit.r7 = 1'b1;
|
||||
R8: hit.r8 = 1'b1;
|
||||
R9: hit.r9 = 1'b1;
|
||||
R10: hit.r10 = 1'b1;
|
||||
R11: hit.r11 = 1'b1;
|
||||
R12: hit.r12 = 1'b1;
|
||||
R13: hit.r13 = 1'b1;
|
||||
R14: hit.r14 = 1'b1;
|
||||
R15: hit.r15 = 1'b1;
|
||||
R16: hit.r16 = 1'b1;
|
||||
R17: hit.r17 = 1'b1;
|
||||
R18: hit.r18 = 1'b1;
|
||||
R19: hit.r19 = 1'b1;
|
||||
R20: hit.r20 = 1'b1;
|
||||
R21: hit.r21 = 1'b1;
|
||||
R22: hit.r22 = 1'b1;
|
||||
R23: hit.r23 = 1'b1;
|
||||
R24: hit.r24 = 1'b1;
|
||||
R25: hit.r25 = 1'b1;
|
||||
R26: hit.r26 = 1'b1;
|
||||
R27: hit.r27 = 1'b1;
|
||||
R28: hit.r28 = 1'b1;
|
||||
R29: hit.r29 = 1'b1;
|
||||
R30: hit.r30 = 1'b1;
|
||||
R31: hit.r31 = 1'b1;
|
||||
R32: hit.r32 = 1'b1;
|
||||
R33: hit.r33 = 1'b1;
|
||||
R34: hit.r34 = 1'b1;
|
||||
R35: hit.r35 = 1'b1;
|
||||
R36: hit.r36 = 1'b1;
|
||||
R37: hit.r37 = 1'b1;
|
||||
R38: hit.r38 = 1'b1;
|
||||
R39: hit.r39 = 1'b1;
|
||||
R40: hit.r40 = 1'b1;
|
||||
R41: hit.r41 = 1'b1;
|
||||
R42: hit.r42 = 1'b1;
|
||||
R43: hit.r43 = 1'b1;
|
||||
R44: hit.r44 = 1'b1;
|
||||
R45: hit.r45 = 1'b1;
|
||||
R46: hit.r46 = 1'b1;
|
||||
R47: hit.r47 = 1'b1;
|
||||
R48: hit.r48 = 1'b1;
|
||||
R49: hit.r49 = 1'b1;
|
||||
R50: hit.r50 = 1'b1;
|
||||
R51: hit.r51 = 1'b1;
|
||||
R52: hit.r52 = 1'b1;
|
||||
R53: hit.r53 = 1'b1;
|
||||
R54: hit.r54 = 1'b1;
|
||||
R55: hit.r55 = 1'b1;
|
||||
R56: hit.r56 = 1'b1;
|
||||
R57: hit.r57 = 1'b1;
|
||||
R58: hit.r58 = 1'b1;
|
||||
R59: hit.r59 = 1'b1;
|
||||
R60: hit.r60 = 1'b1;
|
||||
R61: hit.r61 = 1'b1;
|
||||
R62: hit.r62 = 1'b1;
|
||||
R63: hit.r63 = 1'b1;
|
||||
R64: hit.r64 = 1'b1;
|
||||
R65: hit.r65 = 1'b1;
|
||||
R66: hit.r66 = 1'b1;
|
||||
R67: hit.r67 = 1'b1;
|
||||
R68: hit.r68 = 1'b1;
|
||||
R69: hit.r69 = 1'b1;
|
||||
R70: hit.r70 = 1'b1;
|
||||
R71: hit.r71 = 1'b1;
|
||||
R72: hit.r72 = 1'b1;
|
||||
R73: hit.r73 = 1'b1;
|
||||
R74: hit.r74 = 1'b1;
|
||||
R75: hit.r75 = 1'b1;
|
||||
R76: hit.r76 = 1'b1;
|
||||
R77: hit.r77 = 1'b1;
|
||||
R78: hit.r78 = 1'b1;
|
||||
R79: hit.r79 = 1'b1;
|
||||
R80: hit.r80 = 1'b1;
|
||||
R81: hit.r81 = 1'b1;
|
||||
R82: hit.r82 = 1'b1;
|
||||
R83: hit.r83 = 1'b1;
|
||||
R84: hit.r84 = 1'b1;
|
||||
R85: hit.r85 = 1'b1;
|
||||
R86: hit.r86 = 1'b1;
|
||||
R87: hit.r87 = 1'b1;
|
||||
R88: hit.r88 = 1'b1;
|
||||
R89: hit.r89 = 1'b1;
|
||||
R90: hit.r90 = 1'b1;
|
||||
R91: hit.r91 = 1'b1;
|
||||
R92: hit.r92 = 1'b1;
|
||||
R93: hit.r93 = 1'b1;
|
||||
R94: hit.r94 = 1'b1;
|
||||
R95: hit.r95 = 1'b1;
|
||||
R96: hit.r96 = 1'b1;
|
||||
R97: hit.r97 = 1'b1;
|
||||
R98: hit.r98 = 1'b1;
|
||||
R99: hit.r99 = 1'b1;
|
||||
default: hit = '0;
|
||||
endcase
|
||||
return hit;
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
if (get_hit(R30) !== hit_t'{r30: 1'b1, default: '0}) $stop;
|
||||
if (get_hit('1) !== '0) $stop;
|
||||
if (get_hit('0) !== '0) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
initial begin
|
||||
if (get_hit(R30) !== hit_t'{r30: 1'b1, default: '0}) $stop;
|
||||
if (get_hit('1) !== '0) $stop;
|
||||
if (get_hit('0) !== '0) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,26 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Class1 #(type T);
|
||||
static function int get();
|
||||
return T::Helper::getter();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Class2;
|
||||
typedef Class2 Helper;
|
||||
static function int getter();
|
||||
return 13;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
if (Class1#(Class2)::get() != 13) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,17 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class setup_coefficients;
|
||||
static function int create();
|
||||
return 1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class biquad_vseq;
|
||||
int c_setup = setup_coefficients::create();
|
||||
function void setup_coefficients();
|
||||
endfunction
|
||||
endclass: biquad_vseq
|
|
@ -7,12 +7,11 @@
|
|||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import signal
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
signal.alarm(15) # 15s timeout
|
||||
test.timeout(15)
|
||||
|
||||
test.compile()
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import signal
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
@ -20,7 +19,7 @@ with open(test.top_filename, "w", encoding="utf8") as f:
|
|||
f.write(f" int x{i} = 'd{i};\n")
|
||||
f.write("endmodule\n")
|
||||
|
||||
signal.alarm(30) # 30s timeout
|
||||
test.timeout(30)
|
||||
|
||||
test.lint(verilator_flags2=[f"--max-num-width {2**29}"])
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage-expr'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,26 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Class1;
|
||||
int value0 = 7;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
int i = 0;
|
||||
Class1 q[15];
|
||||
for (int j = 0; j < 15; j = j + 1) begin
|
||||
Class1 x = new;
|
||||
q[j] = x;
|
||||
end
|
||||
while (i < 15) begin
|
||||
if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop;
|
||||
i += 1;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage-expr'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,26 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Class1;
|
||||
int value0 = 7;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
int i = 0;
|
||||
Class1 q[int] = '{};
|
||||
for (int j = 0; j < 15; j = j + 1) begin
|
||||
Class1 x = new;
|
||||
q[j] = x;
|
||||
end
|
||||
while (i < 15) begin
|
||||
if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop;
|
||||
i += 1;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage-expr'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,26 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Class1;
|
||||
int value0 = 7;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
int i = 0;
|
||||
Class1 q[] = new [15];
|
||||
for (int j = 0; j < 15; j = j + 1) begin
|
||||
Class1 x = new;
|
||||
q[j] = x;
|
||||
end
|
||||
while (i < 15) begin
|
||||
if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop;
|
||||
i += 1;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage-expr'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,26 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Class1;
|
||||
int value0 = 7;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
int i = 0;
|
||||
Class1 q[$];
|
||||
repeat(15) begin
|
||||
Class1 x = new;
|
||||
q = { q, x };
|
||||
end
|
||||
while (i < q.size()) begin
|
||||
if ((q[i].value0 > 8) || (q[i].value0 < 5)) $stop;
|
||||
i += 1;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,19 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
module t;
|
||||
covergroup cgArgs(int var1, int var2=42);
|
||||
|
||||
endgroup
|
||||
|
||||
cgArgs cov1 = new(69, 77);
|
||||
cgArgs cov2 = new(69);
|
||||
function x();
|
||||
cov1.sample();
|
||||
cov2.get_coverage();
|
||||
endfunction;
|
||||
endmodule
|
|
@ -25,5 +25,28 @@
|
|||
35 | $display("coverage a = %f", the_cg.a.get_inst_coverage());
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Verilator internal fault, sorry. Suggest trying --debug --gdbbt
|
||||
%Error: Command Failed
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:36:48: Member 'b' not found in class 'cg'
|
||||
: ... note: In instance 't'
|
||||
36 | $display("coverage b = %f", the_cg.b.get_inst_coverage());
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:36:50: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'logic''
|
||||
: ... note: In instance 't'
|
||||
36 | $display("coverage b = %f", the_cg.b.get_inst_coverage());
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:37:24: Member 'a' not found in class 'cg'
|
||||
: ... note: In instance 't'
|
||||
37 | if (the_cg.a.get_inst_coverage() != 15/16.0) $stop();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:37:26: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'logic''
|
||||
: ... note: In instance 't'
|
||||
37 | if (the_cg.a.get_inst_coverage() != 15/16.0) $stop();
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:38:24: Member 'b' not found in class 'cg'
|
||||
: ... note: In instance 't'
|
||||
38 | if (the_cg.b.get_inst_coverage() != 4/5.0) $stop();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:38:26: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'logic''
|
||||
: ... note: In instance 't'
|
||||
38 | if (the_cg.b.get_inst_coverage() != 4/5.0) $stop();
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,39 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
module t;
|
||||
class base;
|
||||
enum {red, green, blue} color;
|
||||
covergroup g1 (bit [3:0] a) with function sample(bit b);
|
||||
option.weight = 10;
|
||||
option.per_instance = 1;
|
||||
coverpoint a;
|
||||
coverpoint b;
|
||||
c: coverpoint color;
|
||||
endgroup
|
||||
function new();
|
||||
g1 = new(0);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class derived extends base;
|
||||
bit d;
|
||||
covergroup extends g1;
|
||||
option.weight = 1; // overrides the weight from base g1
|
||||
// uses per_instance = 1 from base g1
|
||||
c: coverpoint color // overrides the c coverpoint in base g1
|
||||
{
|
||||
ignore_bins ignore = {blue};
|
||||
}
|
||||
coverpoint d; // adds new coverpoint
|
||||
cross a, d; // crosses new coverpoint with inherited one
|
||||
endgroup :g1
|
||||
function new();
|
||||
super.new();
|
||||
endfunction
|
||||
endclass
|
||||
endmodule
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,39 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
module t;
|
||||
class base;
|
||||
function new();
|
||||
g1 = new(0);
|
||||
endfunction
|
||||
enum {red, green, blue} color;
|
||||
covergroup g1 (bit [3:0] a) with function sample(bit b);
|
||||
option.weight = 10;
|
||||
option.per_instance = 1;
|
||||
coverpoint a;
|
||||
coverpoint b;
|
||||
c: coverpoint color;
|
||||
endgroup
|
||||
endclass
|
||||
|
||||
class derived extends base;
|
||||
bit d;
|
||||
function new();
|
||||
super.new();
|
||||
endfunction
|
||||
covergroup extends g1;
|
||||
option.weight = 1; // overrides the weight from base g1
|
||||
// uses per_instance = 1 from base g1
|
||||
c: coverpoint color // overrides the c coverpoint in base g1
|
||||
{
|
||||
ignore_bins ignore = {blue};
|
||||
}
|
||||
coverpoint d; // adds new coverpoint
|
||||
cross a, d; // crosses new coverpoint with inherited one
|
||||
endgroup :g1
|
||||
endclass
|
||||
endmodule
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue