Compare commits

...

82 Commits

Author SHA1 Message Date
Ryszard Rozak 0f21baa478
Merge 24e61af2c0 into 9f04ee68c8 2025-07-22 13:18:43 +02:00
Geza Lore 9f04ee68c8
Optimize combinational cycles through arrays in DFG (#6210)
Extending V3DfgBreakCycles to handle common cases involving unpacked
arrays.
2025-07-22 08:23:45 +01:00
github action b5126a6abe Apply 'make format' 2025-07-21 23:29:42 +00:00
Danny Oler 74d4b0c0ea
Fix automatic task variables in unrolled loops with forks (#6194) (#6201). 2025-07-21 19:28:50 -04:00
Geza Lore 7401a8a43a
Refactor DFG IndependentBits analysis to work for any vertex. (#6209)
This used to be restricted to variable vertices, but now can handle
arbitrary circular vertices that represent packed values. It also
converges faster than the earlier version. Prep for resolving loops
through arrays.
2025-07-21 19:57:02 +01:00
Geza Lore 7646e7d89c
Exclude SystemC variables from DFG (#6208)
SystemC variables are fairly special (they can only be assigned to/from,
but not otherwise participate in expressions), which complicates some
DFG code. These variables only ever appear as port on the top level
wrapper, so excluding them from DFG does not make us loose any
optimizations, but simplifies internals.
2025-07-21 18:32:08 +01:00
Geza Lore a8dca71ed0
Support more complex combinational assignments in DFG. (#6205)
Previously DFG was limited to having a Sel, or an ArraySel potentially
under a Concat on the LHS of combinational assignments. Other forms or
combinations were not representable in the graph.

This adds support for arbitrary combinations of the above by
combining DfgSplicePacked and DfgSpliceArray vertices introduced in
 #6176. In particular, Sel(ArraySel(VarRef,_),_) enables a lot more code
to be represented in DFG.
2025-07-21 12:33:12 -04:00
Igor Zaworski 98b8d43a4a
Fix parameter-dependent type linking (#6170) 2025-07-21 07:30:10 -04:00
Bartłomiej Chmiel d419c49921
Internals: Fix unused variable, no functional change (#6204)
Signed-off-by: Bartłomiej Chmiel <bchmiel@antmicro.com>
2025-07-21 07:28:01 -04:00
Max Wipfli a50ea2a1a6
Optimize 2 ** X to 1 << X if base is signed (#6203) 2025-07-20 09:56:34 -04:00
Wilson Snyder 078bb21a89 Add wire data type checking per IEEE. 2025-07-20 07:21:30 -04:00
Wilson Snyder b8b9478938 Improve enum base type checking error message. 2025-07-19 22:37:07 -04:00
Wilson Snyder f535a73ea7 Commentary: Changes update 2025-07-19 21:12:23 -04:00
Wilson Snyder 641e0e5672 Internals: Fix assertion if bad display 2025-07-19 21:12:10 -04:00
Ibrahim Burak Yorulmaz 9d146eae16
Fix VPI signal range order (#6189) (#6200) 2025-07-19 20:22:02 -04:00
Wilson Snyder 7d43a935bd Add SPECIFYIGN warning for specify constructs that were previously silently ignored. 2025-07-18 19:32:34 -04:00
Yilou Wang 9b99d9697f
Fix virtual interface member propagation (#6175) (#6184) 2025-07-18 09:07:31 -04:00
Ryszard Rozak a21ecb2ab9
Add support for randomize..with on objects of aliased types (#6195) 2025-07-18 13:04:47 +02:00
Ryszard Rozak 28808f38bb
Dump function to which AstAddrOfCFunc points (#6188) 2025-07-18 08:37:00 +02:00
Wilson Snyder 7a6775ca84 Internals: Rename memPeakUsageBytes 2025-07-17 22:16:59 -04:00
Wilson Snyder e527ff49a3 Report `--stats` final results after build phase 2025-07-17 20:41:46 -04:00
Wilson Snyder c1506deef9 Add enum base type checking per IEEE. 2025-07-17 20:20:43 -04:00
Wilson Snyder 87050670b4 Fix structure select causing 'Wide Op' error (#6191). 2025-07-17 18:17:49 -04:00
Wilson Snyder fb1373b854 Tests: Reformat. Ignore whitespace if comparing. No test functional change. 2025-07-16 21:31:40 -04:00
Wilson Snyder 7f1011e5f7 Make some CVTREAL fatal where IEEE requires it. 2025-07-16 18:07:07 -04:00
Wilson Snyder 7a32771c7e Commentary: Changes update 2025-07-16 17:26:01 -04:00
Wilson Snyder 94b043d6c9 Internals: Print versions with `make format` 2025-07-16 17:25:22 -04:00
Igor Zaworski 8c5ba3a0d7
Fix conflicting function/class name linking error (#6182) 2025-07-16 17:25:01 -04:00
Igor Zaworski 826e5b0826
Fix `--coverage-expr` null pointer dereference (#6181) 2025-07-16 12:07:34 -04:00
Artur Bieniek abd509ce53
Support delays in emitted Verilog (#6177) 2025-07-16 11:52:56 -04:00
Ryszard Rozak 1bf24c7eb4
Add support for disabling begin just under fork from outside that begin (#5432 partial) (#6183) 2025-07-16 16:04:17 +02:00
Wilson Snyder 1f0357ba93 Add NOEFFECT warning, replacing previous `foreach` error. 2025-07-16 08:18:57 -04:00
Wilson Snyder db6b17fdb4 Fix error message 2025-07-15 17:41:08 -04:00
Artur Bieniek f3e109d8c5
Support covergroup extends, etc. (#6160) 2025-07-15 09:31:08 -04:00
Wilson Snyder 371ac07c6f Fix CVTREAL not being able to be disabled in e.g. primitive terminals. 2025-07-14 20:08:44 -04:00
Wilson Snyder caf3522364 Support implicit enum declarations with packed dimensions 2025-07-14 19:50:02 -04:00
Geza Lore 03e0d49d99
Optimize DFG partial assignments (#6176)
This is mostly a refactoring, but also enables handling some more
UNOPTFLAT, when the variable is only partially assigned in the cycle.

Previously the way partial assignments to variables were handled were
through the DfgVerexVar types themselves, which kept track of all
drivers. This has been replaced by DfgVertexSplice (which always drives
a DfgVeretexVar), and all DfgVertexVar now only have a single source,
either a DfgVertexSplice, if partially assigned, or an arbitrary
DfgVertex when updated as a whole.
2025-07-14 17:09:34 -04:00
Ryszard Rozak e2e5d9eaf1
Support disabling a fork from outside that fork (#6174) 2025-07-14 06:51:58 -04:00
Wilson Snyder 2f199f20cf Add ENUMITEMWIDTH error, and apply to X-extended and ranged values. 2025-07-12 14:14:17 -04:00
Wilson Snyder cefe1845df Commentary: Changes update 2025-07-11 21:53:29 -04:00
Yilou Wang 1044398f95
Support member-level triggers for virtual interfaces (#5166) (#6148) 2025-07-11 21:04:51 -04:00
Geza Lore 77180c4020
Optimize more cycles in DFG (#6173)
Added a second algorithm to break cycles in DFG by identifying which
bits of a circular variable are actually independent of the variable,
then reuse the existing (but extended) driver tracing algorithm to
eliminate them.

This can fix up things like: `assign gray = binary ^ (gray >> 1)`
2025-07-11 14:19:09 -04:00
github action 2fc12d951e Apply 'make format' 2025-07-11 17:11:31 +00:00
Petr Nohavica 0982260d3b
Fix constructor parameters in inheritance hierarchies (#6036) (#6070) 2025-07-11 13:10:36 -04:00
Ryszard Rozak 24e61af2c0 Change comments
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:46:51 +02:00
Ryszard Rozak 64f18f25b3 Skip top module input ports
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak a573ba9c83 Update number of optimizations
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 977b1cfe3d Change type to bit
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak dd9a0735db Remove initVarp initialization
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak e0abf4bd3d Replace assignments with always
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 7377320889 TMP: Add edges in both directions in V3Gate if varref is child of CoverToggle
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 09cf54a31f Disable coverage of initVarp statements 2025-06-09 11:24:27 +02:00
Ryszard Rozak 8d49cf9365 Skip warnings
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak b285c7ec81 Skip AstCoverToggle in V3Delayed
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 353b328946 Fix checking if type has ranges
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 5b19a916f6 Replace asserts with conditions
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 620a58a11a Add bit variables
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak b7f6627828 Remove cases with initialized var
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak b7844be66f Rename test
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 3f9f853585 Add initial block and run simulation for 10 cycles
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak efe37b2094 Fix CHECK_COVER offsets
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak e8e8e1f27b Change initVat to 2 if it is 1
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 7dacd7ad75 Set initVarp to 1 only if it is 0
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak bdf0450aa7 Add assignment to init var
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 880d838049 Clone varref when adding for 2nd time
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 3be0b11f95 Add new dtype to type table
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak a29bd3cf10 Increment counter if initVarp is 2. If 1, set it to 2
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 0d13399ded Make init var int type 2025-06-09 11:24:27 +02:00
Ryszard Rozak ddb5eefc46 Mark as init only when values change
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 0d764c338c Add initialization and change VAccess
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 579c068578 TMP: Throw fatalSrc if initp is not a varref
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 57a10ed3dc Throw assert on non-opaque type
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak f0747b12a3 Don't increment coverage in 1st assigment to 4-state var
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 5923627427 Delete initRefp in cleanup and add comment
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak f401743a7c Add p suffix
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:27 +02:00
Ryszard Rozak 94590610d3 Make initp field optional
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:26 +02:00
Ryszard Rozak 90dca9c3ab Handle nullptr initp in V3Clock
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:26 +02:00
Ryszard Rozak 890c0dcff8 Pass initVarp only if not null
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:26 +02:00
Ryszard Rozak e13b6b4cda WIP: Add InitVar only if type is fourstate
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:26 +02:00
Ryszard Rozak 6e27371b92 Change bit to logic
Signed-off-by: Ryszard Rozak <rrozak@antmicro.com>
2025-06-09 11:24:26 +02:00
Bartłomiej Chmiel cee15b9144 WIP: add Vtogcovinit for tracking whether initialization happened
Signed-off-by: Bartłomiej Chmiel <bchmiel@antmicro.com>
2025-06-09 11:24:26 +02:00
Bartłomiej Chmiel 94fbdbb68d Failing test
Signed-off-by: Bartłomiej Chmiel <bchmiel@antmicro.com>
2025-06-09 11:24:26 +02:00
199 changed files with 7657 additions and 3404 deletions

24
Changes
View File

@ -13,10 +13,30 @@ 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) (#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).
* Fix class extends dotted error (#6162). [Igor Zaworski]
* Fix constructor parameters in inheritance hierarchies (#6036) (#6070). [Petr Nohavica]
* 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) (#6176). [Geza Lore]
* Fix omitting error when assigning to an input (#6169). [Artur Bieniek, 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 VPI signal range order (#6189) (#6200). [Ibrahim Burak Yorulmaz]
* Fix structure select causing 'Wide Op' error (#6191). [Danny Oler]
Verilator 5.038 2025-07-08
@ -107,7 +127,7 @@ Verilator 5.038 2025-07-08
* Fix wide non-blocking assignment mis-optimization (#6150) (#6152) (#6155). [Todd Strader]
* Fix interface array connections with non-zero low declaration index.
* Fix developer build error on MacOS/Flex2.6.4 (#6153). [Paul Swirhun]
* Fix crash with --dumpi-V3LinkDot without --debug (#6159). [Igor Zaworski]
* Fix crash with --dumpi-V3LinkDot without --debug (#6159). [Igor Zaworski, Antmicro Ltd.]
Verilator 5.036 2025-04-27

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
@ -709,6 +709,28 @@ List Of Warnings
missing."
.. option:: ENUMITEMWIDTH
An error that an enum item value is being assigned from a value which
would be truncated (similar to :option:`WIDTHTRUNC`), or from a sized
literal constant with a different bit width (similar to
:option:`WIDTHTRUNC` or :option:`WIDTHEXPAND`). IEEE requires this
error, but it may be disabled.
Faulty example:
.. code-block:: sv
:linenos:
:emphasize-lines: 2
typedef enum [3:0] {
WRONG_WIDTH = 33'h3 //<--- Warning
} enum_t;
To repair, correct the size of the item's value directly, or use a cast,
so the resulting width matches the enum's width.
.. option:: ENUMVALUE
An error that an enum data type value is being assigned from another data
@ -1286,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
@ -1742,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*/`

View File

@ -314,6 +314,7 @@ Noack
Nodine
Ober
Oleg
Oler
Olof
Olofsson
Oron
@ -481,6 +482,7 @@ Wfuture
Whatson
Wildman
Wim
Wipfli
Wmisleading
Wno
Wojciech
@ -600,6 +602,7 @@ coroutines
countbits
countones
cout
covergroup
cpp
cppstyle
cpu

View File

@ -3061,7 +3061,7 @@ 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;
const double modelMB = VlOs::memPeakUsageBytes() / 1024.0 / 1024.0;
VL_PRINTF("- Verilator: cpu %0.3f s on %u threads; alloced %0.0f MB\n", cputime,
threadsInModels(), modelMB);
}

View File

@ -175,6 +175,14 @@ package std;
`endif
endtask
static task killQueue(ref process processQueue[$]);
`ifdef VERILATOR_TIMING
while (processQueue.size() > 0) begin
processQueue.pop_back().kill();
end
`endif
endtask
// Two process references are equal if the different classes' containing
// m_process are equal. Can't yet use <=> as the base class template
// comparisons doesn't define <=> as they don't yet require --timing and C++20.

View File

@ -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 uint64_t memPeakUsageBytes() VL_MT_SAFE;
// Internal: Record CPU time, starting point on construction, and current delta from that
class DeltaCpuTime final {

View File

@ -102,9 +102,9 @@ uint16_t getcpu() VL_MT_SAFE {
}
//=========================================================================
// VlOs::memUsageBytes implementation
// VlOs::memPeakUsageBytes implementation
uint64_t memUsageBytes() VL_MT_SAFE {
uint64_t memPeakUsageBytes() VL_MT_SAFE {
#if defined(_WIN32) || defined(__MINGW32__)
const HANDLE process = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS pmc;
@ -124,6 +124,7 @@ uint64_t memUsageBytes() VL_MT_SAFE {
&size, &resident, &share, &text, &lib, &data, &dt);
fclose(fp);
if (VL_UNCOVERABLE(7 != items)) return 0;
// Return the vm size, not the current active set size (/proc/self/status VmRSS + VmSwap)
return (text + data) * getpagesize();
#endif
}

View File

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

View File

@ -1974,7 +1974,7 @@ class AstVar final : public AstNode {
bool m_isConst : 1; // Table contains constant data
bool m_isContinuously : 1; // Ever assigned continuously (for force/release)
bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier
bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic)
bool m_isStatic : 1; // Static C variable (for Verilog see instead lifetime())
bool m_isPulldown : 1; // Tri0
bool m_isPullup : 1; // Tri1
bool m_isIfaceParent : 1; // dtype is reference to interface present in this module
@ -3057,12 +3057,15 @@ class AstCoverToggle final : public AstNodeStmt {
// @astgen op1 := incp : AstCoverInc
// @astgen op2 := origp : AstNodeExpr
// @astgen op3 := changep : AstNodeExpr
// @astgen op4 := initp : Optional[AstNodeExpr]
public:
AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNodeExpr* origp, AstNodeExpr* changep)
AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNodeExpr* origp, AstNodeExpr* changep,
AstNodeExpr* initp)
: ASTGEN_SUPER_CoverToggle(fl) {
this->incp(incp);
this->origp(origp);
this->changep(changep);
this->initp(initp);
}
ASTGEN_MEMBERS_AstCoverToggle;
int instrCount() const override { return 3 + INSTR_COUNT_BRANCH + INSTR_COUNT_LD; }

View File

@ -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
@ -1110,6 +1116,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

View File

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

View File

@ -57,28 +57,18 @@ class ClassVisitor final : public VNVisitor {
// METHODS
bool recurseImplements(AstClass* nodep, bool setit) {
// Returns true to set useVirtualPublic().
// If there's an implements of an interface class then we have
// multiple classes that point to same object, that need same
// VlClass (the diamond problem). C++ will require we use 'virtual
// public' for VlClass. So, we need the interface class, and all
// classes above, and any below using any implements to use
// 'virtual public' via useVirtualPublic().
if (nodep->useVirtualPublic()) return true; // Short-circuit
if (nodep->isInterfaceClass()) setit = true;
void recurseImplements(AstClass* nodep) {
// In SystemVerilog, we have two inheritance chains:
// - extends of concrete clasess: mapped to non-virtual C++ inheritance
// as there is only single ancestor allowed
// - implements of concrete classes / extends of interface classes: mapped
// to virtual inheritance to allow diamond patterns with multiple ancestors
if (nodep->useVirtualPublic()) return; // Short-circuit to exit diamond cycles
if (nodep->isInterfaceClass()) { nodep->useVirtualPublic(true); }
for (const AstClassExtends* extp = nodep->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
if (recurseImplements(extp->classp(), setit)) setit = true;
recurseImplements(extp->classp());
}
if (setit) {
nodep->useVirtualPublic(true);
for (const AstClassExtends* extp = nodep->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
(void)recurseImplements(extp->classp(), true);
}
}
return setit;
}
// VISITORS
@ -89,7 +79,7 @@ class ClassVisitor final : public VNVisitor {
nodep->name(m_prefix + nodep->name());
nodep->unlinkFrBack();
v3Global.rootp()->addModulesp(nodep);
(void)recurseImplements(nodep, false);
recurseImplements(nodep);
// Make containing package
// Note origName is the same as the class origName so errors look correct
AstClassPackage* const packagep

View File

@ -100,23 +100,44 @@ class ClockVisitor final : public VNVisitor {
// if (debug()) nodep->dumpTree("- ct: ");
// COVERTOGGLE(INC, ORIG, CHANGE) ->
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
AstNode* const incp = nodep->incp()->unlinkFrBack();
FileLine* fl = nodep->fileline();
AstNodeStmt* const incp = nodep->incp()->unlinkFrBack();
AstNodeExpr* const origp = nodep->origp()->unlinkFrBack();
AstNodeExpr* const changeWrp = nodep->changep()->unlinkFrBack();
AstNodeExpr* const changeRdp = ConvertWriteRefsToRead::main(changeWrp->cloneTree(false));
AstNodeExpr* comparedp = nullptr;
// Xor will optimize better than Eq, when CoverToggle has bit selects,
// but can only use Xor with non-opaque types
// but can only use Xor with non-opaque types.
// Opaque types aren't accepted by V3Coverage::varIgnoreToggle
if (const AstBasicDType* const bdtypep
= VN_CAST(origp->dtypep()->skipRefp(), BasicDType)) {
if (!bdtypep->isOpaque()) comparedp = new AstXor{nodep->fileline(), origp, changeRdp};
if (!bdtypep->isOpaque()) comparedp = new AstXor{fl, origp, changeRdp};
}
if (!comparedp) comparedp = AstEq::newTyped(nodep->fileline(), origp, changeRdp);
AstIf* const newp = new AstIf{nodep->fileline(), comparedp, incp};
UASSERT_OBJ(comparedp, nodep, "Toggle coverage of non-opaque type variable");
AstNodeStmt* incBodyp;
AstIf* initIfp = nullptr;
if (nodep->initp()) {
if (AstVarRef* const writeRefp = VN_CAST(nodep->initp(), VarRef)) {
AstVarRef* const readRefp = writeRefp->cloneTree(false);
readRefp->access(VAccess::READ);
AstAssign* const initAssignp
= new AstAssign{fl, writeRefp->unlinkFrBack(), new AstConst{fl, 2}};
initIfp = new AstIf{fl, new AstEq{fl, readRefp, new AstConst{fl, 1}}, initAssignp};
incBodyp
= new AstIf{fl, new AstEq{fl, readRefp->cloneTree(false), new AstConst{fl, 2}},
incp, initIfp->cloneTree(false)};
} else {
nodep->initp()->v3fatalSrc("Initp is not a var ref");
incBodyp = nullptr;
}
} else {
incBodyp = incp;
}
AstIf* const newp = new AstIf{fl, comparedp, incBodyp, initIfp};
// We could add another IF to detect posedges, and only increment if so.
// It's another whole branch though versus a potential memory miss.
// We'll go with the miss.
newp->addThensp(new AstAssign{nodep->fileline(), changeWrp, origp->cloneTree(false)});
newp->addThensp(new AstAssign{fl, changeWrp, origp->cloneTree(false)});
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}

View File

@ -1267,8 +1267,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());
@ -3550,6 +3554,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

View File

@ -39,17 +39,28 @@ 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;
}
}
@ -92,14 +103,17 @@ class CoverageVisitor final : public VNVisitor {
const string m_comment; // Comment for coverage dump
AstNodeExpr* m_varRefp; // How to get to this element
AstNodeExpr* m_chgRefp; // How to get to this element
ToggleEnt(const string& comment, AstNodeExpr* vp, AstNodeExpr* cp)
AstNodeExpr* m_initRefp; // Expression that stores initialization status
ToggleEnt(const string& comment, AstNodeExpr* vp, AstNodeExpr* cp, AstNodeExpr* initp)
: m_comment{comment}
, m_varRefp{vp}
, m_chgRefp{cp} {}
, m_chgRefp{cp}
, m_initRefp{initp} {}
~ToggleEnt() = default;
void cleanup() {
VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = nullptr);
VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = nullptr);
if (m_initRefp) { VL_DO_CLEAR(m_initRefp->deleteTree(), m_initRefp = nullptr); }
}
};
@ -376,16 +390,55 @@ class CoverageVisitor final : public VNVisitor {
const string newvarname = "__Vtogcov__"s + m_beginHier + nodep->shortName();
FileLine* const fl_nowarn = new FileLine{nodep->fileline()};
fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
fl_nowarn->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true);
fl_nowarn->modifyWarnOff(V3ErrorCode::MULTIDRIVEN, true);
fl_nowarn->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true);
fl_nowarn->coverageOn(false);
AstVar* const chgVarp
= new AstVar{fl_nowarn, VVarType::MODULETEMP, newvarname, nodep};
m_modp->addStmtsp(chgVarp);
AstVar* initVarp = nullptr;
AstVarRef* initWriteRefp = nullptr;
// We need to exclude top module input ports, because they can't have value x.
// TODO: Exclude also variables driven by top module input ports
const bool isTopModuleInput
= (v3Global.rootp()->topModulep() == m_modp) && nodep->isInput();
const AstBasicDType* const basicDTypep
= VN_CAST(nodep->dtypep()->skipRefp(), BasicDType);
if (basicDTypep && basicDTypep->isFourstate() && basicDTypep->isBitLogic()
&& !basicDTypep->isRanged() && !isTopModuleInput) {
const string initVarName
= "__Vtogcovinit__"s + m_beginHier + nodep->shortName();
AstBasicDType* const initDtypep
= new AstBasicDType{fl_nowarn, VBasicDTypeKwd::INT, VSigning::NOSIGN};
v3Global.rootp()->typeTablep()->addTypesp(initDtypep);
initVarp
= new AstVar{fl_nowarn, VVarType::MODULETEMP, initVarName, initDtypep};
m_modp->addStmtsp(initVarp);
initWriteRefp = new AstVarRef{fl_nowarn, initVarp, VAccess::WRITE};
AstAssign* const assignp
= new AstAssign{fl_nowarn, initWriteRefp->cloneTree(false),
new AstConst{fl_nowarn, AstConst::All1{}}};
AstIf* const ifp = new AstIf{
fl_nowarn,
new AstEq{fl_nowarn, new AstVarRef{fl_nowarn, initVarp, VAccess::READ},
new AstConst{fl_nowarn, AstConst::All0{}}},
assignp};
AstSenTree* const sentreep = new AstSenTree{
fl_nowarn, new AstSenItem{fl_nowarn, VEdgeType::ET_CHANGED,
new AstVarRef{fl_nowarn, nodep, VAccess::READ}}};
AstAlways* const alwaysp
= new AstAlways{fl_nowarn, VAlwaysKwd::ALWAYS, sentreep, ifp};
m_modp->addStmtsp(alwaysp);
}
// Create bucket for each dimension * bit.
// This is necessarily an O(n^2) expansion, which is why
// we limit coverage to signals with < 256 bits.
ToggleEnt newvec{""s, new AstVarRef{fl_nowarn, nodep, VAccess::READ},
new AstVarRef{fl_nowarn, chgVarp, VAccess::WRITE}};
new AstVarRef{fl_nowarn, chgVarp, VAccess::WRITE}, initWriteRefp};
toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep);
newvec.cleanup();
}
@ -399,7 +452,8 @@ class CoverageVisitor final : public VNVisitor {
varp->fileline(),
newCoverInc(varp->fileline(), "", "v_toggle",
hierPrefix + varp->name() + above.m_comment, "", 0, ""),
above.m_varRefp->cloneTree(false), above.m_chgRefp->cloneTree(false)};
above.m_varRefp->cloneTree(false), above.m_chgRefp->cloneTree(false),
above.m_initRefp ? above.m_initRefp->cloneTree(false) : nullptr};
m_modp->addStmtsp(newp);
}
@ -414,7 +468,12 @@ class CoverageVisitor final : public VNVisitor {
new AstSel{varp->fileline(),
above.m_varRefp->cloneTree(false), index_code, 1},
new AstSel{varp->fileline(),
above.m_chgRefp->cloneTree(false), index_code, 1}};
above.m_chgRefp->cloneTree(false), index_code, 1},
above.m_initRefp
? new AstSel{varp->fileline(),
above.m_initRefp->cloneTree(false),
index_code, 1}
: nullptr};
toggleVarBottom(newent, varp);
newent.cleanup();
}
@ -428,7 +487,12 @@ class CoverageVisitor final : public VNVisitor {
new AstArraySel{varp->fileline(),
above.m_varRefp->cloneTree(false), index_code},
new AstArraySel{varp->fileline(),
above.m_chgRefp->cloneTree(false), index_code}};
above.m_chgRefp->cloneTree(false), index_code},
above.m_initRefp
? new AstArraySel{varp->fileline(),
above.m_initRefp->cloneTree(false),
index_code}
: nullptr};
toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth + 1, newent, varp);
newent.cleanup();
}
@ -436,11 +500,16 @@ class CoverageVisitor final : public VNVisitor {
for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) {
const AstNodeDType* const subtypep = adtypep->subDTypep()->skipRefp();
const int index_code = index_docs - adtypep->lo();
ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]",
new AstSel{varp->fileline(), above.m_varRefp->cloneTree(false),
index_code * subtypep->width(), subtypep->width()},
new AstSel{varp->fileline(), above.m_chgRefp->cloneTree(false),
index_code * subtypep->width(), subtypep->width()}};
ToggleEnt newent{
above.m_comment + "["s + cvtToStr(index_docs) + "]",
new AstSel{varp->fileline(), above.m_varRefp->cloneTree(false),
index_code * subtypep->width(), subtypep->width()},
new AstSel{varp->fileline(), above.m_chgRefp->cloneTree(false),
index_code * subtypep->width(), subtypep->width()},
above.m_initRefp
? new AstSel{varp->fileline(), above.m_initRefp->cloneTree(false),
index_code * subtypep->width(), subtypep->width()}
: nullptr};
toggleVarRecurse(adtypep->subDTypep()->skipRefp(), depth + 1, newent, varp);
newent.cleanup();
}
@ -455,7 +524,11 @@ class CoverageVisitor final : public VNVisitor {
new AstSel{varp->fileline(), above.m_varRefp->cloneTree(false), index_code,
subtypep->width()},
new AstSel{varp->fileline(), above.m_chgRefp->cloneTree(false), index_code,
subtypep->width()}};
subtypep->width()},
above.m_initRefp
? new AstSel{varp->fileline(), above.m_initRefp->cloneTree(false),
index_code, subtypep->width()}
: nullptr};
toggleVarRecurse(subtypep, depth + 1, newent, varp);
newent.cleanup();
}
@ -467,9 +540,16 @@ class CoverageVisitor final : public VNVisitor {
varp->fileline(), above.m_varRefp->cloneTree(false), itemp->name()};
AstNodeExpr* const chgRefp = new AstStructSel{
varp->fileline(), above.m_chgRefp->cloneTree(false), itemp->name()};
AstNodeExpr* const initRefp
= above.m_initRefp
? new AstStructSel{varp->fileline(),
above.m_initRefp->cloneTree(false), itemp->name()}
: nullptr;
varRefp->dtypep(subtypep);
chgRefp->dtypep(subtypep);
ToggleEnt newent{above.m_comment + "."s + itemp->name(), varRefp, chgRefp};
initRefp->dtypep(subtypep);
ToggleEnt newent{above.m_comment + "."s + itemp->name(), varRefp, chgRefp,
initRefp};
toggleVarRecurse(subtypep, depth + 1, newent, varp);
newent.cleanup();
}
@ -479,9 +559,10 @@ class CoverageVisitor final : public VNVisitor {
if (const AstMemberDType* const itemp = adtypep->membersp()) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefp();
if (adtypep->packed()) {
ToggleEnt newent{above.m_comment + "."s + itemp->name(),
above.m_varRefp->cloneTree(false),
above.m_chgRefp->cloneTree(false)};
ToggleEnt newent{
above.m_comment + "."s + itemp->name(), above.m_varRefp->cloneTree(false),
above.m_chgRefp->cloneTree(false),
above.m_initRefp ? above.m_initRefp->cloneTree(false) : nullptr};
toggleVarRecurse(subtypep, depth + 1, newent, varp);
newent.cleanup();
} else {
@ -489,9 +570,16 @@ class CoverageVisitor final : public VNVisitor {
varp->fileline(), above.m_varRefp->cloneTree(false), itemp->name()};
AstNodeExpr* const chgRefp = new AstStructSel{
varp->fileline(), above.m_chgRefp->cloneTree(false), itemp->name()};
AstNodeExpr* const initRefp
= above.m_initRefp
? new AstStructSel{varp->fileline(),
above.m_initRefp->cloneTree(false), itemp->name()}
: nullptr;
varRefp->dtypep(subtypep);
chgRefp->dtypep(subtypep);
ToggleEnt newent{above.m_comment + "."s + itemp->name(), varRefp, chgRefp};
initRefp->dtypep(subtypep);
ToggleEnt newent{above.m_comment + "."s + itemp->name(), varRefp, chgRefp,
initRefp};
toggleVarRecurse(subtypep, depth + 1, newent, varp);
newent.cleanup();
}
@ -858,7 +946,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));

View File

@ -1265,6 +1265,9 @@ class DelayedVisitor final : public VNVisitor {
void visit(AstAssignPost*) override {}
void visit(AstAlwaysPost*) override {}
// Children of AstCoverToggle aren't part of assignments
void visit(AstCoverToggle* nodep) override {}
//--------------------
void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -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;
@ -694,6 +738,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 {

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#include "V3DfgPasses.h"
#include "V3Hash.h"
#include <deque>
#include <fstream>
#include <limits>
#include <unordered_map>
@ -191,32 +192,56 @@ class TraceDriver final : public DfgVisitor {
DfgGraph& m_dfg; // The graph being processed
// The strongly connected component we are trying to escape
const uint32_t m_component;
const bool m_aggressive; // Trace aggressively, creating intermediate ops
uint32_t m_lsb = 0; // LSB to extract from the currently visited Vertex
uint32_t m_msb = 0; // MSB to extract from the currently visited Vertex
// Result of tracing the currently visited Vertex. Use SET_RESULT below!
DfgVertex* m_resp = nullptr;
std::vector<DfgVertex*> m_newVtxps; // New vertices created during the traversal
std::ofstream m_lineCoverageFile; // Line coverage file, just for testing
std::vector<Visited> m_stack; // Stack of currently visited vertices
// Denotes if a 'Visited' entry appear in m_stack
std::unordered_map<Visited, bool, Visited::Hash, Visited::Equal> m_visited;
std::ofstream m_lineCoverageFile; // Line coverage file, just for testing
// METHODS
// Create and return a new Vertex and add it to m_newVtxps. You should
// 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.
template <typename Vertex>
Vertex* make(FileLine* flp, uint32_t width) {
Vertex* make(const DfgVertex* refp, uint32_t width) {
static_assert(std::is_base_of<DfgVertex, Vertex>::value //
&& !std::is_base_of<DfgVertexVar, Vertex>::value //
&& !std::is_same<DfgConst, DfgVertex>::value,
"Should only make operation vertices");
AstNodeDType* const dtypep = DfgVertex::dtypeForWidth(width);
Vertex* const vtxp = new Vertex{m_dfg, flp, dtypep};
m_newVtxps.emplace_back(vtxp);
return vtxp;
&& !std::is_base_of<DfgVertexVar, Vertex>::value,
"Should only make operation vertices and constants");
constexpr bool okWithoutAggressive = //
std::is_same<DfgConst, Vertex>::value //
|| std::is_same<DfgSel, Vertex>::value //
|| std::is_same<DfgConcat, Vertex>::value //
|| std::is_same<DfgExtend, Vertex>::value;
UASSERT_OBJ(
okWithoutAggressive || m_aggressive, refp,
"Should only create Const, Sel, Concat, Exend Vertices without aggressive mode");
if VL_CONSTEXPR_CXX17 (std::is_same<DfgConst, Vertex>::value) {
DfgConst* const vtxp = new DfgConst{m_dfg, refp->fileline(), width};
m_newVtxps.emplace_back(vtxp);
return reinterpret_cast<Vertex*>(vtxp);
} else {
// TODO: this is a gross hack around lack of C++17 'if constexpr' Vtx is always Vertex
// when this code is actually executed, but needs a fudged type to type check when
// Vertex is DfgConst, in which case this code is unreachable ...
using Vtx = typename std::conditional<std::is_same<DfgConst, Vertex>::value, DfgSel,
Vertex>::type;
AstNodeDType* const dtypep = DfgVertex::dtypeForWidth(width);
Vtx* const vtxp = new Vtx{m_dfg, refp->fileline(), dtypep};
m_newVtxps.emplace_back(vtxp);
return reinterpret_cast<Vertex*>(vtxp);
}
}
// Continue tracing drivers of the given vertex, at the given LSB. Every
@ -256,7 +281,7 @@ class TraceDriver final : public DfgVisitor {
// then we found what we were looking for.
if (msb != vtxp->width() - 1 || lsb != 0) {
// Apply a Sel to extract the relevant bits if only a part is needed
DfgSel* const selp = make<DfgSel>(vtxp->fileline(), msb - lsb + 1);
DfgSel* const selp = make<DfgSel>(vtxp, msb - lsb + 1);
selp->fromp(vtxp);
selp->lsb(lsb);
m_resp = selp;
@ -280,9 +305,49 @@ class TraceDriver final : public DfgVisitor {
m_stack.pop_back();
// Done
if (!m_resp) {
UINFO(9, "TraceDriver - Failed to trace vertex of type: " << vtxp->typeName());
}
return m_resp;
}
template <typename Vertex>
Vertex* bitwiseBinary(Vertex* vtxp) {
static_assert(std::is_base_of<DfgVertexBinary, Vertex>::value,
"Should only call on DfgVertexBinary");
if (DfgVertex* const rp = trace(vtxp->rhsp(), m_msb, m_lsb)) {
if (DfgVertex* const lp = trace(vtxp->lhsp(), m_msb, m_lsb)) {
Vertex* const resp = make<Vertex>(vtxp, m_msb - m_lsb + 1);
resp->rhsp(rp);
resp->lhsp(lp);
return resp;
}
}
return nullptr;
}
// Predicate to do determine if vtxp[$bits(vtxp)-1:idx] is known to be zero
// Somewhat rudimentary but sufficient for current purposes.
static bool knownToBeZeroAtAndAbove(const DfgVertex* vtxp, uint32_t idx) {
if (const DfgConcat* const catp = vtxp->cast<DfgConcat>()) {
DfgConst* const lConstp = catp->lhsp()->cast<DfgConst>();
return lConstp && idx >= catp->rhsp()->width() && lConstp->isZero();
}
if (const DfgExtend* const extp = vtxp->cast<DfgExtend>()) {
return idx >= extp->srcp()->width();
}
return false;
}
// Like knownToBeZeroAtAndAbove, but checks vtxp[idx:0]
static bool knownToBeZeroAtAndBelow(const DfgVertex* vtxp, uint32_t idx) {
if (const DfgConcat* const catp = vtxp->cast<DfgConcat>()) {
DfgConst* const rConstp = catp->rhsp()->cast<DfgConst>();
return rConstp && idx < rConstp->width() && rConstp->isZero();
}
return false;
}
// Use this macro to set the result in 'visit' methods. This also emits
// a line to m_lineCoverageFile for testing.
// TODO: Use C++20 std::source_location instead of a macro
@ -298,7 +363,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) {
@ -313,6 +378,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();
@ -327,10 +420,10 @@ class TraceDriver final : public DfgVisitor {
SET_RESULT(trace(lhsp, m_msb - rWidth, m_lsb - rWidth));
return;
}
// The traced bit span both sides, attempt to trace both
// The traced bit spans both sides, attempt to trace both
if (DfgVertex* const rp = trace(rhsp, rWidth - 1, m_lsb)) {
if (DfgVertex* const lp = trace(lhsp, m_msb - rWidth, 0)) {
DfgConcat* const resp = make<DfgConcat>(vtxp->fileline(), m_msb - m_lsb + 1);
DfgConcat* const resp = make<DfgConcat>(vtxp, m_msb - m_lsb + 1);
resp->rhsp(rp);
resp->lhsp(lp);
SET_RESULT(resp);
@ -341,10 +434,24 @@ class TraceDriver final : public DfgVisitor {
void visit(DfgExtend* vtxp) override {
DfgVertex* const srcp = vtxp->srcp();
if (srcp->width() > m_msb) {
const uint32_t sWidth = srcp->width();
// If the traced bits are wholly in the input
if (sWidth > m_msb) {
SET_RESULT(trace(srcp, m_msb, m_lsb));
return;
}
// If the traced bits are wholly in the extension
if (m_lsb >= sWidth) {
SET_RESULT(make<DfgConst>(vtxp, m_msb - m_lsb + 1));
return;
}
// The traced bits span both sides
if (DfgVertex* const sp = trace(srcp, sWidth - 1, m_lsb)) {
DfgExtend* const resp = make<DfgExtend>(vtxp, m_msb - m_lsb + 1);
resp->srcp(sp);
SET_RESULT(resp);
return;
}
}
void visit(DfgSel* vtxp) override {
@ -353,12 +460,107 @@ class TraceDriver final : public DfgVisitor {
return;
}
void visit(DfgNot* vtxp) override {
if (!m_aggressive) return;
if (DfgVertex* const sp = trace(vtxp->srcp(), m_msb, m_lsb)) {
DfgNot* const resp = make<DfgNot>(vtxp, m_msb - m_lsb + 1);
resp->srcp(sp);
SET_RESULT(resp);
return;
}
}
void visit(DfgAnd* vtxp) override {
if (!m_aggressive) return;
SET_RESULT(bitwiseBinary(vtxp));
}
void visit(DfgOr* vtxp) override {
if (!m_aggressive) return;
SET_RESULT(bitwiseBinary(vtxp));
}
void visit(DfgXor* vtxp) override {
if (!m_aggressive) return;
SET_RESULT(bitwiseBinary(vtxp));
}
void visit(DfgShiftR* vtxp) override {
DfgVertex* const lhsp = vtxp->lhsp();
if (DfgConst* const rConstp = vtxp->rhsp()->cast<DfgConst>()) {
const uint32_t shiftAmnt = rConstp->toU32();
// Width of lower half of result
const uint32_t lowerWidth = shiftAmnt > vtxp->width() ? 0 : vtxp->width() - shiftAmnt;
// If the traced bits are wholly in the input
if (lowerWidth > m_msb) {
SET_RESULT(trace(lhsp, m_msb + shiftAmnt, m_lsb + shiftAmnt));
return;
}
// If the traced bits are wholly in the extension
if (m_lsb >= lowerWidth) {
SET_RESULT(make<DfgConst>(vtxp, m_msb - m_lsb + 1));
return;
}
// The traced bits span both sides
if (DfgVertex* const sp = trace(lhsp, lowerWidth - 1 + shiftAmnt, m_lsb + shiftAmnt)) {
DfgExtend* const resp = make<DfgExtend>(vtxp, m_msb - m_lsb + 1);
resp->srcp(sp);
SET_RESULT(resp);
return;
}
return;
}
// The shift amount is non-negative, so we can conclude zero if all
// bits at and above the LSB we seek are zeroes
if (knownToBeZeroAtAndAbove(lhsp, m_lsb)) {
SET_RESULT(make<DfgConst>(vtxp, m_msb - m_lsb + 1));
return;
}
}
void visit(DfgShiftL* vtxp) override {
DfgVertex* const lhsp = vtxp->lhsp();
if (DfgConst* const rConstp = vtxp->rhsp()->cast<DfgConst>()) {
const uint32_t shiftAmnt = rConstp->toU32();
// Width of lower half of result
const uint32_t lowerWidth = shiftAmnt > vtxp->width() ? vtxp->width() : shiftAmnt;
// If the traced bits are wholly in the input
if (m_lsb >= lowerWidth) {
SET_RESULT(trace(lhsp, m_msb - shiftAmnt, m_lsb - shiftAmnt));
return;
}
// If the traced bits are wholly in the extension
if (lowerWidth > m_msb) {
SET_RESULT(make<DfgConst>(vtxp, m_msb - m_lsb + 1));
return;
}
// The traced bits span both sides
if (DfgVertex* const sp = trace(lhsp, m_msb - shiftAmnt, lowerWidth - shiftAmnt)) {
DfgConcat* const resp = make<DfgConcat>(vtxp, m_msb - m_lsb + 1);
resp->rhsp(make<DfgConst>(vtxp, resp->width() - sp->width()));
resp->lhsp(sp);
SET_RESULT(resp);
return;
}
return;
}
// The shift amount is non-negative, so we can conclude zero if all
// bits at and below the MSB we seek are zeroes
if (knownToBeZeroAtAndBelow(lhsp, m_msb)) {
SET_RESULT(make<DfgConst>(vtxp, m_msb - m_lsb + 1));
return;
}
}
#undef SET_RESULT
// CONSTRUCTOR
TraceDriver(DfgGraph& dfg, uint32_t component)
TraceDriver(DfgGraph& dfg, uint32_t component, bool aggressive)
: m_dfg{dfg}
, m_component{component} {
, m_component{component}
, m_aggressive{aggressive} {
if (v3Global.opt.debugCheck()) {
m_lineCoverageFile.open( //
v3Global.opt.makeDir() + "/" + v3Global.opt.prefix()
@ -371,9 +573,13 @@ public:
// Given a Vertex that is part of an SCC denoted by vtxp->user<uint32_t>(),
// return a vertex that is equivalent to 'vtxp[lsb +: width]', but is not
// part of the same SCC. Returns nullptr if such a vertex cannot be
// computed. This can add new vertices to the graph.
static DfgVertex* apply(DfgGraph& dfg, DfgVertex* vtxp, uint32_t lsb, uint32_t width) {
TraceDriver traceDriver{dfg, vtxp->user<uint32_t>()};
// computed. This can add new vertices to the graph. The 'aggressive' flag
// enables creating many intermediate operations. This should only be set
// if it is reasonably certain the tracing will succeed, otherwise we can
// 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};
// 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
@ -393,6 +599,496 @@ public:
}
};
class IndependentBits final : public DfgVisitor {
// STATE
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) {
// 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
// a line to m_lineCoverageFile for testing.
// TODO: Use C++20 std::source_location instead of a macro
#define MASK(vtxp) \
([this](const DfgVertex* p) -> V3Number& { \
if (VL_UNLIKELY(m_lineCoverageFile.is_open())) m_lineCoverageFile << __LINE__ << '\n'; \
return mask(p); \
}(vtxp))
// VISITORS
void visit(DfgVertex* vtxp) override {
UINFO(9, "Unhandled vertex type " << vtxp->typeName());
// Conservative assumption about all bits being dependent prevails
}
void visit(DfgSplicePacked* vtxp) override {
// Combine the masks of all drivers
V3Number& m = MASK(vtxp);
vtxp->forEachSourceEdge([&](DfgEdge& edge, size_t i) {
const DfgVertex* const srcp = edge.sourcep();
m.opSelInto(MASK(srcp), vtxp->driverLsb(i), srcp->width());
});
}
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();
V3Number& m = MASK(vtxp);
m.opSelInto(MASK(rhsp), 0, rhsp->width());
m.opSelInto(MASK(lhsp), rhsp->width(), lhsp->width());
}
void visit(DfgReplicate* vtxp) override {
const uint32_t count = vtxp->countp()->as<DfgConst>()->toU32();
const DfgVertex* const srcp = vtxp->srcp();
const uint32_t sWidth = srcp->width();
V3Number& vMask = MASK(vtxp);
V3Number& sMask = MASK(srcp);
for (uint32_t i = 0; i < count; ++i) vMask.opSelInto(sMask, i * sWidth, sWidth);
}
void visit(DfgSel* vtxp) override {
const uint32_t lsb = vtxp->lsb();
const uint32_t msb = lsb + vtxp->width() - 1;
MASK(vtxp).opSel(MASK(vtxp->fromp()), msb, lsb);
}
void visit(DfgExtend* vtxp) override {
const DfgVertex* const srcp = vtxp->srcp();
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 { //
MASK(vtxp) = MASK(vtxp->srcp());
}
void visit(DfgAnd* vtxp) override { //
MASK(vtxp).opOr(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
}
void visit(DfgOr* vtxp) override { //
MASK(vtxp).opOr(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
}
void visit(DfgXor* vtxp) override { //
MASK(vtxp).opOr(MASK(vtxp->lhsp()), MASK(vtxp->rhsp()));
}
void visit(DfgShiftR* vtxp) override {
DfgVertex* const rhsp = vtxp->rhsp();
DfgVertex* const lhsp = vtxp->lhsp();
const uint32_t width = vtxp->width();
// Constant shift can be computed precisely
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
const uint32_t shiftAmount = rConstp->toU32();
if (shiftAmount >= width) return;
V3Number shiftedMask{lhsp->fileline(), static_cast<int>(width), 0};
shiftedMask.opShiftR(MASK(lhsp), rConstp->num());
V3Number& m = MASK(vtxp);
m.opSelInto(shiftedMask, 0, width - shiftAmount);
m.opSetRange(width - shiftAmount, shiftAmount, '0');
return;
}
// Otherwise, as the shift amount is non-negative, any bit at or below
// the most significant dependent bit might be dependent
V3Number& lMask = MASK(lhsp);
V3Number& vMask = MASK(vtxp);
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 {
DfgVertex* const rhsp = vtxp->rhsp();
DfgVertex* const lhsp = vtxp->lhsp();
const uint32_t width = vtxp->width();
// Constant shift can be computed precisely
if (DfgConst* const rConstp = rhsp->cast<DfgConst>()) {
const uint32_t shiftAmount = rConstp->toU32();
if (shiftAmount >= width) return;
V3Number shiftedMask{lhsp->fileline(), static_cast<int>(width), 0};
shiftedMask.opShiftL(MASK(lhsp), rConstp->num());
V3Number& m = MASK(vtxp);
m.opSelInto(shiftedMask, shiftAmount, width - shiftAmount);
m.opSetRange(0, shiftAmount, '0');
return;
}
// Otherwise, as the shift amount is non-negative, any bit at or above
// the least significant dependent bit might be dependent
V3Number& lMask = MASK(lhsp);
V3Number& vMask = MASK(vtxp);
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(DfgGraph& dfg, DfgVertex* vtxp)
: m_component{vtxp->getUser<uint32_t>()} {
if (v3Global.opt.debugCheck()) {
m_lineCoverageFile.open( //
v3Global.opt.makeDir() + "/" + v3Global.opt.prefix()
+ "__V3DfgBreakCycles-IndependentBits-line-coverage.txt", //
std::ios_base::out | std::ios_base::app);
}
// Work list for the traversal
std::deque<DfgVertex*> workList;
// 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 = 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);
// Remember current mask
const V3Number prevMask = maskCurr;
// Dispatch
iterate(currp);
// If mask changed, enqueue sinks
if (!prevMask.isCaseEq(maskCurr)) {
currp->forEachSink([&](DfgVertex& vtx) { workList.emplace_back(&vtx); });
// Check the mask only ever contrects (no bit goes 0 -> 1)
if (VL_UNLIKELY(v3Global.opt.debugCheck())) {
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 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 {
static size_t fixUpSelSinks(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 Sel
DfgSel* const selp = sink.cast<DfgSel>();
if (!selp) return;
// Try to find of the driver of the selected bits outside the cycle
DfgVertex* const fixp
= 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 '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();
uint32_t msb = lsb + selp->width() - 1;
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;
}
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,
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);
uint32_t lsb = lo;
for (uint32_t msb = lo; msb <= hi; ++msb) {
const bool endRange = msb == hi || isIndependent != indpBits.bitIs1(msb + 1);
if (!endRange) continue;
const uint32_t width = msb - lsb + 1;
DfgVertex* termp = nullptr;
// If the range is not self-dependent, attempt to trace its driver
if (isIndependent) {
termp = TraceDriver::apply(dfg, vtxp, lsb, width, true);
if (termp) {
++nImprovements;
} else {
UINFO(5, "TraceDriver of independent range failed for "
<< 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, vtxp->fileline(), dtypep};
// Do not connect selp->fromp yet, need to do afer replacing 'vtxp'
selp->lsb(lsb);
termp = selp;
}
// Record the term
termps.emplace_back(termp);
// Next iteration
isIndependent = !isIndependent;
lsb = msb + 1;
}
return nImprovements;
}
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 '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 '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{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 'vtxp' with
std::vector<DfgVertex*> termps;
// Iterate through consecutive used/unused ranges
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) {
const bool endRange = msb == width - 1 || isUsed != usedBits.bitIs1(msb + 1);
if (!endRange) continue;
if (isUsed) {
// The range is used, compute the replacement terms
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});
}
// Next iteration
isUsed = !isUsed;
lsb = msb + 1;
}
// If we managed to imporove something, apply the replacement
if (nImprovements) {
// Concatenate all the terms to create the replacement
DfgVertex* replacementp = termps.front();
for (size_t i = 1; i < termps.size(); ++i) {
DfgVertex* const termp = termps[i];
const uint32_t catWidth = replacementp->width() + termp->width();
AstNodeDType* const dtypep = DfgVertex::dtypeForWidth(catWidth);
DfgConcat* const catp = new DfgConcat{dfg, flp, dtypep};
catp->rhsp(replacementp);
catp->lhsp(termp);
replacementp = catp;
}
// 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(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 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;
}
};
std::pair<std::unique_ptr<DfgGraph>, bool>
V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
// Shorthand for dumping graph at given dump level
@ -441,35 +1137,35 @@ V3DfgPasses::breakCycles(const DfgGraph& dfg, V3DfgOptimizationContext& ctx) {
UINFO(9, "New iteration after " << nImprovements << " improvements");
prevNImprovements = nImprovements;
// Method 1. 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.
// 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;
UINFO(9, "Attempting to TraceDriver " << varp->nodep()->name());
const size_t nFixed = FixUpSelDrivers::apply(res, &vtx);
if (nFixed) {
nImprovements += nFixed;
ctx.m_breakCyclesContext.m_nImprovements += nFixed;
dump(9, res, "FixUpSelDrivers");
}
}
varp->forEachSink([&](DfgVertex& sink) {
// Ignore if sink is not part of cycle
if (sink.getUser<uint32_t>() != component) return;
// Only Handle Sels now
DfgSel* const selp = sink.cast<DfgSel>();
if (!selp) return;
// Try to find of the driver of the selected bits outside the cycle
DfgVertex* const fixp = TraceDriver::apply(res, varp, selp->lsb(), selp->width());
if (!fixp) return;
// Found an out-of-cycle driver. We can replace this sel with that.
selp->replaceWith(fixp);
selp->unlinkDelete(res);
++nImprovements;
++ctx.m_breakCyclesContext.m_nImprovements;
dump(9, res, "TraceDriver");
});
// If we managed to fix something, try again with the earlier methods
if (nImprovements != prevNImprovements) continue;
// Method 2. FixUpIndependentRanges
for (DfgVertexVar& vtx : res.varVertices()) {
// If Variable is not part of a cycle, move on
const uint32_t component = vtx.getUser<uint32_t>();
if (!component) continue;
const size_t nFixed = FixUpIndependentRanges::apply(res, &vtx);
if (nFixed) {
nImprovements += nFixed;
ctx.m_breakCyclesContext.m_nImprovements += nFixed;
dump(9, res, "FixUpIndependentRanges");
}
}
} while (nImprovements != prevNImprovements);

View File

@ -341,32 +341,20 @@ 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;
// Same component is OK
if (sourceComponent == component) return;
// Unlink the source edge (source is reconnected by 'relink'
edge.unlinkSource();
// Apply the fixup
// cppcheck-has-bug-suppress constVariable
DfgVertexVar& clone = getClone(vtx, sourceComponent);
relink(*(clone.as<T_Vertex>()), source, idx);
});
}
// Fix up sinks of given variable vertex that are in a different component
void fixSinks(DfgVertexVar& vtx) {
const size_t component = state(vtx).component;
// All variable vertices have at most a single source, and only variable
// vertices can have multiple sinks, therefore the source must be either:
// - in the same component as the variable vertex
// - be a variable vertex itself, which might be in a different component
// The later case will be fixed up when handling the source variable
DfgVertex* const srcp = vtx.srcp();
UASSERT_OBJ(!srcp || srcp->is<DfgVertexVar>() || state(*srcp).component == component, &vtx,
"Driver of DfgVertexVar must be in the same component");
// Fix up sinks in a differetn component
vtx.forEachSinkEdge([&](DfgEdge& edge) {
const size_t sinkComponent = state(*edge.sinkp()).component;
// Same component is OK
@ -376,49 +364,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 +391,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 +429,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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -261,33 +261,57 @@ public:
if (const AstCNew* const cnewp = getSuperNewCallRecursep(nodep->nextp())) return cnewp;
return nullptr;
}
void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top,
std::set<AstClass*>& doneClassesr) {
void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp) {
// Virtual bases in depth-first left-to-right order
std::vector<AstClass*> virtualBases;
std::unordered_set<AstClass*> doneClasses;
collectVirtualBasesRecursep(classp, virtualBases);
for (AstClass* vbase : virtualBases) {
if (doneClasses.count(vbase)) continue;
puts(doneClasses.empty() ? "" : "\n , ");
doneClasses.emplace(vbase);
puts(prefixNameProtect(vbase));
if (constructorNeedsProcess(vbase)) {
puts("(vlProcess, vlSymsp)");
} else {
puts("(vlSymsp)");
}
}
const AstCNew* const superNewCallp = getSuperNewCallRecursep(cfuncp->stmtsp());
// Direct non-virtual bases in declaration order
for (const AstClassExtends* extp = classp->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
if (extp->classp()->useVirtualPublic()) {
// It's a c++ virtual class (diamond relation)
// Must get the subclasses initialized first
putConstructorSubinit(extp->classp(), cfuncp, false, doneClassesr);
}
// Diamond pattern with same base class twice?
if (doneClassesr.find(extp->classp()) != doneClassesr.end()) continue;
puts(doneClassesr.empty() ? "" : "\n , ");
doneClassesr.emplace(extp->classp());
if (extp->classp()->useVirtualPublic()) continue;
if (doneClasses.count(extp->classp())) continue;
puts(doneClasses.empty() ? "" : "\n , ");
doneClasses.emplace(extp->classp());
puts(prefixNameProtect(extp->classp()));
if (constructorNeedsProcess(extp->classp())) {
puts("(vlProcess, vlSymsp");
} else {
puts("(vlSymsp");
}
if (top) {
const AstCNew* const superNewCallp = getSuperNewCallRecursep(cfuncp->stmtsp());
UASSERT_OBJ(superNewCallp, cfuncp, "super.new call not found");
// Handle super.new() args for the concrete parent
if (!extp->classp()->isInterfaceClass() && superNewCallp) {
putCommaIterateNext(superNewCallp->argsp(), true);
}
puts(")");
top = false;
}
}
void collectVirtualBasesRecursep(const AstClass* classp,
std::vector<AstClass*>& virtualBases) {
std::set<const AstClass*> visited;
collectVirtualBasesRecursep(classp, virtualBases /*ref*/, visited /*ref*/);
}
void collectVirtualBasesRecursep(const AstClass* classp, std::vector<AstClass*>& virtualBases,
std::set<const AstClass*>& visited) {
if (visited.count(classp)) return;
visited.emplace(classp);
for (const AstClassExtends* extp = classp->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
// Depth-first: recurse into this base first
collectVirtualBasesRecursep(extp->classp(), virtualBases, visited);
if (extp->classp()->useVirtualPublic()) { virtualBases.push_back(extp->classp()); }
}
}
@ -314,8 +338,7 @@ public:
const AstClass* const classp = VN_CAST(nodep->scopep()->modp(), Class);
if (nodep->isConstructor() && classp && classp->extendsp()) {
puts("\n : ");
std::set<AstClass*> doneClasses;
putConstructorSubinit(classp, nodep, true, doneClasses /*ref*/);
putConstructorSubinit(classp, nodep);
}
}
puts(" {\n");

View File

@ -564,16 +564,20 @@ class EmitCHeader final : public EmitCConstInit {
if (!VN_IS(modp, Class)) puts("alignas(VL_CACHE_LINE_BYTES) ");
puts(prefixNameProtect(modp));
if (const AstClass* const classp = VN_CAST(modp, Class)) {
const string virtpub = classp->useVirtualPublic() ? "virtual public " : "public ";
puts(" : " + virtpub);
puts(" : ");
if (classp->extendsp()) {
bool needComma = false;
for (const AstClassExtends* extp = classp->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
if (needComma) puts(", ");
// Use virtual only for interfaces for class inheritance
// (extends)
puts(extp->classp()->useVirtualPublic() ? "virtual public " : "public ");
putns(extp, prefixNameProtect(extp->classp()));
if (extp->nextp()) puts(", " + virtpub);
needComma = true;
}
} else {
puts("VlClass");
puts("public virtual VlClass");
}
} else {
puts(" final : public VerilatedModule");

View File

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

View File

@ -922,6 +922,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 {}

View File

@ -99,6 +99,7 @@ public:
DEPRECATED, // Feature will be deprecated
ENCAPSULATED, // Error: local/protected violation
ENDLABEL, // End lable name mismatch
ENUMITEMWIDTH, // Error: enum item width mismatch
ENUMVALUE, // Error: enum type needs explicit cast
EOFNEWLINE, // End-of-file missing newline
GENCLK, // Generated Clock. Historical, never issued.
@ -124,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
@ -144,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
@ -189,40 +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", "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
@ -249,9 +245,9 @@ public:
bool pretendError() const VL_MT_SAFE {
return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BADVLTPRAGMA || m_e == BLKANDNBLK
|| m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED
|| m_e == ENDLABEL || m_e == ENUMVALUE || m_e == IMPURE || m_e == MODMISSING
|| m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE
|| m_e == ZEROREPL // Says IEEE
|| m_e == ENDLABEL || m_e == ENUMITEMWIDTH || m_e == ENUMVALUE || m_e == IMPURE
|| m_e == MODMISSING || m_e == PINNOTFOUND || m_e == PKGNODECL
|| m_e == PROCASSWIRE || m_e == ZEROREPL // Says IEEE
);
}
// Warnings to mention manual

View File

@ -369,6 +369,10 @@ public:
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
&& m_filenameno == rhs.m_filenameno && m_msgEnIdx == rhs.m_msgEnIdx);
}
bool equalFirstLineCol(const FileLine& rhs) const {
return (m_filenameno == rhs.m_filenameno && m_firstLineno == rhs.m_firstLineno
&& m_firstColumn == rhs.m_firstColumn);
}
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
// equivalent.
int operatorCompare(const FileLine& rhs) const {

View File

@ -304,8 +304,14 @@ class GateBuildVisitor final : public VNVisitorConst {
// We use weight of one; if we ref the var more than once, when we simplify,
// the weight will increase
if (nodep->access().isWriteOrRW()) m_graphp->addEdge(m_logicVertexp, vVtxp, 1);
if (nodep->access().isReadOrRW()) m_graphp->addEdge(vVtxp, m_logicVertexp, 1);
if (VN_IS(nodep->backp(), CoverToggle)) {
// Temporary workaround. Otherwise assignments to initp() var are removed
m_graphp->addEdge(m_logicVertexp, vVtxp, 1);
m_graphp->addEdge(vVtxp, m_logicVertexp, 1);
} else {
if (nodep->access().isWriteOrRW()) m_graphp->addEdge(m_logicVertexp, vVtxp, 1);
if (nodep->access().isReadOrRW()) m_graphp->addEdge(vVtxp, m_logicVertexp, 1);
}
}
void visit(AstConcat* nodep) override {
UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign)

View File

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

View File

@ -35,6 +35,7 @@
#include "V3AstUserAllocator.h"
#include "V3Error.h"
#include "V3UniqueNames.h"
#include <vector>
@ -60,6 +61,8 @@ class LinkJumpVisitor final : public VNVisitor {
int m_modRepeatNum = 0; // Repeat counter
VOptionBool m_unrollFull; // Pragma full, disable, or default unrolling
std::vector<AstNodeBlock*> m_blockStack; // All begin blocks above current node
V3UniqueNames m_queueNames{
"__VprocessQueue"}; // Names for queues needed for 'disable' handling
// METHODS
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
@ -159,6 +162,79 @@ class LinkJumpVisitor final : public VNVisitor {
if (AstNode* const refp = nodep->op4p()) addPrefixToBlocksRecurse(prefix, refp);
if (AstNode* const refp = nodep->nextp()) addPrefixToBlocksRecurse(prefix, refp);
}
static AstNode* getMemberp(const AstNodeModule* const nodep, const std::string& name) {
for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) {
if (itemp->name() == name) return itemp;
}
return nullptr;
}
bool existsBlockAbove(const std::string& name) const {
for (const AstNodeBlock* const stackp : vlstd::reverse_view(m_blockStack)) {
if (stackp->name() == name) return true;
}
return false;
}
static AstStmtExpr* getQueuePushProcessSelfp(AstVarRef* const queueRefp) {
// Constructs queue.push_back(std::process::self()) statement
FileLine* const fl = queueRefp->fileline();
AstClass* const processClassp
= VN_AS(getMemberp(v3Global.rootp()->stdPackagep(), "process"), Class);
AstFunc* const selfMethodp = VN_AS(getMemberp(processClassp, "self"), Func);
AstFuncRef* const processSelfp = new AstFuncRef{fl, selfMethodp, nullptr};
processSelfp->classOrPackagep(processClassp);
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 {
@ -338,33 +414,44 @@ class LinkJumpVisitor final : public VNVisitor {
void visit(AstDisable* nodep) override {
UINFO(8, " DISABLE " << nodep);
AstNode* const targetp = nodep->targetp();
FileLine* const fl = nodep->fileline();
UASSERT_OBJ(targetp, nodep, "Unlinked disable statement");
if (VN_IS(targetp, Task)) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling task by name");
} else if (VN_IS(targetp, Fork)) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disabling fork by name");
} else if (AstBegin* const beginp = VN_CAST(targetp, Begin)) {
const std::string targetName = beginp->name();
bool aboveBlock = false;
for (AstNodeBlock* const stackp : vlstd::reverse_view(m_blockStack)) {
UINFO(9, " UNDERBLK " << stackp);
if (stackp->name() == targetName) {
aboveBlock = true;
break;
} else if (AstFork* const forkp = VN_CAST(targetp, Fork)) {
std::vector<AstBegin*> forks;
for (AstNode* forkItemp = forkp->stmtsp(); forkItemp; forkItemp = forkItemp->nextp()) {
// 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};
forkItemp->replaceWith(beginp);
beginp->addStmtsp(forkItemp);
// In order to continue the iteration
forkItemp = beginp;
}
forks.push_back(beginp);
}
if (aboveBlock) {
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});
}
handleDisableOnFork(nodep, forks);
} else if (AstBegin* const beginp = VN_CAST(targetp, Begin)) {
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
AstJumpLabel* const labelp = findAddLabel(beginp, false);
nodep->addNextHere(new AstJumpGo{nodep->fileline(), labelp});
}
} else {
nodep->v3warn(E_UNSUPPORTED, "disable isn't underneath a begin with name: '"
<< targetName << "'");
}
}
} else {
nodep->v3fatalSrc("Disable linked with node of unhandled type "

View File

@ -267,16 +267,17 @@ class LinkParseVisitor final : public VNVisitor {
const int left = nodep->rangep()->leftConst();
const int right = nodep->rangep()->rightConst();
const int increment = (left > right) ? -1 : 1;
int offset_from_init = 0;
uint32_t offset_from_init = 0;
AstEnumItem* addp = nullptr;
FileLine* const flp = nodep->fileline();
for (int i = left; i != (right + increment); i += increment, offset_from_init++) {
for (int i = left; i != (right + increment); i += increment, ++offset_from_init) {
const string name = nodep->name() + cvtToStr(i);
AstNodeExpr* valuep = nullptr;
if (nodep->valuep()) {
// V3Width looks for Adds with same fileline as the EnumItem
valuep
= new AstAdd{flp, nodep->valuep()->cloneTree(true),
new AstConst(flp, AstConst::Unsized32{}, offset_from_init)};
new AstConst{flp, AstConst::Unsized32{}, offset_from_init}};
}
addp = AstNode::addNext(addp, new AstEnumItem{flp, name, nullptr, valuep});
}
@ -577,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;

View File

@ -1188,7 +1188,7 @@ uint32_t V3Number::countOnes() const {
uint32_t V3Number::mostSetBitP1() const {
for (int bit = width() - 1; bit >= 0; bit--) {
if (bitIs1(bit)) return bit + 1;
if (!bitIs0(bit)) return bit + 1;
}
return 0;
}
@ -2242,6 +2242,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.

View File

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

View File

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

View File

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

View File

@ -293,12 +293,12 @@ public:
void dumpInputsFile() VL_MT_DISABLED;
void dumpTokensAhead(int line) VL_MT_DISABLED;
static void candidatePli(VSpellCheck* spellerp) VL_MT_DISABLED;
void importIfInStd(FileLine* fileline, const string& id);
private:
void preprocDumps(std::ostream& os);
void lexFile(const string& modname) VL_MT_DISABLED;
void yylexReadTok() VL_MT_DISABLED;
void importIfInStd(FileLine* fileline, const string& id);
void tokenPull() VL_MT_DISABLED;
void tokenPipeline() VL_MT_DISABLED; // Internal; called from tokenToBison
int tokenPipelineId(int token) VL_MT_DISABLED;

View File

@ -2198,14 +2198,14 @@ class RandomizeVisitor final : public VNVisitor {
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 {

View File

@ -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);
@ -1189,6 +1203,18 @@ VirtIfaceTriggers::makeIfaceToSensMap(AstNetlist* const netlistp, size_t vifTrig
return ifaceToSensMap;
}
VirtIfaceTriggers::IfaceMemberSensMap
VirtIfaceTriggers::makeMemberToSensMap(AstNetlist* const netlistp, size_t vifTriggerIndex,
AstVarScope* trigVscp) const {
IfaceMemberSensMap memberToSensMap;
for (const auto& p : m_memberTriggers) {
memberToSensMap.emplace(
std::make_pair(p.first, createTriggerSenTree(netlistp, trigVscp, vifTriggerIndex)));
++vifTriggerIndex;
}
return memberToSensMap;
}
//============================================================================
// Top level entry-point to scheduling
@ -1359,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,
@ -1367,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);
@ -1396,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(
@ -1405,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);
}
});

View File

@ -153,17 +153,55 @@ public:
};
class VirtIfaceTriggers final {
// Represents a specific member in a virtual interface
struct IfaceMember final {
const AstIface* m_ifacep; // Interface type
const AstVar* m_memberVarp; // pointer to member field
IfaceMember(const AstIface* ifacep, const AstVar* memberVarp)
: m_ifacep(ifacep)
, m_memberVarp(memberVarp) {}
bool operator<(const IfaceMember& other) const {
if (m_ifacep != other.m_ifacep) return m_ifacep < other.m_ifacep;
return m_memberVarp < other.m_memberVarp;
}
};
public:
using IfaceMemberTrigger = std::pair<IfaceMember, AstVarScope*>;
using IfaceMemberTriggerVec = std::vector<IfaceMemberTrigger>;
using IfaceMemberSensMap = std::map<IfaceMember, AstSenTree*>;
using IfaceTrigger = std::pair<const AstIface*, AstVarScope*>;
using IfaceTriggerVec = std::vector<IfaceTrigger>;
using IfaceSensMap = std::map<const AstIface*, AstSenTree*>;
IfaceTriggerVec m_triggers;
public:
void emplace_back(IfaceTrigger&& p) { m_triggers.emplace_back(std::move(p)); }
IfaceTriggerVec::const_iterator begin() const { return m_triggers.begin(); }
IfaceTriggerVec::const_iterator end() const { return m_triggers.end(); }
IfaceMemberTriggerVec m_memberTriggers;
IfaceTriggerVec m_ifaceTriggers;
void addMemberTrigger(const AstIface* ifacep, const AstVar* memberVarp,
AstVarScope* triggerVscp) {
m_memberTriggers.emplace_back(IfaceMember(ifacep, memberVarp), triggerVscp);
}
AstVarScope* findMemberTrigger(const AstIface* ifacep, const AstVar* memberVarp) const {
IfaceMember target{ifacep, memberVarp};
for (const auto& pair : m_memberTriggers) {
if (!(pair.first < target) && !(target < pair.first)) return pair.second;
}
return nullptr;
}
IfaceMemberSensMap makeMemberToSensMap(AstNetlist* netlistp, size_t vifTriggerIndex,
AstVarScope* trigVscp) const;
void emplace_back(IfaceTrigger&& p) { m_ifaceTriggers.emplace_back(std::move(p)); }
IfaceTriggerVec::const_iterator begin() const { return m_ifaceTriggers.begin(); }
IfaceTriggerVec::const_iterator end() const { return m_ifaceTriggers.end(); }
IfaceSensMap makeIfaceToSensMap(AstNetlist* netlistp, size_t vifTriggerIndex,
AstVarScope* trigVscp) const;
VL_UNCOPYABLE(VirtIfaceTriggers);
VirtIfaceTriggers() = default;
VirtIfaceTriggers(VirtIfaceTriggers&&) = default;

View File

@ -49,12 +49,15 @@ private:
// TYPES
using OnWriteToVirtIface = std::function<void(AstVarRef*, AstIface*)>;
using OnWriteToVirtIfaceMember
= std::function<void(AstVarRef*, AstIface*, const std::string&)>;
// STATE
AstNetlist* const m_netlistp; // Root node
AstAssign* m_trigAssignp = nullptr; // Previous/current trigger assignment
AstIface* m_trigAssignIfacep = nullptr; // Interface type whose trigger is assigned
// by m_trigAssignp
AstVar* m_trigAssignMemberVarp; // Member pointer whose trigger is assigned
V3UniqueNames m_vifTriggerNames{"__VvifTrigger"}; // Unique names for virt iface
// triggers
VirtIfaceTriggers m_triggers; // Interfaces and corresponding trigger vars
@ -73,6 +76,25 @@ private:
}
});
}
// For each write across a virtual interface boundary (member-level tracking)
static void foreachWrittenVirtIfaceMember(
AstNode* const nodep, const std::function<void(AstVarRef*, AstIface*, AstVar*)>& onWrite) {
nodep->foreach([&](AstVarRef* const refp) {
if (refp->access().isReadOnly()) return;
if (AstIfaceRefDType* const dtypep = VN_CAST(refp->varp()->dtypep(), IfaceRefDType)) {
if (dtypep->isVirtual()) {
if (AstMemberSel* const memberSelp = VN_CAST(refp->firstAbovep(), MemberSel)) {
// Extract the member varp from the MemberSel node
AstVar* memberVarp = memberSelp->varp();
onWrite(refp, dtypep->ifacep(), memberVarp);
}
}
} else if (AstIface* const ifacep = refp->varp()->sensIfacep()) {
AstVar* memberVarp = refp->varp();
onWrite(refp, ifacep, memberVarp);
}
});
}
// Returns true if there is a write across a virtual interface boundary
static bool writesToVirtIface(const AstNode* const nodep) {
return nodep->exists([](const AstVarRef* const refp) {
@ -103,12 +125,31 @@ private:
return new AstVarRef{flp, VN_AS(ifacep->user1p(), VarScope), VAccess::WRITE};
}
// Create trigger reference for a specific interface member
AstVarRef* createVirtIfaceMemberTriggerRefp(FileLine* const flp, AstIface* ifacep,
const AstVar* memberVarp) {
// Check if we already have a trigger for this specific member
AstVarScope* existingTrigger = m_triggers.findMemberTrigger(ifacep, memberVarp);
if (!existingTrigger) {
AstScope* const scopeTopp = m_netlistp->topScopep()->scopep();
// Create a unique name for this member trigger
const std::string triggerName
= m_vifTriggerNames.get(ifacep) + "_Vtrigm_" + memberVarp->name();
AstVarScope* const vscp = scopeTopp->createTemp(triggerName, 1);
m_triggers.addMemberTrigger(ifacep, memberVarp, vscp);
existingTrigger = vscp;
}
return new AstVarRef{flp, existingTrigger, VAccess::WRITE};
}
// VISITORS
void visit(AstNodeProcedure* nodep) override {
VL_RESTORER(m_trigAssignp);
m_trigAssignp = nullptr;
VL_RESTORER(m_trigAssignIfacep);
m_trigAssignIfacep = nullptr;
VL_RESTORER(m_trigAssignMemberVarp);
m_trigAssignMemberVarp = nullptr;
iterateChildren(nodep);
}
void visit(AstCFunc* nodep) override {
@ -116,6 +157,8 @@ private:
m_trigAssignp = nullptr;
VL_RESTORER(m_trigAssignIfacep);
m_trigAssignIfacep = nullptr;
VL_RESTORER(m_trigAssignMemberVarp);
m_trigAssignMemberVarp = nullptr;
iterateChildren(nodep);
}
void visit(AstAssignW* nodep) override {
@ -140,11 +183,13 @@ private:
{
VL_RESTORER(m_trigAssignp);
VL_RESTORER(m_trigAssignIfacep);
VL_RESTORER(m_trigAssignMemberVarp);
iterateAndNextNull(nodep->thensp());
}
{
VL_RESTORER(m_trigAssignp);
VL_RESTORER(m_trigAssignIfacep);
VL_RESTORER(m_trigAssignMemberVarp);
iterateAndNextNull(nodep->elsesp());
}
if (v3Global.usesTiming()) {
@ -152,6 +197,7 @@ private:
// branch
m_trigAssignp = nullptr;
m_trigAssignIfacep = nullptr;
m_trigAssignMemberVarp = nullptr;
}
}
void visit(AstWhile* nodep) override {
@ -161,18 +207,21 @@ private:
{
VL_RESTORER(m_trigAssignp);
VL_RESTORER(m_trigAssignIfacep);
VL_RESTORER(m_trigAssignMemberVarp);
iterateAndNextNull(nodep->stmtsp());
}
if (v3Global.usesTiming()) {
// Clear the trigger assignment, as there could have been timing controls in the loop
m_trigAssignp = nullptr;
m_trigAssignIfacep = nullptr;
m_trigAssignMemberVarp = nullptr;
}
}
void visit(AstJumpBlock* nodep) override {
{
VL_RESTORER(m_trigAssignp);
VL_RESTORER(m_trigAssignIfacep);
VL_RESTORER(m_trigAssignMemberVarp);
iterateChildren(nodep);
}
if (v3Global.usesTiming()) {
@ -180,29 +229,48 @@ private:
// block
m_trigAssignp = nullptr;
m_trigAssignIfacep = nullptr;
m_trigAssignMemberVarp = nullptr;
}
}
void visit(AstNodeStmt* nodep) override {
if (v3Global.usesTiming()
&& nodep->exists([](AstNode* nodep) { return nodep->isTimingControl(); })) {
m_trigAssignp = nullptr; // Could be after a delay - need new trigger assignment
m_trigAssignp = nullptr;
m_trigAssignIfacep = nullptr;
// No restorer, as following statements should not reuse the old assignment
m_trigAssignMemberVarp = nullptr;
}
FileLine* const flp = nodep->fileline();
foreachWrittenVirtIface(nodep, [&](AstVarRef*, AstIface* ifacep) {
if (ifacep != m_trigAssignIfacep) {
// Write to different interface type than before - need new trigger assignment
// No restorer, as following statements should not reuse the old assignment
foreachWrittenVirtIfaceMember(nodep, [&](AstVarRef*, AstIface* ifacep,
AstVar* memberVarp) {
if (ifacep != m_trigAssignIfacep || memberVarp != m_trigAssignMemberVarp) {
// Write to different interface member than before - need new trigger assignment
m_trigAssignIfacep = ifacep;
m_trigAssignMemberVarp = memberVarp;
m_trigAssignp = nullptr;
}
if (!m_trigAssignp) {
m_trigAssignp = new AstAssign{flp, createVirtIfaceTriggerRefp(flp, ifacep),
new AstConst{flp, AstConst::BitTrue{}}};
m_trigAssignp
= new AstAssign{flp, createVirtIfaceMemberTriggerRefp(flp, ifacep, memberVarp),
new AstConst{flp, AstConst::BitTrue{}}};
nodep->addNextHere(m_trigAssignp);
}
});
// Fallback to whole-interface tracking if no member-specific assignments found
if (!m_trigAssignp) {
foreachWrittenVirtIface(nodep, [&](AstVarRef*, AstIface* ifacep) {
if (ifacep != m_trigAssignIfacep) {
m_trigAssignIfacep = ifacep;
m_trigAssignMemberVarp = nullptr;
m_trigAssignp = nullptr;
}
if (!m_trigAssignp) {
m_trigAssignp = new AstAssign{flp, createVirtIfaceTriggerRefp(flp, ifacep),
new AstConst{flp, AstConst::BitTrue{}}};
nodep->addNextHere(m_trigAssignp);
}
});
}
}
void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -215,7 +215,7 @@ 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;
const double memory = VlOs::memPeakUsageBytes() / 1024.0 / 1024.0;
V3Stats::addStatPerf("Stage, Memory (MB), " + digitName, memory);
}
@ -266,7 +266,7 @@ 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;
const double memory = VlOs::memPeakUsageBytes() / 1024.0 / 1024.0;
if (VL_UNCOVERABLE(memory != 0.0)) std::cout << "; alloced " << memory << " MB";
std::cout << "\n";
}

View File

@ -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
@ -133,6 +134,7 @@ 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);
@ -141,6 +143,8 @@ class UnrollVisitor final : public VNVisitor {
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);
@ -463,6 +467,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 +504,7 @@ public:
m_varModeCheck = false;
m_varModeReplace = false;
m_varAssignHit = false;
m_forkHit = false;
m_generate = generate;
m_beginName = beginName;
}

View File

@ -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());
@ -837,7 +837,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 +971,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 +1510,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 +2422,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 +2495,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);
}
@ -2553,9 +2570,16 @@ class WidthVisitor final : public VNVisitor {
// Default type is int, but common to assign narrower values, so minwidth from value
userIterateAndNext(nodep->valuep(), WidthVP{CONTEXT_DET, PRELIM}.p());
bool warnOn = true;
if (const AstConst* const constp = VN_CAST(nodep->valuep(), Const)) {
AstNodeExpr* valuep = nodep->valuep();
if (const AstAdd* const anodep = VN_CAST(valuep, Add)) {
// If constructed by V3LinkParse due to "enumitem[N_REPEATS] value"
if (anodep->fileline()->equalFirstLineCol(*(nodep->fileline())))
valuep = anodep->lhsp();
}
if (const AstConst* const constp = VN_CAST(valuep, Const)) {
if (static_cast<int>(constp->num().mostSetBitP1()) > nodep->width()) {
constp->v3error("Enum value exceeds width of enum type (IEEE 1800-2023 6.19)");
constp->v3warn(ENUMITEMWIDTH,
"Enum value exceeds width of enum type (IEEE 1800-2023 6.19)");
warnOn = false; // Prevent normal WIDTHTRUNC
}
}
@ -6819,7 +6843,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());
@ -6860,7 +6884,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);
@ -6888,7 +6912,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());
}
@ -6948,8 +6972,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());
@ -6983,8 +7007,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());
@ -7323,8 +7347,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)
@ -7334,7 +7362,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
@ -7350,7 +7379,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();
@ -7667,12 +7696,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;
}
@ -8293,6 +8326,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

View File

@ -649,7 +649,6 @@ static void process() {
// Final statistics
if (v3Global.opt.stats()) V3Stats::statsStage("emit");
reportStatsIfEnabled();
}
static void verilate(const string& argString) {
@ -769,6 +768,7 @@ 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::statsStage("wrote");
// Final writing shouldn't throw warnings, but...
V3Error::abortIfWarnings();
@ -867,6 +867,7 @@ int main(int argc, char** argv) {
execBuildJob();
}
reportStatsIfEnabled();
V3DiagSarif::output(true);
// Explicitly release resources

View File

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

View File

@ -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
@ -3754,7 +3757,9 @@ statement_item<nodep>: // IEEE: statement_item
// // IEEE: disable_statement
| yDISABLE yFORK ';' { $$ = new AstDisableFork{$1}; }
| yDISABLE idDottedSel ';'
{ $$ = new AstDisable{$1, $2}; }
{ $$ = new AstDisable{$1, $2};
PARSEP->importIfInStd($1, "process");
}
// // IEEE: event_trigger
| yP_MINUSGT expr ';'
{ $$ = new AstFireEvent{$1, $2, false}; }
@ -4178,6 +4183,7 @@ loop_variables<nodep>: // IEEE: loop_variables
parseRefBase { $$ = $1; }
| loop_variables ',' parseRefBase { $$ = $1->addNext($3); }
| ',' parseRefBase { $$ = new AstEmpty{$1}; $$->addNext($2); }
| ',' { $$ = new AstEmpty{$1}; }
;
//************************************************
@ -4280,6 +4286,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}; }
//
@ -5349,6 +5356,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); }
@ -5821,8 +5833,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 }
@ -5833,7 +5849,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
@ -5922,9 +5944,9 @@ idAnyE<strp>:
| idAny { $$ = $1; }
;
junkToSemiList:
junkToSemi { } /* ignored */
| junkToSemiList junkToSemi { } /* ignored */
junkToSemiList<fl>:
junkToSemi { $$ = CRELINE(); }
| junkToSemiList junkToSemi { $$ = CRELINE(); }
;
junkToSemi:
@ -6116,6 +6138,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 ']'
@ -6819,21 +6843,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; }
@ -7003,7 +7044,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
@ -7549,7 +7590,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; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,88 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Petr Nohavica
// SPDX-License-Identifier: CC0-1.0
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (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);
interface class IBottomMid;
pure virtual function void moo(int i);
endclass
interface class IBottom;
pure virtual function bit foo();
endclass
interface class IMid extends IBottomMid;
pure virtual function string bar();
endclass
class bottom_class implements IBottom;
string name;
function new(string name);
this.name = name;
endfunction
virtual function bit foo();
$display("%s", name);
endfunction
endclass
class middle_class extends bottom_class implements IMid, IBottom;
function new(string name);
super.new($sformatf("middle %0s", name));
endfunction
virtual function bit foo();
$display("%s", name);
return 0;
endfunction
virtual function void moo(int i);
$display("moo: %d", i);
endfunction
virtual function string bar();
return name;
endfunction
endclass
class top_class extends middle_class;
int i;
function new(string name, int i);
super.new($sformatf("%0s %0d", name, i));
this.i = i;
endfunction
endclass
class sky_class extends top_class;
function new(string name);
super.new(name, 42);
endfunction
endclass
module t;
initial begin
sky_class s = new("ahoj");
bottom_class b = s;
top_class t = s;
IMid im;
`checks( b.name, "middle ahoj 42" );
`checks( s.name, "middle ahoj 42" );
`checks( t.name, "middle ahoj 42" );
`checkh( t.i, 42);
`checks(s.bar(), "middle ahoj 42");
im = s;
im.moo(42);
$finish;
end
endmodule

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,20 @@
#!/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=['--cc --coverage-toggle --stats'])
test.execute()
test.inline_checks()
test.passes()

View File

@ -0,0 +1,63 @@
// 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
module t(clk);
// verilator coverage_off
input clk;
integer cyc;
// verilator coverage_on
logic logic_unused;
// CHECK_COVER(-1,"top.t","logic_unused",0)
bit bit_unused;
// CHECK_COVER(-1,"top.t","bit_unused",0)
logic logic_always_0;
// CHECK_COVER(-1,"top.t","logic_always_0",0)
bit bit_always_0;
// CHECK_COVER(-1,"top.t","bit_always_0",0)
logic logic_always_1;
// CHECK_COVER(-1,"top.t","logic_always_1",0)
bit bit_always_1;
// CHECK_COVER(-1,"top.t","bit_always_1",1)
logic logic_initial_0;
// CHECK_COVER(-1,"top.t","logic_initial_0",0)
bit bit_initial_0;
// CHECK_COVER(-1,"top.t","bit_initial_0",0)
logic logic_initial_1;
// CHECK_COVER(-1,"top.t","logic_initial_1",0)
bit bit_initial_1;
// CHECK_COVER(-1,"top.t","bit_initial_1",1)
initial begin
cyc = 1;
logic_initial_0 = 0;
bit_initial_0 = 0;
logic_initial_1 = 1;
bit_initial_1 = 1;
end
always @(posedge clk) begin
logic_always_0 = 0;
bit_always_0 = 0;
logic_always_1 = 1;
bit_always_1 = 1;
if (cyc != 0) cyc <= cyc + 1;
if (cyc == 10) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -1,7 +1,7 @@
%Warning-UNUSEDSIGNAL: t/t_cover_unused_bad.v:14:10: Signal is not used: 'unu3'
: ... note: In instance 't'
14 | logic unu3 = 0;
| ^~~~
%Warning-UNUSEDSIGNAL: t/t_cover_unused_bad.v:14:8: Signal is not used: 'unu3'
: ... note: In instance 't'
14 | bit unu3 = 0;
| ^~~~
... For warning description see https://verilator.org/warn/UNUSEDSIGNAL?v=latest
... Use "/* verilator lint_off UNUSEDSIGNAL */" and lint_on around source to disable this message.
%Error: Exiting due to

View File

@ -11,7 +11,7 @@ module t (/*AUTOARG*/
input clk;
logic unu3 = 0;
bit unu3 = 0;
logic isusd = 0;
cover property (@(posedge clk) isusd == 0);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,5 @@
%Error: t/t_covergroup_func_override_bad.v:10:5: syntax error, unexpected function
10 | function sample();
| ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/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')
if test.vlt_all:
test.lint(fails=True, expect_filename=test.golden_filename)
else:
test.compile(nc_flags2=["-coverage", "functional"])
test.execute()
test.passes()

View File

@ -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
/* verilator lint_off COVERIGN */
module t();
covergroup cg;
function sample();
endfunction
function get_coverage();
endfunction
endgroup
endmodule

View File

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

View File

@ -0,0 +1,18 @@
// 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 */
class myClass;
covergroup embeddedCg;
endgroup
function new();
embeddedCg = new();
embeddedCg.sample();
embeddedCg.get_coverage();
endfunction
endclass

View File

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

View File

@ -0,0 +1,30 @@
// 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 */
class myClass;
covergroup embeddedCg;
endgroup
function new();
embeddedCg = new();
embeddedCg.sample();
embeddedCg.get_coverage();
endfunction
endclass
class secondClass;
covergroup embeddedCg;
endgroup
function new();
embeddedCg = new();
embeddedCg.sample();
embeddedCg.get_coverage();
endfunction
endclass

View File

@ -0,0 +1,8 @@
%Error: t/t_covergroup_in_class_duplicate_bad.v:13:16: Duplicate declaration of CLASS '__vlAnonCG_embeddedCg': '__vlAnonCG_embeddedCg'
13 | covergroup embeddedCg;
| ^~~~~~~~~~
t/t_covergroup_in_class_duplicate_bad.v:9:16: ... Location of original declaration
9 | covergroup embeddedCg;
| ^~~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -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(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,16 @@
// 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 */
class myClass;
covergroup embeddedCg;
endgroup
covergroup embeddedCg;
endgroup
endclass

View File

@ -0,0 +1,5 @@
%Error: t/t_covergroup_new_override_bad.v:10:5: syntax error, unexpected function
10 | function new();
| ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/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')
if test.vlt_all:
test.lint(fails=True, expect_filename=test.golden_filename)
else:
test.compile(nc_flags2=["-coverage", "functional"])
test.execute()
test.passes()

View File

@ -0,0 +1,14 @@
// 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 cg;
function new();
endfunction
endgroup
endmodule

Some files were not shown because too many files have changed in this diff Show More