Compare commits

...
208 Commits
Author SHA1 Message Date
Wilson Snyder 04c0fc8aa7 Version bump 2020-06-06 07:48:47 -04:00
Wilson Snyder 1d8955fea5 Internal: Update fastcov.py from upstream. 2020-06-06 05:48:36 -04:00
Wilson Snyder 48740a0dba Tests: Add t_param_type 2020-06-05 22:22:44 -04:00
Geza Lore 4a404bd92e Always mask LSB in V3Merge Cond when mergin AstAnd 2020-06-06 00:17:59 +01:00
Wilson Snyder ff41701ddc Fix crash on undeclared packages. 2020-06-05 18:50:06 -04:00
Wilson Snyder 2590c9c4a6 Internal: Update fastcov.py from upstream. 2020-06-05 18:05:49 -04:00
Wilson Snyder c5d61da5d2 Internal coverage: Fix coverage of tests that abort. No functional change intended. 2020-06-05 08:00:22 -04:00
Wilson Snyder 5a622fd9db Tests: Temporary fix for (#2407) 2020-06-05 07:28:51 -04:00
Wilson Snyder c83b1478e1 Internals: Ifdef out V3Combine incomplete dead code. 2020-06-04 21:55:00 -04:00
Wilson Snyder 3243651c63 Internals: Fix misc internal coverage holes. No functional change intended. 2020-06-04 21:40:40 -04:00
Wilson Snyder 8d61cd9029 New fastcov internal coverage scheme 2020-06-04 20:59:52 -04:00
Wilson Snyder 7fe49de420 Tests: Tests to fix misc internal coverage holes. 2020-06-04 20:23:55 -04:00
Wilson Snyder a433096d5a Internals: Fix misc internal coverage holes. No functional change intended. 2020-06-04 19:49:39 -04:00
Geza Lore b88e1e6970 Travis: Fix cron (always build focal) 2020-06-04 17:36:53 +01:00
Wilson Snyder 79f228b04f Remove dead code (bisonreader) 2020-06-03 20:11:09 -04:00
Wilson Snyder d7cc1e6844 Tests: Use lint in many negative tests to avoid running under both vlt and vltmt 2020-06-03 20:05:13 -04:00
Wilson Snyder 42312101b5 Tests: Add array OOB tests as unsupported (#792) 2020-06-03 19:36:50 -04:00
Wilson Snyder 329f5b712a Tests: Add alias tests as unsupported (#697) 2020-06-03 19:27:22 -04:00
Geza Lore 6ddd92c0a1 Travis: Use workspaces and per job persistent ccache (#2399)
Change the Travis builds to use workspaces and persistent ccache

We proceed in 2 stages (as before, but using workspaces for
persistence):
1. In the 'build' stage, we clone the repo, build it and
   save the whole checkout ($TRAVIS_BUILD_DIR) as a workspace
2. In the 'test' stage, rather than cloning the repo, multiple jobs
   pull down the same workspace we built to run the tests from

This enables:
- Reuse of the build in multiple test jobs (this is what we used the Travis
  cache for before)
- Each job having a separate persistent Travis cache, which now only
  contains the ccache. This means all jobs, including 'build' and 'test'
  jobs can make maximum use of ccache across runs. This drastically cuts
  down build times when the ccache hits, which is very often the case for
  'test' jobs. Also, the separate caches only store the objects build by
  the particular job that owns the cache, so we can keep the per job
  ccache small.

If the commit message contains '[travis ccache clear]', the ccache will
be cleared at the beginning of the build. This can be used to test build
complete within the 50 minute timeout imposed by Travis, even without a
persistent ccache.
2020-06-03 21:10:13 +01:00
Tomasz Gorochowik 277dee109c Fix Ariane issues with PostAdd nodes (#2400) 2020-06-03 12:50:24 -04:00
Wilson Snyder ef71576825 Fix coredump from increment patch (#2391) 2020-06-03 08:30:49 -04:00
Wilson Snyder c3271aa891 Fix duplicate VLCOVGEN short code 2020-06-02 21:42:24 -04:00
Geza Lore 1cf17b5e78 Fix unused variable. 2020-06-02 22:45:55 +01:00
Ludwig Rogiers 2b6353b36e Support vpi_handle type vpiLeftRange and vpiRightRange for vpiRange objects (#2395)
* Implement vpi_handle type vpiLeftRange and vpiRightRange for vpiRange objects

* Change VerilatedVpioConst type to vpiConstant
2020-06-02 08:04:22 -04:00
Wilson Snyder 8b647f0977 Fix error on UNPACKED in parser. (#1541) 2020-06-02 08:00:37 -04:00
Wilson Snyder 4c31c5fab5 Fix unused variable. 2020-06-02 07:52:27 -04:00
Wilson Snyder 6ce878cb0d Fix some clang-tidy warnings 2020-06-01 23:16:17 -04:00
Geza Lore a67ba04c37 Remove dead code and some unused parameters
Found with CLion inspections
2020-06-01 17:49:42 +01:00
Wilson Snyder ae448e5ef9 Fix older GCC compiler error. 2020-06-01 09:08:50 -04:00
Wilson Snyder a57826b125 Line Coverage now tracks all statement lines, not just branch lines. 2020-05-31 15:52:17 -04:00
Geza Lore 656c460605 Add --dump-tree-addrids developer option 2020-05-31 20:21:55 +01:00
Geza Lore 95534fa5c5 Remove unused headers (#2389) 2020-05-31 20:21:07 +01:00
Wilson Snyder 611e8b10c6 Fix Verilog coverage to pass real column information 2020-05-31 09:05:10 -04:00
Michael Killough 047852eb08 Fix OpenBSD make in tests. (#2388) 2020-05-31 09:03:51 -04:00
Geza Lore 6318a08056 Fix --dump-tree with sparse dumps.
"No changes since last dump!" is now only printed if the "last" dump was
actually performed and not skipped due to V3Option::dumpTreeLevel
settings.
2020-05-31 13:48:30 +01:00
Wilson Snyder b60a92eed3 Fix pre-C11 compiler warning. 2020-05-30 21:11:37 -04:00
Geza Lore fe306a36b8 Add MergeCond pass to combine assignments with ?: on rhs (#2376)
This provides minor simulation performance benefit, but can provide
large C++ compilation time improvement, notably with Clang (4x).

This patch implements #2366 .
2020-05-30 21:09:05 +01:00
Geza Lore 18870f8b62 Remove remnants of long removed --trace-dups option
See #2385
2020-05-30 20:16:40 +01:00
Geza Lore 9712ceedd7 Internals: Remove empty statements. No functional change intended.
Remove stray semicolons, mostly by capturing them in macros accurately.
This removes a ton on lint warnings from CLion.
2020-05-30 19:13:18 +01:00
Wilson Snyder 2e32387e5c Fix GCC false warning on array bounds. (#2386) 2020-05-30 13:47:53 -04:00
Wilson Snyder b66877c9df Internals: Refactor V3Expand newWordSel. No functional change intended. 2020-05-30 13:47:53 -04:00
Geza Lore 74a6f94e2b Internals: Remove dead code 2020-05-30 17:20:23 +01:00
Wilson Snyder 35fc8b7259 Debug: Show column numbers in .tree files 2020-05-30 10:08:30 -04:00
Wilson Snyder e591afd101 Disable over-sensitive debug dump. 2020-05-30 09:35:48 -04:00
Wilson Snyder a41cdf4cfb Tests: Add driver_verilator_flags (for verilator_ext_tests) 2020-05-30 08:19:44 -04:00
Wilson Snyder ef72c42aa7 Commentary 2020-05-29 19:58:59 -04:00
Wilson Snyder fbc814b54a Internal code coverage fixes 2020-05-29 19:35:54 -04:00
Wilson Snyder 4cfa3f879a Internals: Allow VL_DANGLING on pointer const. 2020-05-29 18:31:53 -04:00
Wilson Snyder 4a8c7e869f Fix coverage issue 2020-05-29 17:59:35 -04:00
Tomasz Gorochowik a4a1c7a384 Fix swerv issues with Increment nodes (#2380) 2020-05-29 13:03:04 -04:00
Ludwig Rogiers 460315128b Fix vpi_get_value() error message when passing unsupported vpiHandle. (#2378) 2020-05-29 08:10:22 -04:00
Wilson Snyder 8ddafb4d9f Update contributors (from email) 2020-05-28 21:35:38 -04:00
Wilson Snyder ebda8f866c Cleanup codacity and missing consts. 2020-05-28 21:04:36 -04:00
Wilson Snyder 5ee4595aa8 Remove dead code (git_untabify), instead use make clang-format 2020-05-28 21:04:17 -04:00
Wilson Snyder 5089ac6119 Remove VL_ULL as ULL now in MSVC & C++11 2020-05-28 20:32:07 -04:00
Wilson Snyder 3f66f846cd Travis enable SystemC test (#1601) 2020-05-28 18:52:03 -04:00
Wilson Snyder 279f21bb5b Configure now enables SystemC if it is installed as a system headers. 2020-05-28 18:51:46 -04:00
Wilson Snyder 773ed97504 Internals Most VerilatedLockGuard can be const. No functional change intended. 2020-05-28 18:23:46 -04:00
Wilson Snyder b6d4899d3f Commentary 2020-05-28 18:09:31 -04:00
Maciej Sobkowski 9d48ff7745 Support pre/postifx incrementation/decrementation in array index (#2223) 2020-05-28 18:08:15 -04:00
Stephen Henry c4aab57c62 Internals: Refactor to introduce VerilatedFdList. (#2363) 2020-05-28 17:59:18 -04:00
Maarten De Braekeleer e8f27be200 Fix Visual Studio compiler issues (#2375)
* Make sure compiler creates same object file as target of rule
* MSVC requires a string return
* Case ranges are a gnu extension which MSVC does not understand
* _dupenv_s also returns 0 if the var could not be found
See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/dupenv-s-wdupenv-s?view=vs-2019
2020-05-28 17:39:20 -04:00
Wilson Snyder 15f0f967b3 Fix uninit variable warning 2020-05-28 17:33:44 -04:00
Wilson Snyder cbafff8a71 Commentary 2020-05-27 21:52:55 -04:00
Wilson Snyder 41e362b580 Tests: Remove some old conditional-fail checks. 2020-05-27 21:44:28 -04:00
Geza Lore 622f59ad65 Set OPT_FAST=-Os as default (#2374) 2020-05-28 00:57:49 +01:00
Wilson Snyder c5da38206e Fix configure over-disabling warnings. 2020-05-27 08:45:11 -04:00
Geza Lore d737266f64 Add OPT_GLOBAL to use for run-time library (#2373)
This allows compiling the run-time library with optimization even when OPT_FAST is not used in order to imporove model build speed, possibly during debug cycles.
2020-05-27 01:52:08 +01:00
Wilson Snyder 978c35995a Support const cast (ignored since not linting const yet) 2020-05-26 20:44:20 -04:00
Wilson Snyder 2af7f2fa18 Internals: Parser cleanup of cast. 2020-05-26 20:29:54 -04:00
Wilson Snyder 373c9090d3 Update contributors (from email) 2020-05-26 19:12:19 -04:00
Stefan Wallentowitz 723d407a87 [docker] Unify docker files (#2371)
Unify the actions in the Dockerfiles between the runtime environment
and the run containers.

Fixes #2345

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-26 20:38:43 +02:00
Stefan Wallentowitz dc90e6c3c3 Generate file with waivers (#2354)
This adds the flag --generate-waivefile <filename>. This will generate
a verilator config file with the proper lint_off statemens to turn off
warnings emitted during this particular run.

This feature can be used to start with using Verilator as linter and
systematically capture all known lint warning for further
elimination. It hopefully helps people turning of -Wno-fatal or
-Wno-lint and gradually improve their code base.

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-26 20:38:14 +02:00
Stefan Wallentowitz 68a2ed6776 Fix output of loops on waiving (#2355)
When an unopt loop is waived, we also don't want the loop's example
path being plot.

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-26 08:45:57 +02:00
Wilson Snyder 7f32d4dc45 Internals: Parser cleanup of expressions. 2020-05-25 21:51:05 -04:00
Geza Lore 7b683fe258 Use sane --output-split values by default to help large builds
--output-split is now on by default with value 20000.
--output-split-cfuncs and --output-split-ctrace now defaults to the
value of --output-split unless explicitly specified.
2020-05-26 01:22:10 +01:00
Geza Lore 72858175a2 Only emit VM_PARALLEL_BUILDS=1 iff --output-split caused a split.
Previously we set VM_PARALLEL_BUILDS=1 if the --output-split option was
provided. Now we only do it iff it actually causes a split.
2020-05-26 01:22:10 +01:00
Geza Lore 9d7086067c Rework serial/parallel build mode
Instead of __ALLfast.cpp and __ALLslow.cpp, we now create only a single
__ALL.cpp and compile it with OPT_FAST, this speeds up small builds
where the C compiler does not dominate. A separate patch will follow
turning VM_PARALLEL_BUILDS on by default at a certain size.

Given this change to the build there is now no point in emitting both
fast and slow routines into the same .cpp file when --output-split is
not set as they will be just included in the same __ALL.cpp file. To
keep things simpler and the output easier to comprehend, V3EmitC has
also been changed to always emit the fast and slow files separately.

Also change verilated.mk to apply OPT_SLOW to all slow files, not just
ones called *__Slow.cpp. This change in particular ensures __Syms.cpp
is build as slow.

Part of #2360.
2020-05-26 01:22:10 +01:00
Wilson Snyder 5bb1da88ed Internals: Comment grammar continuations. No functional change. 2020-05-25 19:40:20 -04:00
Wilson Snyder 9969a60b34 Commentary 2020-05-25 18:51:12 -04:00
Wilson Snyder 72402fa91e Internals: Parser cleanup of parameters, second part. 2020-05-25 18:49:29 -04:00
Wilson Snyder 8255f3f9fe Internals: Parser cleanup of parameters, first part. 2020-05-25 18:41:47 -04:00
Wilson Snyder 8957f77793 Internals: Refector needHeavy into methods. No functional change intended. 2020-05-25 15:34:24 -04:00
Wilson Snyder 7187b82d1d Update contributors (from email). 2020-05-25 13:36:24 -04:00
Ahmed El-Mahmoudy 1a92a58720 Fix spelling mistakes (#2364) 2020-05-25 12:43:32 -04:00
Wilson Snyder 2351f9b9ad Update contributors (from email). 2020-05-25 10:54:22 -04:00
Wilson Snyder abc3c216f8 Internal code coverage: Better support fastcov [still not default]. 2020-05-25 10:50:46 -04:00
Wilson Snyder f1afa667d7 Update contributors. 2020-05-25 09:16:40 -04:00
Wilson Snyder 76d0671952 Travis: Fix cron. 2020-05-25 08:46:46 -04:00
Jan Van Winkel 424769c32b Fix warning for unused param in VL_RTOIROUND_Q_D (#2356) 2020-05-25 08:13:12 -04:00
Wilson Snyder f7249ad23a Internals: AstRefDType points to AstTypedef instead of sub-dtype, in prep for future commits. 2020-05-24 14:22:06 -04:00
Wilson Snyder 613d76c578 Travis: Fix cron. 2020-05-24 08:30:59 -04:00
Wilson Snyder 50662751fe Fix compiler unsigned warnings 2020-05-23 22:38:17 -04:00
Wilson Snyder c9e59e767a Tests: Add setenv method. 2020-05-23 22:24:26 -04:00
Vassilis Papaefstathiou a7432bdea7 Support wide operands in queues and dynamic arrays (#2352) 2020-05-23 21:59:56 -04:00
Wilson Snyder 9ffad7f0db Internal cleanups. No functional change intended 2020-05-23 21:57:08 -04:00
Wilson Snyder 3097d5e093 Commentary 2020-05-23 21:56:56 -04:00
Yuri Victorovich cff4b5a5ee Fix WIFEXITED error on FreeBSD. (#2351) (#2353) 2020-05-23 16:30:36 -04:00
Wilson Snyder eda46e3949 Internals: Favor exprOrDataType where possible. No functional change intended. 2020-05-23 13:08:56 -04:00
Wilson Snyder 71651718d4 Internals: Track :: in AstDot parsing. No parsing change intended. 2020-05-23 12:44:15 -04:00
Wilson Snyder da0cb44954 Internals: Refactor parsing id's up to parent rules. No functional change intended. 2020-05-23 12:19:43 -04:00
Wilson Snyder 57621a93ad Internals: Move PLI errors into linker, and better test. 2020-05-23 11:55:34 -04:00
Wilson Snyder 6a882f9dc6 Internal code coverage improvements. No functional change intended. 2020-05-23 10:34:58 -04:00
Wilson Snyder c18b0eb122 Internal coverage: Limit parallelism to core count. 2020-05-23 09:50:04 -04:00
Wilson Snyder 3c28a66acf Internal coverage: Fix --hashset option. --stop now default. 2020-05-23 09:17:16 -04:00
Wilson Snyder 5c11de1663 Tests: Check queue typedef. 2020-05-22 22:14:26 -04:00
Wilson Snyder 72ea6bf414 Travis: Fix cron. 2020-05-22 08:39:56 -04:00
Ludwig Rogiers 101314a572 Add VPI error reset to vpi_get_time() (#2347) 2020-05-22 07:09:47 -04:00
Wilson Snyder 01f3e81a36 Internals: Parse extend/implements/etc using generic identifiers. 2020-05-21 21:31:15 -04:00
Wilson Snyder 3cb3b6c400 clang-format verilog.l. No functional change. 2020-05-21 19:46:21 -04:00
Wilson Snyder 8f58b58853 Internals: Parse using idAny where can to better detect id errors. 2020-05-20 23:29:37 -04:00
Wilson Snyder b66826169d Internals: Refactor inherits/extends parse so don't need type vs nontype IDs. 2020-05-20 23:10:45 -04:00
Wilson Snyder d2a7376f14 Fix spacing. No functional change 2020-05-20 22:33:32 -04:00
Wilson Snyder c9e8a1cb4d Commentary 2020-05-20 20:31:57 -04:00
Wilson Snyder 8170f6f03f Travis: Fix cron. 2020-05-20 17:39:32 -04:00
Stefan Wallentowitz 0abf88823f Docker upgrade to Ubuntu 20.04 (#2318)
* [docker] Remove versions from Docker files

There is no dependency on an actual version, it was only there to
silence the linter. Instead the linter is now set to not warn about
it.

Signed-off-by: Stefan Wallentowitz <[email protected]>

* [docker] Update to Ubuntu 20.04

Update to new Ubuntu release:

 - Only GCC 9.3 available. Also add clang (10.0) now.
 - SystemC is now a package 🎉

Signed-off-by: Stefan Wallentowitz <[email protected]>
2020-05-20 06:58:43 -04:00
Todd Strader accf5a9a17 Check if Parallel::Forker is new enough (#2343) 2020-05-19 14:31:13 -04:00
Wilson Snyder c64c81b7a3 Workaround missing guard (partial #2333). 2020-05-19 08:31:52 -04:00
Wilson Snyder 7834028842 Tests: Skip genhtml if too old 2020-05-19 08:24:21 -04:00
Wilson Snyder 1e0d5eb238 Release examples/Makefiles under CC0. 2020-05-18 22:23:19 -04:00
Wilson Snyder b5460bd867 Travis-CI fixes 2020-05-18 18:34:26 -04:00
Geza Lore 53cde90c8f De-constify fields to appease old GCC with broken STL
No functional change intended, fixes #2342
2020-05-18 19:01:08 +01:00
Geza Lore d20a4db773 Fix regression due to early constant folding in +: and -: (#2338) 2020-05-18 18:46:00 +01:00
Wilson Snyder 0f7677480f Commentary 2020-05-18 08:11:56 -04:00
Stephen Henry ba3930777a Support display/scan %u/%z (#2324) (#2332) 2020-05-18 08:10:32 -04:00
Geza Lore 9c054a5774 Optimize trace activity flags a bit more
- Improve flag pruning heuristic
- Set all trace activity flags in slow code. This in turns enables us
to remove checking the slow flag on the fast path.
2020-05-17 19:41:24 +01:00
Stephen Henry cef0105dfc Fix requiring C++11 algorithms. (#2339) (#2340) 2020-05-17 11:44:42 -04:00
Wilson Snyder 4773a1e77c Misc internal coverage improvements. 2020-05-17 11:06:14 -04:00
Wilson Snyder ed4c7038b4 Tracing: Remove dead code. No functional change intended. 2020-05-17 09:53:58 -04:00
Wilson Snyder c4f31d3bb6 Tracing: Remove dead code. No functional change intended. 2020-05-17 09:52:03 -04:00
Geza Lore dc25e9b949 Optimize fine grained trace activity flags (#2336)
Firstly, we always use a byte array for fine grained activity flags
instead of a bit vector (we used to use a byte array only if we had
parallel mtasks). The byte vector can be set more cheaply in eval,
closing about 1/3 of the gap in performance between compiling with
or without --trace on SweRV EH1. The speed of tracing itself is not
measurably different.

Secondly, we prune the activity tracking such that if a set of activity
flag combinations only guard a small number of signals, we will turn
those signals into awayls traced signals. This avoids code which
sometimes tests dozens of activity flags just to subsequently check one
signal and dump it if it's value changed. We can just check the signal
state straight instead, and not bother with the flags. This removes
about 30% of activity flags in SweRV EH1, and makes both single threaded
VCD and FST tracing 8-9% faster.
2020-05-17 13:53:02 +01:00
Wilson Snyder 1f52b01b2c Travis: Fix cron. 2020-05-17 08:48:31 -04:00
Wilson Snyder d5fc0fca41 Travis: Fix cron. 2020-05-17 08:19:42 -04:00
Wilson Snyder 212aa332dd Commentary 2020-05-16 18:53:18 -04:00
Wilson Snyder 17e7da77f0 Misc internal coverage improvements. 2020-05-16 18:02:54 -04:00
Wilson Snyder 201f0d3f5f Codecov badge 2020-05-16 15:02:22 -04:00
Wilson Snyder 7d0b3b300a Travis: Setup cron coverage 2020-05-16 14:59:30 -04:00
Wilson Snyder 0b55e205f7 Internal code_coverage: speedup aggregation. 2020-05-16 14:53:22 -04:00
Wilson Snyder 9c0c6439cc Clean additional objects. 2020-05-16 13:28:03 -04:00
Wilson Snyder d33d0301f8 Support verilator_coverage --write-info for lcov HTML reports. 2020-05-16 09:18:35 -04:00
Wilson Snyder 6fd7f45cef Internals: Remove dead needHInlines code 2020-05-16 07:53:27 -04:00
Wilson Snyder 57a937df03 Misc internal coverage cleanups 2020-05-16 07:43:22 -04:00
Wilson Snyder ffd461dcf8 Tests: Check need -cc message 2020-05-16 07:10:44 -04:00
Wilson Snyder f77058774e Add codecov.yml 2020-05-16 06:15:45 -04:00
Wilson Snyder 1d0a726437 Update internal code coverage framework. 2020-05-16 06:15:25 -04:00
Wilson Snyder 29bcbb0417 Suppress impossible code coverage issues 2020-05-15 22:34:29 -04:00
Wilson Snyder 2d11c2cbb3 Tests: Fix driver called with no tests 2020-05-15 22:33:35 -04:00
Wilson Snyder 2edbcce032 Tests: Need only one run of t_trace_c_api.pl 2020-05-15 22:33:20 -04:00
Wilson Snyder 35a53d9adb Add t_trace_c_api test. 2020-05-15 20:38:08 -04:00
Wilson Snyder 2885c2ce97 Fix coredump on countbits. 2020-05-15 19:29:17 -04:00
Geza Lore 900c023bb5 Refactor trace implementation to allow experimentation
The main goal of this patch is to enable splitting the full and
incremental tracing functions into multiple functions, which can then be
run in parallel at a later stage. It also simplifies further
experimentation as all of the interesting trace code construction now
happens in V3Trace. No functional change is intended by this patch, but
there are some implementation changes in the generated code.

Highlights:
- Pass symbol table directly to trace callbacks for simplicity.
- A new traceRegister function is generated which adds each trace
function as an individual callback, which means we can have multiple
callbacks for each trace function type.
- A new traceCleanup function is generated which clears the activity
flags, as the trace callbacks might be implemented as multiple functions.
- Re-worked sub-function handling so there is no separate sub-function
for each trace activity class. Sub-functions are generate when required
by splitting.
- traceFull/traceChg are now created in V3Trace rather than V3TraceDecl,
this requires carrying the trace value tree in TraceDecl until it
reaches V3Trace where the TraceInc nodes are created (previously a
TraceInc was also created in V3TraceDecl which carries the value).
2020-05-15 18:34:29 +01:00
Geza Lore 12b95f6b93 Clean up V3TraceDecl & V3Trace. No functional change intended.
- Constify variables
- Remove redundancies
- [Hopefully] make some code a bit more readable
2020-05-15 18:34:29 +01:00
Wilson Snyder 85de3048a5 Tests: Avoid poluting non-obj_ files. 2020-05-14 18:50:49 -04:00
Wilson Snyder c1a9fe07e9 Support multi channel descriptor I/O (#2190)
clang-format and Changes update. No functional change.
2020-05-14 18:14:50 -04:00
Stephen Henry 1a0da2e4ec Support multi-channel descriptor (MCD) I/O (#2197) 2020-05-14 18:03:00 -04:00
Wilson Snyder 38d11ecabe Commentary 2020-05-13 21:06:00 -04:00
Wilson Snyder 148762364b Tests: Complicated for loops long ago supported. 2020-05-13 20:53:55 -04:00
Huang Rui 68d7596adf Fix compile error when using bison 3.6.1 (#2320)
Workaround issue: bison 3.6.1 generated unexpected nested-comment
Closes: https://github.com/verilator/verilator/issues/2320
Signed-off-by: Huang Rui <[email protected]>
2020-05-13 19:18:56 -04:00
Wilson Snyder f005b7fd87 Support scan %* format 2020-05-11 22:13:59 -04:00
Wilson Snyder 68ed683681 Travis: Run 20.04 for non-cron, more others for cron. 2020-05-11 20:31:37 -04:00
Wilson Snyder 61e41595a2 Fix clang warning 2020-05-11 20:31:37 -04:00
Stephen Henry 484b574cef Fix crash on self-referential enum type. (#2319) 2020-05-11 18:44:28 -04:00
Wilson Snyder 29695adf70 Fix 10s/100s timeunits. 2020-05-11 08:15:52 -04:00
Wilson Snyder fac43811fd Commentary 2020-05-10 21:26:09 -04:00
Wilson Snyder 15f63d12d5 Fix message for seeded random. 2020-05-10 21:15:48 -04:00
Wilson Snyder ba7b3fd60f Support $display(,,). 2020-05-10 20:48:18 -04:00
Wilson Snyder 897b9ccfe2 Fix display of huge double. 2020-05-10 16:03:46 -04:00
Wilson Snyder b97e1aa9fe Support cast to string 2020-05-10 15:42:16 -04:00
Wilson Snyder d4a631446b Fix crash in unroller on increment-only while loops. 2020-05-10 15:26:41 -04:00
Wilson Snyder a2cc053c6f Tests: Fix t_math_svl.pl 2020-05-10 15:19:38 -04:00
Wilson Snyder 8998ffc4e5 Support reporting some fork syntax errors. 2020-05-10 15:01:43 -04:00
Wilson Snyder ca162716c6 Internals: clang-format 2020-05-10 14:29:15 -04:00
Wilson Snyder 629dd16714 Tests: Rename t_delay_func_bad 2020-05-10 14:28:42 -04:00
Wilson Snyder 12b903caf4 Improve error on using array.unique method. 2020-05-10 14:28:42 -04:00
Yossi Nivin f9a0cf0cff Support $countbits (#2287) 2020-05-10 14:27:22 -04:00
Wilson Snyder 070bcddf5a Support unpacked array .sum and .product. 2020-05-10 12:48:33 -04:00
Wilson Snyder feb1e2bd48 Commentary 2020-05-10 11:01:57 -04:00
Wilson Snyder 6e7ee23644 Internals: Code cleanups. 2020-05-09 15:00:46 -04:00
Wilson Snyder c00cc18d37 Optimize dead code after gotos 2020-05-09 15:00:36 -04:00
Wilson Snyder a7e17a8855 Fix double conversion on half of conditional. 2020-05-08 21:35:45 -04:00
Wilson Snyder 60fa1db731 Tests: Trivial cleanup 2020-05-08 21:35:45 -04:00
Geza Lore ac09ad3ffd Minor improvements to DPI open array handling (#2316)
- Allow arbitrary number of open array dimensions, not just 3. Note
right now this only works with the array querying functions specified
in IEEE 1800-2017 H.12.2
- Issue error when passing dynamic array or queue as DPI open array
(currently unsupported)
- Also tweaked AstVar::vlArgTypeRecurse, which should now error or fail
for unsupported types.
2020-05-08 18:22:44 +01:00
Wilson Snyder 27953e26b6 Backout example change. 2020-05-08 07:35:54 -04:00
Wilson Snyder 9375d9f603 Fix $isunknown with constant Zs. 2020-05-07 21:40:08 -04:00
Wilson Snyder 72bd91c7f1 Support $isunbounded and parameter $. (#2104) 2020-05-07 21:12:58 -04:00
Wilson Snyder 8850ca962e Fix newish error to use standard parens to ref IEEE. 2020-05-07 21:12:58 -04:00
Wilson Snyder 7fd590f855 Commentary 2020-05-07 21:12:58 -04:00
Wilson Snyder 5f7ae1fbce wip 2020-05-07 21:04:26 -04:00
Wilson Snyder b56a25e89c Fix newish error to use standard parens to ref IEEE. 2020-05-07 18:21:11 -04:00
Wilson Snyder 4f32b093e6 Commentary 2020-05-07 18:11:06 -04:00
Geza Lore 6a54fb6f96 Modify std::multimap in V3Combine safely.
We used to iterate the m_callMmap std::multimap by getting limit
iterators from equal_range, but we also modify the same map in the loop
which invalidates those limit iterators. Note this only caused actual
problems if the new AstCCall inserted via 'addCall' in the loop had a
memory address (which is used as the key) which fell into the range
returned by equal_range, so was pretty hard to trigger.
2020-05-07 14:31:43 +01:00
Wilson Snyder 546ccd56c4 Internals: Enable future JumpGo to non-end. No functional change intended. 2020-05-06 21:33:05 -04:00
Wilson Snyder ca77a93214 Add lint check for bad delay locations. 2020-05-06 19:25:13 -04:00
Dan Petrisko ee1b20e1cd Adding missing sstream include (#2312) 2020-05-06 19:16:41 -04:00
Yutetsu TAKATSUKASA aa86e0bbc0 Support 'E', 'p', and 'P' when overriding floating point parameter. (#2310) 2020-05-06 07:45:07 -04:00
Wilson Snyder b6b3482010 Internals: Use typ delay by default 2020-05-05 20:42:19 -04:00
Wilson Snyder 05aecd2c0b Internals: Fix tabs in astgen. No effective functional change. 2020-05-05 20:33:35 -04:00
Wilson Snyder 6ab3d8f3ed Internals: Refactor to add AstNodeProcedure. No functional change intended. 2020-05-05 19:12:36 -04:00
Wilson Snyder 0fcc7f2987 Fix default pkgconfig version to have no spaces (#2308) 2020-05-05 08:46:24 -04:00
Wilson Snyder 7d7e67b49b Show Verilog reference on V3Number asserts. 2020-05-04 19:57:21 -04:00
Wilson Snyder a41ea180fa Fix +: and -: on unpacked arrays. (#2304) 2020-05-04 19:40:50 -04:00
Wilson Snyder 98889b3f4e Tests: Fix permission 2020-05-04 19:35:48 -04:00
Tim Snyder 83fbfa8c71 Fix /usr/bin/env perl in lieu of /usr/bin/perl (#2307)
Enables scripts to work where perl is not installed at /usr/bin/perl
2020-05-04 19:27:30 -04:00
Tim Snyder a57262d6e7 Fix use /usr/bin/env perl in lieu of /usr/bin/perl (#2306)
Enables scripts to work where perl is not installed at /usr/bin/perl
2020-05-04 18:42:15 -04:00
Geza Lore fe708f045a Fix Travis oddity 2020-05-04 00:21:07 +01:00
Geza Lore 8afcd67a1f Fix FST tracing of little endian vectors 2020-05-03 22:39:45 +01:00
Wilson Snyder 16e258eb4c Commentary: reformat changes, relocate announcements 2020-05-03 16:10:02 -04:00
Wilson Snyder d6fbbddac9 devel release 2020-05-03 11:18:53 -04:00
1677 changed files with 16506 additions and 6920 deletions
+1
View File
@@ -3,3 +3,4 @@ exclude_paths:
- '.github/**' - '.github/**'
- 'ci/build_verilator.sh' - 'ci/build_verilator.sh'
- 'include/vltstd/**' - 'include/vltstd/**'
- 'nodist/fastcov.py'
+91 -160
View File
@@ -8,176 +8,107 @@
version: ~> 1.0 version: ~> 1.0
os: linux
language: cpp language: cpp
cache: ccache
env:
global:
- VERILATOR_CACHE=$HOME/verilator_cache
- VERILATOR_ROOT=$PWD
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
- VERILATOR_AUTHOR_SITE=1
cache: cache:
directories: directories:
- $VERILATOR_CACHE - $HOME/.ccache
before_install: env:
# Perl modules needed for testing global:
# Not listing Bit::Vector as slow to install, and only skips one test - VERILATOR_ROOT=$TRAVIS_BUILD_DIR
- touch temp.cpp ; g++ -E -dM -c temp.cpp | sort ; rm -rf temp.cpp
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
- sudo apt-get install gdb gtkwave
- sudo apt-get install libgoogle-perftools-dev
before_script:
- bash -x ci/build_vcddiff.sh
- bash -x ci/build_verilator.sh
after_script:
- ccache -s
# The list and order of build stages
stages: stages:
- "Build Verilator" - build # Build Verilator
- test - test # Run tests
# Dump info about the environment for debugging
before_install:
# To dump the script that Travis itself is executing, add 'cat $0' here
- cd "$TRAVIS_BUILD_DIR" # Skipping the git clone in later stages requires this
- export CCACHE_MAXSIZE=$(ci/travis-ccache-size.bash) # Set here after the 'cd'
- env | sort
- ls -lA .
- ls -lA bin
- g++ -E -dM -c -x c++ /dev/null | sort
- clang++ -E -dM -c -x c++ /dev/null | sort
# Install all dependencies
install:
- ./ci/travis-install.bash
before_script:
# ccache maintenance
- ./ci/travis-ccache-maint.bash
# On Focal, set the SystemC installation location
- |
if [ "$TRAVIS_DIST" = "focal" ]; then
export SYSTEMC_INCLUDE=/usr/include
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
fi
before_cache:
- ccache -s -z
# All jobs run the same script
script: ./ci/travis-script.bash
# Enumerate all the jobs
jobs: jobs:
include: include:
- if: type != cron ############################################################################
stage: "Build Verilator" # Jobs in the 'build' stage
name: Build Verilator ############################################################################
compiler: gcc # GCC builds
script: echo "Done building Verilator" - {stage: build, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {create: {name: trusty-gcc, paths: .}}}
# Non-cron build will just run on whatever linux flavor we get - {stage: build, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {create: {name: xenial-gcc, paths: .}}}
- if: type != cron - {stage: build, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {create: {name: bionic-gcc, paths: .}}}
stage: test - {stage: build, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc, paths: .}}}
name: Dist test # Clang builds
compiler: gcc - {stage: build, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {create: {name: xenial-clang, paths: .}}}
script: ci/test.sh dist - {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
- if: type != cron # Coverage build
stage: test - {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
name: Vlt test ############################################################################
compiler: gcc # Jobs in the 'test' stage
script: ci/test.sh vlt ############################################################################
- if: type != cron # GCC tests
stage: test - {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
name: Vltmt set 0 test - {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
compiler: gcc - {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
script: ci/test.sh vltmt0 - {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
- if: type != cron - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
stage: test - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
name: Vltmt set 1 test - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
compiler: gcc - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
script: ci/test.sh vltmt1 - {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
# Cron builds try different OS/compiler combinations - {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
- if: type = cron - {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
stage: "Build Verilator" - {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
name: Build xenial gcc Verilator - {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
os: linux - {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
dist: xenial - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
compiler: gcc - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
script: echo "Done building Verilator" # Clang tests
- if: type = cron - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
stage: test - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
name: Xenial gcc dist test - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
os: linux - {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
dist: xenial - {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
compiler: gcc - {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
script: ci/test.sh dist - {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
- if: type = cron - {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
stage: test # Coverage tests
name: Xenial gcc vlt test - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
os: linux - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-0}
dist: xenial - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
compiler: gcc - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
script: ci/test.sh vlt - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
- if: type = cron - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
stage: test - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
name: Xenial gcc vltmt test - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
os: linux - {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
dist: xenial
compiler: gcc
script: ci/test.sh vltmt
- if: type = cron
stage: "Build Verilator"
name: Build xenial clang Verilator
os: linux
dist: xenial
compiler: clang
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Xenial clang dist test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh dist
- if: type = cron
stage: test
name: Xenial clang vlt test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh vlt
- if: type = cron
stage: test
name: Xenial clang vltmt test
os: linux
dist: xenial
compiler: clang
script: ci/test.sh vltmt
# - if: type = cron
# stage: "Build Verilator"
# name: Build OSX gcc Verilator
# os: osx
# compiler: gcc
# script: echo "Done building Verilator"
# - if: type = cron
# stage: test
# name: OSX gcc dist test
# os: osx
# compiler: gcc
# script: ci/test.sh dist
# - if: type = cron
# stage: test
# name: OSX gcc vlt test
# os: osx
# compiler: gcc
# script: ci/test.sh vlt
# - if: type = cron
# stage: test
# name: OSX gcc vltmt test
# os: osx
# compiler: gcc
# script: ci/test.sh vltmt
- if: type = cron
stage: "Build Verilator"
name: Build trusty gcc Verilator
os: linux
dist: trusty
compiler: gcc
script: echo "Done building Verilator"
- if: type = cron
stage: test
name: Trusty gcc dist test
os: linux
dist: trusty
compiler: gcc
script: ci/test.sh dist
- if: type = cron
stage: test
name: Trusty gcc vlt test
os: linux
dist: trusty
compiler: gcc
script: ci/test.sh vlt
- if: type = cron
stage: test
os: linux
dist: trusty
name: Trusty gcc vltmt test
compiler: gcc
script: ci/test.sh vltmt
notifications: notifications:
email: email:
+912 -868
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -45,6 +45,7 @@ src/Makefile$
src/Makefile_obj$ src/Makefile_obj$
include/verilated.mk$ include/verilated.mk$
test_regress/.gdbinit$ test_regress/.gdbinit$
codecov.yml
config.cache$ config.cache$
config.status$ config.status$
verilator\.log verilator\.log
+9 -6
View File
@@ -5,6 +5,7 @@ ifdef::env-github[]
image:https://img.shields.io/badge/License-LGPL%20v3-blue.svg[license LGPLv3,link=https://www.gnu.org/licenses/lgpl-3.0] image:https://img.shields.io/badge/License-LGPL%20v3-blue.svg[license LGPLv3,link=https://www.gnu.org/licenses/lgpl-3.0]
image:https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg[license Artistic-2.0,link=https://opensource.org/licenses/Artistic-2.0] image:https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg[license Artistic-2.0,link=https://opensource.org/licenses/Artistic-2.0]
image:https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f[Code Quality,link=https://www.codacy.com/gh/verilator/verilator] image:https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f[Code Quality,link=https://www.codacy.com/gh/verilator/verilator]
image:https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg[Coverage,link=https://codecov.io/gh/verilator/verilator]
image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator] image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator]
endif::[] endif::[]
@@ -20,9 +21,9 @@ endif::[]
== Welcome to Verilator == Welcome to Verilator
[cols="a,a",indent=0,frame="none"] [cols="a,a",indent=0,frame="none",grid="rows"]
|=== |===
^.^| *Welcome to Verilator, the fastest Verilog HDL simulator.* ^.^| *Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.*
+++ <br/> +++ &bullet; Accepts synthesizable Verilog or SystemVerilog +++ <br/> +++ &bullet; Accepts synthesizable Verilog or SystemVerilog
+++ <br/> +++ &bullet; Performs lint code-quality checks +++ <br/> +++ &bullet; Performs lint code-quality checks
+++ <br/> +++ &bullet; Compiles into multithreaded {cpp}, or SystemC +++ <br/> +++ &bullet; Compiles into multithreaded {cpp}, or SystemC
@@ -73,15 +74,15 @@ replacement for NC-Verilog, VCS or another commercial Verilog simulator, or
if you are looking for a behavioral Verilog simulator e.g. for a quick if you are looking for a behavioral Verilog simulator e.g. for a quick
class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for
this.) However, if you are looking for a path to migrate SystemVerilog to this.) However, if you are looking for a path to migrate SystemVerilog to
{cpp} or SystemC, and your team is comfortable writing just a {cpp} or SystemC, or your team is comfortable writing just a touch of {cpp}
touch of {cpp} code, Verilator is the tool for you. code, Verilator is the tool for you.
== Performance == Performance
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather, Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather,
Verilator compiles your code into a much faster optimized and optionally Verilator compiles your code into a much faster optimized and optionally
thread-partitioned model, which is in turn wrapped inside a thread-partitioned model, which is in turn wrapped inside a
{cpp}/SystemC/{cpp}-under-Python module. The results are a compiled {cpp}/SystemC module. The results are a compiled
Verilog model that executes even on a single-thread over 10x faster than Verilog model that executes even on a single-thread over 10x faster than
standalone SystemC, and on a single thread is about 100 times faster than standalone SystemC, and on a single thread is about 100 times faster than
interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus
@@ -112,9 +113,11 @@ For more information:
* https://verilator.org/verilator_doc.html[Verilator manual (HTML)], * https://verilator.org/verilator_doc.html[Verilator manual (HTML)],
or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)] or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
* https://github.com/verilator/verilator-announce[Subscribe to verilator announcements]
* https://verilator.org/forum[Verilator forum] * https://verilator.org/forum[Verilator forum]
* https://verilator.org/issues[Verilator Issues] * https://verilator.org/issues[Verilator issues]
== Support == Support
+244 -204
View File
@@ -300,6 +300,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--dump-tree Enable dumping .tree files --dump-tree Enable dumping .tree files
--dump-treei <level> Enable dumping .tree files at a level --dump-treei <level> Enable dumping .tree files at a level
--dump-treei-<srcfile> <level> Enable dumping .tree file at a source file at a level --dump-treei-<srcfile> <level> Enable dumping .tree file at a source file at a level
--dump-tree-addrids Use short identifiers instead of addresses
-E Preprocess, but do not compile -E Preprocess, but do not compile
--error-limit <value> Abort after this number of errors --error-limit <value> Abort after this number of errors
--exe Link to create executable --exe Link to create executable
@@ -399,6 +400,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext> +verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
--version Displays program version and exits --version Displays program version and exits
--vpi Enable VPI compiles --vpi Enable VPI compiles
--waiver-output <filename> Create a waiver file based on the linter warnings
-Wall Enable all style warnings -Wall Enable all style warnings
-Werror-<message> Convert warnings to errors -Werror-<message> Convert warnings to errors
-Wfuture-<message> Disable unknown message warnings -Wfuture-<message> Disable unknown message warnings
@@ -811,6 +813,14 @@ file to the specified tree dumping level (e.g. C<--dump-treei-V3Order 9>).
Level 0 disbles dumps and is equivalent to "--no-dump-tree". Level 9 Level 0 disbles dumps and is equivalent to "--no-dump-tree". Level 9
enables dumping of every stage. enables dumping of every stage.
=item --dump-tree-addrids
Rarely needed - for developer use. Replace AST node addresses with short
identifiers in tree dumps to enhance readability. Each unique pointer value
is mapped to a unique identifier, but note that this is not necessarily
unique per node instance as an address might get reused by a newly allocated
node after a node with the same address has been dumped then freed.
=item -E =item -E
Preprocess the source code, but do not compile, as with 'gcc -E'. Output Preprocess the source code, but do not compile, as with 'gcc -E'. Output
@@ -881,7 +891,10 @@ octal (0..) or binary (0b..) notation.
=item Double literals =item Double literals
Double literals must contain a dot (.) and/or an exponent (e). Double literals must be one of the following styles:
- contains a dot (.) (e.g. 1.23)
- contains an expornent (e/E) (e.g. 12e3)
- contains p/P for hexadecimal floating point in C99 (e.g. 0x123.ABCp1)
=item Strings =item Strings
@@ -1119,17 +1132,15 @@ developers.
Enables splitting the output .cpp files into multiple outputs. When a C++ Enables splitting the output .cpp files into multiple outputs. When a C++
file exceeds the specified number of operations, a new file will be created file exceeds the specified number of operations, a new file will be created
at the next function boundary. In addition, any infrequently executed at the next function boundary. In addition, if the total output code size
"cold" routines will be placed into __Slow files. This accelerates exceeds the specified value, VM_PARALLEL_BUILDS will be set to 1 by default
compilation by as optimization can be disabled on the routines in __Slow, in the generated make files, making parallel compilation possible. Using
and the remaining files can be compiled on parallel machines. Using --output-split should have only a trivial impact on model performance. But
--output-split should have only a trivial impact on performance. On one can greatly improve C++ compilation speed. The use of I<ccache> (set for you
design --output-split 20000 resulted in splitting into approximately if present at configure time) is also more effective with this option.
one-minute-compile chunks.
Typically when using this, make with VM_PARALLEL_BUILDS=1 (set for you if This option is on by default with a value of 20000. To disable, pass with a
using the default makefiles), and use I<ccache> (set for you if present at value of 0.
configure time).
=item --output-split-cfuncs I<statements> =item --output-split-cfuncs I<statements>
@@ -1141,10 +1152,14 @@ worse with decreasing split values. Note that this option is stronger than
--output-split in the sense that --output-split will not split inside a --output-split in the sense that --output-split will not split inside a
function. function.
Defaults to the value of --output-split, unless explicitly specified.
=item --output-split-ctrace I<statements> =item --output-split-ctrace I<statements>
Enables splitting trace functions in the output .cpp files into Similar to --output-split-cfuncs, enables splitting trace functions in the
multiple functions. Defaults to same setting as --output-split-cfuncs. output .cpp files into multiple functions.
Defaults to the value of --output-split, unless explicitly specified.
=item -P =item -P
@@ -1451,7 +1466,7 @@ good value.
Sets default timescale, timeunit and timeprecision for when `timescale does Sets default timescale, timeunit and timeprecision for when `timescale does
not occur in sources. Default is "1ps/1ps" (to match SystemC). This is not occur in sources. Default is "1ps/1ps" (to match SystemC). This is
overriden by C<--timescale-override>. overridden by C<--timescale-override>.
=item --timescale-override I<timeunit>/I<timeprecision> =item --timescale-override I<timeunit>/I<timeprecision>
@@ -1539,7 +1554,7 @@ larger trace files.
=item --trace-threads I<threads> =item --trace-threads I<threads>
Enable waveform tracing using separate threads. This is typically faster in Enable waveform tracing using separate threads. This is typically faster in
simulation runtime but uses more total compute. This option is independend of, simulation runtime but uses more total compute. This option is independent of,
and works with, both C<--trace> and C<--trace-fst>. Different trace formats can and works with, both C<--trace> and C<--trace-fst>. Different trace formats can
take advantage of more trace threads to varying degrees. Currently VCD tracing take advantage of more trace threads to varying degrees. Currently VCD tracing
can utilize at most --trace-threads 1, and FST tracing can utilize at most can utilize at most --trace-threads 1, and FST tracing can utilize at most
@@ -1601,6 +1616,17 @@ Displays program version and exits.
Enable use of VPI and linking against the verilated_vpi.cpp files. Enable use of VPI and linking against the verilated_vpi.cpp files.
=item --waiver-output <filename>
Generate a waiver file which contains all waiver statements to suppress the
warnings emitted during this Verilator run. This is in particular useful as
a starting point for solving linter warnings or suppressing them
systematically.
The generated file is in the Verilator Configuration format, see
L</"CONFIGURATION FILES">, and can directly be consumed by Verilator. The
standard file extension is .vlt.
=item -Wall =item -Wall
Enable all code style warnings, including code style warnings that are Enable all code style warnings, including code style warnings that are
@@ -2001,7 +2027,7 @@ depending on the operating system.
# Might be needed if SystemC 2.3.0 # Might be needed if SystemC 2.3.0
export SYSTEMC_CXX_FLAGS=-pthread export SYSTEMC_CXX_FLAGS=-pthread
g++ -L$SYSTEMC_LIBDIR ../sc_main.o Vour__ALL*.o verilated.o \ g++ -L$SYSTEMC_LIBDIR ../sc_main.o Vour__ALL.a verilated.o \
-o Vour -lsystemc -o Vour -lsystemc
And now we run it And now we run it
@@ -2054,11 +2080,11 @@ distribution.
=head1 BENCHMARKING & OPTIMIZATION =head1 BENCHMARKING & OPTIMIZATION
For best performance, run Verilator with the "-O3 --x-assign fast For best performance, run Verilator with the "-O3 --x-assign fast --x-initial
--x-initial fast --noassert" flags. The -O3 flag will require longer fast --noassert" flags. The -O3 flag will require longer time to run
compile times, and "--x-assign fast --x-initial fast" may increase the risk Verilator, and "--x-assign fast --x-initial fast" may increase the risk of
of reset bugs in trade for performance; see the above documentation for reset bugs in trade for performance; see the above documentation for these
these flags. flags.
If using Verilated multithreaded, use C<numactl> to ensure you are using If using Verilated multithreaded, use C<numactl> to ensure you are using
non-conflicting hardware resources. See L</"MULTITHREADING">. non-conflicting hardware resources. See L</"MULTITHREADING">.
@@ -2070,49 +2096,69 @@ simple change to a clock latch used to gate clocks and gained a 60%
performance improvement. performance improvement.
Beyond that, the performance of a Verilated model depends mostly on your Beyond that, the performance of a Verilated model depends mostly on your
C++ compiler and size of your CPU's caches. C++ compiler and size of your CPU's caches. Experience shows that large models
are often limited by the size of the instruction cache, and as such reducing
code size if possible can be beneficial.
By default, the lib/verilated.mk file has optimization turned off. This is The supplied $VERILATOR_ROOT/include/verilated.mk file uses the OPT, OPT_FAST,
for the benefit of new users, as it improves compile times at the cost of OPT_SLOW and OPT_GLOBAL variables to control optimization. You can set these
simulation runtimes. To add optimization as the default, set one of three variables, when compiling the output of Verilator with Make, for example:
OPT, OPT_FAST, or OPT_SLOW lib/verilated.mk. Or, use the -CFLAGS and/or
-LDFLAGS option on the verilator command line to pass the flags directly to
the compiler or linker. Or, just for one run, pass them on the command
line to make:
make OPT_FAST="-Os -march=native -fno-stack-protector" -f Vour.mk Vour__ALL.a make OPT_FAST="-Os -march=native" -f Vour.mk Vour__ALL.a
OPT_FAST specifies optimizations for those programs that are part of the OPT_FAST specifies optimization flags for those parts of the model that are on
fast path, mostly code that is executed every cycle. OPT_SLOW specifies the fast path. This is mostly code that is executed every cycle. OPT_SLOW
optimizations for slow-path files (plus tracing), which execute only applies to slow-path code, which executes rarely, often only once at the
rarely, yet take a long time to compile with optimization on. OPT beginning or end of simulation. Note that OPT_SLOW is ignored if
specifies overall optimization and affects all compiles, including those VM_PARALLEL_BUILDS is not 1, in which case all generated code will be compiled
OPT_FAST and OPT_SLOW control. For best results, use OPT="-Os in a single compilation unit using OPT_FAST. See also the C<--output-split>
-march=native", and link with "-static". Nearly the same results can be option. The OPT_GLOBAL variable applies to common code in the run-time library
had with much better compile times with OPT_FAST="-O1 -fstrict-aliasing". used by verilated models (shipped in $VERILATOR_ROOT/include). Additional C++
Higher optimization such as "-O2" or "-O3" may help, but gcc compile times files passed on the verilator command line use OPT_FAST. The OPT variable
may be excessive under O3 on even medium sized designs. applies to all compilation units in addition to the specific OPT_* variables
described above.
Unfortunately, using the optimizer with SystemC files can result in You can also use the -CFLAGS and/or -LDFLAGS options on the verilator command
compiles taking several minutes. (The SystemC libraries have many little line to pass flags directly to the compiler or linker.
inlined functions that drive the compiler nuts.)
For best results, use the latest clang compiler (about 10% faster than The default values of the OPT_* variables are chosen to yield good simulation
GCC). Note the now fairly old GCC 3.2 and earlier have optimization bugs speed with reasonable C++ compilation times. To this end, OPT_FAST is set to
around pointer aliasing detection, which can result in 2x performance "-Os" by default. Higher optimization such as "-O2" or "-O3" may help (though
losses. often they provide only a very small performance benefit), but compile times
may be excessively large even with medium sized designs. Compilation times can
be improved at the expense of simulation speed by reducing optimization, for
example with OPT_FAST="-O0". Often good simulation speed can be achieved with
OPT_FAST="-O1 -fstrict-aliasing" but with improved compilation times. Files
controlled by OPT_SLOW have little effect on performance and therefore OPT_SLOW
is empty by default (equivalent to "-O0") for improved compilation speed. In
common use-cases there should be little benefit in changing OPT_SLOW.
OPT_GLOBAL is set to "-Os" by default and there should rarely be a need to
change it. As the run-time library is small in comparison to a lot of verilated
models, disabling optimization on the run-time library should not have a
serious effect on overall compilation time, but may have detrimental effect on
simulation speed, especially with tracing. In addition to the above, for best
results use OPT="-march=native", the latest Clang compiler (about 10% faster
than GCC), and link statically.
If you will be running many simulations on a single compile, investigate Generally the answer to which optimization level gives the best user experience
feedback driven compilation. With GCC, using -fprofile-arcs, then depends on the use case and some experimentation can pay dividends. For a
speedy debug cycle during development, especially on large designs where C++
compilation speed can dominate, consider using lower optimization to get to an
executable faster. For throughput oriented use cases, for example regressions,
it is usually worth spending extra compilation time to reduce total CPU time.
If you will be running many simulations on a single model, you can investigate
profile guided optimization. With GCC, using -fprofile-arcs, then
-fbranch-probabilities will yield another 15% or so. -fbranch-probabilities will yield another 15% or so.
Modern compilers also support link-time optimization (LTO), which can help Modern compilers also support link-time optimization (LTO), which can help
especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in both
both compilation and link. Note LTO may cause excessive compile times on compilation and link. Note LTO may cause excessive compile times on large
large designs. designs.
Using profile driven compiler optimization, with feedback from a real Unfortunately, using the optimizer with SystemC files can result in compilation
design, can yield up to30% improvements. taking several minutes. (The SystemC libraries have many little inlined
functions that drive the compiler nuts.)
If you are using your own makefiles, you may want to compile the Verilated If you are using your own makefiles, you may want to compile the Verilated
code with -DVL_INLINE_OPT=inline. This will inline functions, however this code with -DVL_INLINE_OPT=inline. This will inline functions, however this
@@ -2184,8 +2230,7 @@ After running Make, the C++ compiler may produce the following:
{mod_prefix}{misc}.o // Intermediate objects {mod_prefix}{misc}.o // Intermediate objects
{prefix} // Final executable (w/--exe argument) {prefix} // Final executable (w/--exe argument)
{prefix}__ALL.a // Library of all Verilated objects {prefix}__ALL.a // Library of all Verilated objects
{prefix}__ALLfast.cpp // Include of hot code for single compile {prefix}__ALL.cpp // Include of all code for single compile
{prefix}__ALLslow.cpp // Include of slow code for single compile
{prefix}{misc}.d // Intermediate dependencies {prefix}{misc}.d // Intermediate dependencies
{prefix}{misc}.o // Intermediate objects {prefix}{misc}.o // Intermediate objects
@@ -2653,7 +2698,7 @@ Verilator and add the generated C++ sources to the target specified.
verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name] verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name]
[TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE] [TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE]
[INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...] [INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...]
[DIRECTORY dir] [VERILATOR_ARGS ...]) [OPT_GLOBAL ..] [DIRECTORY dir] [VERILATOR_ARGS ...])
Lowercase and ... should be replaced with arguments, the uppercase parts Lowercase and ... should be replaced with arguments, the uppercase parts
delimit the arguments and can be passed in any order, or left out entirely delimit the arguments and can be passed in any order, or left out entirely
@@ -2744,6 +2789,11 @@ optimization level to improve compile times with large designs.
Optional. Set compiler flags for the fast path. Optional. Set compiler flags for the fast path.
=item OPT_GLOBAL
Optional. Set compiler flags for the common run-time library used by verilated
models.
=item DIRECTORY =item DIRECTORY
Optional. Set the verilator output directory. It is preferable to use the Optional. Set the verilator output directory. It is preferable to use the
@@ -2769,8 +2819,7 @@ underneath NC:
cd obj_dir cd obj_dir
ncsc_run \ ncsc_run \
sc_main.cpp \ sc_main.cpp \
Vour__ALLfast.cpp \ Vour__ALL.cpp \
Vour__ALLslow.cpp \
verilated.cpp verilated.cpp
For larger designs you'll want to automate this using makefiles, which pull For larger designs you'll want to automate this using makefiles, which pull
@@ -3076,7 +3125,7 @@ information.
Break the variable into multiple pieces typically to resolve UNOPTFLAT Break the variable into multiple pieces typically to resolve UNOPTFLAT
performance issues. Typically the variables to attach this to are performance issues. Typically the variables to attach this to are
recommeded by Verilator itself, see UNOPTFLAT. recommended by Verilator itself, see UNOPTFLAT.
Same as /*verilator split_var*/, see L</"LANGUAGE EXTENSIONS"> for more Same as /*verilator split_var*/, see L</"LANGUAGE EXTENSIONS"> for more
information. information.
@@ -3101,11 +3150,11 @@ uwire keyword.
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support =head2 SystemVerilog 2005 (IEEE 1800-2005) Support
Verilator supports ==? and !=? operators, ++ and -- in some contexts, Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0, $bits, $countbits, $countones, $error, $fatal, $info, $isunknown, $onehot,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle, $onehot0, $unit, $warning, always_comb, always_ff, always_latch, bit, byte,
const, do-while, enum, export, final, import, int, interface, logic, chandle, const, do-while, enum, export, final, import, int, interface,
longint, modport, package, program, shortint, struct, time, typedef, union, logic, longint, modport, package, program, shortint, struct, time, typedef,
var, void, priority case/if, and unique case/if. union, var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection. It also supports .name and .* interconnection.
@@ -3571,7 +3620,7 @@ for more information.
Attached to a variable or a net declaration to break the variable into Attached to a variable or a net declaration to break the variable into
multiple pieces typically to resolve UNOPTFLAT performance issues. multiple pieces typically to resolve UNOPTFLAT performance issues.
Typically the variables to attach this to are recommeded by Verilator Typically the variables to attach this to are recommended by Verilator
itself, see UNOPTFLAT below. itself, see UNOPTFLAT below.
For example, Verilator will internally convert a variable with the For example, Verilator will internally convert a variable with the
@@ -3620,29 +3669,24 @@ declared.
=head1 LANGUAGE LIMITATIONS =head1 LANGUAGE LIMITATIONS
There are some limitations and lack of features relative to a commercial There are some limitations and lack of features relative to the major
simulator, by intent. User beware. closed-source simulators, by intent.
It is strongly recommended you use a lint tool before running this program.
Verilator isn't designed to easily uncover common mistakes that a lint
program will find for you.
=head2 Synthesis Subset =head2 Synthesis Subset
Verilator supports only the Synthesis subset with a few minor additions Verilator supports the Synthesis subset with other verification constructs
such as $stop, $finish and $display. That is, you cannot use hierarchical being added over time. Verilator also simulates events as Synopsys's Design
references, events or similar features of the Verilog language. It also Compiler would; namely given a block of the form:
simulates as Synopsys's Design Compiler would; namely a block of the form:
always @ (x) y = x & z; always @ (x) y = x & z;
This will recompute y when there is even a potential for change in x or a This will recompute y when there is even a potential for change in x or a
change in z, that is when the flops computing x or z evaluate (which is change in z, that is when the flops computing x or z evaluate (which is
what Design Compiler will synthesize.) A compliant simulator would only what Design Compiler will synthesize.) A compliant simulator would only
calculate y if x changes. Use Verilog-Mode's /*AS*/ or Verilog 2001's calculate y if x changes. We recommend using always_comb to make the code
always @* to reduce missing activity items. Avoid putting $displays in run the same everywhere. Also avoid putting $displays in combo blocks, as
combo blocks, as they may print multiple times when not desired, even on they may print multiple times when not desired, even on compliant
compliant simulators as event ordering is not specified. simulators as event ordering is not specified.
=head2 Signal Naming =head2 Signal Naming
@@ -3659,9 +3703,9 @@ path.
=head2 Class =head2 Class
Verilator class support is very limited and in active development. Verilator class support is limited but in active development. Verilator
Verilator supports members, and methods. Verilator doe not support class supports members, and methods. Verilator doe not support class static
static members, class extend, or class parameters. members, class extend, or class parameters.
=head2 Dotted cross-hierarchy references =head2 Dotted cross-hierarchy references
@@ -3675,18 +3719,9 @@ specified in the Verilog standard; arrayed instances are named
{cellName}[{instanceNumber}] in Verilog, which becomes {cellName}[{instanceNumber}] in Verilog, which becomes
{cellname}__BRA__{instanceNumber}__KET__ inside the generated C++ code. {cellname}__BRA__{instanceNumber}__KET__ inside the generated C++ code.
Verilator creates numbered "genblk" when a begin: name is not specified
around a block inside a generate statement. These numbers may differ
between other simulators, but the Verilog specification does not allow
users to use these names, so it should not matter.
If you are having trouble determining where a dotted path goes wrong, note If you are having trouble determining where a dotted path goes wrong, note
that Verilator will print a list of known scopes to help your debugging. that Verilator will print a list of known scopes to help your debugging.
=head2 Floating Point
Short floating point (shortreal) numbers are converted to real.
=head2 Latches =head2 Latches
Verilator is optimized for edge sensitive (flop based) designs. It will Verilator is optimized for edge sensitive (flop based) designs. It will
@@ -3788,12 +3823,6 @@ primary inputs to the model, or wires directly attached to primary inputs.
For proper behavior clock enables may also need the /*verilator For proper behavior clock enables may also need the /*verilator
clock_enable*/ attribute. clock_enable*/ attribute.
=head2 Ranges must be big-bit-endian
Bit ranges must be numbered with the MSB being numbered greater or the same
as the LSB. Little-bit-endian buses [0:15] are not supported as they
aren't easily made compatible with C++.
=head2 Gate Primitives =head2 Gate Primitives
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are
@@ -3802,7 +3831,8 @@ primitives are not supported. Tables are not supported.
=head2 Specify blocks =head2 Specify blocks
All specify blocks and timing checks are ignored. All specify blocks and timing checks are ignored. All min:typ:max delays
use the typical value.
=head2 Array Initialization =head2 Array Initialization
@@ -3831,7 +3861,6 @@ coverage section.
Verilator does not support SEREs yet. All assertion and coverage Verilator does not support SEREs yet. All assertion and coverage
statements must be simple expressions that complete in one cycle. statements must be simple expressions that complete in one cycle.
(Arguably SEREs are much of the point, but one must start somewhere.)
=head2 Encrypted Verilog =head2 Encrypted Verilog
@@ -3908,41 +3937,26 @@ Interfaces and modports, including with generated data types are supported.
Generate blocks around modports are not supported, nor are virtual Generate blocks around modports are not supported, nor are virtual
interfaces nor unnamed interfaces. interfaces nor unnamed interfaces.
=item priority if, unique if =item shortreal
Priority and unique if's are treated as normal ifs and not asserted to be Short floating point (shortreal) numbers are converted to real. Most other
full nor unique. simulators either do not support float, or convert likewise.
=item specify specparam =item specify specparam
All specify blocks and timing checks are ignored. All specify blocks and timing checks are ignored.
=item string
String is supported only to the point that they can be assigned,
concatenated, compared, and passed to DPI imports. Standard method calls
on strings are not supported.
=item timeunit, timeprecision
All timing control statements are ignored.
=item uwire =item uwire
Verilator does not perform warning checking on uwires, it treats the uwire Verilator does not perform warning checking on uwires, it treats the uwire
keyword as if it were the normal wire keyword. keyword as if it were the normal wire keyword.
=item $bits, $countones, $error, $fatal, $finish, $info, $isunknown, =item $bits, $countbits, $countones, $error, $fatal, $finish, $info,
$onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop, $time, $isunknown, $onehot, $onehot0, $readmemb, $readmemh, $signed, $stime, $stop,
$unsigned, $warning. $time, $unsigned, $warning.
Generally supported. Generally supported.
=item $displayb, $displayh, $displayo, $writeb, $writeh, $writeo, etc
The sized display functions are rarely used and so not supported. Replace
them with a $write with the appropriate format specifier.
=item $dump/$dumpports and related =item $dump/$dumpports and related
$dumpfile or $dumpports will create a VCD or FST file (which is based on $dumpfile or $dumpports will create a VCD or FST file (which is based on
@@ -3980,6 +3994,11 @@ $setup, $setuphold, $skew, $timeskew, $width
All specify blocks and timing checks are ignored. All specify blocks and timing checks are ignored.
=item $monitor, $strobe
Monitor and strobe are not supported, convert to always_comb $display or
similar.
=item $random =item $random
$random does not support the optional argument to set the seed. Use the $random does not support the optional argument to set the seed. Use the
@@ -4049,7 +4068,7 @@ the source line directly above.
Warns that an always_comb block has a variable which is set after it is Warns that an always_comb block has a variable which is set after it is
used. This may cause simulation-synthesis mismatches, as not all used. This may cause simulation-synthesis mismatches, as not all
commercial simulators allow this ordering. simulators allow this ordering.
always_comb begin always_comb begin
a = b; a = b;
@@ -4797,7 +4816,10 @@ correctly.
Warns that unpacked structs and unions are not supported. Warns that unpacked structs and unions are not supported.
Ignoring this warning will make Verilator treat the structure as packed, Ignoring this warning will make Verilator treat the structure as packed,
which may make Verilator simulations differ from other simulators. which may make Verilator simulations differ from other simulators. This
downgrading may also result what would normally be a legal unpacked
struct/array inside an unpacked struct/array becomming an illegal unpacked
struct/array inside a packed struct/array.
=item UNSIGNED =item UNSIGNED
@@ -4975,14 +4997,14 @@ Note people sometimes request binaries when they are having problems with
their C++ compiler. Alas, binaries won't help this, as in the end a fully their C++ compiler. Alas, binaries won't help this, as in the end a fully
working C++ compiler is required to compile the output of Verilator. working C++ compiler is required to compile the output of Verilator.
=item How can it be faster than (name-the-commercial-simulator)? =item How can it be faster than (name-a-big-3-closed-source-simulator)?
Generally, the implied part is of the question is "... with all of the Generally, the implied part is of the question is "... with all of the
manpower they can put into developing it." manpower they can put into developing it."
Most commercial simulators have to be Verilog compliant, meaning event Most simulators have to be Verilog compliant, meaning event driven. This
driven. This prevents them from being able to reorder blocks and make prevents them from being able to reorder blocks and make netlist-style
netlist-style optimizations, which are where most of the gains come from. optimizations, which are where most of the gains come from.
Non-compliance shouldn't be scary. Your synthesis program isn't compliant, Non-compliance shouldn't be scary. Your synthesis program isn't compliant,
so your simulator shouldn't have to be -- and Verilator is closer to the so your simulator shouldn't have to be -- and Verilator is closer to the
@@ -5021,8 +5043,8 @@ simulator in order to optimize it. If it takes more than a minute or so
(and you're not using --debug since debug is disk bound), see if your (and you're not using --debug since debug is disk bound), see if your
machine is paging; most likely you need to run it on a machine with more machine is paging; most likely you need to run it on a machine with more
memory. Verilator is a full 64-bit application and may use more than 4GB, memory. Verilator is a full 64-bit application and may use more than 4GB,
but about 1GB is the maximum typically needed, and very large commercial but about 1GB is the maximum typically needed, and very large designs have
designs have topped 16GB. topped 16GB.
=item How do I generate waveforms (traces) in C++? =item How do I generate waveforms (traces) in C++?
@@ -5125,10 +5147,10 @@ format instead.
=item How do I view waveforms (aka dumps or traces)? =item How do I view waveforms (aka dumps or traces)?
Verilator makes standard VCD (Value Change Dump) and FST files. VCD files are viewable Verilator makes standard VCD (Value Change Dump) and FST files. VCD files
with the public domain GTKWave (recommended) or Dinotrace (legacy) are viewable with the public domain GTKWave (recommended) or Dinotrace
programs, or any of the many commercial offerings; (legacy) programs, or any of the many closed-source offerings; FST is
FST is supported by GTKWave only. supported by GTKWave only.
=item How do I reduce the size of large waveform (trace) files? =item How do I reduce the size of large waveform (trace) files?
@@ -5168,6 +5190,10 @@ For an example, after running 'make test' in the Verilator distribution,
see the examples/make_tracing_c/logs directory. Grep for lines starting see the examples/make_tracing_c/logs directory. Grep for lines starting
with '%' to see what lines Verilator believes need more coverage. with '%' to see what lines Verilator believes need more coverage.
Info files can be written by verilator_coverage for import to C<lcov>.
This enables use of C<genhtml> for HTML reports and importing reports to
sites such as L<https://codecov.io>.
=item Where is the translate_off command? (How do I ignore a construct?) =item Where is the translate_off command? (How do I ignore a construct?)
Translate on/off pragmas are generally a bad idea, as it's easy to have Translate on/off pragmas are generally a bad idea, as it's easy to have
@@ -5240,10 +5266,15 @@ test_regress/t/t_extend_class files show an example of how to do this.
=item How do I get faster build times? =item How do I get faster build times?
When running make pass the make variable VM_PARALLEL_BUILDS=1 so that When running make pass the make variable VM_PARALLEL_BUILDS=1 so that
builds occur in parallel. builds occur in parallel. Note this is now set by default if an output
file was large enough to be split due to the --output-split option.
Use a recent compiler. Newer compilers tend do be faster, with the Verilator emits any infrequently executed "cold" routines into separate
now relatively old GCC 3.0 to 3.3 being horrible. __Slow.cpp files. This can accelerate compilation as optimization can be
disabled on these routines. See the OPT_FAST and OPT_SLOW make variables
and the BENCHMARKING & OPTIMIZATION section of the manual.
Use a recent compiler. Newer compilers tend to be faster.
Compile in parallel on many machines and use caching; see the web for the Compile in parallel on many machines and use caching; see the web for the
ccache, distcc and icecream packages. ccache will skip GCC runs between ccache, distcc and icecream packages. ccache will skip GCC runs between
@@ -5365,7 +5396,7 @@ outputs. Now, the following should fail:
cd test_regress cd test_regress
t/t_BUG.pl # Run on Verilator t/t_BUG.pl # Run on Verilator
t/t_BUG.pl --debug # Run on Verilator, passing --debug to Verilator t/t_BUG.pl --debug # Run on Verilator, passing --debug to Verilator
t/t_BUG.pl --vcs # Run on a commercial simulator t/t_BUG.pl --vcs # Run on VCS simulator
t/t_BUG.pl --nc|--iv|--ghdl # Likewise on other simulators t/t_BUG.pl --nc|--iv|--ghdl # Likewise on other simulators
The test driver accepts a number of options, many of which mirror the main The test driver accepts a number of options, many of which mirror the main
@@ -5408,7 +5439,7 @@ In 2018, Verilator 4.000 was released with multithreaded support.
Currently, various language features and performance enhancements are added Currently, various language features and performance enhancements are added
as the need arises. Verilator is now about 3x faster than in 2002, and is as the need arises. Verilator is now about 3x faster than in 2002, and is
faster than many popular commercial simulators. faster than most (if not every) other simulator.
=head1 AUTHORS =head1 AUTHORS
@@ -5424,83 +5455,92 @@ Major concepts by Paul Wasson, Duane Galbi, John Coiner and Jie Xu.
Many people have provided ideas and other assistance with Verilator. Many people have provided ideas and other assistance with Verilator.
The major corporate sponsors of Verilator, by providing significant Verilator is receiving major development support from the CHIPS Alliance.
contributions of time or funds include include Atmel Corporation, Cavium
Previous major corporate sponsors of Verilator, by providing significant
contributions of time or funds included include Atmel Corporation, Cavium
Inc., Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd., Inc., Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd.,
Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune
Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc., Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
and SiCortex Inc. and SiCortex Inc.
The people who have contributed major functionality are Byron Bradley, The people who have contributed major functionality are Byron Bradley,
Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Todd Strader, Paul Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Geza Lore, Todd
Wasson, Jie Xu, and Wilson Snyder. Major testers included Jeff Dutton, Strader, Stefan Wallentowitz, Paul Wasson, Jie Xu, and Wilson Snyder.
Jonathon Donaldson, Ralf Karge, David Hewson, Iztok Jeras, Wim Michiels, Major testers included Jeff Dutton, Jonathon Donaldson, Ralf Karge, David
Alex Solomatnikov, Sebastien Van Cauwenberghe, Gene Weber, and Clifford Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov, Sebastien Van
Wolf. Cauwenberghe, Gene Weber, and Clifford Wolf.
Some of the people who have provided ideas and feedback for Verilator Some of the people who have provided ideas, and feedback for Verilator
include: David Addison, Tariq B. Ahmad, Nikana Anastasiadis, Hans Van include: David Addison, Tariq B. Ahmad, Nikana Anastasiadis, Hans Van
Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad Bagri, Matthew Ballance, Antwerpen, Vasu Arasanipalai, Jens Arm, Sharad Bagri, Matthew Ballance,
Andrew Bardsley, Matthew Barr, Geoff Barrett, Julius Baxter, Jeremy Andrew Bardsley, Matthew Barr, Geoff Barrett, Julius Baxter, Jeremy
Bennett, Michael Berman, Victor Besyakov, David Binderman, Piotr Binkowski, Bennett, Michael Berman, Victor Besyakov, Moinak Bhattacharyya, David
Johan Bjork, David Black, Tymoteusz Blazejczyk, Daniel Bone, Gregg Binderman, Piotr Binkowski, Johan Bjork, David Black, Tymoteusz Blazejczyk,
Bouchard, Christopher Boumenot, Nick Bowler, Byron Bradley, Bryan Brady, Daniel Bone, Gregg Bouchard, Christopher Boumenot, Nick Bowler, Byron
Maarten De Braekeleer, Charlie Brej, J Briquet, Lane Brooks, John Brownlee, Bradley, Bryan Brady, Maarten De Braekeleer, Charlie Brej, J Briquet, Lane
Jeff Bush, Lawrence Butcher, Tony Bybell, Ted Campbell, Chris Candler, Brooks, John Brownlee, Jeff Bush, Lawrence Butcher, Tony Bybell, Ted
Lauren Carlson, Donal Casey, Sebastien Van Cauwenberghe, Alex Chadwick, Campbell, Chris Candler, Lauren Carlson, Donal Casey, Sebastien Van
Terry Chen, Yi-Chung Chen, Enzo Chi, Robert A. Clark, Allan Cochrane, John Cauwenberghe, Alex Chadwick, Terry Chen, Yi-Chung Chen, Enzo Chi, Robert
Coiner, Gianfranco Costamagna, George Cuan, Joe DErrico, Lukasz Dalek, A. Clark, Allan Cochrane, John Coiner, Gianfranco Costamagna, Sean Cross,
Laurens van Dam, Gunter Dannoritzer, Ashutosh Das, Bernard Deadman, John George Cuan, Joe DErrico, Lukasz Dalek, Laurens van Dam, Gunter
Demme, Mike Denio, John Deroo, Philip Derrick, John Dickol, Ruben Diez, Dannoritzer, Ashutosh Das, Bernard Deadman, John Demme, Mike Denio, John
Danny Ding, Jacko Dirks, Ivan Djordjevic, Jonathon Donaldson, Leendert van Deroo, Philip Derrick, John Dickol, Ruben Diez, Danny Ding, Jacko Dirks,
Doorn, Sebastian Dressler, Alex Duller, Jeff Dutton, Tomas Dzetkulic, Ivan Djordjevic, Jonathon Donaldson, Leendert van Doorn, Sebastian
Usuario Eda, Charles Eddleston, Chandan Egbert, Joe Eiler, Ahmed Dressler, Alex Duller, Jeff Dutton, Tomas Dzetkulic, Usuario Eda, Charles
El-Mahmoudy, Trevor Elbourne, Robert Farrell, Eugen Fekete, Fabrizio Eddleston, Chandan Egbert, Joe Eiler, Ahmed El-Mahmoudy, Trevor Elbourne,
Ferrandi, Udi Finkelstein, Brian Flachs, Andrea Foletto, Bob Fredieu, Duane Mats Engstrom, Robert Farrell, Eugen Fekete, Fabrizio Ferrandi, Udi
Galbi, Benjamin Gartner, Christian Gelinek, Peter Gerst, Glen Gibb, Shankar Finkelstein, Brian Flachs, Andrea Foletto, Bob Fredieu, Duane Galbi,
Giri, Dan Gisselquist, Sam Gladstone, Amir Gonnen, Chitlesh Goorah, Sergi Benjamin Gartner, Christian Gelinek, Peter Gerst, Glen Gibb, Michael
Granell, Al Grant, Xuan Guo, Driss Hafdi, Neil Hamilton, Oyvind Harboe, Gielda, Shankar Giri, Dan Gisselquist, Petr Gladkikh, Sam Gladstone, Amir
Gonnen, Chitlesh Goorah, Kai Gossner, Sergi Granell, Al Grant, Alexander
Grobman, Xuan Guo, Driss Hafdi, Neil Hamilton, James Hanlon, Oyvind Harboe,
Jannis Harder, Junji Hashimoto, Thomas Hawkins, Mitch Hayenga, Robert Jannis Harder, Junji Hashimoto, Thomas Hawkins, Mitch Hayenga, Robert
Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew Holme, Hiroki Henry, Stephen Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew
Honda, Alex Hornung, David Horton, Jae Hossell, Alan Hunter, James Holme, Hiroki Honda, Alex Hornung, David Horton, Peter Horvath, Jae
Hutchinson, Jamie Iles, Ben Jackson, Shareef Jalloq, Krzysztof Jankowski, Hossell, Alan Hunter, James Hutchinson, Jamie Iles, Ben Jackson, Shareef
HyungKi Jeong, Iztok Jeras, James Johnson, Christophe Joly, Franck Jullien, Jalloq, Krzysztof Jankowski, HyungKi Jeong, Iztok Jeras, James Johnson,
James Jung, Mike Kagen, Arthur Kahlich, Kaalia Kahn, Guy-Armand Kamendje, Christophe Joly, Franck Jullien, James Jung, Mike Kagen, Arthur Kahlich,
Vasu Kandadi, Kanad Kanhere, Patricio Kaplan, Pieter Kapsenberg, Ralf Kaalia Kahn, Guy-Armand Kamendje, Vasu Kandadi, Kanad Kanhere, Patricio
Karge, Dan Katz, Sol Katzman, Jonathan Kimmitt, Olof Kindgren, Kevin Kaplan, Pieter Kapsenberg, Ralf Karge, Dan Katz, Sol Katzman, Ian Kennedy,
Kiningham, Dan Kirkham, Sobhan Klnv, Gernot Koch, Soon Koh, Steve Kolecki, Jonathan Kimmitt, Olof Kindgren, Kevin Kiningham, Dan Kirkham, Sobhan Klnv,
Brett Koonce, Will Korteland, Wojciech Koszek, Varun Koyyalagunta, David Gernot Koch, Soon Koh, Nathan Kohagen, Steve Kolecki, Brett Koonce, Will
Kravitz, Roland Kruse, Sergey Kvachonok, Ed Lander, Steve Lang, Stephane Korteland, Wojciech Koszek, Varun Koyyalagunta, David Kravitz, Roland
Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor Lesik, John Li, Kruse, Sergey Kvachonok, Charles Eric LaForest, Ed Lander, Steve Lang,
Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Paul Liu, Derek Stephane Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor Lesik,
Lockhart, Jake Longo, Arthur Low, Stefan Ludwig, Dan Lussier, Fred Ma, John Li, Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Jiuyang
Duraid Madina, Affe Mao, Julien Margetts, Mark Marshall, Alfonso Martinez, Liu, Paul Liu, Derek Lockhart, Jake Longo, Geza Lore, Arthur Low, Stefan
Yves Mathieu, Patrick Maupin, Jason McMullan, Elliot Mednick, Wim Michiels, Ludwig, Dan Lussier, Fred Ma, Duraid Madina, Affe Mao, Julien Margetts,
Miodrag Milanovic, Wai Sum Mong, Peter Monsson, Sean Moore, Dennis Mark Marshall, Alfonso Martinez, Yves Mathieu, Patrick Maupin, Jason
Muhlestein, John Murphy, Matt Myers, Richard Myers, Dimitris Nalbantis, McMullan, Elliot Mednick, Wim Michiels, Miodrag Milanovic, Wai Sum Mong,
Peter Nelson, Bob Newgard, Cong Van Nguyen, Paul Nitza, Yossi Nivin, Pete Peter Monsson, Sean Moore, Dennis Muhlestein, John Murphy, Matt Myers,
Nixon, Lisa Noack, Mark Nodine, Andreas Olofsson, Aleksander Osman, James Nathan Myers, Richard Myers, Dimitris Nalbantis, Peter Nelson, Bob Newgard,
Pallister, Brad Parker, Dan Petrisko, Maciej Piechotka, David Pierce, Cong Van Nguyen, Paul Nitza, Yossi Nivin, Pete Nixon, Lisa Noack, Mark
Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich Porter, Nodine, Kuba Ober, Andreas Olofsson, Aleksander Osman, James Pallister,
Niranjan Prabhu, Usha Priyadharshini, Mark Jackson Pulver, Prateek Puri, Vassilis Papaefstathiou, Brad Parker, Dan Petrisko, Maciej Piechotka, David
Marshal Qiao, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford, Odd Pierce, Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich
Magne Reitan, Frederic Requin, Frederick Requin, Alberto Del Rio, Eric Porter, Niranjan Prabhu, Usha Priyadharshini, Mark Jackson Pulver, Prateek
Rippey, Oleg Rodionov, Paul Rolfe, Arjen Roodselaar, Tobias Rosenkranz, Jan Puri, Marshal Qiao, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford,
Egil Ruud, Denis Rystsov, John Sanguinetti, Galen Seitz, Salman Sheikh, Hao Odd Magne Reitan, Frederic Requin, Frederick Requin, Dustin Richmond,
Shi, Mike Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Anderson Ignacio Alberto Del Rio, Eric Rippey, Oleg Rodionov, Ludwig Rogiers, Paul Rolfe,
Da Silva, Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith, Arjen Roodselaar, Tobias Rosenkranz, Huang Rui, Jan Egil Ruud, Denis
Wilson Snyder, Stan Sokorac, Alex Solomatnikov, Wei Song, Art Stamness, Rystsov, John Sanguinetti, Galen Seitz, Salman Sheikh, Hao Shi, Mike
John Stevenson, Patrick Stewart, Rob Stoddard, Todd Strader, John Stroebel, Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Anderson Ignacio Da Silva,
Sven Stucki, Howard Su, Emerson Suguimoto, Gene Sullivan, Renga Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith, Tim Snyder,
Sundararajan, Rupert Swarbrick, Yutetsu Takatsukasa, Peter Tengstrand, Maciej Sobkowski, Stan Sokorac, Alex Solomatnikov, Wei Song, Art Stamness,
Wesley Terpstra, Rui Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin David Stanford, John Stevenson, Pete Stevenson, Patrick Stewart, Rob
Thompson, Mike Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Michael Stoddard, Todd Strader, John Stroebel, Sven Stucki, Howard Su, Emerson
Tresidder, Neil Turton, Bogdan Vukobratovic, Holger Waechtler, Philipp Suguimoto, Gene Sullivan, Qingyao Sun, Renga Sundararajan, Rupert
Wagner, Stefan Wallentowitz, Shawn Wang, Paul Wasson, Greg Waters, Thomas Swarbrick, Yutetsu Takatsukasa, Peter Tengstrand, Wesley Terpstra, Rui
Watts, Eugene Weber, David Welch, Thomas J Whatson, Leon Wildman, Gerald Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin Thompson, Mike
Williams, Trevor Williams, Jeff Winston, Joshua Wise, Clifford Wolf, Johan Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Michael Tresidder, Neil
Wouters, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu, Luke Yang, and Amir Turton, Srini Vemuri, Yuri Victorovich, Bogdan Vukobratovic, Holger
Yazdanbakhsh. Waechtler, Philipp Wagner, Stefan Wallentowitz, Shawn Wang, Paul Wasson,
Greg Waters, Thomas Watts, Eugene Weber, David Welch, Thomas J Whatson,
Marco Widmer, Leon Wildman, Daniel Wilkerson, Gerald Williams, Trevor
Williams, Jan Van Winkel, Jeff Winston, Joshua Wise, Clifford Wolf, Tobias
Wolfel, Johan Wouters, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu,
Takatsukasa Y, Luke Yang, and Amir Yazdanbakhsh.
Thanks to them, and all those we've missed including above, or wished to Thanks to them, and all those we've missed including above, or wished to
remain anonymous. remain anonymous.
+17 -3
View File
@@ -156,6 +156,8 @@ verilator_coverage - Verilator coverage analyzer
verilator_coverage -write merged.dat -read <datafiles>... verilator_coverage -write merged.dat -read <datafiles>...
verilator_coverage -write-info merged.info -read <datafiles>...
Verilator_coverage processes Verilator coverage reports. Verilator_coverage processes Verilator coverage reports.
With --anotate, it reads the specified data file and generates annotated With --anotate, it reads the specified data file and generates annotated
@@ -224,8 +226,20 @@ Displays program version and exits.
=item --write I<filename> =item --write I<filename>
Specifies the aggregate coverage results, summed across all the files, Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename. This is useful in scripts to should be written to the given filename in verilator_coverage data format.
combine many sequential runs into one master coverage file. This is useful in scripts to combine many sequential runs into one master
coverage file.
=item --write-info I<filename.info>
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in C<lcov> .info format.
This may be used to use C<lcov> to aggregate or generate reports.
The info format loses data compared to the Verilator coverage data format;
the info will all forms of coverage converted to line style coverage, and
if there are multiple coverage points on a single line, the minimum
coverage across those points will be used to report coverage of the line.
=back =back
@@ -277,7 +291,7 @@ Wilson Snyder <[email protected]>
=head1 SEE ALSO =head1 SEE ALSO
C<verilator> C<verilator>, C<lcov>
L<verilator_coverage --help> which is the source for this document. L<verilator_coverage --help> which is the source for this document.
-19
View File
@@ -1,19 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Build script for vcddiff
#
# Copyright 2019 by Todd Strader. 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
set -e
# NB: it would be better to add this via a PPA
TMP_DIR=$(mktemp -d)
git -C "${TMP_DIR}" clone https://github.com/veripool/vcddiff
VCDDIFF_DIR=${TMP_DIR}/vcddiff
git -C "${VCDDIFF_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${VCDDIFF_DIR}"
sudo cp "${VCDDIFF_DIR}/vcddiff" /usr/local/bin
-65
View File
@@ -1,65 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Travis CI build script
#
# Copyright 2019 by Todd Strader. 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
#
# This script builds and caches the Verilator binaries for Travis CI
# (and possibly other CI platforms). The Verilator CI system uses this
# script, but other CI systems that depend on Verilator may also use
# the script.
# see: https://github.com/verilator/verilator_ext_tests/blob/master/.travis.yml
# To use this script, either checkout Verilator as part of the CI build
# process or add Verilator as a Git submodule. Verilator tarballs can
# not be used as the script relies on Git revisions for caching.
set -e
if [ -z "${VERILATOR_NUM_JOBS}" ]; then
VERILATOR_NUM_JOBS=$(nproc)
fi
# Caching would be simpler if we installed without VERILATOR_ROOT, but
# it's needed for driver.pl outside of the repo
if [ -z "${VERILATOR_ROOT}" ]; then
echo "VERILATOR_ROOT not set"
exit -1
fi
if [ -z "${VERILATOR_CACHE}" ]; then
echo "VERILATOR_CACHE not set"
exit -1
fi
VERILATOR_REV=$(cd "${VERILATOR_ROOT}" && git rev-parse HEAD)
echo "Found Verilator rev ${VERILATOR_REV}"
CACHED_REV_FILE=${VERILATOR_CACHE}/.rev.txt
if [[ ! -f "${CACHED_REV_FILE}" || \
$(< "${CACHED_REV_FILE}") != "${VERILATOR_REV}" ]]; then
echo "Building Verilator"
# Unsure why Travis monkies with the capitalization of the stage name, but it does
if [[ -n ${TRAVIS_BUILD_STAGE_NAME} && \
${TRAVIS_BUILD_STAGE_NAME} != "Build verilator" ]]; then
echo "WARNING: Building Verilator in Travis build stage other than \"Build verilator\": ${TRAVIS_BUILD_STAGE_NAME}"
fi
cd "${VERILATOR_ROOT}"
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS} && make -j ${VERILATOR_NUM_JOBS}
# Copy the Verilator build artifacts
mkdir -p "${VERILATOR_CACHE}"
rm -rf ${VERILATOR_CACHE}/*
cp bin/*bin* "${VERILATOR_CACHE}"
# Remember the Git revision
echo "${VERILATOR_REV}" > "${CACHED_REV_FILE}"
else
echo "Using cached Verilator"
cd "${VERILATOR_ROOT}"
# Create include/verilated_config.h and maybe other things
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS}
cp ${VERILATOR_CACHE}/* bin
fi
+27 -29
View File
@@ -6,44 +6,40 @@
# Version 2.0. # Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:18.04 FROM ubuntu:20.04
RUN apt-get update \ RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \ && DEBIAN_FRONTEND=noninteractive \
apt-get install --no-install-recommends -y \ apt-get install --no-install-recommends -y \
autoconf=2.69-11 \ autoconf \
bc=1.07.1-2 \ bc \
bison=2:3.0.4.dfsg-1build1 \ bison \
build-essential=12.4ubuntu1 \ build-essential \
ca-certificates=20180409 \ ca-certificates \
cmake=3.10.2-1ubuntu2.18.04.1 \ ccache \
flex=2.6.4-6 \ clang \
gdb=8.1-0ubuntu3.2 \ cmake \
gcc-6=6.5.0-2ubuntu1~18.04 \ flex \
gcc-5=5.5.0-12ubuntu1 \ gdb \
gcc-4.8=4.8.5-4ubuntu8 \ git \
git=1:2.17.1-1ubuntu0.5 \ gtkwave \
gtkwave=3.3.86-1 \ libfl2 \
g++-6=6.5.0-2ubuntu1~18.04 \ libfl-dev \
g++-5=5.5.0-12ubuntu1 \ libgoogle-perftools-dev \
g++-4.8=4.8.5-4ubuntu8 \ libsystemc \
libfl2=2.6.4-6 \ libsystemc-dev \
libfl-dev=2.6.4-6 \ numactl \
numactl=2.0.11-2.1ubuntu0.1 \ perl \
perl=5.26.1-6ubuntu0.3 \ python3 \
python3=3.6.7-1~18.04 \ wget \
wget=1.19.4-1ubuntu2.2 \ zlibc \
zlibc=0.9k-4.3 \ zlib1g \
zlib1g=1:1.2.11.dfsg-0ubuntu2 \ zlib1g-dev \
zlib1g-dev=1:1.2.11.dfsg-0ubuntu2 \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
WORKDIR /tmp WORKDIR /tmp
COPY build-systemc.sh /tmp/
RUN ./build-systemc.sh
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
RUN git clone https://github.com/veripool/vcddiff.git && \ RUN git clone https://github.com/veripool/vcddiff.git && \
@@ -55,4 +51,6 @@ COPY build.sh /tmp/build.sh
ENV VERILATOR_AUTHOR_SITE=1 ENV VERILATOR_AUTHOR_SITE=1
WORKDIR /work
ENTRYPOINT [ "/tmp/build.sh" ] ENTRYPOINT [ "/tmp/build.sh" ]
+3 -3
View File
@@ -5,7 +5,7 @@ build. It uses the following parameters:
* Source repository (default: https://github.com/verilator/verilator) * Source repository (default: https://github.com/verilator/verilator)
* Source revision (default: master) * Source revision (default: master)
* GCC version (4.8.5, 5.5.0, 6.5.0, 7.4.0, default: 7.4.0) * Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0)
The container is published as `verilator/verilator-buildenv` on The container is published as `verilator/verilator-buildenv` on
https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub]. https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub].
@@ -20,13 +20,13 @@ To also run tests:
To change the compiler: To change the compiler:
docker run -ti -e CC=gcc-4.8 -e CXX=g++-4.8 verilator/verilator-buildenv test docker run -ti -e CC=clang-10 -e CXX=clang++-10 verilator/verilator-buildenv test
The tests that involve gdb are not working due to security restrictions. The tests that involve gdb are not working due to security restrictions.
To run those too: To run those too:
.... ....
docker run -ti -v ${PWD}:/tmp/repo -e REPO=/tmp/repo -e REV=`git rev-parse --short HEAD` -e CC=gcc-4.8 -e CXX=g++-4.8 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test docker run -ti -e CC=clang-10 -e CXX=clang++-10 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
.... ....
Rather then building using a remote git repository you may prefer to use a Rather then building using a remote git repository you may prefer to use a
-30
View File
@@ -1,30 +0,0 @@
#!/bin/bash -e
# DESCRIPTION: Build SystemC in Ubuntu 18.04 with different g++/gcc
#
# Copyright 2020 by Stefan Wallentowitz. 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
build_variant () {
version=$($1 --version | grep gcc | awk '{print $4}')
mkdir "/usr/local/systemc-2.3.3-gcc$version"
mkdir build
cd build
../configure --prefix="/usr/local/systemc-2.3.3-gcc$version" CC="$1" CXX="$2" LD="$2"
make -j
make install
cd ..
rm -r build
}
wget https://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.3.tar.gz
tar -xzf systemc-2.3.3.tar.gz
cd systemc-2.3.3
build_variant gcc g++
build_variant gcc-6 g++-6
build_variant gcc-5 g++-5
build_variant gcc-4.8 g++-4.8
cd ..
rm -r systemc-2.3.3*
-6
View File
@@ -12,12 +12,6 @@
: "${CC:=gcc}" : "${CC:=gcc}"
: "${CXX:=g++}" : "${CXX:=g++}"
GCCVERSION=$(${CC} --version | grep gcc | awk '{print $4}')
export SYSTEMC_INCLUDE="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/include"
export SYSTEMC_LIBDIR="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/lib-linux64"
export LD_LIBRARY_PATH=${SYSTEMC_LIBDIR}
SRCS=$PWD/verilator SRCS=$PWD/verilator
git clone "$REPO" "$SRCS" git clone "$REPO" "$SRCS"
+9 -8
View File
@@ -6,19 +6,20 @@
# Version 2.0. # Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
FROM ubuntu:18.04 FROM ubuntu:20.04
RUN apt-get update \ RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive \
&& apt-get install --no-install-recommends -y \ && apt-get install --no-install-recommends -y \
autoconf=2.69-11 \ autoconf \
bc=1.07.1-2 \ bc \
bison=2:3.0.4.dfsg-1build1 \ bison \
build-essential=12.4ubuntu1 \ build-essential \
ca-certificates=20180409 \ ca-certificates \
ccache \ ccache \
flex=2.6.4-6 \ flex \
git \ git \
libfl-dev=2.6.4-6 \ libfl-dev \
libgoogle-perftools-dev \ libgoogle-perftools-dev \
perl \ perl \
python3 \ python3 \
-34
View File
@@ -1,34 +0,0 @@
#!/bin/bash
# DESCRIPTION: Verilator: Travis CI test script
#
# Copyright 2019 by Todd Strader. 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
set -e
export DRIVER_FLAGS='-j 0 --quiet --rerun'
case $1 in
dist)
make -C test_regress SCENARIOS=--dist
;;
vlt)
make -C test_regress SCENARIOS=--vlt
;;
vltmt)
make -C test_regress SCENARIOS=--vltmt
;;
vltmt0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
*)
echo "Usage: test.sh (dist|vlt|vltmt)"
exit -1
;;
esac
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI ccache maintenance
#
# Copyright 2020 by Geza Lore. 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
################################################################################
# This script is run in 'before_script', once ccache has been set up.
################################################################################
set -e
set -x
# Show version
ccache --version
# Flush ccache if requested in commit message
COMMIT="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[travis\s\+ccache\s\+clear\]'; then
echo "Flushing ccache due to commit message"
ccache -C
fi
# Dump stats, then zero stats
ccache -s -z
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI ccache sizer
#
# Copyright 2020 by Geza Lore. 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
################################################################################
# This script computes the size of the ccache to be used for a job. We want the
# ccache to be just big enough to be able to hold a whole build so a re-build
# of the same does not miss in the cache due to capacity, but we don't want the
# ccache too big as pulling it down from the network takes time, and it is
# unlikely objects from much earlier builds would be useful.
################################################################################
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
if [ "$COVERAGE" == 1 ]; then
echo "1024M"
else
echo "768M"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
if [[ $TESTS == coverage-* ]]; then
echo "1536M"
else
echo "256M"
fi
else
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI dependency install script
#
# Copyright 2020 by Geza Lore. 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
################################################################################
# This script runs in the 'install' phase of all jobs, in all stages. We try to
# minimize the time spent in this by selectively installing only the components
# required by the particular build stage.
################################################################################
# Note that Travis runs "apt-get update" when "apt-get install" is used in the
# .travis.yml file directly, but since we invoke it via this script, we need to
# run it manually where requried, otherwise some packages cannot be found.
set -e
set -x
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
install-vcddiff() {
TMP_DIR="$(mktemp -d)"
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${TMP_DIR}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
# build Verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
time sudo apt-get update
sudo apt-get install libfl-dev
sudo apt-get install libgoogle-perftools-dev
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
# run the tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get update
sudo apt-get install gdb gtkwave lcov
if [ "$TRAVIS_DIST" = "focal" ]; then
sudo apt-get install libsystemc-dev
fi
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
# Not listing Bit::Vector as slow to install, and only skips one test
install-vcddiff
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
else
##############################################################################
# Unknown build stage
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi
+101
View File
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
# DESCRIPTION: Verilator: Travis CI main job script
#
# Copyright 2020 by Geza Lore. 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
################################################################################
# This is the main script executed in the 'script' phase by all jobs. We use a
# single script to keep the .travis.yml spec simple. We pass job parameters via
# environment variables using 'env' keys. Having different 'env' keys in jobs
# ensures they use different Travis build caches.
################################################################################
set -e
set -x
fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Build verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn
make -j $(nproc)
else
nodist/code_coverage --stages 1-2
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Run tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# Run the specified test
case $TESTS in
dist-vlt-0)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
;;
dist-vlt-1)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
;;
vltmt-0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt-1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
coverage-dist)
nodist/code_coverage --stages 3- --scenarios=--dist
;;
coverage-vlt-0)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
;;
coverage-vlt-1)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
;;
coverage-vlt-2)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
;;
coverage-vlt-3)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
;;
coverage-vltmt-0)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
;;
coverage-vltmt-1)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
;;
coverage-vltmt-2)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
;;
coverage-vltmt-3)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
;;
*)
fatal "Unknown test: $TESTS"
;;
esac
# Upload coverage data to codecov.io
if [[ $TESTS == coverage-* ]]; then
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
else
##############################################################################
# Unknown build stage
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
fi
+38
View File
@@ -0,0 +1,38 @@
# DESCRIPTION: codecov.io config
#
# Copyright 2020-2020 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
####################
# Validate:
# curl --data-binary @codecov.yml https://codecov.io/validate
codecov:
require_ci_to_pass: no
coverage:
precision: 2
round: down
range: "70...100"
ignore:
- "ci"
- "docs"
- "examples"
- "include/gtkwave"
- "include/vltstd"
- "test_regress"
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment:
layout: "reach,diff,flags,tree"
behavior: default
require_changes: yes
+19 -1
View File
@@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel]) #AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.034 2020-05-03], AC_INIT([Verilator],[4.036 2020-06-06],
[https://verilator.org], [https://verilator.org],
[verilator],[https://verilator.org]) [verilator],[https://verilator.org])
# When releasing, also update header of Changes file # When releasing, also update header of Changes file
@@ -16,7 +16,10 @@ AC_INIT([Verilator],[4.034 2020-05-03],
AC_CONFIG_HEADER(src/config_build.h) AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake) AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
# Version
AC_MSG_RESULT([configuring for $PACKAGE_STRING]) AC_MSG_RESULT([configuring for $PACKAGE_STRING])
PACKAGE_VERSION_NUMBER=`AS_ECHO("$PACKAGE_VERSION") | sed 's/ .*//g'`
AC_SUBST(PACKAGE_VERSION_NUMBER)
# Ignore automake flags passed by Ubuntu builds # Ignore automake flags passed by Ubuntu builds
AC_ARG_ENABLE([dependency-tracking], AC_ARG_ENABLE([dependency-tracking],
@@ -416,6 +419,7 @@ AC_LINK_IFELSE(
CFG_WITH_THREADED=$_my_result CFG_WITH_THREADED=$_my_result
AC_SUBST(CFG_WITH_THREADED) AC_SUBST(CFG_WITH_THREADED)
AC_MSG_RESULT($CFG_WITH_THREADED) AC_MSG_RESULT($CFG_WITH_THREADED)
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
# Check compiler flag # Check compiler flag
if test "$CFG_WITH_THREADED" = "no" ; then if test "$CFG_WITH_THREADED" = "no" ; then
@@ -438,6 +442,20 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])], [AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
[], [#include <sys/stat.h>]) [], [#include <sys/stat.h>])
# HAVE_SYSTEMC
# - If found the default search path has it, so support is always enabled.
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
AC_MSG_CHECKING([whether SystemC is found (in system path)])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <systemc.h>
]],[])],
[_my_result=yes
AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])],
[_my_result=no])
AC_MSG_RESULT($_my_result)
AC_SUBST(HAVE_SYSTEMC_H)
# Checks for system services # Checks for system services
# Other install directories # Other install directories
+17
View File
@@ -6,15 +6,22 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
Ahmed El-Mahmoudy Ahmed El-Mahmoudy
Alex Chadwick Alex Chadwick
Chris Randall Chris Randall
Dan Petrisko
David Horton
David Stanford David Stanford
Driss Hafdi Driss Hafdi
Eric Rippey Eric Rippey
Garrett Smith Garrett Smith
Geza Lore Geza Lore
Gianfranco Costamagna Gianfranco Costamagna
Glen Gibb
Howard Su Howard Su
Huang Rui
Iztok Jeras Iztok Jeras
James Hanlon James Hanlon
James Hutchinson
Jamey Hicks
Jan Van Winkel
Jeremy Bennett Jeremy Bennett
John Coiner John Coiner
John Demme John Demme
@@ -22,11 +29,13 @@ Julien Margetts
Kanad Kanhere Kanad Kanhere
Kevin Kiningham Kevin Kiningham
Kuba Ober Kuba Ober
Ludwig Rogiers
Lukasz Dalek Lukasz Dalek
Maarten De Braekeleer Maarten De Braekeleer
Maciej Sobkowski Maciej Sobkowski
Marco Widmer Marco Widmer
Matthew Ballance Matthew Ballance
Michael Killough
Mike Popoloski Mike Popoloski
Nathan Kohagen Nathan Kohagen
Nathan Myers Nathan Myers
@@ -39,11 +48,19 @@ Qingyao Sun
Richard Myers Richard Myers
Sean Cross Sean Cross
Sebastien Van Cauwenberghe Sebastien Van Cauwenberghe
Sergi Granell
Stefan Wallentowitz Stefan Wallentowitz
Stephen Henry
Tim Snyder
Tobias Rosenkranz Tobias Rosenkranz
Tobias Wölfel Tobias Wölfel
Todd Strader Todd Strader
Tomasz Gorochowik
Tymoteusz Blazejczyk
Vassilis Papaefstathiou
Veripool API Bot Veripool API Bot
Wilson Snyder Wilson Snyder
Yossi Nivin
Yuri Victorovich
Yutetsu TAKATSUKASA Yutetsu TAKATSUKASA
Yves Mathieu Yves Mathieu
+6 -9
View File
@@ -80,8 +80,7 @@ MSVC++.
To build or run Verilator you need these standard packages: To build or run Verilator you need these standard packages:
sudo apt-get install perl python3 sudo apt-get install perl python3 make
sudo apt-get install make
sudo apt-get install g++ # Alternatively, clang sudo apt-get install g++ # Alternatively, clang
sudo apt-get install libgz # Non-Ubuntu (ignore if gives error) sudo apt-get install libgz # Non-Ubuntu (ignore if gives error)
sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error) sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
@@ -95,12 +94,11 @@ good performance:
To build Verilator you will need to install these packages; these do not To build Verilator you will need to install these packages; these do not
need to be present to run Verilator: need to be present to run Verilator:
sudo apt-get install git sudo apt-get install git autoconf flex bison
sudo apt-get install autoconf flex bison
Those developing Verilator itself may also want these (see internals.adoc): Those developing Verilator itself may also want these (see internals.adoc):
sudo apt-get install gdb asciidoctor graphviz cmake clang-format sudo apt-get install gdb asciidoctor graphviz cmake clang clang-format gprof lcov
cpan install Pod::Perldoc cpan install Pod::Perldoc
cpan install Unix::Processors cpan install Unix::Processors
cpan install Parallel::Forker cpan install Parallel::Forker
@@ -266,10 +264,9 @@ set in your environment; it is built into the executable.
== Announcements == Announcements
To get notified of new releases, login to To get notified of new releases, go to
https://www.veripool.org[Veripool], and click the "watch" button near the https://github.com/verilator/verilator-announce[Verilator announcement
top right under https://www.veripool.org/projects/verilator/news[Verilator repository] and follow the instructions there.
News].
== Directory Structure == Directory Structure
+29 -7
View File
@@ -786,10 +786,10 @@ better viewers let us know; ZGRViewer isn't great for large graphs.
Tree files are dumps of the AST Tree and are produced between every major Tree files are dumps of the AST Tree and are produced between every major
algorithmic stage. An example: algorithmic stage. An example:
NETLIST 0x90fb00 <e1> {a0} NETLIST 0x90fb00 <e1> {a0ah}
1: MODULE 0x912b20 <e8822> {a8} top L2 [P] 1: MODULE 0x912b20 <e8822> {a8ah} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE *1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0] 1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24ah} @dt=this(sw32) integer kwd=integer range=[31:0]
The following summarizes the above example dump, with more detail on each The following summarizes the above example dump, with more detail on each
field in the section below. field in the section below.
@@ -807,8 +807,9 @@ the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
| `<e74>` | means the 74th edit to the netlist was the last modification to | `<e74>` | means the 74th edit to the netlist was the last modification to
this node. this node.
| `{a22}` | indicates this node is related to line 22 in the source filename | `{a22ah}` | indicates this node is related to the source filename "a",
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th. where "a" is the first file read, "z" the 26th, and "aa" the 27th. Then
line 22 in that file, then column 8 (aa=0, az=25, ba=26, ...).
| `@dt=0x...` | indicates the address of the data type this node contains. | `@dt=0x...` | indicates the address of the data type this node contains.
@@ -849,7 +850,10 @@ correspond directly to Verilog entities (for example `MODULE` and
Address of the node:: Address of the node::
A hexadecimal address of the node in memory. Useful for examining with the A hexadecimal address of the node in memory. Useful for examining with the
debugger. debugger. If the actual address values are not important, then using the
`--dump-tree-addrids` option will convert address values to short identifiers
of the form `([A-Z]*)`, which is hopefully easier for the reader to cross
reference throughout the dump.
Last edit number:: Last edit number::
@@ -996,6 +1000,24 @@ function in `src/verilator.cpp`.
To get your pass to build you'll need to add its binary filename to the To get your pass to build you'll need to add its binary filename to the
list in `src/Makefile_obj.in` and reconfigure. list in `src/Makefile_obj.in` and reconfigure.
=== "Never" features
Verilator ideally would support all of IEEE, and has the goal to get close
to full support. However the following IEEE sections and features are not
anticipated to be ever implemented for the reasons indicated.
[horizontal]
IEEE 1800-2017 3.3 recursive modules:: Little/no tool support, and arguably not a good practice.
IEEE 1800-2017 6.12 "shortreal":: Little/no tool support, and easily simply promoted to real.
IEEE 1800-2017 11.11 Min, typ, max:: No SDF support so will always use typical.
IEEE 1800-2017 11.12 "let":: Little/no tool support, makes difficult to implement parsers.
IEEE 1800-2017 20.15 Probabilistic functions:: Little industry use.
IEEE 1800-2017 20.16 Stochastic analysis:: Little industry use.
IEEE 1800-2017 20.17 PLA modeling:: Little industry use and outdated technology.
IEEE 1800-2017 31 Timing checks:: No longer relevant with static timing analysis tools.
IEEE 1800-2017 32 SDF annotation:: No longer relevant with static timing analysis tools.
IEEE 1800-2017 33 Config:: Little/no tool support or industry use.
== Distribution == Distribution
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project # This is an example cmake script to build a verilog to systemc project
# using cmake and verilator. # using cmake and verilator.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should # This makefile is here for testing the examples and should
# generally not be added to a CMake project. # generally not be added to a CMake project.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to SystemC project # This is an example cmake script to build a verilog to SystemC project
# using CMake and Verilator. # using CMake and Verilator.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should # This makefile is here for testing the examples and should
# generally not be added to a CMake project. # generally not be added to a CMake project.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project # This is an example cmake script to build a verilog to systemc project
# using cmake and verilator. # using cmake and verilator.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should # This makefile is here for testing the examples and should
# generally not be added to a CMake project. # generally not be added to a CMake project.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to systemc project # This is an example cmake script to build a verilog to systemc project
# using cmake and verilator. # using cmake and verilator.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should # This makefile is here for testing the examples and should
# generally not be added to a CMake project. # generally not be added to a CMake project.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This is an example cmake script to build a verilog to SystemC project # This is an example cmake script to build a verilog to SystemC project
# using CMake and Verilator. # using CMake and Verilator.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -6,11 +6,9 @@
# This makefile is here for testing the examples and should # This makefile is here for testing the examples and should
# generally not be added to a CMake project. # generally not be added to a CMake project.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to # This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile. # be placed in the "current directory" which simplifies the Makefile.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
# Check for sanity to avoid later confusion # Check for sanity to avoid later confusion
+1 -1
View File
@@ -19,7 +19,7 @@ int main(int argc, char** argv, char** env) {
// e.g. examples/c_tracing. // e.g. examples/c_tracing.
// Prevent unused variable warnings // Prevent unused variable warnings
if (0 && argc && argv && env) {} if (false && argc && argv && env) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v" // Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop; Vtop* top = new Vtop;
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to # This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile. # be placed in the "current directory" which simplifies the Makefile.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
# Check for sanity to avoid later confusion # Check for sanity to avoid later confusion
+1 -1
View File
@@ -23,7 +23,7 @@ int sc_main(int argc, char* argv[]) {
// e.g. examples/c_tracing. // e.g. examples/c_tracing.
// Prevent unused variable warnings // Prevent unused variable warnings
if (0 && argc && argv) {} if (false && argc && argv) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v" // Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop("top"); Vtop* top = new Vtop("top");
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefiles. That allows the objects to # This calls the object directory makefiles. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile. # be placed in the "current directory" which simplifies the Makefile.
# #
# Copyright 2019 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
# Check for sanity to avoid later confusion # Check for sanity to avoid later confusion
+1 -1
View File
@@ -20,7 +20,7 @@ vluint64_t main_time = 0;
double sc_time_stamp() { return main_time; } double sc_time_stamp() { return main_time; }
int main(int argc, char** argv, char** env) { int main(int argc, char** argv, char** env) {
if (0 && argc && argv && env) {} if (false && argc && argv && env) {}
Verilated::debug(0); Verilated::debug(0);
Verilated::randReset(2); Verilated::randReset(2);
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to # This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile. # be placed in the "current directory" which simplifies the Makefile.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
# Check for sanity to avoid later confusion # Check for sanity to avoid later confusion
+3 -5
View File
@@ -5,11 +5,9 @@
# #
# This is executed in the object directory, and called by ../Makefile # This is executed in the object directory, and called by ../Makefile
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
####################################################################### #######################################################################
+1 -1
View File
@@ -22,7 +22,7 @@ int main(int argc, char** argv, char** env) {
// This is a more complicated example, please also see the simpler examples/make_hello_c. // This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings // Prevent unused variable warnings
if (0 && argc && argv && env) {} if (false && argc && argv && env) {}
// Set debug level, 0 is off, 9 is highest presently used // Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs // May be overridden by commandArgs
+3 -5
View File
@@ -5,11 +5,9 @@
# This calls the object directory makefile. That allows the objects to # This calls the object directory makefile. That allows the objects to
# be placed in the "current directory" which simplifies the Makefile. # be placed in the "current directory" which simplifies the Makefile.
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
# Check for sanity to avoid later confusion # Check for sanity to avoid later confusion
+5 -7
View File
@@ -5,11 +5,9 @@
# #
# This is executed in the object directory, and called by ../Makefile # This is executed in the object directory, and called by ../Makefile
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
####################################################################### #######################################################################
@@ -39,8 +37,8 @@ endif
# If you build your own rules from scratch, note you need to include # If you build your own rules from scratch, note you need to include
# SystemC as follows (Vtop.mk file includes verilated.mk with these # SystemC as follows (Vtop.mk file includes verilated.mk with these
# already). # already).
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE) # CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR) # LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
# See the benchmarking section of bin/verilator. # See the benchmarking section of bin/verilator.
# Support class optimizations. This includes the tracing and symbol table. # Support class optimizations. This includes the tracing and symbol table.
+1 -1
View File
@@ -24,7 +24,7 @@ int sc_main(int argc, char* argv[]) {
// This is a more complicated example, please also see the simpler examples/make_hello_c. // This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings // Prevent unused variable warnings
if (0 && argc && argv) {} if (false && argc && argv) {}
// Set debug level, 0 is off, 9 is highest presently used // Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs // May be overridden by commandArgs
+3 -5
View File
@@ -2,11 +2,9 @@
# #
# DESCRIPTION: Verilator Example: XML tests # DESCRIPTION: Verilator Example: XML tests
# #
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you # This file ONLY is placed under the Creative Commons Public Domain, for
# can redistribute it and/or modify it under the terms of either the GNU # any use, without warranty, 2020 by Wilson Snyder.
# Lesser General Public License Version 3 or the Perl Artistic License # SPDX-License-Identifier: CC0-1.0
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# #
###################################################################### ######################################################################
+221 -176
View File
@@ -29,7 +29,7 @@
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <cerrno> #include <cerrno>
#include <tgmath.h> #include <sstream>
#include <sys/stat.h> // mkdir #include <sys/stat.h> // mkdir
// clang-format off // clang-format off
@@ -77,7 +77,7 @@ VerilatedImp VerilatedImp::s_s;
#ifndef VL_USER_FINISH ///< Define this to override this function #ifndef VL_USER_FINISH ///< Define this to override this function
void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
if (0 && hier) {} if (false && hier) {}
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
"- %s:%d: Verilog $finish\n", filename, linenum); "- %s:%d: Verilog $finish\n", filename, linenum);
if (Verilated::gotFinish()) { if (Verilated::gotFinish()) {
@@ -100,7 +100,7 @@ void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
#ifndef VL_USER_FATAL ///< Define this to override this function #ifndef VL_USER_FATAL ///< Define this to override this function
void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE { void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE {
if (0 && hier) {} if (false && hier) {}
Verilated::gotFinish(true); Verilated::gotFinish(true);
if (filename && filename[0]) { if (filename && filename[0]) {
// Not VL_PRINTF_MT, already on main thread // Not VL_PRINTF_MT, already on main thread
@@ -215,7 +215,7 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
// Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF // Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF
// from within the guts of the thread execution machinery (and it goes // from within the guts of the thread execution machinery (and it goes
// to the screen and not into the queues we're debugging) // to the screen and not into the queues we're debugging)
VL_PRINTF("-V{t%d,%" VL_PRI64 "u}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str()); VL_PRINTF("-V{t%u,%" VL_PRI64 "u}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
} }
#ifdef VL_THREADED #ifdef VL_THREADED
@@ -243,8 +243,8 @@ Verilated::Serialized::Serialized() {
s_errorLimit = 1; s_errorLimit = 1;
s_randReset = 0; s_randReset = 0;
s_randSeed = 0; s_randSeed = 0;
s_timeunit = -VL_TIME_UNIT; // Initial value until overriden by _Vconfigure s_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure
s_timeprecision = -VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure
} }
Verilated::NonSerialized::NonSerialized() { Verilated::NonSerialized::NonSerialized() {
@@ -283,7 +283,7 @@ vluint64_t vl_rand64() VL_MT_SAFE {
if (VL_UNLIKELY(!t_seeded)) { if (VL_UNLIKELY(!t_seeded)) {
t_seeded = true; t_seeded = true;
{ {
VerilatedLockGuard lock(s_mutex); const VerilatedLockGuard lock(s_mutex);
if (Verilated::randSeed() != 0) { if (Verilated::randSeed() != 0) {
t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32) t_state[0] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed()))); ^ (static_cast<vluint64_t>(Verilated::randSeed())));
@@ -311,7 +311,8 @@ vluint64_t vl_rand64() VL_MT_SAFE {
IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); } IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); }
QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); } QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); }
// VL_RANDOM_W currently unused as $random always 32 bits // VL_RANDOM_W currently unused as $random always 32 bits, left for backwards compatibility
// LCOV_EXCL_START
WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
for (int i = 0; i < VL_WORDS_I(obits); ++i) { for (int i = 0; i < VL_WORDS_I(obits); ++i) {
if (i < (VL_WORDS_I(obits) - 1)) { if (i < (VL_WORDS_I(obits) - 1)) {
@@ -322,6 +323,7 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE {
} }
return outwp; return outwp;
} }
// LCOV_EXCL_STOP
IData VL_RAND_RESET_I(int obits) VL_MT_SAFE { IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
if (Verilated::randReset() == 0) return 0; if (Verilated::randReset() == 0) return 0;
@@ -334,7 +336,7 @@ IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
} }
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE { QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
if (Verilated::randReset() == 0) return 0; if (Verilated::randReset() == 0) return 0;
QData data = VL_ULL(~0); QData data = ~0ULL;
if (Verilated::randReset() != 1) { // if 2, randomize if (Verilated::randReset() != 1) { // if 2, randomize
data = VL_RANDOM_Q(obits); data = VL_RANDOM_Q(obits);
} }
@@ -391,7 +393,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
if (vw == 1) { // Single divisor word breaks rest of algorithm if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0; vluint64_t k = 0;
for (int j = uw - 1; j >= 0; --j) { for (int j = uw - 1; j >= 0; --j) {
vluint64_t unw64 = ((k << VL_ULL(32)) + static_cast<vluint64_t>(lwp[j])); vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lwp[j]));
owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]); owp[j] = unw64 / static_cast<vluint64_t>(rwp[0]);
k = unw64 - static_cast<vluint64_t>(owp[j]) * static_cast<vluint64_t>(rwp[0]); k = unw64 - static_cast<vluint64_t>(owp[j]) * static_cast<vluint64_t>(rwp[0]);
} }
@@ -433,26 +435,25 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
// Main loop // Main loop
for (int j = uw - vw; j >= 0; --j) { for (int j = uw - vw; j >= 0; --j) {
// Estimate // Estimate
vluint64_t unw64 = (static_cast<vluint64_t>(un[j + vw]) << VL_ULL(32) vluint64_t unw64 = (static_cast<vluint64_t>(un[j + vw]) << 32ULL
| static_cast<vluint64_t>(un[j + vw - 1])); | static_cast<vluint64_t>(un[j + vw - 1]));
vluint64_t qhat = unw64 / static_cast<vluint64_t>(vn[vw - 1]); vluint64_t qhat = unw64 / static_cast<vluint64_t>(vn[vw - 1]);
vluint64_t rhat = unw64 - qhat * static_cast<vluint64_t>(vn[vw - 1]); vluint64_t rhat = unw64 - qhat * static_cast<vluint64_t>(vn[vw - 1]);
again: again:
if (qhat >= VL_ULL(0x100000000) if (qhat >= 0x100000000ULL || ((qhat * vn[vw - 2]) > ((rhat << 32ULL) + un[j + vw - 2]))) {
|| ((qhat * vn[vw - 2]) > ((rhat << VL_ULL(32)) + un[j + vw - 2]))) {
qhat = qhat - 1; qhat = qhat - 1;
rhat = rhat + vn[vw - 1]; rhat = rhat + vn[vw - 1];
if (rhat < VL_ULL(0x100000000)) goto again; if (rhat < 0x100000000ULL) goto again;
} }
vlsint64_t t = 0; // Must be signed vlsint64_t t = 0; // Must be signed
vluint64_t k = 0; vluint64_t k = 0;
for (int i = 0; i < vw; ++i) { for (int i = 0; i < vw; ++i) {
vluint64_t p = qhat * vn[i]; // Multiply by estimate vluint64_t p = qhat * vn[i]; // Multiply by estimate
t = un[i + j] - k - (p & VL_ULL(0xFFFFFFFF)); // Subtract t = un[i + j] - k - (p & 0xFFFFFFFFULL); // Subtract
un[i + j] = t; un[i + j] = t;
k = (p >> VL_ULL(32)) - (t >> VL_ULL(32)); k = (p >> 32ULL) - (t >> 32ULL);
} }
t = un[j + vw] - k; t = un[j + vw] - k;
un[j + vw] = t; un[j + vw] = t;
@@ -465,7 +466,7 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp,
for (int i = 0; i < vw; ++i) { for (int i = 0; i < vw; ++i) {
t = static_cast<vluint64_t>(un[i + j]) + static_cast<vluint64_t>(vn[i]) + k; t = static_cast<vluint64_t>(un[i + j]) + static_cast<vluint64_t>(vn[i]) + k;
un[i + j] = t; un[i + j] = t;
k = t >> VL_ULL(32); k = t >> 32ULL;
} }
un[j + vw] = un[j + vw] + k; un[j + vw] = un[j + vw] + k;
} }
@@ -516,7 +517,7 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, WDataInP rwp) VL_MT_SAFE {
// Skip check for rhs == 0, as short-circuit doesn't save time // Skip check for rhs == 0, as short-circuit doesn't save time
if (VL_UNLIKELY(lhs == 0)) return 0; if (VL_UNLIKELY(lhs == 0)) return 0;
QData power = lhs; QData power = lhs;
QData out = VL_ULL(1); QData out = 1ULL;
for (int bit = 0; bit < rbits; ++bit) { for (int bit = 0; bit < rbits; ++bit) {
if (bit > 0) power = power * power; if (bit > 0) power = power * power;
if (VL_BITISSET_W(rwp, bit)) out *= power; if (VL_BITISSET_W(rwp, bit)) out *= power;
@@ -630,7 +631,7 @@ std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) {
QData fracDiv = static_cast<QData>(vl_time_multiplier(fracDigits)); QData fracDiv = static_cast<QData>(vl_time_multiplier(fracDigits));
QData whole = static_cast<QData>(scaled) / fracDiv; QData whole = static_cast<QData>(scaled) / fracDiv;
QData fraction = static_cast<QData>(scaled) % fracDiv; QData fraction = static_cast<QData>(scaled) % fracDiv;
int digits; int digits = 0;
if (!fracDigits) { if (!fracDigits) {
digits = sprintf(tmp, "%" VL_PRI64 "u%s", whole, suffix.c_str()); digits = sprintf(tmp, "%" VL_PRI64 "u%s", whole, suffix.c_str());
} else { } else {
@@ -678,7 +679,16 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
inPct = false; inPct = false;
char fmt = pos[0]; char fmt = pos[0];
switch (fmt) { switch (fmt) {
case '0' ... '9': case '0': // FALLTHRU
case '1': // FALLTHRU
case '2': // FALLTHRU
case '3': // FALLTHRU
case '4': // FALLTHRU
case '5': // FALLTHRU
case '6': // FALLTHRU
case '7': // FALLTHRU
case '8': // FALLTHRU
case '9':
inPct = true; // Get more digits inPct = true; // Get more digits
widthSet = true; widthSet = true;
width = width * 10 + (fmt - '0'); width = width * 10 + (fmt - '0');
@@ -721,20 +731,14 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const int lbits = va_arg(ap, int); const int lbits = va_arg(ap, int);
double d = va_arg(ap, double); double d = va_arg(ap, double);
if (lbits) {} // UNUSED - always 64 if (lbits) {} // UNUSED - always 64
switch (fmt) { if (fmt == '^') { // Realtime
case '^': { // Realtime
if (!widthSet) width = VerilatedImp::timeFormatWidth(); if (!widthSet) width = VerilatedImp::timeFormatWidth();
output += _vl_vsformat_time(tmp, d, left, width); output += _vl_vsformat_time(tmp, d, left, width);
break; } else {
}
default: {
std::string fmt(pctp, pos - pctp + 1); std::string fmt(pctp, pos - pctp + 1);
sprintf(tmp, fmt.c_str(), d); sprintf(tmp, fmt.c_str(), d);
output += tmp; output += tmp;
break; }
} //
break;
} // switch
break; break;
} }
default: { default: {
@@ -742,7 +746,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
const int lbits = va_arg(ap, int); const int lbits = va_arg(ap, int);
QData ld = 0; QData ld = 0;
WData qlwp[VL_WQ_WORDS_E]; WData qlwp[VL_WQ_WORDS_E];
WDataInP lwp; WDataInP lwp = NULL;
if (lbits <= VL_QUADSIZE) { if (lbits <= VL_QUADSIZE) {
ld = _VL_VA_ARG_Q(ap, lbits); ld = _VL_VA_ARG_Q(ap, lbits);
VL_SET_WQ(qlwp, ld); VL_SET_WQ(qlwp, ld);
@@ -758,7 +762,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
switch (fmt) { switch (fmt) {
case 'c': { case 'c': {
IData charval = ld & 0xff; IData charval = ld & 0xff;
output += charval; output += static_cast<char>(charval);
break; break;
} }
case 's': { case 's': {
@@ -774,7 +778,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
break; break;
} }
case 'd': { // Signed decimal case 'd': { // Signed decimal
int digits; int digits = 0;
std::string append; std::string append;
if (lbits <= VL_QUADSIZE) { if (lbits <= VL_QUADSIZE) {
digits = sprintf(tmp, "%" VL_PRI64 "d", digits = sprintf(tmp, "%" VL_PRI64 "d",
@@ -803,7 +807,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
break; break;
} }
case '#': { // Unsigned decimal case '#': { // Unsigned decimal
int digits; int digits = 0;
std::string append; std::string append;
if (lbits <= VL_QUADSIZE) { if (lbits <= VL_QUADSIZE) {
digits = sprintf(tmp, "%" VL_PRI64 "u", ld); digits = sprintf(tmp, "%" VL_PRI64 "u", ld);
@@ -838,30 +842,28 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
// Octal numbers may span more than one wide word, // Octal numbers may span more than one wide word,
// so we need to grab each bit separately and check for overrun // so we need to grab each bit separately and check for overrun
// Octal is rare, so we'll do it a slow simple way // Octal is rare, so we'll do it a slow simple way
output += ('0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0) output += static_cast<char>(
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0) '0' + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 0)) ? 1 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0)); + ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 1)) ? 2 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb + 2)) ? 4 : 0));
} }
break; break;
case 'u': // Packed 2-state case 'u':
output.reserve(output.size() + 4 * VL_WORDS_I(lbits)); case 'z': { // Packed 4-state
for (int i = 0; i < VL_WORDS_I(lbits); ++i) { const bool is_4_state = (fmt == 'z');
output += static_cast<char>((lwp[i]) & 0xff); output.reserve(output.size() + ((is_4_state ? 2 : 1) * VL_WORDS_I(lbits)));
output += static_cast<char>((lwp[i] >> 8) & 0xff); int bytes_to_go = VL_BYTES_I(lbits);
output += static_cast<char>((lwp[i] >> 16) & 0xff); int bit = 0;
output += static_cast<char>((lwp[i] >> 24) & 0xff); while (bytes_to_go > 0) {
} const int wr_bytes = std::min(4, bytes_to_go);
break; for (int byte = 0; byte < wr_bytes; byte++, bit += 8)
case 'z': // Packed 4-state output += static_cast<char>(VL_BITRSHIFT_W(lwp, bit) & 0xff);
output.reserve(output.size() + 8 * VL_WORDS_I(lbits)); output.append(4 - wr_bytes, static_cast<char>(0));
for (int i = 0; i < VL_WORDS_I(lbits); ++i) { if (is_4_state) output.append(4, static_cast<char>(0));
output += static_cast<char>((lwp[i]) & 0xff); bytes_to_go -= wr_bytes;
output += static_cast<char>((lwp[i] >> 8) & 0xff);
output += static_cast<char>((lwp[i] >> 16) & 0xff);
output += static_cast<char>((lwp[i] >> 24) & 0xff);
output += "\0\0\0\0"; // No tristate
} }
break; break;
}
case 'v': // Strength; assume always strong case 'v': // Strength; assume always strong
for (lsb = lbits - 1; lsb >= 0; --lsb) { for (lsb = lbits - 1; lsb >= 0; --lsb) {
if (VL_BITRSHIFT_W(lwp, lsb) & 1) { if (VL_BITRSHIFT_W(lwp, lsb) & 1) {
@@ -891,7 +893,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA
static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE { static inline bool _vl_vsss_eof(FILE* fp, int floc) VL_MT_SAFE {
if (fp) { if (fp) {
return feof(fp) ? 1 : 0; // 1:0 to prevent MSVC++ warning return feof(fp) ? true : false; // true : false to prevent MSVC++ warning
} else { } else {
return floc < 0; return floc < 0;
} }
@@ -929,8 +931,8 @@ static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp,
_vl_vsss_advance(fp, floc); _vl_vsss_advance(fp, floc);
} }
} }
static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr, static inline void _vl_vsss_read_str(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* tmpp, const char* acceptp) VL_MT_SAFE { char* tmpp, const char* acceptp) VL_MT_SAFE {
// Read into tmp, consisting of characters from acceptp list // Read into tmp, consisting of characters from acceptp list
char* cp = tmpp; char* cp = tmpp;
while (true) { while (true) {
@@ -944,6 +946,19 @@ static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp, const std:
*cp++ = '\0'; *cp++ = '\0';
// VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n"); // VL_DBG_MSGF(" _read got='"<<tmpp<<"'\n");
} }
static inline char* _vl_vsss_read_bin(FILE* fp, int& floc, WDataInP fromp, const std::string& fstr,
char* beginp, std::size_t n, bool inhibit = false) {
// Variant of _vl_vsss_read_str using the same underlying I/O functions but optimized
// specifically for block reads of N bytes (read operations are not demarcated by
// whitespace). In the fp case, except descriptor to have been opened in binary mode.
while (n-- > 0) {
const int c = _vl_vsss_peek(fp, floc, fromp, fstr);
if (c == EOF) return NULL;
if (!inhibit) *beginp++ = c;
_vl_vsss_advance(fp, floc);
}
return beginp;
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits,
IData ld) VL_MT_SAFE { IData ld) VL_MT_SAFE {
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) { for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) {
@@ -992,12 +1007,14 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
int floc = fbits - 1; int floc = fbits - 1;
IData got = 0; IData got = 0;
bool inPct = false; bool inPct = false;
bool inIgnore = false;
const char* pos = formatp; const char* pos = formatp;
for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) { for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) {
// VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc, // VL_DBG_MSGF("_vlscan fmt='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
// fromp, fstr)<<"'"<<endl); // fromp, fstr)<<"'"<<endl);
if (!inPct && pos[0] == '%') { if (!inPct && pos[0] == '%') {
inPct = true; inPct = true;
inIgnore = false;
} else if (!inPct && isspace(pos[0])) { // Format spaces } else if (!inPct && isspace(pos[0])) { // Format spaces
while (isspace(pos[1])) pos++; while (isspace(pos[1])) pos++;
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
@@ -1017,12 +1034,16 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_advance(fp, floc); _vl_vsss_advance(fp, floc);
break; break;
} }
case '*':
inPct = true;
inIgnore = true;
break;
default: { default: {
// Deal with all read-and-scan somethings // Deal with all read-and-scan somethings
// Note LSBs are preserved if there's an overflow // Note LSBs are preserved if there's an overflow
const int obits = va_arg(ap, int); const int obits = inIgnore ? 0 : va_arg(ap, int);
WData qowp[VL_WQ_WORDS_E]; WData qowp[VL_WQ_WORDS_E];
VL_SET_WQ(qowp, VL_ULL(0)); VL_SET_WQ(qowp, 0ULL);
WDataOutP owp = qowp; WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP); if (obits > VL_QUADSIZE) owp = va_arg(ap, WDataOutP);
for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0; for (int i = 0; i < VL_WORDS_I(obits); ++i) owp[i] = 0;
@@ -1036,7 +1057,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
} }
case 's': { case 's': {
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, NULL); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, NULL);
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
int lpos = (static_cast<int>(strlen(tmp))) - 1; int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lsb = 0; int lsb = 0;
@@ -1048,9 +1069,9 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
} }
case 'd': { // Signed decimal case 'd': { // Signed decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_"); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
vlsint64_t ld; vlsint64_t ld = 0;
sscanf(tmp, "%30" VL_PRI64 "d", &ld); sscanf(tmp, "%30" VL_PRI64 "d", &ld);
VL_SET_WQ(owp, ld); VL_SET_WQ(owp, ld);
break; break;
@@ -1059,7 +1080,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 'e': case 'e':
case 'g': { // Real number case 'g': { // Real number
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "+-.0123456789eE"); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "+-.0123456789eE");
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
// cppcheck-suppress unusedStructMember // It's used // cppcheck-suppress unusedStructMember // It's used
union { union {
@@ -1073,43 +1094,71 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
case 't': // FALLTHRU // Time case 't': // FALLTHRU // Time
case '#': { // Unsigned decimal case '#': { // Unsigned decimal
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_"); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
QData ld; QData ld = 0;
sscanf(tmp, "%30" VL_PRI64 "u", &ld); sscanf(tmp, "%30" VL_PRI64 "u", &ld);
VL_SET_WQ(owp, ld); VL_SET_WQ(owp, ld);
break; break;
} }
case 'b': { case 'b': {
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "01xXzZ?_"); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01xXzZ?_");
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp)); _vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp));
break; break;
} }
case 'o': { case 'o': {
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_"); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_");
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp)); _vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp));
break; break;
} }
case 'x': { case 'x': {
_vl_vsss_skipspace(fp, floc, fromp, fstr); _vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_"); _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_");
if (!tmp[0]) goto done; if (!tmp[0]) goto done;
_vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp)); _vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp));
break; break;
} }
case 'u': {
// Read packed 2-value binary data
const int bytes = VL_BYTES_I(obits);
char* out = reinterpret_cast<char*>(owp);
if (!_vl_vsss_read_bin(fp, floc, fromp, fstr, out, bytes)) goto done;
const int last = bytes % 4;
if (last != 0
&& !_vl_vsss_read_bin(fp, floc, fromp, fstr, out, 4 - last, true))
goto done;
break;
}
case 'z': {
// Read packed 4-value binary data
char* out = reinterpret_cast<char*>(owp);
int bytes = VL_BYTES_I(obits);
while (bytes > 0) {
const int abytes = std::min(4, bytes);
// aval (4B) read {0, 1} state
out = _vl_vsss_read_bin(fp, floc, fromp, fstr, out, abytes);
if (!out) goto done;
// bval (4B) disregard {X, Z} state and align to new 8B boundary.
out = _vl_vsss_read_bin(fp, floc, fromp, fstr, out, 8 - abytes, true);
if (!out) goto done;
bytes -= abytes;
}
break;
}
default: default:
std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0]; std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0];
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
break; break;
} // switch } // switch
got++; if (!inIgnore) ++got;
// Reload data if non-wide (if wide, we put it in the right place directly) // Reload data if non-wide (if wide, we put it in the right place directly)
if (obits <= VL_BYTESIZE) { if (obits == 0) { // Due to inIgnore
} else if (obits <= VL_BYTESIZE) {
CData* p = va_arg(ap, CData*); CData* p = va_arg(ap, CData*);
*p = owp[0]; *p = owp[0];
} else if (obits <= VL_SHORTSIZE) { } else if (obits <= VL_SHORTSIZE) {
@@ -1133,7 +1182,10 @@ done:
//=========================================================================== //===========================================================================
// File I/O // File I/O
FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE { return VerilatedImp::fdToFp(lhs); } FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE {
// Expected non-MCD case; returns null on MCD descriptors.
return VerilatedImp::fdToFp(lhs);
}
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE { void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) VL_MT_SAFE {
// See also VL_DATA_TO_STRING_NW // See also VL_DATA_TO_STRING_NW
@@ -1159,7 +1211,7 @@ void _VL_STRING_TO_VINT(int obits, void* destp, size_t srclen, const char* srcp)
size_t bytes = VL_BYTES_I(obits); size_t bytes = VL_BYTES_I(obits);
char* op = reinterpret_cast<char*>(destp); char* op = reinterpret_cast<char*>(destp);
if (srclen > bytes) srclen = bytes; // Don't overflow destination if (srclen > bytes) srclen = bytes; // Don't overflow destination
size_t i; size_t i = 0;
for (i = 0; i < srclen; ++i) { *op++ = srcp[srclen - 1 - i]; } for (i = 0; i < srclen; ++i) { *op++ = srcp[srclen - 1 - i]; }
for (; i < bytes; ++i) { *op++ = 0; } for (; i < bytes; ++i) { *op++ = 0; }
} }
@@ -1201,38 +1253,21 @@ IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
return ret; return ret;
} }
IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE { IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) {
// While threadsafe, each thread can only access different file handles return VerilatedImp::fdNew(filename.c_str(), mode.c_str());
char modez[5];
EData modee = mode;
_VL_VINT_TO_STRING(VL_IDATASIZE, modez, &modee);
return VL_FOPEN_S(filename.c_str(), modez);
} }
IData VL_FOPEN_QI(QData filename, IData mode) VL_MT_SAFE { IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles return VerilatedImp::fdNewMcd(filename.c_str());
WData fnw[VL_WQ_WORDS_E];
VL_SET_WQ(fnw, filename);
return VL_FOPEN_WI(VL_WQ_WORDS_E, fnw, mode);
}
IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
char filenamez[VL_TO_STRING_MAX_WORDS * VL_EDATASIZE + 1];
_VL_VINT_TO_STRING(fnwords * VL_EDATASIZE, filenamez, filenamep);
EData modee = mode;
char modez[5];
_VL_VINT_TO_STRING(4 * sizeof(char), modez, &modee);
return VL_FOPEN_S(filenamez, modez);
}
IData VL_FOPEN_S(const char* filenamep, const char* modep) VL_MT_SAFE {
return VerilatedImp::fdNew(fopen(filenamep, modep));
} }
void VL_FFLUSH_I(IData fdi) VL_MT_SAFE { VerilatedImp::fdFlush(fdi); }
IData VL_FSEEK_I(IData fdi, IData offset, IData origin) VL_MT_SAFE {
return VerilatedImp::fdSeek(fdi, offset, origin);
}
IData VL_FTELL_I(IData fdi) VL_MT_SAFE { return VerilatedImp::fdTell(fdi); }
void VL_FCLOSE_I(IData fdi) VL_MT_SAFE { void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles // While threadsafe, each thread can only access different file handles
FILE* fp = VL_CVT_I_FP(fdi); VerilatedImp::fdClose(fdi);
if (VL_UNLIKELY(!fp)) return;
fclose(fp);
VerilatedImp::fdDelete(fdi);
} }
void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); } void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); }
@@ -1327,15 +1362,13 @@ void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles // While threadsafe, each thread can only access different file handles
static VL_THREAD_LOCAL std::string output; // static only for speed static VL_THREAD_LOCAL std::string output; // static only for speed
output = ""; output = "";
FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return;
va_list ap; va_list ap;
va_start(ap, formatp); va_start(ap, formatp);
_vl_vsformat(output, formatp, ap); _vl_vsformat(output, formatp, ap);
va_end(ap); va_end(ap);
fputs(output.c_str(), fp); VerilatedImp::fdWrite(fpi, output);
} }
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE { IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE {
@@ -1484,36 +1517,38 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
VL_ZERO_RESET_W(rbits, rwp); VL_ZERO_RESET_W(rbits, rwp);
switch (tolower(fmt)) { switch (tolower(fmt)) {
case 'd': case 'd': {
vlsint64_t lld; vlsint64_t lld = 0;
sscanf(dp, "%30" VL_PRI64 "d", &lld); sscanf(dp, "%30" VL_PRI64 "d", &lld);
VL_SET_WQ(rwp, lld); VL_SET_WQ(rwp, lld);
break; break;
}
case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, strlen(dp)); break; case 'b': _vl_vsss_based(rwp, rbits, 1, dp, 0, strlen(dp)); break;
case 'o': _vl_vsss_based(rwp, rbits, 3, dp, 0, strlen(dp)); break; case 'o': _vl_vsss_based(rwp, rbits, 3, dp, 0, strlen(dp)); break;
case 'h': // FALLTHRU case 'h': // FALLTHRU
case 'x': _vl_vsss_based(rwp, rbits, 4, dp, 0, strlen(dp)); break; case 'x': _vl_vsss_based(rwp, rbits, 4, dp, 0, strlen(dp)); break;
case 's': // string/no conversion case 's': { // string/no conversion
for (int i = 0, lsb = 0, posp = static_cast<int>(strlen(dp)) - 1; i < rbits && posp >= 0; for (int i = 0, lsb = 0, posp = static_cast<int>(strlen(dp)) - 1; i < rbits && posp >= 0;
--posp) { --posp) {
_vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]); _vl_vsss_setbit(rwp, rbits, lsb, 8, dp[posp]);
lsb += 8; lsb += 8;
} }
break; break;
}
case 'e': { case 'e': {
double temp = 0.f; double temp = 0.F;
sscanf(dp, "%le", &temp); sscanf(dp, "%le", &temp);
VL_SET_WQ(rwp, VL_CVT_Q_D(temp)); VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
break; break;
} }
case 'f': { case 'f': {
double temp = 0.f; double temp = 0.F;
sscanf(dp, "%lf", &temp); sscanf(dp, "%lf", &temp);
VL_SET_WQ(rwp, VL_CVT_Q_D(temp)); VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
break; break;
} }
case 'g': { case 'g': {
double temp = 0.f; double temp = 0.F;
sscanf(dp, "%lg", &temp); sscanf(dp, "%lg", &temp);
VL_SET_WQ(rwp, VL_CVT_Q_D(temp)); VL_SET_WQ(rwp, VL_CVT_Q_D(temp));
break; break;
@@ -1761,7 +1796,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
m_addr = (m_addr << 4) + value; m_addr = (m_addr << 4) + value;
} else { } else {
indata = true; indata = true;
valuer += c; valuer += static_cast<char>(c);
// printf(" Value width=%d @%x = %c\n", width, m_addr, c); // printf(" Value width=%d @%x = %c\n", width, m_addr, c);
if (VL_UNLIKELY(value > 1 && !m_hex)) { if (VL_UNLIKELY(value > 1 && !m_hex)) {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "", VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
@@ -1775,7 +1810,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
lastc = c; lastc = c;
} }
if (VL_UNLIKELY(m_end != ~VL_ULL(0) && m_addr <= m_end)) { if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end)) {
VL_FATAL_MT(m_filename.c_str(), m_linenum, "", VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
"$readmem file ended before specified final address (IEEE 2017 21.4)"); "$readmem file ended before specified final address (IEEE 2017 21.4)");
} }
@@ -1783,7 +1818,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
return false; // EOF return false; // EOF
} }
void VlReadMem::setData(void* valuep, const std::string& rhs) { void VlReadMem::setData(void* valuep, const std::string& rhs) {
QData shift = m_hex ? VL_ULL(4) : VL_ULL(1); QData shift = m_hex ? 4ULL : 1ULL;
bool innum = false; bool innum = false;
// Shift value in // Shift value in
for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) { for (std::string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) {
@@ -1906,7 +1941,7 @@ void VL_READMEM_N(bool hex, // Hex format, else binary
VlReadMem rmem(hex, bits, filename, start, end); VlReadMem rmem(hex, bits, filename, start, end);
if (VL_UNLIKELY(!rmem.isOpen())) return; if (VL_UNLIKELY(!rmem.isOpen())) return;
while (true) { while (true) {
QData addr; QData addr = 0;
std::string value; std::string value;
if (rmem.get(addr /*ref*/, value /*ref*/)) { if (rmem.get(addr /*ref*/, value /*ref*/)) {
if (VL_UNLIKELY(addr < static_cast<QData>(array_lsb) if (VL_UNLIKELY(addr < static_cast<QData>(array_lsb)
@@ -2006,50 +2041,55 @@ int VL_TIME_STR_CONVERT(const char* strp) {
} }
static const char* vl_time_str(int scale) { static const char* vl_time_str(int scale) {
static const char* const names[] static const char* const names[]
= {"1s", "100ms", "10ms", "1ms", "100us", "10us", "1us", "100ns", = {"100s", "10s", "1s", "100ms", "10ms", "1ms", "100us", "10us", "1us",
"10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"}; "100ns", "10ns", "1ns", "100ps", "10ps", "1ps", "100fs", "10fs", "1fs"};
if (scale < 0) scale = -scale; if (VL_UNLIKELY(scale > 2 || scale < -15)) scale = 0;
if (VL_UNLIKELY(scale > 15)) scale = 0; return names[2 - scale];
return names[scale];
} }
double vl_time_multiplier(int scale) { double vl_time_multiplier(int scale) {
// Return timescale multipler -15 to +15 // Return timescale multipler -18 to +18
// For speed, this does not check for illegal values // For speed, this does not check for illegal values
static double pow10[] = {1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
100000000000.0,
1000000000000.0,
10000000000000.0,
100000000000000.0,
1000000000000000.0};
static double neg10[] = {1.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001};
if (scale < 0) { if (scale < 0) {
static const double neg10[] = {1.0,
0.1,
0.01,
0.001,
0.0001,
0.00001,
0.000001,
0.0000001,
0.00000001,
0.000000001,
0.0000000001,
0.00000000001,
0.000000000001,
0.0000000000001,
0.00000000000001,
0.000000000000001,
0.0000000000000001,
0.00000000000000001,
0.000000000000000001};
return neg10[-scale]; return neg10[-scale];
} else { } else {
static const double pow10[] = {1.0,
10.0,
100.0,
1000.0,
10000.0,
100000.0,
1000000.0,
10000000.0,
100000000.0,
1000000000.0,
10000000000.0,
100000000000.0,
1000000000000.0,
10000000000000.0,
100000000000000.0,
1000000000000000.0,
10000000000000000.0,
100000000000000000.0,
1000000000000000000.0};
return pow10[scale]; return pow10[scale];
} }
} }
@@ -2085,7 +2125,7 @@ Verilated::ThreadLocal::ThreadLocal()
Verilated::ThreadLocal::~ThreadLocal() {} Verilated::ThreadLocal::~ThreadLocal() {}
void Verilated::debug(int level) VL_MT_SAFE { void Verilated::debug(int level) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_debug = level; s_s.s_debug = level;
if (level) { if (level) {
#ifdef VL_DEBUG #ifdef VL_DEBUG
@@ -2099,49 +2139,49 @@ void Verilated::debug(int level) VL_MT_SAFE {
} }
} }
void Verilated::randReset(int val) VL_MT_SAFE { void Verilated::randReset(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_randReset = val; s_s.s_randReset = val;
} }
void Verilated::randSeed(int val) VL_MT_SAFE { void Verilated::randSeed(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_randSeed = val; s_s.s_randSeed = val;
} }
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE { void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_calcUnusedSigs = flag; s_s.s_calcUnusedSigs = flag;
} }
void Verilated::errorCount(int val) VL_MT_SAFE { void Verilated::errorCount(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_errorCount = val; s_s.s_errorCount = val;
} }
void Verilated::errorCountInc() VL_MT_SAFE { void Verilated::errorCountInc() VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
++s_s.s_errorCount; ++s_s.s_errorCount;
} }
void Verilated::errorLimit(int val) VL_MT_SAFE { void Verilated::errorLimit(int val) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_errorLimit = val; s_s.s_errorLimit = val;
} }
void Verilated::gotFinish(bool flag) VL_MT_SAFE { void Verilated::gotFinish(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_gotFinish = flag; s_s.s_gotFinish = flag;
} }
void Verilated::assertOn(bool flag) VL_MT_SAFE { void Verilated::assertOn(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_assertOn = flag; s_s.s_assertOn = flag;
} }
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE { void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_fatalOnVpiError = flag; s_s.s_fatalOnVpiError = flag;
} }
void Verilated::timeunit(int value) VL_MT_SAFE { void Verilated::timeunit(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15 if (value < 0) value = -value; // Stored as 0..15
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_timeunit = value; s_s.s_timeunit = value;
} }
void Verilated::timeprecision(int value) VL_MT_SAFE { void Verilated::timeprecision(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15 if (value < 0) value = -value; // Stored as 0..15
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_s.s_timeprecision = value; s_s.s_timeprecision = value;
#ifdef SYSTEMC_VERSION #ifdef SYSTEMC_VERSION
sc_time sc_res = sc_get_time_resolution(); sc_time sc_res = sc_get_time_resolution();
@@ -2172,15 +2212,15 @@ void Verilated::timeprecision(int value) VL_MT_SAFE {
#endif #endif
} }
void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE { void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_ns.s_profThreadsStart = flag; s_ns.s_profThreadsStart = flag;
} }
void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE { void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
s_ns.s_profThreadsWindow = flag; s_ns.s_profThreadsWindow = flag;
} }
void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE { void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
if (s_ns.s_profThreadsFilenamep) free(const_cast<char*>(s_ns.s_profThreadsFilenamep)); if (s_ns.s_profThreadsFilenamep) free(const_cast<char*>(s_ns.s_profThreadsFilenamep));
s_ns.s_profThreadsFilenamep = strdup(flagp); s_ns.s_profThreadsFilenamep = strdup(flagp);
} }
@@ -2203,7 +2243,7 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
} }
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE { void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
if (s_flushCb == cb) { // Ok - don't duplicate if (s_flushCb == cb) { // Ok - don't duplicate
} else if (!s_flushCb) { } else if (!s_flushCb) {
s_flushCb = cb; s_flushCb = cb;
@@ -2214,18 +2254,22 @@ void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
} }
} }
// When running internal code coverage (gcc --coverage, as opposed to
// verilator --coverage), dump coverage data to properly cover failing
// tests.
void Verilated::flushCall() VL_MT_SAFE { void Verilated::flushCall() VL_MT_SAFE {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
if (s_flushCb) (*s_flushCb)(); if (s_flushCb) (*s_flushCb)();
fflush(stderr); fflush(stderr);
fflush(stdout); fflush(stdout);
VL_GCOV_FLUSH();
} }
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; } const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; } const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE { void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
VerilatedLockGuard lock(s_args.m_argMutex); const VerilatedLockGuard lock(s_args.m_argMutex);
s_args.argc = argc; s_args.argc = argc;
s_args.argv = argv; s_args.argv = argv;
VerilatedImp::commandArgs(argc, argv); VerilatedImp::commandArgs(argc, argv);
@@ -2301,11 +2345,11 @@ void Verilated::endOfEvalGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
// VerilatedImp:: Methods // VerilatedImp:: Methods
std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE { std::string VerilatedImp::timeFormatSuffix() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_sergMutex); const VerilatedLockGuard lock(s_s.m_sergMutex);
return s_s.m_serg.m_timeFormatSuffix; return s_s.m_serg.m_timeFormatSuffix;
} }
void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE { void VerilatedImp::timeFormatSuffix(const std::string& value) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_sergMutex); const VerilatedLockGuard lock(s_s.m_sergMutex);
s_s.m_serg.m_timeFormatSuffix = value; s_s.m_serg.m_timeFormatSuffix = value;
} }
void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = value; } void VerilatedImp::timeFormatUnits(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatUnits = value; }
@@ -2315,7 +2359,7 @@ void VerilatedImp::timeFormatPrecision(int value) VL_MT_SAFE {
void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; } void VerilatedImp::timeFormatWidth(int value) VL_MT_SAFE { s_s.m_ser.m_timeFormatWidth = value; }
void VerilatedImp::internalsDump() VL_MT_SAFE { void VerilatedImp::internalsDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_argMutex); const VerilatedLockGuard lock(s_s.m_argMutex);
VL_PRINTF_MT("internalsDump:\n"); VL_PRINTF_MT("internalsDump:\n");
versionDump(); versionDump();
VL_PRINTF_MT(" Argv:"); VL_PRINTF_MT(" Argv:");
@@ -2332,12 +2376,12 @@ void VerilatedImp::versionDump() VL_MT_SAFE {
} }
void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) { void VerilatedImp::commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex); const VerilatedLockGuard lock(s_s.m_argMutex);
s_s.m_argVec.clear(); // Always clear s_s.m_argVec.clear(); // Always clear
commandArgsAddGuts(argc, argv); commandArgsAddGuts(argc, argv);
} }
void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) { void VerilatedImp::commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex); const VerilatedLockGuard lock(s_s.m_argMutex);
commandArgsAddGuts(argc, argv); commandArgsAddGuts(argc, argv);
} }
void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) { void VerilatedImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex) {
@@ -2444,12 +2488,12 @@ vluint32_t VerilatedVarProps::entSize() const {
size_t VerilatedVarProps::totalSize() const { size_t VerilatedVarProps::totalSize() const {
size_t size = entSize(); size_t size = entSize();
for (int dim = 0; dim <= dims(); ++dim) size *= m_unpacked[dim].elements(); for (int udim = 0; udim <= udims(); ++udim) size *= m_unpacked[udim].elements();
return size; return size;
} }
void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const { void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const {
if (VL_UNLIKELY(dim <= 0 || dim > m_udims || dim > 3)) return NULL; if (VL_UNLIKELY(dim <= 0 || dim > udims())) return NULL;
if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL; if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL;
int indxAdj = indx - low(dim); int indxAdj = indx - low(dim);
vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap); vluint8_t* bytep = reinterpret_cast<vluint8_t*>(datap);
@@ -2470,6 +2514,7 @@ VerilatedScope::VerilatedScope() {
m_funcnumMax = 0; m_funcnumMax = 0;
m_symsp = NULL; m_symsp = NULL;
m_varsp = NULL; m_varsp = NULL;
m_timeunit = 0;
m_type = SCOPE_OTHER; m_type = SCOPE_OTHER;
} }
@@ -2484,7 +2529,7 @@ VerilatedScope::~VerilatedScope() {
void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, void VerilatedScope::configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const char* identifier, vlsint8_t timeunit,
const Type type) VL_MT_UNSAFE { const Type& type) VL_MT_UNSAFE {
// Slowpath - called once/scope at construction // Slowpath - called once/scope at construction
// We don't want the space and reference-count access overhead of strings. // We don't want the space and reference-count access overhead of strings.
m_symsp = symsp; m_symsp = symsp;
@@ -2538,7 +2583,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
if (i == 0) { if (i == 0) {
var.m_packed.m_left = msb; var.m_packed.m_left = msb;
var.m_packed.m_right = lsb; var.m_packed.m_right = lsb;
} else if (i >= 1 && i <= 3) { } else if (i >= 1 && i <= var.udims()) {
var.m_unpacked[i - 1].m_left = msb; var.m_unpacked[i - 1].m_left = msb;
var.m_unpacked[i - 1].m_right = lsb; var.m_unpacked[i - 1].m_right = lsb;
} else { } else {
+80 -53
View File
@@ -337,7 +337,7 @@ public: // But internals only - called from VerilatedModule's
VerilatedScope(); VerilatedScope();
~VerilatedScope(); ~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const Type type) VL_MT_UNSAFE; const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE; void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
int vlflags, int dims, ...) VL_MT_UNSAFE; int vlflags, int dims, ...) VL_MT_UNSAFE;
@@ -365,7 +365,7 @@ public: // But internals only - called from VerilatedModule's
class VerilatedHierarchy { class VerilatedHierarchy {
public: public:
void add(VerilatedScope* fromp, VerilatedScope* top); static void add(VerilatedScope* fromp, VerilatedScope* top);
}; };
//=========================================================================== //===========================================================================
@@ -386,8 +386,8 @@ class Verilated {
bool s_assertOn; ///< Assertions are enabled bool s_assertOn; ///< Assertions are enabled
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
// Slow path // Slow path
unsigned s_timeunit : 4; ///< Time unit as 0..15 vlsint8_t s_timeunit; ///< Time unit as 0..15
unsigned s_timeprecision : 4; ///< Time precision as 0..15 vlsint8_t s_timeprecision; ///< Time precision as 0..15
int s_errorCount; ///< Number of errors int s_errorCount; ///< Number of errors
int s_errorLimit; ///< Stop on error number int s_errorLimit; ///< Stop on error number
int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
@@ -673,13 +673,9 @@ extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP r
/// File I/O /// File I/O
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi); extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
extern IData VL_FOPEN_S(const char* filenamep, const char* modep); extern void VL_FFLUSH_I(IData fdi);
extern IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode); extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin);
extern IData VL_FOPEN_QI(QData filename, IData mode); extern IData VL_FTELL_I(IData fdi);
inline IData VL_FOPEN_II(IData filename, IData mode) VL_MT_SAFE {
return VL_FOPEN_QI(filename, mode);
}
extern void VL_FCLOSE_I(IData fdi); extern void VL_FCLOSE_I(IData fdi);
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi, extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
@@ -711,7 +707,7 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
/// Return true if data[bit] set; not 0/1 return, but 0/non-zero return. /// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit))) #define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit)))
#define VL_BITISSET_Q(data, bit) ((data) & (VL_ULL(1) << VL_BITBIT_Q(bit))) #define VL_BITISSET_Q(data, bit) ((data) & (1ULL << VL_BITBIT_Q(bit)))
#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit))) #define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit))) #define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit)))
#define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit)) #define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit))
@@ -722,22 +718,22 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
/// Create two 32-bit words from quadword /// Create two 32-bit words from quadword
/// WData is always at least 2 words; does not clean upper bits /// WData is always at least 2 words; does not clean upper bits
#define VL_SET_WQ(owp, data) \ #define VL_SET_WQ(owp, data) \
{ \ do { \
(owp)[0] = static_cast<IData>(data); \ (owp)[0] = static_cast<IData>(data); \
(owp)[1] = static_cast<IData>((data) >> VL_EDATASIZE); \ (owp)[1] = static_cast<IData>((data) >> VL_EDATASIZE); \
} } while (false)
#define VL_SET_WI(owp, data) \ #define VL_SET_WI(owp, data) \
{ \ do { \
(owp)[0] = static_cast<IData>(data); \ (owp)[0] = static_cast<IData>(data); \
(owp)[1] = 0; \ (owp)[1] = 0; \
} } while (false)
#define VL_SET_QW(lwp) \ #define VL_SET_QW(lwp) \
((static_cast<QData>((lwp)[0])) \ ((static_cast<QData>((lwp)[0])) \
| (static_cast<QData>((lwp)[1]) << (static_cast<QData>(VL_EDATASIZE)))) | (static_cast<QData>((lwp)[1]) << (static_cast<QData>(VL_EDATASIZE))))
#define _VL_SET_QII(ld, rd) ((static_cast<QData>(ld) << VL_ULL(32)) | static_cast<QData>(rd)) #define _VL_SET_QII(ld, rd) ((static_cast<QData>(ld) << 32ULL) | static_cast<QData>(rd))
/// Return FILE* from IData /// Return FILE* from IData
extern FILE* VL_CVT_I_FP(IData lhs); extern FILE* VL_CVT_I_FP(IData lhs) VL_MT_SAFE;
// clang-format off // clang-format off
// Use a union to avoid cast-to-different-size warnings // Use a union to avoid cast-to-different-size warnings
@@ -780,7 +776,7 @@ static inline IData VL_RTOI_I_D(double lhs) VL_PURE {
// Sign extend such that if MSB set, we get ffff_ffff, else 0s // Sign extend such that if MSB set, we get ffff_ffff, else 0s
// (Requires clean input) // (Requires clean input)
#define VL_SIGN_I(nbits, lhs) ((lhs) >> VL_BITBIT_I((nbits)-VL_UL(1))) #define VL_SIGN_I(nbits, lhs) ((lhs) >> VL_BITBIT_I((nbits)-VL_UL(1)))
#define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-VL_ULL(1))) #define VL_SIGN_Q(nbits, lhs) ((lhs) >> VL_BITBIT_Q((nbits)-1ULL))
#define VL_SIGN_E(nbits, lhs) ((lhs) >> VL_BITBIT_E((nbits)-VL_EUL(1))) #define VL_SIGN_E(nbits, lhs) ((lhs) >> VL_BITBIT_E((nbits)-VL_EUL(1)))
#define VL_SIGN_W(nbits, rwp) \ #define VL_SIGN_W(nbits, rwp) \
((rwp)[VL_BITWORD_E((nbits)-VL_EUL(1))] >> VL_BITBIT_E((nbits)-VL_EUL(1))) ((rwp)[VL_BITWORD_E((nbits)-VL_EUL(1))] >> VL_BITBIT_E((nbits)-VL_EUL(1)))
@@ -792,7 +788,7 @@ static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) VL_PURE {
return (-((lhs) & (VL_UL(1) << (lbits - 1)))); return (-((lhs) & (VL_UL(1) << (lbits - 1))));
} }
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE { static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
return (-((lhs) & (VL_ULL(1) << (lbits - 1)))); return (-((lhs) & (1ULL << (lbits - 1))));
} }
// Debugging prints // Debugging prints
@@ -930,8 +926,7 @@ static inline void VL_ASSIGNBIT_II(int, int bit, IData& lhsr, IData rhs) VL_PURE
lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit))); lhsr = ((lhsr & ~(VL_UL(1) << VL_BITBIT_I(bit))) | (rhs << VL_BITBIT_I(bit)));
} }
static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE { static inline void VL_ASSIGNBIT_QI(int, int bit, QData& lhsr, QData rhs) VL_PURE {
lhsr = ((lhsr & ~(VL_ULL(1) << VL_BITBIT_Q(bit))) lhsr = ((lhsr & ~(1ULL << VL_BITBIT_Q(bit))) | (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
| (static_cast<QData>(rhs) << VL_BITBIT_Q(bit)));
} }
static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE { static inline void VL_ASSIGNBIT_WI(int, int bit, WDataOutP owp, IData rhs) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)]; EData orig = owp[VL_BITWORD_E(bit)];
@@ -949,7 +944,7 @@ static inline void VL_ASSIGNBIT_IO(int, int bit, IData& lhsr, IData) VL_PURE {
lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit))); lhsr = (lhsr | (VL_UL(1) << VL_BITBIT_I(bit)));
} }
static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE { static inline void VL_ASSIGNBIT_QO(int, int bit, QData& lhsr, IData) VL_PURE {
lhsr = (lhsr | (VL_ULL(1) << VL_BITBIT_Q(bit))); lhsr = (lhsr | (1ULL << VL_BITBIT_Q(bit)));
} }
static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE { static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) VL_MT_SAFE {
EData orig = owp[VL_BITWORD_E(bit)]; EData orig = owp[VL_BITWORD_E(bit)];
@@ -1217,6 +1212,36 @@ static inline IData VL_COUNTONES_W(int words, WDataInP lwp) VL_MT_SAFE {
return r; return r;
} }
// EMIT_RULE: VL_COUNTBITS_II: oclean = false; lhs clean
static inline IData VL_COUNTBITS_I(int lbits, IData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
int ctrlSum = (ctrl0 & 0x1) + (ctrl1 & 0x1) + (ctrl2 & 0x1);
if (ctrlSum == 3) {
return VL_COUNTONES_I(lhs);
} else if (ctrlSum == 0) {
IData mask = (lbits == 32) ? -1 : ((1 << lbits) - 1);
return VL_COUNTONES_I(~lhs & mask);
} else {
return (lbits == 32) ? 32 : lbits;
}
}
static inline IData VL_COUNTBITS_Q(int lbits, QData lhs, IData ctrl0, IData ctrl1,
IData ctrl2) VL_PURE {
return VL_COUNTBITS_I(32, static_cast<IData>(lhs), ctrl0, ctrl1, ctrl2)
+ VL_COUNTBITS_I(lbits - 32, static_cast<IData>(lhs >> 32), ctrl0, ctrl1, ctrl2);
}
#define VL_COUNTBITS_E VL_COUNTBITS_I
static inline IData VL_COUNTBITS_W(int lbits, int words, WDataInP lwp, IData ctrl0, IData ctrl1,
IData ctrl2) VL_MT_SAFE {
EData r = 0;
IData wordLbits = 32;
for (int i = 0; i < words; ++i) {
if (i == words - 1) { wordLbits = lbits % 32; }
r += VL_COUNTBITS_E(wordLbits, lwp[i], ctrl0, ctrl1, ctrl2);
}
return r;
}
static inline IData VL_ONEHOT_I(IData lhs) VL_PURE { static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
return (((lhs & (lhs - 1)) == 0) & (lhs != 0)); return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
} }
@@ -1261,7 +1286,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
if (VL_UNLIKELY(!lhs)) return 0; if (VL_UNLIKELY(!lhs)) return 0;
lhs--; lhs--;
int shifts = 0; int shifts = 0;
for (; lhs != 0; ++shifts) lhs = lhs >> VL_ULL(1); for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
return shifts; return shifts;
} }
static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE { static inline IData VL_CLOG2_W(int words, WDataInP lwp) VL_MT_SAFE {
@@ -1459,8 +1484,8 @@ static inline WDataOutP VL_ADD_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
QData carry = 0; QData carry = 0;
for (int i = 0; i < words; ++i) { for (int i = 0; i < words; ++i) {
carry = carry + static_cast<QData>(lwp[i]) + static_cast<QData>(rwp[i]); carry = carry + static_cast<QData>(lwp[i]) + static_cast<QData>(rwp[i]);
owp[i] = (carry & VL_ULL(0xffffffff)); owp[i] = (carry & 0xffffffffULL);
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff); carry = (carry >> 32ULL) & 0xffffffffULL;
} }
// Last output word is dirty // Last output word is dirty
return owp; return owp;
@@ -1472,8 +1497,8 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
carry = (carry + static_cast<QData>(lwp[i]) carry = (carry + static_cast<QData>(lwp[i])
+ static_cast<QData>(static_cast<IData>(~rwp[i]))); + static_cast<QData>(static_cast<IData>(~rwp[i])));
if (i == 0) ++carry; // Negation of rwp if (i == 0) ++carry; // Negation of rwp
owp[i] = (carry & VL_ULL(0xffffffff)); owp[i] = (carry & 0xffffffffULL);
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff); carry = (carry >> 32ULL) & 0xffffffffULL;
} }
// Last output word is dirty // Last output word is dirty
return owp; return owp;
@@ -1486,8 +1511,8 @@ static inline WDataOutP VL_MUL_W(int words, WDataOutP owp, WDataInP lwp, WDataIn
QData mul = static_cast<QData>(lwp[lword]) * static_cast<QData>(rwp[rword]); QData mul = static_cast<QData>(lwp[lword]) * static_cast<QData>(rwp[rword]);
for (int qword = lword + rword; qword < words; ++qword) { for (int qword = lword + rword; qword < words; ++qword) {
mul += static_cast<QData>(owp[qword]); mul += static_cast<QData>(owp[qword]);
owp[qword] = (mul & VL_ULL(0xffffffff)); owp[qword] = (mul & 0xffffffffULL);
mul = (mul >> VL_ULL(32)) & VL_ULL(0xffffffff); mul = (mul >> 32ULL) & 0xffffffffULL;
} }
} }
} }
@@ -1535,8 +1560,8 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
for (int i = 0; i < words; ++i) { for (int i = 0; i < words; ++i) {
carry = carry + static_cast<QData>(static_cast<IData>(~owp[i])); carry = carry + static_cast<QData>(static_cast<IData>(~owp[i]));
if (i == 0) ++carry; // Negation of temp2 if (i == 0) ++carry; // Negation of temp2
owp[i] = (carry & VL_ULL(0xffffffff)); owp[i] = (carry & 0xffffffffULL);
carry = (carry >> VL_ULL(32)) & VL_ULL(0xffffffff); carry = (carry >> 32ULL) & 0xffffffffULL;
} }
// Not needed: owp[words-1] |= 1<<VL_BITBIT_E(lbits-1); // Set sign bit // Not needed: owp[words-1] |= 1<<VL_BITBIT_E(lbits-1); // Set sign bit
} }
@@ -1627,7 +1652,7 @@ static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) VL_PUR
IData out = 1; IData out = 1;
for (int i = 0; i < rbits; ++i) { for (int i = 0; i < rbits; ++i) {
if (i > 0) power = power * power; if (i > 0) power = power * power;
if (rhs & (VL_ULL(1) << i)) out *= power; if (rhs & (1ULL << i)) out *= power;
} }
return out; return out;
} }
@@ -1635,10 +1660,10 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) VL_PUR
if (VL_UNLIKELY(rhs == 0)) return 1; if (VL_UNLIKELY(rhs == 0)) return 1;
if (VL_UNLIKELY(lhs == 0)) return 0; if (VL_UNLIKELY(lhs == 0)) return 0;
QData power = lhs; QData power = lhs;
QData out = VL_ULL(1); QData out = 1ULL;
for (int i = 0; i < rbits; ++i) { for (int i = 0; i < rbits; ++i) {
if (i > 0) power = power * power; if (i > 0) power = power * power;
if (rhs & (VL_ULL(1) << i)) out *= power; if (rhs & (1ULL << i)) out *= power;
} }
return out; return out;
} }
@@ -1884,7 +1909,8 @@ static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_
case 1: ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU case 1: ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU
case 2: ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU case 2: ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU
case 3: ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU case 3: ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU
case 4: ret = ((ret >> 16) | (ret << 16)); case 4: ret = ((ret >> 16) | (ret << 16)); // FALLTHRU
default:;
} }
return ret >> (VL_IDATASIZE - lbits); return ret >> (VL_IDATASIZE - lbits);
} }
@@ -1896,25 +1922,26 @@ static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_
vluint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2); vluint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2);
vluint32_t lbitsRem = lbits - lbitsFloor; vluint32_t lbitsRem = lbits - lbitsFloor;
QData msbMask = VL_MASK_Q(lbitsRem) << lbitsFloor; QData msbMask = VL_MASK_Q(lbitsRem) << lbitsFloor;
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_ULL(1) << rd_log2) - lbitsRem)); ret = (ret & ~msbMask) | ((ret & msbMask) << ((1ULL << rd_log2) - lbitsRem));
} }
switch (rd_log2) { switch (rd_log2) {
case 0: case 0:
ret = (((ret >> 1) & VL_ULL(0x5555555555555555)) ret = (((ret >> 1) & 0x5555555555555555ULL)
| ((ret & VL_ULL(0x5555555555555555)) << 1)); // FALLTHRU | ((ret & 0x5555555555555555ULL) << 1)); // FALLTHRU
case 1: case 1:
ret = (((ret >> 2) & VL_ULL(0x3333333333333333)) ret = (((ret >> 2) & 0x3333333333333333ULL)
| ((ret & VL_ULL(0x3333333333333333)) << 2)); // FALLTHRU | ((ret & 0x3333333333333333ULL) << 2)); // FALLTHRU
case 2: case 2:
ret = (((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f)) ret = (((ret >> 4) & 0x0f0f0f0f0f0f0f0fULL)
| ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4)); // FALLTHRU | ((ret & 0x0f0f0f0f0f0f0f0fULL) << 4)); // FALLTHRU
case 3: case 3:
ret = (((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff)) ret = (((ret >> 8) & 0x00ff00ff00ff00ffULL)
| ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8)); // FALLTHRU | ((ret & 0x00ff00ff00ff00ffULL) << 8)); // FALLTHRU
case 4: case 4:
ret = (((ret >> 16) & VL_ULL(0x0000ffff0000ffff)) ret = (((ret >> 16) & 0x0000ffff0000ffffULL)
| ((ret & VL_ULL(0x0000ffff0000ffff)) << 16)); // FALLTHRU | ((ret & 0x0000ffff0000ffffULL) << 16)); // FALLTHRU
case 5: ret = ((ret >> 32) | (ret << 32)); case 5: ret = ((ret >> 32) | (ret << 32)); // FALLTHRU
default:;
} }
return ret >> (VL_QUADSIZE - lbits); return ret >> (VL_QUADSIZE - lbits);
} }
@@ -2358,14 +2385,14 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, int, int, WDataOutP ow
/// Return QData from double (numeric) /// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real // EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
static inline QData VL_RTOIROUND_Q_D(int bits, double lhs) VL_PURE { static inline QData VL_RTOIROUND_Q_D(int, double lhs) VL_PURE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa // IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
// This does not need to support subnormals as they are sub-integral // This does not need to support subnormals as they are sub-integral
lhs = VL_ROUND(lhs); lhs = VL_ROUND(lhs);
if (lhs == 0.0) return 0; if (lhs == 0.0) return 0;
QData q = VL_CVT_Q_D(lhs); QData q = VL_CVT_Q_D(lhs);
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52; int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52); vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
vluint64_t out = 0; vluint64_t out = 0;
if (lsb < 0) { if (lsb < 0) {
out = mantissa >> -lsb; out = mantissa >> -lsb;
@@ -2385,8 +2412,8 @@ static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) V
VL_ZERO_W(obits, owp); VL_ZERO_W(obits, owp);
if (lhs == 0.0) return owp; if (lhs == 0.0) return owp;
QData q = VL_CVT_Q_D(lhs); QData q = VL_CVT_Q_D(lhs);
int lsb = static_cast<int>((q >> VL_ULL(52)) & VL_MASK_Q(11)) - 1023 - 52; int lsb = static_cast<int>((q >> 52ULL) & VL_MASK_Q(11)) - 1023 - 52;
vluint64_t mantissa = (q & VL_MASK_Q(52)) | (VL_ULL(1) << 52); vluint64_t mantissa = (q & VL_MASK_Q(52)) | (1ULL << 52);
if (lsb < 0) { if (lsb < 0) {
VL_SET_WQ(owp, mantissa >> -lsb); VL_SET_WQ(owp, mantissa >> -lsb);
} else if (lsb < obits) { } else if (lsb < obits) {
+42 -39
View File
@@ -84,27 +84,29 @@ CPPFLAGS += $(VM_USER_CFLAGS)
LDFLAGS += $(VM_USER_LDFLAGS) LDFLAGS += $(VM_USER_LDFLAGS)
LDLIBS += $(VM_USER_LDLIBS) LDLIBS += $(VM_USER_LDLIBS)
# See the benchmarking section of bin/verilator. ######################################################################
# Support class optimizations. This includes the tracing and symbol table. # Optimization control.
# SystemC takes minutes to optimize, thus it is off by default.
#OPT_SLOW =
# Fast path optimizations. Most time is spent in these classes.
#OPT_FAST = -Os -fstrict-aliasing
#OPT_FAST = -O
#OPT_FAST =
####################################################################### # See also the BENCHMARKING & OPTIMIZATION section of the manual.
##### Aggregates
VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW) # Optimization flags for non performance-critical/rarely executed code.
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW) # No optimization by default, which improves compilation speed.
OPT_SLOW =
# Optimization for performance critical/hot code. Most time is spent in these
# routines. Optimizing by default for improved execution speed.
OPT_FAST = -Os
# Optimization applied to the common run-time library used by verilated models.
# For compatibility this is called OPT_GLOBAL even though it only applies to
# files in the run-time library. Normally there should be no need for the user
# to change this as the library is small, but can have significant speed impact.
OPT_GLOBAL = -Os
####################################################################### #######################################################################
##### SystemC builds ##### SystemC builds
ifeq ($(VM_SC),1) ifeq ($(VM_SC),1)
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE) CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR) LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
SC_LIBS = -lsystemc SC_LIBS = -lsystemc
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),) ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
# Systemc 1.2.1beta # Systemc 1.2.1beta
@@ -163,35 +165,39 @@ ifneq ($(VK_LIBS_THREADED),0)
endif endif
####################################################################### #######################################################################
##### Stub ### Aggregates
preproc: VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
####################################################################### #######################################################################
# Overall Objects Linking ### Overall Objects Linking
VK_CLASSES_FAST_CPP = $(addsuffix .cpp, $(VM_CLASSES_FAST)) VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
VK_CLASSES_SLOW_CPP = $(addsuffix .cpp, $(VM_CLASSES_SLOW)) VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
VK_SUPPORT_FAST_CPP = $(addsuffix .cpp, $(VM_SUPPORT_FAST))
VK_SUPPORT_SLOW_CPP = $(addsuffix .cpp, $(VM_SUPPORT_SLOW))
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES)) VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
# Note VM_GLOBAL_FAST and VM_GLOBAL_SLOW holds the files required from the
# run-time library. In practice everything is actually in VM_GLOBAL_FAST,
# but keeping the distinction for compatibility for now.
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW)) VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
ifneq ($(VM_PARALLEL_BUILDS),1) ifneq ($(VM_PARALLEL_BUILDS),1)
# Fast building, all .cpp's in one fell swoop # Fast build for small designs: All .cpp files in one fell swoop. This
# This saves about 5 sec per module, but can be slower if only a little changes # saves total compute, but can be slower if only a little changes. It is
VK_OBJS += $(VM_PREFIX)__ALLfast.o $(VM_PREFIX)__ALLslow.o # also a lot slower for medium to large designs when the speed of the C
all_cpp: $(VM_PREFIX)__ALLfast.cpp $(VM_PREFIX)__ALLslow.cpp # compiler dominates, which in this mode is not parallelizable.
$(VM_PREFIX)__ALLfast.cpp: $(VK_CLASSES_FAST_CPP) $(VK_SUPPORT_FAST_CPP)
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@ VK_OBJS += $(VM_PREFIX)__ALL.o
$(VM_PREFIX)__ALLslow.cpp: $(VK_CLASSES_SLOW_CPP) $(VK_SUPPORT_SLOW_CPP) $(VM_PREFIX)__ALL.cpp: $(addsuffix .cpp, $(VM_FAST) $(VM_SLOW))
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@ $(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
all_cpp: $(VM_PREFIX)__ALL.cpp
else else
#Slow way of building... Each .cpp file by itself # Parallel build: Each .cpp file by itself. This can be somewhat slower for
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT)) # very small designs and examples, but is a lot faster for large designs.
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
endif endif
$(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_PREFIX)__ALL.a: $(VK_OBJS)
@@ -202,19 +208,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS)
### Compile rules ### Compile rules
ifneq ($(VM_DEFAULT_RULES),0) ifneq ($(VM_DEFAULT_RULES),0)
$(VM_PREFIX)__ALLfast.o: $(VM_PREFIX)__ALLfast.cpp # Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $< # and user files passed on the Verilator command line use this rule.
$(VM_PREFIX)__ALLslow.o: $(VM_PREFIX)__ALLslow.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
# VM_GLOBAL_FAST files including verilated.o use this rule
%.o: %.cpp %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $< $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
%__Slow.o: %__Slow.cpp $(VK_SLOW_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $< $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
$(VK_GLOBAL_OBJS): %.o: %.cpp
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
endif endif
#Default rule embedded in make: #Default rule embedded in make:
+11 -12
View File
@@ -94,7 +94,6 @@ private:
typedef std::map<int, std::string> IndexValueMap; typedef std::map<int, std::string> IndexValueMap;
typedef std::deque<VerilatedCovImpItem*> ItemList; typedef std::deque<VerilatedCovImpItem*> ItemList;
private:
// MEMBERS // MEMBERS
VerilatedMutex m_mutex; ///< Protects all members VerilatedMutex m_mutex; ///< Protects all members
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
@@ -250,12 +249,12 @@ public:
// PUBLIC METHODS // PUBLIC METHODS
void clear() VL_EXCLUDES(m_mutex) { void clear() VL_EXCLUDES(m_mutex) {
Verilated::quiesce(); Verilated::quiesce();
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
clearGuts(); clearGuts();
} }
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) { void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
Verilated::quiesce(); Verilated::quiesce();
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) { if (matchp && matchp[0]) {
ItemList newlist; ItemList newlist;
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) { for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
@@ -271,7 +270,7 @@ public:
} }
void zero() VL_EXCLUDES(m_mutex) { void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce(); Verilated::quiesce();
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) { for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {
(*it)->zero(); (*it)->zero();
} }
@@ -279,17 +278,17 @@ public:
// We assume there's always call to i/f/p in that order // We assume there's always call to i/f/p in that order
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) { void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
assert(!m_insertp); assert(!m_insertp);
m_insertp = itemp; m_insertp = itemp;
} }
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) { void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep; m_insertFilenamep = filenamep;
m_insertLineno = lineno; m_insertLineno = lineno;
} }
void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) { void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
assert(m_insertp); assert(m_insertp);
// First two key/vals are filename // First two key/vals are filename
ckeyps[0] = "filename"; ckeyps[0] = "filename";
@@ -332,10 +331,10 @@ public:
m_insertp->m_keys[addKeynum] = valueIndex(key); m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val); m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++; addKeynum++;
if (!legalKey(key)) { if (VL_UNCOVERABLE(!legalKey(key))) {
std::string msg std::string msg
= ("%Error: Coverage keys of one character, or letter+digit are illegal: " = ("%Error: Coverage keys of one character, or letter+digit are illegal: "
+ key); + key); // LCOV_EXCL_LINE
VL_FATAL_MT("", 0, "", msg.c_str()); VL_FATAL_MT("", 0, "", msg.c_str());
} }
} }
@@ -347,7 +346,7 @@ public:
void write(const char* filename) VL_EXCLUDES(m_mutex) { void write(const char* filename) VL_EXCLUDES(m_mutex) {
Verilated::quiesce(); Verilated::quiesce();
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
#ifndef VM_COVERAGE #ifndef VM_COVERAGE
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n"); VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif #endif
@@ -475,11 +474,11 @@ void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8)
} }
// Backward compatibility for Verilator // Backward compatibility for Verilator
void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
const std::string& val4, A(5), A(6)) VL_MT_SAFE { const std::string& val4, A(5), A(6), A(7)) VL_MT_SAFE {
std::string val2str = vlCovCvtToStr(val2); std::string val2str = vlCovCvtToStr(val2);
std::string val3str = vlCovCvtToStr(val3); std::string val3str = vlCovCvtToStr(val3);
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5), _insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
C(6), N(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18), C(6), C(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29)); N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
} }
#undef A #undef A
+1 -1
View File
@@ -121,7 +121,7 @@ public:
D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29)); D(22), D(23), D(24), D(25), D(26), D(27), D(28), D(29));
// Backward compatibility for Verilator // Backward compatibility for Verilator
static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4, static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4,
A(5), A(6)); A(5), A(6), A(7));
#undef K #undef K
#undef A #undef A
+3
View File
@@ -38,6 +38,7 @@ VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr
VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'") VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'") VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'")
VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ") VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ")
VLCOVGEN_ITEM("name=>'linescov', short=>'S', group=>1, default=>'', descr=>'List of comma-separated lines covered'")
VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'") VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'") VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ") VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ")
@@ -80,6 +81,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
#define VL_CIK_HIER "h" #define VL_CIK_HIER "h"
#define VL_CIK_LIMIT "L" #define VL_CIK_LIMIT "L"
#define VL_CIK_LINENO "l" #define VL_CIK_LINENO "l"
#define VL_CIK_LINESCOV "S"
#define VL_CIK_PER_INSTANCE "P" #define VL_CIK_PER_INSTANCE "P"
#define VL_CIK_ROW0 "r0" #define VL_CIK_ROW0 "r0"
#define VL_CIK_ROW0_NAME "R0" #define VL_CIK_ROW0_NAME "R0"
@@ -121,6 +123,7 @@ public:
if (key == "hier") return VL_CIK_HIER; if (key == "hier") return VL_CIK_HIER;
if (key == "limit") return VL_CIK_LIMIT; if (key == "limit") return VL_CIK_LIMIT;
if (key == "lineno") return VL_CIK_LINENO; if (key == "lineno") return VL_CIK_LINENO;
if (key == "linescov") return VL_CIK_LINESCOV;
if (key == "per_instance") return VL_CIK_PER_INSTANCE; if (key == "per_instance") return VL_CIK_PER_INSTANCE;
if (key == "row0") return VL_CIK_ROW0; if (key == "row0") return VL_CIK_ROW0;
if (key == "row0_name") return VL_CIK_ROW0_NAME; if (key == "row0_name") return VL_CIK_ROW0_NAME;
+2 -2
View File
@@ -47,7 +47,7 @@
// Function requires a "context" in the import declaration // Function requires a "context" in the import declaration
#define _VL_SVDPI_CONTEXT_WARN() \ #define _VL_SVDPI_CONTEXT_WARN() \
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \ _VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
"'context' keyword.\n"); "'context' keyword.\n")
//====================================================================== //======================================================================
//====================================================================== //======================================================================
@@ -416,7 +416,7 @@ static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1
case VLVT_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1; case VLVT_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1;
case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1; case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
case VLVT_UINT64: case VLVT_UINT64:
return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & VL_ULL(1); return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & 1ULL;
case VLVT_WDATA: { case VLVT_WDATA: {
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap)); WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
return VL_BITRSHIFT_W(wdatap, lsb) & 1; return VL_BITRSHIFT_W(wdatap, lsb) & 1;
+13 -28
View File
@@ -36,17 +36,12 @@
#include "gtkwave/lz4.c" #include "gtkwave/lz4.c"
#include <algorithm> #include <algorithm>
#include <cerrno>
#include <ctime>
#include <fcntl.h>
#include <iterator> #include <iterator>
#include <sstream> #include <sstream>
#include <sys/stat.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h> # include <io.h>
#else #else
# include <stdint.h>
# include <unistd.h> # include <unistd.h>
#endif #endif
@@ -132,15 +127,17 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elem
m_local2fstdtype[dtypenum] = enumNum; m_local2fstdtype[dtypenum] = enumNum;
} }
void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, vluint32_t len, fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
vluint32_t bits) { const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
VerilatedTrace<VerilatedFst>::declCode(code, bits, false); VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
std::pair<Code2SymbolType::iterator, bool> p std::pair<Code2SymbolType::iterator, bool> p
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL))); = m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
std::istringstream nameiss(name); std::istringstream nameiss(name);
std::istream_iterator<std::string> beg(nameiss), end; std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
std::list<std::string> tokens(beg, end); // Split name std::list<std::string> tokens(beg, end); // Split name
std::string symbol_name(tokens.back()); std::string symbol_name(tokens.back());
tokens.pop_back(); // Remove symbol name from hierarchy tokens.pop_back(); // Remove symbol name from hierarchy
@@ -178,39 +175,32 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
fstWriterEmitEnumTableRef(m_fst, enumNum); fstWriterEmitEnumTableRef(m_fst, enumNum);
} }
if (p.second) { // New if (p.second) { // New
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), 0); p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
assert(p.first->second); assert(p.first->second);
} else { // Alias } else { // Alias
fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), p.first->second); fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second);
} }
} }
void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) { fstVarType vartype, bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1); declare(code, name, dtypenum, vardir, vartype, array, arraynum, 0, 0);
} }
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) { fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
msb - lsb + 1);
} }
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) { fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
msb - lsb + 1);
} }
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb) { fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1, declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
msb - lsb + 1);
}
void VerilatedFst::declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
} }
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) { fstVarType vartype, bool array, int arraynum) {
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64); declare(code, name, dtypenum, vardir, vartype, array, arraynum, 63, 0);
} }
// Note: emit* are only ever called from one place (full* in // Note: emit* are only ever called from one place (full* in
@@ -266,11 +256,6 @@ void VerilatedFst::emitWData(vluint32_t code, const WData* newvalp, int bits) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf); fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
} }
VL_ATTR_ALWINLINE
void VerilatedFst::emitFloat(vluint32_t code, float newval) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedFst::emitDouble(vluint32_t code, double newval) { void VerilatedFst::emitDouble(vluint32_t code, double newval) {
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval); fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
+2 -5
View File
@@ -55,8 +55,8 @@ private:
// CONSTRUCTORS // CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFst); VL_UNCOPYABLE(VerilatedFst);
void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits); fstVarType vartype, bool array, int arraynum, int msb, int lsb);
protected: protected:
//========================================================================= //=========================================================================
@@ -77,7 +77,6 @@ protected:
inline void emitIData(vluint32_t code, IData newval, int bits); inline void emitIData(vluint32_t code, IData newval, int bits);
inline void emitQData(vluint32_t code, QData newval, int bits); inline void emitQData(vluint32_t code, QData newval, int bits);
inline void emitWData(vluint32_t code, const WData* newvalp, int bits); inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
inline void emitFloat(vluint32_t code, float newval);
inline void emitDouble(vluint32_t code, double newval); inline void emitDouble(vluint32_t code, double newval);
public: public:
@@ -112,8 +111,6 @@ public:
fstVarType vartype, bool array, int arraynum, int msb, int lsb); fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum, int msb, int lsb); fstVarType vartype, bool array, int arraynum, int msb, int lsb);
void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir, void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum); fstVarType vartype, bool array, int arraynum);
}; };
+2 -1
View File
@@ -427,7 +427,8 @@ extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld); extern std::string VL_TOUPPER_NN(const std::string& ld);
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE; extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE; extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb, extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, void* memp, QData start, const std::string& filename, void* memp, QData start,
QData end) VL_MT_SAFE; QData end) VL_MT_SAFE;
+137 -37
View File
@@ -32,6 +32,7 @@
#include <deque> #include <deque>
#include <set> #include <set>
#include <vector> #include <vector>
#include <numeric>
#ifdef VL_THREADED #ifdef VL_THREADED
# include <functional> # include <functional>
# include <queue> # include <queue>
@@ -95,7 +96,7 @@ public:
// METHODS // METHODS
//// Add message to queue (called by producer) //// Add message to queue (called by producer)
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) { void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex); const VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth; ++m_depth;
} }
@@ -168,6 +169,24 @@ public:
}; };
#endif // VL_THREADED #endif // VL_THREADED
// FILE* list constructed from a file-descriptor
class VerilatedFpList {
FILE* m_fp[31];
std::size_t m_sz;
public:
typedef FILE* const* const_iterator;
explicit VerilatedFpList()
: m_sz(0) {}
const_iterator begin() const { return m_fp; }
const_iterator end() const { return m_fp + m_sz; }
std::size_t size() const { return m_sz; }
std::size_t capacity() const { return 31; }
void push_back(FILE* fd) {
if (VL_LIKELY(size() < capacity())) m_fp[m_sz++] = fd;
}
};
//====================================================================== //======================================================================
// VerilatedImp // VerilatedImp
@@ -229,17 +248,21 @@ protected:
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
/// List of free descriptors (SLOW - FOPEN/CLOSE only) /// List of free descriptors (SLOW - FOPEN/CLOSE only)
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); std::vector<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
// List of free descriptors in the MCT region [4, 32)
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
public: // But only for verilated*.cpp public: // But only for verilated*.cpp
// CONSTRUCTORS // CONSTRUCTORS
VerilatedImp() VerilatedImp()
: m_argVecLoaded(false) : m_argVecLoaded(false)
, m_exportNext(0) { , m_exportNext(0) {
m_fdps.resize(3); s_s.m_fdps.resize(31);
m_fdps[0] = stdin; std::fill(s_s.m_fdps.begin(), s_s.m_fdps.end(), (FILE*)0);
m_fdps[1] = stdout; s_s.m_fdFreeMct.resize(30);
m_fdps[2] = stderr; for (std::size_t i = 0, id = 1; i < s_s.m_fdFreeMct.size(); ++i, ++id) {
s_s.m_fdFreeMct[i] = id;
}
} }
~VerilatedImp() {} ~VerilatedImp() {}
@@ -256,7 +279,7 @@ public:
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex); static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex); static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) { static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex); const VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+" // Note prefixp does not include the leading "+"
size_t len = strlen(prefixp); size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) { if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
@@ -285,7 +308,7 @@ public:
// There's often many more scopes than userdata's and thus having a ~48byte // There's often many more scopes than userdata's and thus having a ~48byte
// per map overhead * N scopes would take much more space and cache thrashing. // per map overhead * N scopes would take much more space and cache thrashing.
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE { static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex); const VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey)); UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (it != s_s.m_userMap.end()) { if (it != s_s.m_userMap.end()) {
it->second = userData; it->second = userData;
@@ -294,7 +317,7 @@ public:
} }
} }
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE { static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex); const VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey)); UserMap::const_iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL; if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL;
return it->second; return it->second;
@@ -304,7 +327,7 @@ private:
/// Symbol table destruction cleans up the entries for each scope. /// Symbol table destruction cleans up the entries for each scope.
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE { static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope on destruction, so we simply iterate. // Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard lock(s_s.m_userMapMutex); const VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) { for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) {
if (it->first.first == scopep) { if (it->first.first == scopep) {
s_s.m_userMap.erase(it++); s_s.m_userMap.erase(it++);
@@ -314,7 +337,7 @@ private:
} }
} }
static void userDump() VL_MT_SAFE { static void userDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump const VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true; bool first = true;
for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) { for (UserMap::const_iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end(); ++it) {
if (first) { if (first) {
@@ -330,14 +353,14 @@ public: // But only for verilated*.cpp
// METHODS - scope name // METHODS - scope name
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE { static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at construction // Slow ok - called once/scope at construction
VerilatedLockGuard lock(s_s.m_nameMutex); const VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name()); VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) { if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep)); s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
} }
} }
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE { static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex); const VerilatedLockGuard lock(s_s.m_nameMutex);
// If too slow, can assume this is only VL_MT_SAFE_POSINIT // If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep); VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.find(namep);
if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL; if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL;
@@ -345,13 +368,13 @@ public: // But only for verilated*.cpp
} }
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE { static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at destruction // Slow ok - called once/scope at destruction
VerilatedLockGuard lock(s_s.m_nameMutex); const VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep); userEraseScope(scopep);
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name()); VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it); if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
} }
static void scopesDump() VL_MT_SAFE { static void scopesDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex); const VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n"); VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin(); for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
it != s_s.m_nameMap.end(); ++it) { it != s_s.m_nameMap.end(); ++it) {
@@ -369,7 +392,7 @@ public: // But only for verilated*.cpp
// METHODS - hierarchy // METHODS - hierarchy
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE { static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
// Slow ok - called at construction for VPI accessible elements // Slow ok - called at construction for VPI accessible elements
VerilatedLockGuard lock(s_s.m_hierMapMutex); const VerilatedLockGuard lock(s_s.m_hierMapMutex);
s_s.m_hierMap[fromp].push_back(top); s_s.m_hierMap[fromp].push_back(top);
} }
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT { static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
@@ -388,7 +411,7 @@ public: // But only for verilated*.cpp
// miss at the cost of a multiply, and all lookups move to slowpath. // miss at the cost of a multiply, and all lookups move to slowpath.
static int exportInsert(const char* namep) VL_MT_SAFE { static int exportInsert(const char* namep) VL_MT_SAFE {
// Slow ok - called once/function at creation // Slow ok - called once/function at creation
VerilatedLockGuard lock(s_s.m_exportMutex); const VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it = s_s.m_exportMap.find(namep); ExportNameMap::iterator it = s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) { if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++)); s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
@@ -398,7 +421,7 @@ public: // But only for verilated*.cpp
} }
} }
static int exportFind(const char* namep) VL_MT_SAFE { static int exportFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex); const VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep); ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second; if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ") + namep std::string msg = (std::string("%Error: Testbench C called ") + namep
@@ -408,7 +431,7 @@ public: // But only for verilated*.cpp
} }
static const char* exportName(int funcnum) VL_MT_SAFE { static const char* exportName(int funcnum) VL_MT_SAFE {
// Slowpath; find name for given export; errors only so no map to reverse-map it // Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard lock(s_s.m_exportMutex); const VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin(); for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
it != s_s.m_exportMap.end(); ++it) { it != s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first; if (it->second == funcnum) return it->first;
@@ -416,7 +439,7 @@ public: // But only for verilated*.cpp
return "*UNKNOWN*"; return "*UNKNOWN*";
} }
static void exportsDump() VL_MT_SAFE { static void exportsDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex); const VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true; bool first = true;
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin(); for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
it != s_s.m_exportMap.end(); ++it) { it != s_s.m_exportMap.end(); ++it) {
@@ -448,16 +471,29 @@ public: // But only for verilated*.cpp
public: // But only for verilated*.cpp public: // But only for verilated*.cpp
// METHODS - file IO // METHODS - file IO
static IData fdNew(FILE* fp) VL_MT_SAFE { static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFreeMct.empty()) return 0;
IData idx = s_s.m_fdFreeMct.back();
s_s.m_fdFreeMct.pop_back();
s_s.m_fdps[idx] = fopen(filenamep, "w");
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return 0;
return (1 << idx);
}
static IData fdNew(const char* filenamep, const char* modep) VL_MT_SAFE {
FILE* fp = fopen(filenamep, modep);
if (VL_UNLIKELY(!fp)) return 0; if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD // Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard lock(s_s.m_fdMutex); const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) { if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree // Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size(); const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
s_s.m_fdps.resize(start * 2); const size_t excess = 10;
for (size_t i = start; i < start * 2; ++i) { s_s.m_fdps.resize(start + excess);
s_s.m_fdFree.push_back(static_cast<IData>(i)); std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0);
s_s.m_fdFree.resize(excess);
for (std::size_t i = 0, id = start; i < s_s.m_fdFree.size(); ++i, ++id) {
s_s.m_fdFree[i] = id;
} }
} }
IData idx = s_s.m_fdFree.back(); IData idx = s_s.m_fdFree.back();
@@ -465,19 +501,83 @@ public: // But only for verilated*.cpp
s_s.m_fdps[idx] = fp; s_s.m_fdps[idx] = fp;
return (idx | (1UL << 31)); // bit 31 indicates not MCD return (idx | (1UL << 31)); // bit 31 indicates not MCD
} }
static void fdDelete(IData fdi) VL_MT_SAFE { static void fdFlush(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi; const VerilatedLockGuard lock(s_s.m_fdMutex);
VerilatedLockGuard lock(s_s.m_fdMutex); const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return; for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free fflush(*it);
s_s.m_fdps[idx] = NULL; }
s_s.m_fdFree.push_back(idx); }
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(
fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
}
static IData fdTell(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
return static_cast<IData>(ftell(*fdlist.begin()));
}
static void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
const VerilatedFpList fdlist = fdToFpList(fdi);
for (VerilatedFpList::const_iterator it = fdlist.begin(); it != fdlist.end(); ++it) {
if (VL_UNLIKELY(!*it)) continue;
fwrite(output.c_str(), 1, output.size(), *it);
}
}
static void fdClose(IData fdi) VL_MT_SAFE {
const VerilatedLockGuard lock(s_s.m_fdMutex);
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
fclose(s_s.m_fdps[idx]);
s_s.m_fdps[idx] = (FILE*)0;
s_s.m_fdFree.push_back(idx);
} else {
// MCD case
for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) {
fclose(s_s.m_fdps[i]);
s_s.m_fdps[i] = NULL;
s_s.m_fdFreeMct.push_back(i);
}
}
}
} }
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE { static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi; const VerilatedLockGuard lock(s_s.m_fdMutex);
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it const VerilatedFpList fdlist = fdToFpList(fdi);
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return NULL; if (VL_UNLIKELY(fdlist.size() != 1)) return NULL;
return s_s.m_fdps[idx]; return *fdlist.begin();
}
private:
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.m_fdMutex) {
VerilatedFpList fp;
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
const IData idx = fdi & VL_MASK_I(31);
switch (idx) {
case 0: fp.push_back(stdin); break;
case 1: fp.push_back(stdout); break;
case 2: fp.push_back(stderr); break;
default:
if (VL_LIKELY(idx < s_s.m_fdps.size())) fp.push_back(s_s.m_fdps[idx]);
break;
}
} else {
// MCD Case
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.m_fdps[i]);
}
}
return fp;
} }
}; };
+12 -8
View File
@@ -123,8 +123,8 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
if (isOpen()) return; if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep);); VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
if (filenamep[0] == '|') { if (VL_UNCOVERABLE(filenamep[0] == '|')) {
assert(0); // Not supported yet. assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else { } else {
// cppcheck-suppress duplicateExpression // cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, m_fd = ::open(filenamep,
@@ -146,8 +146,8 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
if (isOpen()) return; if (isOpen()) return;
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep);); VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
if (filenamep[0] == '|') { if (VL_UNCOVERABLE(filenamep[0] == '|')) {
assert(0); // Not supported yet. assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else { } else {
// cppcheck-suppress duplicateExpression // cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666); m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
@@ -194,13 +194,15 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
ssize_t got = ::write(m_fd, wp, remaining); ssize_t got = ::write(m_fd, wp, remaining);
if (got > 0) { if (got > 0) {
wp += got; wp += got;
} else if (got < 0) { } else if (VL_UNCOVERABLE(got < 0)) {
if (errno != EAGAIN && errno != EINTR) { if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space) // write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno); std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str()); VL_FATAL_MT("", 0, "", msg.c_str());
close(); close();
break; break;
// LCOV_EXCL_STOP
} }
} }
} }
@@ -223,13 +225,15 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
ssize_t got = ::read(m_fd, m_endp, remaining); ssize_t got = ::read(m_fd, m_endp, remaining);
if (got > 0) { if (got > 0) {
m_endp += got; m_endp += got;
} else if (got < 0) { } else if (VL_UNCOVERABLE(got < 0)) {
if (errno != EAGAIN && errno != EINTR) { if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space) // write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno); std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str()); VL_FATAL_MT("", 0, "", msg.c_str());
close(); close();
break; break;
// LCOV_EXCL_STOP
} }
} else { // got==0, EOF } else { // got==0, EOF
// Fill buffer from here to end with NULLs so reader's don't // Fill buffer from here to end with NULLs so reader's don't
+29 -60
View File
@@ -29,6 +29,8 @@
#include "verilatedos.h" #include "verilatedos.h"
#include <vector>
//=========================================================================== //===========================================================================
/// Verilator range /// Verilator range
/// Thread safety: Assume is constructed only with model, then any number of readers /// Thread safety: Assume is constructed only with model, then any number of readers
@@ -78,7 +80,14 @@ class VerilatedVarProps {
const int m_pdims; // Packed dimensions const int m_pdims; // Packed dimensions
const int m_udims; // Unpacked dimensions const int m_udims; // Unpacked dimensions
VerilatedRange m_packed; // Packed array range VerilatedRange m_packed; // Packed array range
VerilatedRange m_unpacked[3]; // Unpacked array range std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
void initUnpacked(const int* ulims) {
for (int i = 0; i < m_udims; ++i) {
const int left = ulims ? ulims[2 * i + 0] : 0;
const int right = ulims ? ulims[2 * i + 1] : 0;
m_unpacked.push_back(VerilatedRange(left, right));
}
}
// CONSTRUCTORS // CONSTRUCTORS
protected: protected:
friend class VerilatedScope; friend class VerilatedScope;
@@ -87,7 +96,9 @@ protected:
, m_vltype(vltype) , m_vltype(vltype)
, m_vlflags(vlflags) , m_vlflags(vlflags)
, m_pdims(pdims) , m_pdims(pdims)
, m_udims(udims) {} , m_udims(udims) {
initUnpacked(NULL);
}
public: public:
class Unpacked {}; class Unpacked {};
@@ -98,34 +109,13 @@ public:
, m_vlflags(VerilatedVarFlags(vlflags)) , m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0) , m_pdims(0)
, m_udims(0) {} , m_udims(0) {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r) VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
: m_magic(MAGIC) : m_magic(MAGIC)
, m_vltype(vltype) , m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags)) , m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0) , m_pdims(0)
, m_udims(1) { , m_udims(udims) {
m_unpacked[0].init(u0l, u0r); initUnpacked(ulims);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l,
int u1r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(2) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l,
int u1r, int u2l, int u2r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(0)
, m_udims(3) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
m_unpacked[2].init(u2l, u2r);
} }
// With packed // With packed
class Packed {}; class Packed {};
@@ -137,37 +127,14 @@ public:
, m_udims(0) , m_udims(0)
, m_packed(pl, pr) {} , m_packed(pl, pr) {}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r) int udims, const int* ulims)
: m_magic(MAGIC) : m_magic(MAGIC)
, m_vltype(vltype) , m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags)) , m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1) , m_pdims(1)
, m_udims(1) , m_udims(udims)
, m_packed(pl, pr) { , m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r); initUnpacked(ulims);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r, int u1l, int u1r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(2)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
}
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
: m_magic(MAGIC)
, m_vltype(vltype)
, m_vlflags(VerilatedVarFlags(vlflags))
, m_pdims(1)
, m_udims(3)
, m_packed(pl, pr) {
m_unpacked[0].init(u0l, u0r);
m_unpacked[1].init(u1l, u1r);
m_unpacked[2].init(u2l, u2r);
} }
public: public:
@@ -189,27 +156,29 @@ public:
// DPI accessors // DPI accessors
int left(int dim) const { int left(int dim) const {
return dim == 0 ? m_packed.left() return dim == 0 ? m_packed.left()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].left() : 0; : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left() : 0;
} }
int right(int dim) const { int right(int dim) const {
return dim == 0 ? m_packed.right() return dim == 0 ? m_packed.right()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].right() : 0; : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right() : 0;
} }
int low(int dim) const { int low(int dim) const {
return dim == 0 ? m_packed.low() return dim == 0 ? m_packed.low()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].low() : 0; : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low() : 0;
} }
int high(int dim) const { int high(int dim) const {
return dim == 0 ? m_packed.high() return dim == 0 ? m_packed.high()
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].high() : 0; : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high() : 0;
} }
int increment(int dim) const { int increment(int dim) const {
return dim == 0 ? m_packed.increment() return dim == 0
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].increment() : 0; ? m_packed.increment()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0;
} }
int elements(int dim) const { int elements(int dim) const {
return dim == 0 ? m_packed.elements() return dim == 0
: VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].elements() : 0; ? m_packed.elements()
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements() : 0;
} }
/// Total size in bytes (note DPI limited to 4GB) /// Total size in bytes (note DPI limited to 4GB)
size_t totalSize() const; size_t totalSize() const;
+3 -3
View File
@@ -120,13 +120,13 @@ void VlThreadPool::setupProfilingClientThread() {
// try not to malloc while collecting profiling. // try not to malloc while collecting profiling.
t_profilep->reserve(4096); t_profilep->reserve(4096);
{ {
VerilatedLockGuard lk(m_mutex); const VerilatedLockGuard lk(m_mutex);
m_allProfiles.insert(t_profilep); m_allProfiles.insert(t_profilep);
} }
} }
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) { void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
VerilatedLockGuard lk(m_mutex); const VerilatedLockGuard lk(m_mutex);
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) { for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
// Every thread's profile trace gets a copy of rec. // Every thread's profile trace gets a copy of rec.
(*it)->emplace_back(rec); (*it)->emplace_back(rec);
@@ -134,7 +134,7 @@ void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
} }
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) { void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
VerilatedLockGuard lk(m_mutex); const VerilatedLockGuard lk(m_mutex);
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep);); VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
FILE* fp = fopen(filenamep, "w"); FILE* fp = fopen(filenamep, "w");
+1 -1
View File
@@ -234,7 +234,7 @@ public:
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) { inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
bool notify; bool notify;
{ {
VerilatedLockGuard lk(m_mutex); const VerilatedLockGuard lk(m_mutex);
m_ready.emplace_back(fnp, evenCycle, sym); m_ready.emplace_back(fnp, evenCycle, sym);
m_ready_size.fetch_add(1, std::memory_order_relaxed); m_ready_size.fetch_add(1, std::memory_order_relaxed);
notify = m_waiting; notify = m_waiting;
+37 -27
View File
@@ -40,7 +40,7 @@
// Threaded tracing // Threaded tracing
// A simple synchronized first in first out queue // A simple synchronized first in first out queue
template <class T> class VerilatedThreadQueue { template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
private: private:
VerilatedMutex m_mutex; // Protects m_queue VerilatedMutex m_mutex; // Protects m_queue
std::condition_variable_any m_cv; std::condition_variable_any m_cv;
@@ -73,7 +73,7 @@ public:
// Non blocking get // Non blocking get
bool tryGet(T& result) { bool tryGet(T& result) {
VerilatedLockGuard lockGuard(m_mutex); const VerilatedLockGuard lockGuard(m_mutex);
if (m_queue.empty()) { return false; } if (m_queue.empty()) { return false; }
result = m_queue.front(); result = m_queue.front();
m_queue.pop_front(); m_queue.pop_front();
@@ -95,7 +95,6 @@ public:
CHG_IDATA = 0x4, CHG_IDATA = 0x4,
CHG_QDATA = 0x5, CHG_QDATA = 0x5,
CHG_WDATA = 0x6, CHG_WDATA = 0x6,
CHG_FLOAT = 0x7,
CHG_DOUBLE = 0x8, CHG_DOUBLE = 0x8,
// TODO: full.. // TODO: full..
TIME_CHANGE = 0xd, TIME_CHANGE = 0xd,
@@ -105,8 +104,6 @@ public:
}; };
#endif #endif
class VerilatedTraceCallInfo;
//============================================================================= //=============================================================================
// VerilatedTrace // VerilatedTrace
@@ -114,13 +111,38 @@ class VerilatedTraceCallInfo;
// implementations in the format specific derived class, which must be passed // implementations in the format specific derived class, which must be passed
// as the type parameter T_Derived // as the type parameter T_Derived
template <class T_Derived> class VerilatedTrace { template <class T_Derived> class VerilatedTrace {
private: public:
//========================================================================= //=========================================================================
// Generic tracing internals // Generic tracing internals
typedef void (*initCb_t)(void*, T_Derived*, uint32_t); // Type of init callbacks
typedef void (*dumpCb_t)(void*, T_Derived*); // Type of all but init callbacks
private:
struct CallbackRecord {
// Note: would make these fields const, but some old STL implementations
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
// assignment operator on inserting into collections, so they don't work
// with const fields...
union {
initCb_t m_initCb; // The callback function
dumpCb_t m_dumpCb; // The callback function
};
void* m_userp; // The user pointer to pass to the callback (the symbol table)
CallbackRecord(initCb_t cb, void* userp)
: m_initCb(cb)
, m_userp(userp) {}
CallbackRecord(dumpCb_t cb, void* userp)
: m_dumpCb(cb)
, m_userp(userp) {}
};
vluint32_t* m_sigs_oldvalp; ///< Old value store vluint32_t* m_sigs_oldvalp; ///< Old value store
vluint64_t m_timeLastDump; ///< Last time we did a dump vluint64_t m_timeLastDump; ///< Last time we did a dump
std::vector<VerilatedTraceCallInfo*> m_callbacks; ///< Routines to perform dumping std::vector<CallbackRecord> m_initCbs; ///< Routines to initialize traciong
std::vector<CallbackRecord> m_fullCbs; ///< Routines to perform full dump
std::vector<CallbackRecord> m_chgCbs; ///< Routines to perform incremental dump
std::vector<CallbackRecord> m_cleanupCbs; ///< Routines to call at the end of dump
bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump' bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump'
vluint32_t m_nextCode; ///< Next code number to assign vluint32_t m_nextCode; ///< Next code number to assign
vluint32_t m_numSignals; ///< Number of distinct signals vluint32_t m_numSignals; ///< Number of distinct signals
@@ -130,6 +152,8 @@ private:
double m_timeRes; ///< Time resolution (ns/ms etc) double m_timeRes; ///< Time resolution (ns/ms etc)
double m_timeUnit; ///< Time units (ns/ms etc) double m_timeUnit; ///< Time units (ns/ms etc)
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec);
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->' // Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
// to access duck-typed functions to avoid a virtual function call. // to access duck-typed functions to avoid a virtual function call.
T_Derived* self() { return static_cast<T_Derived*>(this); } T_Derived* self() { return static_cast<T_Derived*>(this); }
@@ -209,8 +233,8 @@ protected:
// These hooks are called before a full or change based dump is produced. // These hooks are called before a full or change based dump is produced.
// The return value indicates whether to proceed with the dump. // The return value indicates whether to proceed with the dump.
virtual bool preFullDump() { return true; } virtual bool preFullDump() = 0;
virtual bool preChangeDump() { return true; } virtual bool preChangeDump() = 0;
public: public:
//========================================================================= //=========================================================================
@@ -232,13 +256,13 @@ public:
//========================================================================= //=========================================================================
// Non-hot path internal interface to Verilator generated code // Non-hot path internal interface to Verilator generated code
typedef void (*callback_t)(T_Derived* tracep, void* userthis, vluint32_t code); void addInitCb(initCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addFullCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addChgCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
void changeThread() { m_assertOne.changeThread(); } void changeThread() { m_assertOne.changeThread(); }
void addCallback(callback_t initcb, callback_t fullcb, callback_t changecb,
void* userthis) VL_MT_UNSAFE_ONE;
void module(const std::string& name) VL_MT_UNSAFE_ONE { void module(const std::string& name) VL_MT_UNSAFE_ONE {
m_assertOne.check(); m_assertOne.check();
m_moduleName = name; m_moduleName = name;
@@ -261,7 +285,6 @@ public:
// duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0; // duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0;
// duck-typed void emitQData(vluint32_t code, QData newval, int bits) = 0; // duck-typed void emitQData(vluint32_t code, QData newval, int bits) = 0;
// duck-typed void emitWData(vluint32_t code, const WData* newvalp, int bits) = 0; // duck-typed void emitWData(vluint32_t code, const WData* newvalp, int bits) = 0;
// duck-typed void emitFloat(vluint32_t code, float newval) = 0;
// duck-typed void emitDouble(vluint32_t code, double newval) = 0; // duck-typed void emitDouble(vluint32_t code, double newval) = 0;
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; } vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
@@ -273,7 +296,6 @@ public:
void fullIData(vluint32_t* oldp, IData newval, int bits); void fullIData(vluint32_t* oldp, IData newval, int bits);
void fullQData(vluint32_t* oldp, QData newval, int bits); void fullQData(vluint32_t* oldp, QData newval, int bits);
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits); void fullWData(vluint32_t* oldp, const WData* newvalp, int bits);
void fullFloat(vluint32_t* oldp, float newval);
void fullDouble(vluint32_t* oldp, double newval); void fullDouble(vluint32_t* oldp, double newval);
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_THREADED
@@ -319,14 +341,6 @@ public:
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; } for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp);); VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
} }
inline void chgFloat(vluint32_t code, float newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_FLOAT;
m_traceBufferWritep[1] = code;
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<float*>(m_traceBufferWritep + 2) = newval;
m_traceBufferWritep += 3;
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
}
inline void chgDouble(vluint32_t code, double newval) { inline void chgDouble(vluint32_t code, double newval) {
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE; m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
m_traceBufferWritep[1] = code; m_traceBufferWritep[1] = code;
@@ -374,10 +388,6 @@ public:
} }
} }
} }
inline void CHG(Float)(vluint32_t* oldp, float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<float*>(oldp) != newval)) fullFloat(oldp, newval);
}
inline void CHG(Double)(vluint32_t* oldp, double newval) { inline void CHG(Double)(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast // cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval); if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
+46 -64
View File
@@ -39,7 +39,7 @@
// Static utility functions // Static utility functions
static double timescaleToDouble(const char* unitp) { static double timescaleToDouble(const char* unitp) {
char* endp; char* endp = NULL;
double value = strtod(unitp, &endp); double value = strtod(unitp, &endp);
// On error so we allow just "ns" to return 1e-9. // On error so we allow just "ns" to return 1e-9.
if (value == 0.0 && endp == unitp) value = 1; if (value == 0.0 && endp == unitp) value = 1;
@@ -73,31 +73,6 @@ static std::string doubleToTimescale(double value) {
return valuestr; // Gets converted to string, so no ref to stack return valuestr; // Gets converted to string, so no ref to stack
} }
//=============================================================================
// Internal callback routines for each module being traced.
// Each module that wishes to be traced registers a set of callbacks stored in
// this class. When the trace file is being constructed, this class provides
// the callback routines to be executed.
class VerilatedTraceCallInfo {
public: // This is in .cpp file so is not widely visible
typedef VerilatedTrace<VL_DERIVED_T>::callback_t callback_t;
callback_t m_initcb; ///< Initialization Callback function
callback_t m_fullcb; ///< Full Dumping Callback function
callback_t m_changecb; ///< Incremental Dumping Callback function
void* m_userthis; ///< User data pointer for callback
vluint32_t m_code; ///< Starting code number (set later by traceInit)
// CONSTRUCTORS
VerilatedTraceCallInfo(callback_t icb, callback_t fcb, callback_t changecb, void* ut)
: m_initcb(icb)
, m_fullcb(fcb)
, m_changecb(changecb)
, m_userthis(ut)
, m_code(1) {}
~VerilatedTraceCallInfo() {}
};
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_THREADED
//========================================================================= //=========================================================================
// Buffer management // Buffer management
@@ -196,11 +171,6 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
chgWDataImpl(oldp, readp, top); chgWDataImpl(oldp, readp, top);
readp += VL_WORDS_I(top); readp += VL_WORDS_I(top);
continue; continue;
case VerilatedTraceCommand::CHG_FLOAT:
VL_TRACE_THREAD_DEBUG("Command CHG_FLOAT " << top);
chgFloatImpl(oldp, *reinterpret_cast<const float*>(readp));
readp += 1;
continue;
case VerilatedTraceCommand::CHG_DOUBLE: case VerilatedTraceCommand::CHG_DOUBLE:
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top); VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp)); chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
@@ -224,13 +194,14 @@ template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
shutdown = true; shutdown = true;
break; break;
//=== //===
// Unknown command // Unknown command
default: default: { // LCOV_EXCL_START
VL_TRACE_THREAD_DEBUG("Command UNKNOWN"); VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd); VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command"); VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
break; break;
} // LCOV_EXCL_STOP
} }
// The above switch will execute 'continue' when necessary, // The above switch will execute 'continue' when necessary,
@@ -311,10 +282,6 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() { template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL); if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
while (!m_callbacks.empty()) {
delete m_callbacks.back();
m_callbacks.pop_back();
}
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_THREADED
close(); close();
#endif #endif
@@ -334,11 +301,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
m_numSignals = 0; m_numSignals = 0;
m_maxBits = 0; m_maxBits = 0;
// Call all initialize callbacks, which will call decl* for each signal. // Call all initialize callbacks, which will:
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { // - Call decl* for each signal
VerilatedTraceCallInfo* cip = m_callbacks[ent]; // - Store the base code
cip->m_code = nextCode(); for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
(cip->m_initcb)(self(), cip->m_userthis, cip->m_code); const CallbackRecord& cbr = m_initCbs[i];
cbr.m_initCb(cbr.m_userp, self(), nextCode());
} }
if (expectedCodes && nextCode() != expectedCodes) { if (expectedCodes && nextCode() != expectedCodes) {
@@ -409,12 +377,12 @@ template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const std::st
template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) { template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
m_assertOne.check(); m_assertOne.check();
if (VL_UNLIKELY(m_timeLastDump && timeui <= m_timeLastDump)) { if (VL_UNCOVERABLE(m_timeLastDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64
"u, dump call ignored\n", "u, dump call ignored\n",
m_timeLastDump, timeui); m_timeLastDump, timeui);
return; return;
} } // LCOV_EXCL_STOP
m_timeLastDump = timeui; m_timeLastDump = timeui;
Verilated::quiesce(); Verilated::quiesce();
@@ -452,17 +420,22 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
// Run the callbacks // Run the callbacks
if (VL_UNLIKELY(m_fullDump)) { if (VL_UNLIKELY(m_fullDump)) {
m_fullDump = false; // No more need for next dump to be full m_fullDump = false; // No more need for next dump to be full
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { for (vluint32_t i = 0; i < m_fullCbs.size(); ++i) {
VerilatedTraceCallInfo* cip = m_callbacks[ent]; const CallbackRecord& cbr = m_fullCbs[i];
(cip->m_fullcb)(self(), cip->m_userthis, cip->m_code); cbr.m_dumpCb(cbr.m_userp, self());
} }
} else { } else {
for (vluint32_t ent = 0; ent < m_callbacks.size(); ++ent) { for (vluint32_t i = 0; i < m_chgCbs.size(); ++i) {
VerilatedTraceCallInfo* cip = m_callbacks[ent]; const CallbackRecord& cbr = m_chgCbs[i];
(cip->m_changecb)(self(), cip->m_userthis, cip->m_code); cbr.m_dumpCb(cbr.m_userp, self());
} }
} }
for (vluint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
const CallbackRecord& cbr = m_cleanupCbs[i];
cbr.m_dumpCb(cbr.m_userp, self());
}
#ifdef VL_TRACE_THREADED #ifdef VL_TRACE_THREADED
if (VL_LIKELY(bufferp)) { if (VL_LIKELY(bufferp)) {
// Mark end of the trace buffer we just filled // Mark end of the trace buffer we just filled
@@ -481,17 +454,32 @@ template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
// Non-hot path internal interface to Verilator generated code // Non-hot path internal interface to Verilator generated code
template <> template <>
void VerilatedTrace<VL_DERIVED_T>::addCallback(callback_t initcb, callback_t fullcb, void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
callback_t changecb, CallbackRecord& cbRec) {
void* userthis) VL_MT_UNSAFE_ONE {
m_assertOne.check(); m_assertOne.check();
if (VL_UNLIKELY(timeLastDump() != 0)) { if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__ std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
+ " called with already open file"); + " called with already open file");
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
} } // LCOV_EXCL_STOP
VerilatedTraceCallInfo* cip = new VerilatedTraceCallInfo(initcb, fullcb, changecb, userthis); cbVec.push_back(cbRec);
m_callbacks.push_back(cip); }
template <> void VerilatedTrace<VL_DERIVED_T>::addInitCb(initCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_initCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addFullCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_fullCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addChgCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_chgCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::addCleanupCb(dumpCb_t cb, void* userp) {
CallbackRecord cbr(cb, userp);
addCallbackRecord(m_cleanupCbs, cbr);
} }
//========================================================================= //=========================================================================
@@ -537,12 +525,6 @@ void VerilatedTrace<VL_DERIVED_T>::fullWData(vluint32_t* oldp, const WData* newv
self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits); self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits);
} }
template <> void VerilatedTrace<VL_DERIVED_T>::fullFloat(vluint32_t* oldp, float newval) {
// cppcheck-suppress invalidPointerCast
*reinterpret_cast<float*>(oldp) = newval;
self()->emitFloat(oldp - m_sigs_oldvalp, newval);
}
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) { template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast // cppcheck-suppress invalidPointerCast
*reinterpret_cast<double*>(oldp) = newval; *reinterpret_cast<double*>(oldp) = newval;
+12 -8
View File
@@ -31,8 +31,8 @@
// //
//************************************************************************* //*************************************************************************
#ifndef _V3_UNORDERED_SET_MAP_H_ #ifndef _VERILATED_UNORDERED_SET_MAP_H_
#define _V3_UNORDERED_SET_MAP_H_ #define _VERILATED_UNORDERED_SET_MAP_H_
#include "verilatedos.h" #include "verilatedos.h"
@@ -55,6 +55,12 @@ inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
return hash; return hash;
} }
template <> inline size_t vl_hash<int>::operator()(const int& k) const { return k; }
template <> inline bool vl_equal_to<int>::operator()(const int& a, const int& b) const {
return a == b;
}
template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const { template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const {
return k; return k;
} }
@@ -225,8 +231,7 @@ public:
return end(); return end();
} }
const_iterator end() const { const_iterator end() const {
return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF), const_cast<Bucket&>(m_emptyBucket).begin(), return iterator(0xFFFFFFFFFFFFFFFFULL, const_cast<Bucket&>(m_emptyBucket).begin(), this);
this);
} }
bool empty() const { return m_numElements == 0; } bool empty() const { return m_numElements == 0; }
@@ -249,8 +254,7 @@ public:
// function further. This permits the use of very fast client // function further. This permits the use of very fast client
// hash funcs (like just returning the int or pointer value as // hash funcs (like just returning the int or pointer value as
// is!) and tolerates crappy client hash functions pretty well. // is!) and tolerates crappy client hash functions pretty well.
size_t mult size_t mult = hashVal * ((sizeof(size_t) == 8) ? 11400714819323198485ULL : 2654435769lu);
= hashVal * ((sizeof(size_t) == 8) ? VL_ULL(11400714819323198485) : 2654435769lu);
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets)); size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
return result; return result;
} }
@@ -339,7 +343,7 @@ public:
} }
private: private:
size_t numBuckets() const { return (VL_ULL(1) << m_log2Buckets); } size_t numBuckets() const { return (1ULL << m_log2Buckets); }
Bucket* getBucket(size_t idx) { Bucket* getBucket(size_t idx) {
initBuckets(); initBuckets();
@@ -372,7 +376,7 @@ private:
new_log2Buckets = m_log2Buckets - 2; new_log2Buckets = m_log2Buckets - 2;
} }
size_t new_num_buckets = VL_ULL(1) << new_log2Buckets; size_t new_num_buckets = 1ULL << new_log2Buckets;
Bucket* new_bucketsp = new Bucket[new_num_buckets]; Bucket* new_bucketsp = new Bucket[new_num_buckets];
for (size_t i = 0; i < numBuckets(); i++) { for (size_t i = 0; i < numBuckets(); i++) {
+64 -92
View File
@@ -27,7 +27,6 @@
#include <cerrno> #include <cerrno>
#include <ctime> #include <ctime>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h> # include <io.h>
@@ -35,8 +34,6 @@
# include <unistd.h> # include <unistd.h>
#endif #endif
#include "verilated_intrinsics.h"
// SPDIFF_ON // SPDIFF_ON
#ifndef O_LARGEFILE // For example on WIN32 #ifndef O_LARGEFILE // For example on WIN32
@@ -88,11 +85,11 @@ private:
public: public:
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard lock(singleton().s_vcdMutex); const VerilatedLockGuard lock(singleton().s_vcdMutex);
singleton().s_vcdVecp.push_back(vcdp); singleton().s_vcdVecp.push_back(vcdp);
} }
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) { static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard lock(singleton().s_vcdMutex); const VerilatedLockGuard lock(singleton().s_vcdMutex);
VcdVec::iterator pos VcdVec::iterator pos
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp); = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); } if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
@@ -101,7 +98,7 @@ public:
// Thread safety: Although this function is protected by a mutex so // Thread safety: Although this function is protected by a mutex so
// perhaps in the future we can allow tracing in separate threads, // perhaps in the future we can allow tracing in separate threads,
// vcdp->flush() assumes call from single thread // vcdp->flush() assumes call from single thread
VerilatedLockGuard lock(singleton().s_vcdMutex); const VerilatedLockGuard lock(singleton().s_vcdMutex);
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin(); for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
it != singleton().s_vcdVecp.end(); ++it) { it != singleton().s_vcdVecp.end(); ++it) {
VerilatedVcd* vcdp = *it; VerilatedVcd* vcdp = *it;
@@ -203,8 +200,8 @@ void VerilatedVcd::openNext(bool incFilename) {
} }
m_filename = name; m_filename = name;
} }
if (m_filename[0] == '|') { if (VL_UNCOVERABLE(m_filename[0] == '|')) {
assert(0); // Not supported yet. assert(0); // LCOV_EXCL_LINE // Not supported yet.
} else { } else {
// cppcheck-suppress duplicateExpression // cppcheck-suppress duplicateExpression
if (!m_filep->open(m_filename)) { if (!m_filep->open(m_filename)) {
@@ -358,13 +355,15 @@ void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
if (got > 0) { if (got > 0) {
wp += got; wp += got;
m_wroteBytes += got; m_wroteBytes += got;
} else if (got < 0) { } else if (VL_UNCOVERABLE(got < 0)) {
if (errno != EAGAIN && errno != EINTR) { if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
// LCOV_EXCL_START
// write failed, presume error (perhaps out of disk space) // write failed, presume error (perhaps out of disk space)
std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno); std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str()); VL_FATAL_MT("", 0, "", msg.c_str());
closeErr(); closeErr();
break; break;
// LCOV_EXCL_STOP
} }
} }
} }
@@ -583,9 +582,6 @@ void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int
int lsb) { int lsb) {
declare(code, name, "wire", array, arraynum, false, true, msb, lsb); declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
} }
void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 31, 0);
}
void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) { void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "real", array, arraynum, false, false, 63, 0); declare(code, name, "real", array, arraynum, false, false, 63, 0);
} }
@@ -699,15 +695,6 @@ void VerilatedVcd::emitWData(vluint32_t code, const WData* newvalp, int bits) {
finishLine(code, wp); finishLine(code, wp);
} }
VL_ATTR_ALWINLINE
void VerilatedVcd::emitFloat(vluint32_t code, float newval) {
char* wp = m_writep;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(wp, "r%.16g", static_cast<double>(newval));
wp += strlen(wp);
finishLine(code, wp);
}
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
void VerilatedVcd::emitDouble(vluint32_t code, double newval) { void VerilatedVcd::emitDouble(vluint32_t code, double newval) {
char* wp = m_writep; char* wp = m_writep;
@@ -742,7 +729,7 @@ void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits)
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval; (*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
*m_writep++ = 'b'; *m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) { for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0'); *m_writep++ = ((newval & (1ULL << bit)) ? '1' : '0');
} }
*m_writep++ = ' '; *m_writep++ = ' ';
m_writep = writeCode(m_writep, code); m_writep = writeCode(m_writep, code);
@@ -764,7 +751,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; } for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; }
*m_writep++ = 'b'; *m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) { for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0'); *m_writep++ = ((newval[(bit / 64)] & (1ULL << (bit & 0x3f))) ? '1' : '0');
} }
*m_writep++ = ' '; *m_writep++ = ' ';
m_writep = writeCode(m_writep, code); m_writep = writeCode(m_writep, code);
@@ -792,14 +779,13 @@ void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vl
*m_writep++ = '\n'; *m_writep++ = '\n';
bufferCheck(); bufferCheck();
} }
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
int bits) { int bits) {
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval; (*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
(*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri; (*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri;
*m_writep++ = 'b'; *m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) { for (int bit = bits - 1; bit >= 0; --bit) {
*m_writep++ *m_writep++ = "01zz"[((newval >> bit) & 1ULL) | (((newtri >> bit) & 1ULL) << 1ULL)];
= "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
} }
*m_writep++ = ' '; *m_writep++ = ' ';
m_writep = writeCode(m_writep, code); m_writep = writeCode(m_writep, code);
@@ -834,33 +820,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
*m_writep++ = '\n'; *m_writep++ = '\n';
bufferCheck(); bufferCheck();
} }
void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
(*(reinterpret_cast<float*>(oldp(code)))) = newval;
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", static_cast<double>(newval));
m_writep += strlen(m_writep);
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullBitX(vluint32_t code) {
*m_writep++ = 'x';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullBusX(vluint32_t code, int bits) {
*m_writep++ = 'b';
for (int bit = bits - 1; bit >= 0; --bit) *m_writep++ = 'x';
*m_writep++ = ' ';
m_writep = writeCode(m_writep, code);
*m_writep++ = '\n';
bufferCheck();
}
void VerilatedVcd::fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); }
void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); }
#endif // VL_TRACE_VCD_OLD_API #endif // VL_TRACE_VCD_OLD_API
@@ -873,8 +832,6 @@ void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_a
//====================================================================== //======================================================================
//====================================================================== //======================================================================
// clang-format off
#ifdef VERILATED_VCD_TEST #ifdef VERILATED_VCD_TEST
#include <iostream> #include <iostream>
@@ -882,34 +839,39 @@ vluint32_t v1, v2, s1, s2[3];
vluint32_t tri96[3]; vluint32_t tri96[3];
vluint32_t tri96__tri[3]; vluint32_t tri96__tri[3];
vluint64_t quad96[2]; vluint64_t quad96[2];
vluint64_t tquad;
vluint64_t tquad__tri;
vluint8_t ch; vluint8_t ch;
vluint64_t timestamp = 1; vluint64_t timestamp = 1;
double doub = 0; double doub = 0.0;
float flo = 0.0f;
void vcdInit(VerilatedVcd* vcdp, void* userthis, vluint32_t code) { void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) {
vcdp->scopeEscape('.'); vcdp->scopeEscape('.');
vcdp->module("top"); vcdp->module("top");
vcdp->declBus(0x2, "v1",-1,5,1); /**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1);
vcdp->declBus(0x3, "v2",-1,6,0); /**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1);
vcdp->module("top.sub1"); /**/ vcdp->module("top.sub1");
vcdp->declBit(0x4, "s1",-1); /***/ vcdp->declBit(0x4, "s1", -1, 0);
vcdp->declBit(0x5, "ch",-1); /***/ vcdp->declBit(0x5, "ch", -1, 0);
vcdp->module("top.sub2"); /**/ vcdp->module("top.sub2");
vcdp->declArray(0x6, "s2",-1, 40,3); /***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3);
// Note need to add 3 for next code. // Note need to add 3 for next code.
vcdp->module("top2"); vcdp->module("top2");
vcdp->declBus(0x2, "t2v1",-1,4,1); /**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1);
vcdp->declTriBit(0x10, "io1",-1); /**/ vcdp->declTriBit(0x10, "io1", -1, 0);
vcdp->declTriBus(0x12, "io5",-1,4,0); /**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0);
vcdp->declTriArray(0x16, "io96",-1,95,0); /**/ vcdp->declTriArray(0x16, "io96", -1, 0, 95, 0);
// Note need to add 6 for next code. /**/ // Note need to add 6 for next code.
vcdp->declDouble(0x1c, "doub",-1); /**/ vcdp->declDouble(0x1c, "doub", -1, 0);
// Note need to add 2 for next code. /**/ // Note need to add 2 for next code.
vcdp->declArray(0x1e, "q2",-1,95,0); /**/ vcdp->declArray(0x20, "q2", -1, 0, 95, 0);
// Note need to add 4 for next code. /**/ // Note need to add 4 for next code.
/**/ vcdp->declTriQuad(0x24, "tq", -1, 0, 63, 0);
/**/ // Note need to add 4 for next code.
} }
void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) { void vcdFull(void*, VerilatedVcd* vcdp) {
vcdp->fullBus(0x2, v1, 5); vcdp->fullBus(0x2, v1, 5);
vcdp->fullBus(0x3, v2, 7); vcdp->fullBus(0x3, v2, 7);
vcdp->fullBit(0x4, s1); vcdp->fullBit(0x4, s1);
@@ -919,10 +881,11 @@ void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5); vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
vcdp->fullTriArray(0x16, tri96, tri96__tri, 96); vcdp->fullTriArray(0x16, tri96, tri96__tri, 96);
vcdp->fullDouble(0x1c, doub); vcdp->fullDouble(0x1c, doub);
vcdp->fullArray(0x1e, &quad96[0], 96); vcdp->fullArray(0x20, &quad96[0], 96);
vcdp->fullTriQuad(0x24, tquad, tquad__tri, 64);
} }
void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) { void vcdChange(void*, VerilatedVcd* vcdp) {
vcdp->chgBus(0x2, v1, 5); vcdp->chgBus(0x2, v1, 5);
vcdp->chgBus(0x3, v2, 7); vcdp->chgBus(0x3, v2, 7);
vcdp->chgBit(0x4, s1); vcdp->chgBit(0x4, s1);
@@ -932,12 +895,12 @@ void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5); vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
vcdp->chgTriArray(0x16, tri96, tri96__tri, 96); vcdp->chgTriArray(0x16, tri96, tri96__tri, 96);
vcdp->chgDouble(0x1c, doub); vcdp->chgDouble(0x1c, doub);
vcdp->chgArray(0x1e, &quad96[0], 96); vcdp->chgArray(0x20, &quad96[0], 96);
vcdp->chgTriQuad(0x24, tquad, tquad__tri, 64);
} }
main() { // clang-format off
std::cout << "test: O_LARGEFILE=" << O_LARGEFILE << std::endl; void vcdTestMain(const char* filenamep) {
v1 = v2 = s1 = 0; v1 = v2 = s1 = 0;
s2[0] = s2[1] = s2[2] = 0; s2[0] = s2[1] = s2[2] = 0;
tri96[2] = tri96[1] = tri96[0] = 0; tri96[2] = tri96[1] = tri96[0] = 0;
@@ -945,43 +908,52 @@ main() {
quad96[1] = quad96[0] = 0; quad96[1] = quad96[0] = 0;
ch = 0; ch = 0;
doub = 0; doub = 0;
tquad = tquad__tri = 0;
{ {
VerilatedVcdC* vcdp = new VerilatedVcdC; VerilatedVcdC* vcdp = new VerilatedVcdC;
vcdp->spTrace()->addCallback(&vcdInit, &vcdFull, &vcdChange, 0); vcdp->evcd(true);
vcdp->open("test.vcd"); vcdp->spTrace()->addInitCb(&vcdInit, 0);
vcdp->spTrace()->addFullCb(&vcdFull, 0);
vcdp->spTrace()->addChgCb(&vcdChange, 0);
vcdp->open(filenamep);
// Dumping // Dumping
vcdp->dump(timestamp++); vcdp->dump(++timestamp);
v1 = 0xfff; v1 = 0xfff;
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1; tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
quad96[1] = 0xffffffff; quad96[0] = 0; quad96[1] = 0xffffffff; quad96[0] = 0;
doub = 1.5; doub = 1.5;
vcdp->dump(timestamp++); flo = 1.4f;
vcdp->dump(++timestamp);
v2 = 0x1; v2 = 0x1;
s2[1] = 2; s2[1] = 2;
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
quad96[1] = 0; quad96[0] = ~0; quad96[1] = 0; quad96[0] = ~0;
doub = -1.66e13; doub = -1.66e13;
vcdp->dump(timestamp++); flo = 0.123f;
tquad = 0x00ff00ff00ff00ffULL;
tquad__tri = 0x0000fffff0000ffffULL;
vcdp->dump(++timestamp);
ch = 2; ch = 2;
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1; tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
doub = -3.33e-13; doub = -3.33e-13;
vcdp->dump(timestamp++); vcdp->dump(++timestamp);
vcdp->dump(timestamp++); vcdp->dump(++timestamp);
# ifdef VERILATED_VCD_TEST_64BIT # ifdef VERILATED_VCD_TEST_64BIT
vluint64_t bytesPerDump = VL_ULL(15); vluint64_t bytesPerDump = 15ULL;
for (vluint64_t i = 0; i < ((VL_ULL(1) << 32) / bytesPerDump); i++) { for (vluint64_t i = 0; i < ((1ULL << 32) / bytesPerDump); i++) {
v1 = i; v1 = i;
vcdp->dump(timestamp++); vcdp->dump(++timestamp);
} }
# endif # endif
vcdp->close(); vcdp->close();
} }
} }
#endif #endif
// clang-format on
//******************************************************************** //********************************************************************
// ;compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd" // ;compile-command: "v4make test_regress/t/t_trace_c_api.pl"
// //
// Local Variables: // Local Variables:
// End: // End:
+14 -27
View File
@@ -130,7 +130,6 @@ protected:
inline void emitIData(vluint32_t code, IData newval, int bits); inline void emitIData(vluint32_t code, IData newval, int bits);
inline void emitQData(vluint32_t code, QData newval, int bits); inline void emitQData(vluint32_t code, QData newval, int bits);
inline void emitWData(vluint32_t code, const WData* newvalp, int bits); inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
inline void emitFloat(vluint32_t code, float newval);
inline void emitDouble(vluint32_t code, double newval); inline void emitDouble(vluint32_t code, double newval);
public: public:
@@ -163,7 +162,6 @@ public:
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb); void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declFloat(vluint32_t code, const char* name, bool array, int arraynum);
void declDouble(vluint32_t code, const char* name, bool array, int arraynum); void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
#ifdef VL_TRACE_VCD_OLD_API #ifdef VL_TRACE_VCD_OLD_API
@@ -195,7 +193,6 @@ public:
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) { void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
fullArray(oldp - this->oldp(0), newvalp, bits); fullArray(oldp - this->oldp(0), newvalp, bits);
} }
void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - this->oldp(0), newval); }
void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); } void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }
inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); } inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
@@ -214,9 +211,6 @@ public:
inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) { inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
chgArray(oldp - this->oldp(0), newvalp, bits); chgArray(oldp - this->oldp(0), newvalp, bits);
} }
inline void chgFloat(vluint32_t* oldp, float newval) {
chgFloat(oldp - this->oldp(0), newval);
}
inline void chgDouble(vluint32_t* oldp, double newval) { inline void chgDouble(vluint32_t* oldp, double newval) {
chgDouble(oldp - this->oldp(0), newval); chgDouble(oldp - this->oldp(0), newval);
} }
@@ -230,20 +224,10 @@ public:
void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits); void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri); void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits); void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits); void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
int bits); int bits);
void fullDouble(vluint32_t code, const double newval); void fullDouble(vluint32_t code, const double newval);
void fullFloat(vluint32_t code, const float newval);
/// Inside dumping routines, dump one signal as unknowns
/// Presently this code doesn't change the oldval vector.
/// Thus this is for special standalone applications that after calling
/// fullBitX, must when then value goes non-X call fullBit.
void fullBitX(vluint32_t code);
void fullBusX(vluint32_t code, int bits);
void fullQuadX(vluint32_t code, int bits);
void fullArrayX(vluint32_t code, int bits);
/// Inside dumping routines, dump one signal if it has changed. /// Inside dumping routines, dump one signal if it has changed.
/// We do want to inline these to avoid calls when the value did not change. /// We do want to inline these to avoid calls when the value did not change.
@@ -262,7 +246,7 @@ public:
inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) { inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval; vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(diff)) {
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) { if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
fullQuad(code, newval, bits); fullQuad(code, newval, bits);
} }
} }
@@ -303,12 +287,12 @@ public:
} }
} }
} }
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
int bits) { int bits) {
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval) vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
| ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri)); | ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
if (VL_UNLIKELY(diff)) { if (VL_UNLIKELY(diff)) {
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) { if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
fullTriQuad(code, newval, newtri, bits); fullTriQuad(code, newval, newtri, bits);
} }
} }
@@ -329,15 +313,9 @@ public:
fullDouble(code, newval); fullDouble(code, newval);
} }
} }
inline void chgFloat(vluint32_t code, const float newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY((*(reinterpret_cast<float*>(oldp(code)))) != newval)) {
fullFloat(code, newval);
}
}
protected:
// METHODS // METHODS
// Old/standalone API only
void evcd(bool flag) { m_evcd = flag; } void evcd(bool flag) { m_evcd = flag; }
#endif // VL_TRACE_VCD_OLD_API #endif // VL_TRACE_VCD_OLD_API
}; };
@@ -405,6 +383,15 @@ public:
/// Internal class access /// Internal class access
inline VerilatedVcd* spTrace() { return &m_sptrace; } inline VerilatedVcd* spTrace() { return &m_sptrace; }
#ifdef VL_TRACE_VCD_OLD_API
//=========================================================================
// Note: These are only for testing for backward compatibility with foreign
// code and is not used by Verilator. Do not use these as there is no
// guarantee of functionality.
/// Use evcd format
void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); }
#endif
}; };
#endif // guard #endif // guard
+1 -1
View File
@@ -77,7 +77,7 @@ private:
virtual void set_time_unit(int exponent10_seconds) {} // deprecated virtual void set_time_unit(int exponent10_seconds) {} // deprecated
#endif #endif
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100) #if defined(NC_SYSTEMC) || (SYSTEMC_VERSION >= 20111100)
virtual void set_time_unit(double v, sc_time_unit tu) {} virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
#endif #endif
//-------------------------------------------------- //--------------------------------------------------
+45 -29
View File
@@ -30,7 +30,6 @@
#include <list> #include <list>
#include <map> #include <map>
#include <set> #include <set>
#include <sstream>
//====================================================================== //======================================================================
// Internal constants // Internal constants
@@ -50,7 +49,7 @@
// Not supported yet // Not supported yet
#define _VL_VPI_UNIMP() \ #define _VL_VPI_UNIMP() \
_VL_VPI_ERROR(__FILE__, __LINE__, Verilated::catName("Unsupported VPI function: ", VL_FUNC)); (_VL_VPI_ERROR(__FILE__, __LINE__, Verilated::catName("Unsupported VPI function: ", VL_FUNC)))
//====================================================================== //======================================================================
// Implementation // Implementation
@@ -136,7 +135,7 @@ public:
static inline VerilatedVpioConst* castp(vpiHandle h) { static inline VerilatedVpioConst* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(h)); return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(h));
} }
virtual vluint32_t type() const { return vpiUndefined; } virtual vluint32_t type() const { return vpiConstant; }
vlsint32_t num() const { return m_num; } vlsint32_t num() const { return m_num; }
}; };
@@ -377,8 +376,8 @@ struct VerilatedVpiTimedCbsCmp {
/// Ordering sets keyed by time, then callback descriptor /// Ordering sets keyed by time, then callback descriptor
bool operator()(const std::pair<QData, VerilatedVpioCb*>& a, bool operator()(const std::pair<QData, VerilatedVpioCb*>& a,
const std::pair<QData, VerilatedVpioCb*>& b) const { const std::pair<QData, VerilatedVpioCb*>& b) const {
if (a.first < b.first) return 1; if (a.first < b.first) return true;
if (a.first > b.first) return 0; if (a.first > b.first) return false;
return a.second < b.second; return a.second < b.second;
} }
}; };
@@ -450,7 +449,7 @@ public:
static QData cbNextDeadline() { static QData cbNextDeadline() {
VpioTimedCbs::const_iterator it = s_s.m_timedCbs.begin(); VpioTimedCbs::const_iterator it = s_s.m_timedCbs.begin();
if (VL_LIKELY(it != s_s.m_timedCbs.end())) return it->first; if (VL_LIKELY(it != s_s.m_timedCbs.end())) return it->first;
return ~VL_ULL(0); // maxquad return ~0ULL; // maxquad
} }
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE { static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
VpioCbList& cbObjList = s_s.m_cbObjLists[reason]; VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
@@ -624,7 +623,7 @@ const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE {
"vpiRawFourStateVal", "vpiRawFourStateVal",
}; };
// clang-format on // clang-format on
if (vpiVal < 0) return names[0]; if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0]; return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0];
} }
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE { const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
@@ -768,7 +767,7 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
"vpiGenVar" "vpiGenVar"
}; };
// clang-format on // clang-format on
if (vpiVal < 0) return names[0]; if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiGenVar) ? vpiVal : 0]; return names[(vpiVal <= vpiGenVar) ? vpiVal : 0];
} }
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE { const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
@@ -851,7 +850,7 @@ const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_
"cbAtEndOfSimTime" "cbAtEndOfSimTime"
}; };
// clang-format on // clang-format on
if (vpiVal < 0) return names[0]; if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 0]; return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 0];
} }
@@ -940,7 +939,7 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
} }
#define CHECK_RESULT_CSTR(got, exp) \ #define CHECK_RESULT_CSTR(got, exp) \
if (strcmp((got), (exp))) { \ if (0 != strcmp((got), (exp))) { \
std::string msg \ std::string msg \
= std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \ = std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \ VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
@@ -1026,7 +1025,7 @@ vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", VL_FUNC, _VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported callback type %s", VL_FUNC,
VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason)); VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason));
return NULL; return NULL;
}; }
} }
PLI_INT32 vpi_remove_cb(vpiHandle object) { PLI_INT32 vpi_remove_cb(vpiHandle object) {
@@ -1135,16 +1134,30 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
_VL_VPI_ERROR_RESET(); _VL_VPI_ERROR_RESET();
switch (type) { switch (type) {
case vpiLeftRange: { case vpiLeftRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop)) return 0; if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return 0; return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle(); } else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
} }
case vpiRightRange: { case vpiRightRange: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
if (VL_UNLIKELY(!vop)) return 0; if (VL_UNLIKELY(!vop->rangep())) return 0;
if (VL_UNLIKELY(!vop->rangep())) return 0; return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle(); } else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
if (VL_UNLIKELY(!vop->rangep())) return 0;
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
}
_VL_VPI_WARNING(__FILE__, __LINE__,
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
return 0;
} }
case vpiIndex: { case vpiIndex: {
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object); VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
@@ -1361,7 +1374,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
} }
case VLVT_UINT64: { case VLVT_UINT64: {
QData data = *(reinterpret_cast<QData*>(vop->varDatap())); QData data = *(reinterpret_cast<QData*>(vop->varDatap()));
out[1].aval = static_cast<IData>(data >> VL_ULL(32)); out[1].aval = static_cast<IData>(data >> 32ULL);
out[1].bval = 0; out[1].bval = 0;
out[0].aval = static_cast<IData>(data); out[0].aval = static_cast<IData>(data);
out[0].bval = 0; out[0].bval = 0;
@@ -1600,8 +1613,8 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname()); VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
return; return;
} }
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format %s", VL_FUNC,
VerilatedVpiError::strFromVpiVal(value_p->format)); _VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
} }
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time_p*/, vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p, p_vpi_time /*time_p*/,
@@ -1907,6 +1920,7 @@ void vpi_put_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/
void vpi_get_time(vpiHandle object, p_vpi_time time_p) { void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
VerilatedVpiImp::assertOneCheck(); VerilatedVpiImp::assertOneCheck();
_VL_VPI_ERROR_RESET();
// cppcheck-suppress nullPointer // cppcheck-suppress nullPointer
if (VL_UNLIKELY(!time_p)) { if (VL_UNLIKELY(!time_p)) {
_VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_get_time with NULL value pointer"); _VL_VPI_WARNING(__FILE__, __LINE__, "Ignoring vpi_get_time with NULL value pointer");
@@ -1937,7 +1951,7 @@ void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
PLI_UINT32 vpi_mcd_open(PLI_BYTE8* filenamep) { PLI_UINT32 vpi_mcd_open(PLI_BYTE8* filenamep) {
VerilatedVpiImp::assertOneCheck(); VerilatedVpiImp::assertOneCheck();
_VL_VPI_ERROR_RESET(); _VL_VPI_ERROR_RESET();
return VL_FOPEN_S(filenamep, "wb"); return VL_FOPEN_NN(filenamep, "wb");
} }
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) { PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
@@ -2072,17 +2086,19 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
_VL_VPI_ERROR_RESET(); _VL_VPI_ERROR_RESET();
switch (operation) { switch (operation) {
case vpiFinish: { case vpiFinish: {
VL_FINISH_MT(__FILE__, __LINE__, "*VPI*"); VL_FINISH_MT("", 0, "*VPI*");
return 1; return 1;
} }
case vpiStop: { case vpiStop: {
VL_STOP_MT(__FILE__, __LINE__, "*VPI*"); VL_STOP_MT("", 0, "*VPI*");
return 1; return 1; // LCOV_EXCL_LINE
}
default: {
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", VL_FUNC,
VerilatedVpiError::strFromVpiProp(operation));
return 0;
} }
} }
_VL_VPI_WARNING(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", VL_FUNC,
VerilatedVpiError::strFromVpiProp(operation));
return 0;
} }
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/, vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
+22 -15
View File
@@ -144,30 +144,23 @@
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, #define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
///< protected to make sure single-caller ///< protected to make sure single-caller
#ifdef _MSC_VER #define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
// Was "(c##ui64)". C++11 has standardized on ULL, and MSVC now supports this.
// We propose to no longer require using this macro no sooner than June 2020.
// File an issue ASAP if this breaks anything.
#else
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
#endif
// This is not necessarily the same as #UL, depending on what the IData typedef is. // This is not necessarily the same as #UL, depending on what the IData typedef is.
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant #define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__) #if defined(VL_CPPCHECK) || defined(__clang_analyzer__) || __cplusplus < 201103L
# define VL_DANGLING(var) # define VL_DANGLING(var)
#else #else
///< After e.g. delete, set variable to NULL to indicate must not use later /// After e.g. delete, set variable to NULL to indicate must not use later
# define VL_DANGLING(var) \ # define VL_DANGLING(var) \
do { \ do { \
(var) = NULL; \ *const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = NULL; \
} while (false) } while (false)
#endif #endif
///< Perform an e.g. delete, then set variable to NULL to indicate must not use later. /// Perform an e.g. delete, then set variable to NULL to indicate must not use later.
///< Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons. /// Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
#define VL_DO_DANGLING(stmt, var) \ #define VL_DO_DANGLING(stmt, var) \
do { \ do { \
do { \ do { \
@@ -176,7 +169,7 @@
VL_DANGLING(var); \ VL_DANGLING(var); \
} while (false) } while (false)
///< Perform an e.g. delete, then set variable to NULL as a requirement /// Perform an e.g. delete, then set variable to NULL as a requirement
#define VL_DO_CLEAR(stmt, stmt2) \ #define VL_DO_CLEAR(stmt, stmt2) \
do { \ do { \
do { \ do { \
@@ -224,6 +217,20 @@
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run # define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
#endif #endif
//=========================================================================
// Internal coverage
#ifdef VL_GCOV
extern "C" {
void __gcov_flush(); // gcc sources gcc/gcov-io.h has the prototype
}
/// Flush internal code coverage data before e.g. abort()
# define VL_GCOV_FLUSH() \
__gcov_flush()
#else
# define VL_GCOV_FLUSH()
#endif
//========================================================================= //=========================================================================
// Warning disabled // Warning disabled
@@ -401,7 +408,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0) #define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
/// Mask for quads with 1's where relevant bits are (0=all bits) /// Mask for quads with 1's where relevant bits are (0=all bits)
#define VL_MASK_Q(nbits) \ #define VL_MASK_Q(nbits) \
(((nbits) & VL_SIZEBITS_Q) ? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q)) - VL_ULL(1)) : VL_ULL(~0)) (((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL)
/// Mask for EData with 1's where relevant bits are (0=all bits) /// Mask for EData with 1's where relevant bits are (0=all bits)
#define VL_MASK_E(nbits) VL_MASK_I(nbits) #define VL_MASK_E(nbits) VL_MASK_I(nbits)
#define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized #define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized
-58
View File
@@ -1,58 +0,0 @@
#!/usr/bin/env perl
######################################################################
#
# Copyright 2007-2020 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
#
######################################################################
# DESCRIPTION: Debugging of bison output
use warnings;
use strict;
my $Debug;
my %declared;
my %used;
my $body = 0;
my $rule = "";
my $lineno = 0;
foreach my $line (<STDIN>) {
$lineno++;
chomp $line;
$line =~ s!//.*$!!g;
$line =~ s!\s+! !g;
next if $line eq '';
if ($line =~ m!^\%\%!) {
$body++;
} elsif ($body == 1) {
$rule .= $line;
if ($line =~ m!^\s*;\s*$!) {
#print "Rule: $rule\n";
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
my $rulename = $1; my $preaction = $3;
$declared{$rulename} = $lineno;
$preaction =~ s/\{[^\}]*\}/ /g;
#print "RULEN $rulename PA $preaction\n" if $Debug;
$rule = '';
foreach my $ref (split /\s+/, $preaction) {
next if $ref !~ /^[a-zA-Z]/;
next if $ref eq $rulename;
if (!$used{$ref} && $declared{$ref}) {
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
}
$used{$ref} = $lineno;
print " ref $ref\n" if $Debug;
}
}
}
}
# Local Variables:
# compile-command: "./bisonreader < ../src/verilog.y"
# End:
+302 -57
View File
@@ -6,30 +6,71 @@ use warnings;
use Cwd; use Cwd;
use File::Copy qw(cp); use File::Copy qw(cp);
use File::Path qw(mkpath); use File::Path qw(mkpath);
use File::Spec;
use FindBin qw($RealBin);
use Getopt::Long; use Getopt::Long;
use Parallel::Forker;
use Unix::Processors;
use IO::File; use IO::File;
use Pod::Usage; use Pod::Usage;
use strict; use strict;
use vars qw($Debug); use vars qw($Debug);
our $Opt_Stop = 1;
our $Opt_Fastcov = 1;
our $Exclude_Branch_Regexp;
our $Exclude_Line_Regexp; our $Exclude_Line_Regexp;
our $Remove_Gcda_Regexp;
our @Remove_Sources; our @Remove_Sources;
our @Source_Globs; our @Source_Globs;
our $Fork = new Parallel::Forker(use_sig_child => 1, poll_interval => 10*1000);
$Fork->max_proc(Unix::Processors->new->max_online * 1.5);
$SIG{CHLD} = sub { Parallel::Forker::sig_child($Fork); };
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork && $Fork->in_parent; die "Quitting...\n"; };
#====================================================================== #======================================================================
# main # main
our $Opt_Stage = 0; our $Opt_Hashset;
our $opt_stages = '';
our $Opt_Scenarios;
our %Opt_Stages;
our @Opt_Tests;
autoflush STDOUT 1; autoflush STDOUT 1;
autoflush STDERR 1; autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev"); Getopt::Long::config("no_auto_abbrev");
if (! GetOptions( if (! GetOptions(
"debug" => sub { $Debug = 1; }, "debug" => sub { $Debug = 1; },
"hashset=s" => \$Opt_Hashset, # driver.pl hashset
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; }, "<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage, "fastcov!" => \$Opt_Fastcov, # use fastcov, not documented, for debug
"scenarios=s" => \$Opt_Scenarios, # driver.pl scenarios
"stage=s" => \$opt_stages, # starting stage number
"stages=s" => \$opt_stages, # starting stage number
"stop!" => \$Opt_Stop, # stop/do not stop on error in tests
"test=s@" => \@Opt_Tests, # test name
)) { )) {
die "%Error: Bad usage, try 'install_test --help'\n"; die "%Error: Bad usage, try 'code_coverage --help'\n";
}
{
my $start = 0;
my $end = 99;
if ($opt_stages && $opt_stages =~ /^(\d+)$/) {
$start = $end = $1;
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-(\d+$)$/) {
$start = $1; $end = $2;
} elsif ($opt_stages && $opt_stages =~ /^-(\d+$)$/) {
$end = $1;
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-$/) {
$start = $1;
} elsif ($opt_stages) {
die "%Error: --stages not understood: $opt_stages,";
}
for (my $n = $start; $n <= $end; ++$n) { $Opt_Stages{$n} = 1; }
} }
test(); test();
@@ -41,97 +82,238 @@ sub test {
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,"; -r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
require "./nodist/code_coverage.dat"; require "./nodist/code_coverage.dat";
if ($Opt_Stage <= 0) { if ($Opt_Stages{1}) {
print "Stage 0: configure (coverage on)\n"; travis_fold_start("configure");
run("make distclean"); print "Stage 1: configure (coverage on)\n";
run("./configure --enable-longtests CXX='g++ --coverage'"); run("make distclean || true");
run("make -k"); run("autoconf");
# Exceptions can pollute the branch coverage data
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'");
travis_fold_end();
}
if ($Opt_Stages{2}) {
travis_fold_start("build");
print "Stage 2: build\n";
my $nproc = Unix::Processors->new->max_online;
run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1");
# The optimized versions will not collect good coverage, overwrite them # The optimized versions will not collect good coverage, overwrite them
run("cp bin/verilator_bin_dbg bin/verilator_bin"); run("cp bin/verilator_bin_dbg bin/verilator_bin");
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin"); run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
travis_fold_end();
} }
if ($Opt_Stage <= 1) { if ($Opt_Stages{3}) {
print "Stage 1: make examples (with coverage on)\n"; travis_fold_start("test");
run("make examples"); print "Stage 3: make tests (with coverage on)\n";
run("make test_regress"); if ($#Opt_Tests < 0) {
run("make examples VERILATOR_NO_OPT_BUILD=1")
if !$Opt_Scenarios || $Opt_Scenarios =~ /dist/i;
run("make test_regress VERILATOR_NO_OPT_BUILD=1"
. ($Opt_Scenarios ? " SCENARIOS='".$Opt_Scenarios."'" : "")
. ($Opt_Hashset ? " DRIVER_HASHSET='--hashset=".$Opt_Hashset."'" : "")
. ($Opt_Stop ? '' : ' || true'));
} else {
foreach my $test (@Opt_Tests) {
if (! -f $test && -f "test_regress/t/${test}") {
$test = "test_regress/t/${test}";
}
run($test);
}
}
travis_fold_end();
} }
my $cc_dir = "nodist/obj_dir/coverage"; my $cc_dir = "nodist/obj_dir/coverage";
if ($Opt_Stage <= 2) { if ($Opt_Stages{4}) {
print "Stage 2: Create info files under $cc_dir\n"; travis_fold_start("gcno");
print "Stage 4: Create gcno files under $cc_dir\n";
mkpath($cc_dir); mkpath($cc_dir);
mkpath("$cc_dir/info"); mkpath("$cc_dir/info");
my $dats = `find . -print | grep .gcda`; my $dats = `find . -print | grep .gcda`;
my %dats;
foreach my $dat (split '\n', $dats) {
$dats{$dat} = 1;
}
foreach my $dat (sort keys %dats) {
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
if ($dat =~ /$Remove_Gcda_Regexp/) {
# Remove .gcda/.gcno for files we don't care about before we slowly
# read them
unlink $dat;
unlink $gcno;
delete $dats{$dat};
next;
}
}
$dats = `find . -print | grep .gcno`;
my %gcnos;
foreach my $gcno (split '\n', $dats) {
(my $gbase = $gcno) =~ s!.*/!!;
$gcnos{$gbase} = File::Spec->rel2abs($gcno);
}
# We need a matching .gcno for every .gcda, try to find a matching file elsewhere
foreach my $dat (sort keys %dats) {
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
(my $gbase = $gcno) =~ s!.*/!!;
if (!-r $gcno) {
if ($gcnos{$gbase}) {
symlink($gcnos{$gbase}, $gcno)
or die "%Error: can't ln -s $gcnos{$gbase} $gcno,";
} else {
warn "MISSING .gcno for a .gcda: $gcno\n";
}
}
}
travis_fold_end();
}
if ($Opt_Stages{5} && $Opt_Fastcov) {
travis_fold_start("fastcov");
# Must run in root directory to find all files
mkpath($cc_dir);
#run("${RealBin}/fastcov.py -b -c src/obj_dbg -X".
# " --exclude /usr --exclude test_regress"
# ." -o ${cc_dir}/app_total.json");
run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov".
" --exclude /usr --exclude test_regress"
." -o ${cc_dir}/app_total.info");
travis_fold_end();
}
if ($Opt_Stages{5} && !$Opt_Fastcov) {
travis_fold_start("infos");
print "Stage 5: make infos\n";
my $dats = `find . -print | grep .gcda`;
my %dirs; my %dirs;
foreach my $dat (split '\n', $dats) { foreach my $dat (split '\n', $dats) {
$dat =~ s!/[^/]+$!!; (my $dir = $dat) =~ s!/[^/]+$!!;
$dirs{$dat} = 1; $dirs{$dir} = 1;
} }
foreach my $dir (sort keys %dirs) { foreach my $dir (sort keys %dirs) {
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g; (my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info"); $Fork->schedule(run_on_start => sub {
# .info may be empty, so ignore errors (unfortunately)
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir --exclude /usr -o app_test_${outname}.info || true");
})->run;
} }
$Fork->wait_all;
travis_fold_end();
} }
if ($Opt_Stage <= 3) { if ($Opt_Stages{6}) {
# lcov doesn't have a control file to override single lines, so replicate the sources travis_fold_start("clone");
print "Stage 3: Clone sources under $cc_dir\n"; # No control file to override single lines, so replicate the sources
# Also lets us see the insertion markers in the HTML source res
print "Stage 6: Clone sources under $cc_dir\n";
clone_sources($cc_dir); clone_sources($cc_dir);
travis_fold_end();
} }
if ($Opt_Stage <= 4) { if ($Opt_Stages{8} && !$Opt_Fastcov) {
print "Stage 4: Copy .gcno files\n"; travis_fold_start("copy");
print "Stage 8: Copy .gcno files\n";
my $dats = `find . -print | grep .gcno`; my $dats = `find . -print | grep .gcno`;
foreach my $dat (split '\n', $dats) { foreach my $dat (sort (split '\n', $dats)) {
next if $dat =~ /$cc_dir/; next if $dat =~ /$cc_dir/;
my $outdat = $cc_dir."/".$dat; my $outdat = $cc_dir."/".$dat;
#print "cp $dat, $outdat);\n"; #print "cp $dat, $outdat);\n";
cp($dat, $outdat); cp($dat, $outdat);
} }
travis_fold_end();
} }
if ($Opt_Stage <= 5) { if ($Opt_Stages{10} && !$Opt_Fastcov) {
print "Stage 5: Combine data files\n"; travis_fold_start("combine");
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info"); print "Stage 10: Combine data files\n";
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info"); {
my $infos = `cd $cc_dir ; find info -print | grep .info`; run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
my $comb = ""; run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my @infos = (split /\n/, $infos); my $infos = `cd $cc_dir ; find info -print | grep .info`;
foreach my $info (@infos) { my $comb = "";
$comb .= " -a $info"; my @infos = (sort (split /\n/, $infos));
# Need to batch them to avoid overrunning shell command length limit foreach my $info (@infos) {
if (length($comb) > 10000 || $info eq $infos[$#infos]) { $comb .= " -a $info";
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info"); # Need to batch them to avoid overrunning shell command length limit
$comb = ""; if (length($comb) > 10000 || $info eq $infos[$#infos]) {
# .info may be empty, so ignore errors (unfortunately)
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info || true");
$comb = "";
}
} }
} }
travis_fold_end();
} }
if ($Opt_Stage <= 6) { if ($Opt_Stages{11}) {
print "Stage 6: Filter processed source files\n"; travis_fold_start("dirs");
my $cmd = ''; print "Stage 11: Cleanup paths\n";
foreach my $glob (@Remove_Sources) { if ($Opt_Fastcov) {
$cmd .= " '$glob'"; cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
#cleanup_abs_paths_json($cc_dir, "$cc_dir/app_total.json", "$cc_dir/app_total.json");
} else {
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
} }
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info"); travis_fold_end();
} }
if ($Opt_Stage <= 7) { if ($Opt_Stages{12}) {
print "Stage 7: Create HTML\n"; travis_fold_start("filter");
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info"); print "Stage 12: Filter processed source files\n";
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp" my $inc = '';
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$inc .= " '$infile'";
}
}
my $exc = '';
foreach my $glob (@Remove_Sources) {
# Fastcov does exact match not globbing at present
# Lcov requires whole path match so needs the glob
$glob =~ s!^\*!! if $Opt_Fastcov;
$glob =~ s!\*$!! if $Opt_Fastcov;
$exc .= " '$glob'";
}
if ($Opt_Fastcov) {
$inc = "--include ".$inc if $inc ne '';
$exc = "--exclude ".$exc if $exc ne '';
run("cd $cc_dir ; ${RealBin}/fastcov.py -C app_total.info ${inc} ${exc} -x --lcov -o app_total_f.info");
} else {
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
}
travis_fold_end();
}
if ($Opt_Stages{17}) {
travis_fold_start("report");
print "Stage 17: Create HTML\n";
run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp"
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html"); ." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
travis_fold_end();
} }
if ($Opt_Stage <= 9) { if ($Opt_Stages{18}) {
travis_fold_start("upload");
print "Stage 18: Upload\n";
my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info";
print "print: Not running: export CODECOV_TOKEN=<hidden>\n";
print "print: Not running: $cmd\n";
travis_fold_end();
}
if ($Opt_Stages{19}) {
print "*-* All Finished *-*\n"; print "*-* All Finished *-*\n";
print "\n";
print "* See report in ${cc_dir}/html/index.html\n";
print "* Remember to make distclean && ./configure before working on non-coverage\n";
} }
} }
sub clone_sources { sub clone_sources {
my $cc_dir = shift; my $cc_dir = shift;
my $excluded_lines = 0; my $excluded_lines = 0;
my $excluded_br_lines = 0;
foreach my $glob (@Source_Globs) { foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) { foreach my $infile (glob $glob) {
$infile !~ m!^/! $infile !~ m!^/!
@@ -145,21 +327,35 @@ sub clone_sources {
while (defined(my $line = $fh->getline)) { while (defined(my $line = $fh->getline)) {
$lineno++; $lineno++;
chomp $line; chomp $line;
if ($line !~ m!// LCOV_EXCL_LINE! if ($line =~ /LCOV_EXCL_LINE/) {
&& $line =~ /$Exclude_Line_Regexp/) { $line .= " LCOV_EXCL_BR_LINE";
$line .= " //code_coverage: // LCOV_EXCL_LINE"; }
elsif ($line =~ /LCOV_EXCL_START/) {
$line .= " LCOV_EXCL_BR_START";
}
elsif ($line =~ /LCOV_EXCL_STOP/) {
$line .= " LCOV_EXCL_BR_STOP";
}
elsif ($line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE LCOV_EXCL_BR_LINE";
$excluded_lines++; $excluded_lines++;
$excluded_br_lines++;
#print "$infile:$lineno: $line";
}
elsif ($line =~ /$Exclude_Branch_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_BR_LINE";
$excluded_br_lines++;
#print "$infile:$lineno: $line"; #print "$infile:$lineno: $line";
} else {
} }
$ofh->print("$line\n"); $ofh->print("$line\n");
} }
} }
} }
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n"; print "Number of source lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
print "Number of source lines automatically LCOV_EXCL_BR_LINE'ed: $excluded_br_lines\n";
} }
sub cleanup_abs_paths { sub cleanup_abs_paths_info {
my $cc_dir = shift; my $cc_dir = shift;
my $infile = shift; my $infile = shift;
my $outfile = shift; my $outfile = shift;
@@ -178,18 +374,41 @@ sub cleanup_abs_paths {
$ofh->print(@lines); $ofh->print(@lines);
} }
sub cleanup_abs_paths_json {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
# Handcrafted cleanup, alternative would be to deserialize/serialize JSON
# But JSON::Parse not installed by default
# JSON::PP more likely to be installed, but slower
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my @lines;
while (defined(my $line = $fh->getline)) {
$line =~ s!"$ENV{VERILATOR_ROOT}/!"!g;
$line =~ s!"$cc_dir/!"!g;
$line =~ s!obj_dbg/verilog.y$!verilog.y!g;
push @lines, $line;
}
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
$ofh->print(@lines);
}
####################################################################### #######################################################################
# .dat file callbacks # .dat file callbacks
sub exclude_branch_regexp {
$Exclude_Branch_Regexp = shift;
}
sub exclude_line_regexp { sub exclude_line_regexp {
$Exclude_Line_Regexp = shift; $Exclude_Line_Regexp = shift;
} }
sub remove_gcda_regexp {
$Remove_Gcda_Regexp = shift;
}
sub remove_source { sub remove_source {
my @srcs = @_; my @srcs = @_;
push @Remove_Sources, @srcs; push @Remove_Sources, @srcs;
} }
sub source_globs { sub source_globs {
my @dirs = @_; my @dirs = @_;
push @Source_Globs, @dirs; push @Source_Globs, @dirs;
@@ -206,6 +425,15 @@ sub run {
($status == 0) or die "%Error: Command Failed $command, $status, stopped"; ($status == 0) or die "%Error: Command Failed $command, $status, stopped";
} }
our $_Travis_Action;
sub travis_fold_start {
$_Travis_Action = shift;
print "travis_fold:start:$_Travis_Action\n";
}
sub travis_fold_end {
print "travis_fold:end:$_Travis_Action\n";
}
####################################################################### #######################################################################
__END__ __END__
@@ -231,13 +459,30 @@ This will rebuild the current object files.
=over 4 =over 4
=item --hashset I<hashset>
Pass test hashset onto driver.pl test harness.
=item --help =item --help
Displays this message and program version and exits. Displays this message and program version and exits.
=item -stage I<stage> =item --scenarios I<scenarios>
Runs a specific stage (see the script). Pass test scenarios onto driver.pl test harness.
=item --stages I<stage>
Runs a specific stage or range of stages (see the script).
=item --no-stop
Do not stop collecting data if tests fail.
=item --test I<test_regress_test_name>
Instead of normal regressions, run the specified test. May be specified
multiple times for multiple tests.
=back =back
+17 -2
View File
@@ -21,7 +21,8 @@ source_globs("src/*.cpp",
"include/*/*.c", "include/*/*.c",
); );
remove_source("/usr/include/*"); # Note *'s are removed when using fastcov
remove_source("/usr/*");
remove_source("*/include/sysc/*"); remove_source("*/include/sysc/*");
remove_source("*/V3ClkGater.cpp"); remove_source("*/V3ClkGater.cpp");
remove_source("*/V3ClkGater.h"); remove_source("*/V3ClkGater.h");
@@ -37,7 +38,21 @@ remove_source("*include/gtkwave/*");
remove_source("*test_regress/*"); remove_source("*test_regress/*");
remove_source("*examples/*"); remove_source("*examples/*");
# Remove collected coverage on each little test main file
# Would just be removed with remove_source in later step
remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/); # Exclude line entirely, also excludes from function and branch coverage
exclude_line_regexp(qr/(\bv3fatalSrc\b
|\bfatalSrc\b
|\bVL_UNCOVERABLE\b
|\bVL_FATAL
|\bUASSERT
|\bERROR_RSVD_WORD
|\bV3ERROR_NA
|\bUINFO\b)/x);
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\))/x);
1; 1;
+744
View File
@@ -0,0 +1,744 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# Copyright 2018-present, Bryan Gillespie
"""
Author: Bryan Gillespie
https://github.com/RPGillespie6/fastcov
A massively parallel gcov wrapper for generating intermediate coverage formats fast
The goal of fastcov is to generate code coverage intermediate formats as fast as possible,
even for large projects with hundreds of gcda objects. The intermediate formats may then be
consumed by a report generator such as lcov's genhtml, or a dedicated frontend such as coveralls.
Sample Usage:
$ cd build_dir
$ ./fastcov.py --zerocounters
$ <run unit tests>
$ ./fastcov.py --exclude /usr/include test/ --lcov -o report.info
$ genhtml -o code_coverage report.info
"""
import re
import os
import sys
import glob
import json
import time
import logging
import argparse
import threading
import subprocess
import multiprocessing
FASTCOV_VERSION = (1,7)
MINIMUM_PYTHON = (3,5)
MINIMUM_GCOV = (9,0,0)
# Interesting metrics
START_TIME = time.monotonic()
GCOVS_TOTAL = 0
GCOVS_SKIPPED = 0
# For when things go wrong...
# Start error codes at 3 because 1-2 are special
# See https://stackoverflow.com/a/1535733/2516916
EXIT_CODE = 0
EXIT_CODES = {
"gcov_version": 3,
"python_version": 4,
"unsupported_coverage_format": 5,
"excl_not_found": 6,
}
# Disable all logging in case developers are using this as a module
logging.disable(level=logging.CRITICAL)
class FastcovFormatter(logging.Formatter):
def format(self, record):
record.levelname = record.levelname.lower()
log_message = super(FastcovFormatter, self).format(record)
return "[{:.3f}s] {}".format(stopwatch(), log_message)
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
def setExitCode(key):
global EXIT_CODE
EXIT_CODE = EXIT_CODES[key]
def incrementCounters(total, skipped):
global GCOVS_TOTAL
global GCOVS_SKIPPED
GCOVS_TOTAL += total
GCOVS_SKIPPED += skipped
def stopwatch():
"""Return number of seconds since last time this was called."""
global START_TIME
end_time = time.monotonic()
delta = end_time - START_TIME
START_TIME = end_time
return delta
def parseVersionFromLine(version_str):
"""Given a string containing a dotted integer version, parse out integers and return as tuple."""
version = re.search(r'(\d+\.\d+\.\d+)', version_str)
if not version:
return (0,0,0)
return tuple(map(int, version.group(1).split(".")))
def getGcovVersion(gcov):
p = subprocess.Popen([gcov, "-v"], stdout=subprocess.PIPE)
output = p.communicate()[0].decode('UTF-8')
p.wait()
return parseVersionFromLine(output.split("\n")[0])
def removeFiles(files):
for file in files:
os.remove(file)
def getFilteredCoverageFiles(coverage_files, exclude):
def excludeGcda(gcda):
for ex in exclude:
if ex in gcda:
logging.debug("Omitting %s due to '--exclude-gcda %s'", gcda, ex)
return False
return True
return list(filter(excludeGcda, coverage_files))
def findCoverageFiles(cwd, coverage_files, use_gcno):
coverage_type = "user provided"
if not coverage_files:
coverage_type = "gcno" if use_gcno else "gcda"
coverage_files = glob.glob(os.path.join(os.path.abspath(cwd), "**/*." + coverage_type), recursive=True)
logging.info("Found {} coverage files ({})".format(len(coverage_files), coverage_type))
logging.debug("Coverage files found:\n %s", "\n ".join(coverage_files))
return coverage_files
def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
base_report = {"sources": {}}
gcovs_total = 0
gcovs_skipped = 0
gcov_args = "-it"
if args.branchcoverage or args.xbranchcoverage:
gcov_args += "b"
p = subprocess.Popen([args.gcov, gcov_args] + chunk, cwd=args.cdirectory, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
for line in iter(p.stdout.readline, b''):
intermediate_json = json.loads(line.decode(sys.stdout.encoding))
intermediate_json_files = processGcovs(args.cdirectory, intermediate_json["files"], gcov_filter_options)
for f in intermediate_json_files:
distillSource(f, base_report["sources"], args.test_name, args.xbranchcoverage)
gcovs_total += len(intermediate_json["files"])
gcovs_skipped += len(intermediate_json["files"]) - len(intermediate_json_files)
p.wait()
data_q.put(base_report)
metrics_q.put((gcovs_total, gcovs_skipped))
def processGcdas(args, coverage_files, gcov_filter_options):
chunk_size = max(args.minimum_chunk, int(len(coverage_files) / args.jobs) + 1)
processes = []
data_q = multiprocessing.Queue()
metrics_q = multiprocessing.Queue()
for chunk in chunks(coverage_files, chunk_size):
p = multiprocessing.Process(target=gcovWorker, args=(data_q, metrics_q, args, chunk, gcov_filter_options))
processes.append(p)
p.start()
logging.info("Spawned {} gcov processes, each processing at most {} coverage files".format(len(processes), chunk_size))
fastcov_jsons = []
for p in processes:
fastcov_jsons.append(data_q.get())
incrementCounters(*metrics_q.get())
for p in processes:
p.join()
base_fastcov = fastcov_jsons.pop()
for fj in fastcov_jsons:
combineReports(base_fastcov, fj)
return base_fastcov
def shouldFilterSource(source, gcov_filter_options):
"""Returns true if the provided source file should be filtered due to CLI options, otherwise returns false."""
# If explicit sources were passed, check for match
if gcov_filter_options["sources"]:
if source not in gcov_filter_options["sources"]:
logging.debug("Filtering coverage for '%s' due to option '--source-files'", source)
return True
# Check exclude filter
for ex in gcov_filter_options["exclude"]:
if ex in source:
logging.debug("Filtering coverage for '%s' due to option '--exclude %s'", source, ex)
return True
# Check include filter
if gcov_filter_options["include"]:
included = False
for inc in gcov_filter_options["include"]:
if inc in source:
included = True
break
if not included:
logging.debug("Filtering coverage for '%s' due to option '--include %s'", source, " ".join(gcov_filter_options["include"]))
return True
return False
def filterFastcov(fastcov_json, args):
logging.info("Performing filtering operations (if applicable)")
gcov_filter_options = getGcovFilterOptions(args)
for source in list(fastcov_json["sources"].keys()):
if shouldFilterSource(source, gcov_filter_options):
del fastcov_json["sources"][source]
def processGcov(cwd, gcov, files, gcov_filter_options):
# Add absolute path
gcov["file_abs"] = os.path.abspath(os.path.join(cwd, gcov["file"]))
if shouldFilterSource(gcov["file_abs"], gcov_filter_options):
return
files.append(gcov)
logging.debug("Accepted coverage for '%s'", gcov["file_abs"])
def processGcovs(cwd, gcov_files, gcov_filter_options):
files = []
for gcov in gcov_files:
processGcov(cwd, gcov, files, gcov_filter_options)
return files
def dumpBranchCoverageToLcovInfo(f, branches):
branch_miss = 0
branch_found = 0
brda = []
for line_num, branch_counts in branches.items():
for i, count in enumerate(branch_counts):
# Branch (<line number>, <block number>, <branch number>, <taken>)
brda.append((line_num, int(i/2), i, count))
branch_miss += int(count == 0)
branch_found += 1
for v in sorted(brda):
f.write("BRDA:{},{},{},{}\n".format(*v))
f.write("BRF:{}\n".format(branch_found)) # Branches Found
f.write("BRH:{}\n".format(branch_found - branch_miss)) # Branches Hit
def dumpToLcovInfo(fastcov_json, output):
with open(output, "w") as f:
sources = fastcov_json["sources"]
for sf in sorted(sources.keys()):
for tn in sorted(sources[sf].keys()):
data = sources[sf][tn]
f.write("TN:{}\n".format(tn)) #Test Name - used mainly in conjuction with genhtml --show-details
f.write("SF:{}\n".format(sf)) #Source File
fn_miss = 0
fn = []
fnda = []
for function, fdata in data["functions"].items():
fn.append((fdata["start_line"], function)) # Function Start Line
fnda.append((fdata["execution_count"], function)) # Function Hits
fn_miss += int(fdata["execution_count"] == 0)
# NOTE: lcov sorts FN, but not FNDA.
for v in sorted(fn):
f.write("FN:{},{}\n".format(*v))
for v in sorted(fnda):
f.write("FNDA:{},{}\n".format(*v))
f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found
f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit
if data["branches"]:
dumpBranchCoverageToLcovInfo(f, data["branches"])
line_miss = 0
da = []
for line_num, count in data["lines"].items():
da.append((line_num, count))
line_miss += int(count == 0)
for v in sorted(da):
f.write("DA:{},{}\n".format(*v)) # Line
f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found
f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit
f.write("end_of_record\n")
def getSourceLines(source, fallback_encodings=[]):
"""Return a list of lines from the provided source, trying to decode with fallback encodings if the default fails."""
default_encoding = sys.getdefaultencoding()
for encoding in [default_encoding] + fallback_encodings:
try:
with open(source, encoding=encoding) as f:
return f.readlines()
except UnicodeDecodeError:
pass
logging.warning("Could not decode '{}' with {} or fallback encodings ({}); ignoring errors".format(source, default_encoding, ",".join(fallback_encodings)))
with open(source, errors="ignore") as f:
return f.readlines()
def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings):
start_line = 0
end_line = 0
# Start enumeration at line 1 because the first line of the file is line 1 not 0
for i, line in enumerate(getSourceLines(source, fallback_encodings), 1):
# Cycle through test names (likely only 1)
for test_name in fastcov_sources[source]:
fastcov_data = fastcov_sources[source][test_name]
# Build line to function dict so can quickly delete by line number
line_to_func = {}
for f in fastcov_data["functions"].keys():
l = fastcov_data["functions"][f]["start_line"]
if l not in line_to_func:
line_to_func[l] = set()
line_to_func[l].add(f)
if i in fastcov_data["branches"]:
del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw)
del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw)
if del_exclude_br or del_include_br:
del fastcov_data["branches"][i]
if "LCOV_EXCL" not in line:
continue
if "LCOV_EXCL_LINE" in line:
for key in ["lines", "branches"]:
if i in fastcov_data[key]:
del fastcov_data[key][i]
if i in line_to_func:
for key in line_to_func[i]:
if key in fastcov_data["functions"]:
del fastcov_data["functions"][key]
elif "LCOV_EXCL_START" in line:
start_line = i
elif "LCOV_EXCL_STOP" in line:
end_line = i
if not start_line:
end_line = 0
continue
for key in ["lines", "branches"]:
for line_num in list(fastcov_data[key].keys()):
if start_line <= line_num <= end_line:
del fastcov_data[key][line_num]
for line_num in range(start_line, end_line):
if line_num in line_to_func:
for key in line_to_func[line_num]:
if key in fastcov_data["functions"]:
del fastcov_data["functions"][key]
start_line = end_line = 0
elif "LCOV_EXCL_BR_LINE" in line:
if i in fastcov_data["branches"]:
del fastcov_data["branches"][i]
def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, fallback_encodings):
for source in chunk:
try:
exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings)
except FileNotFoundError:
logging.error("Could not find '%s' to scan for exclusion markers...", source)
setExitCode("excl_not_found") # Set exit code because of error
def scanExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, min_chunk_size, fallback_encodings):
chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1)
threads = []
for chunk in chunks(list(fastcov_json["sources"].keys()), chunk_size):
t = threading.Thread(target=exclMarkerWorker, args=(fastcov_json["sources"], chunk, exclude_branches_sw, include_branches_sw, fallback_encodings))
threads.append(t)
t.start()
logging.info("Spawned {} threads each scanning at most {} source files".format(len(threads), chunk_size))
for t in threads:
t.join()
def distillFunction(function_raw, functions):
function_name = function_raw["name"]
# NOTE: need to explicitly cast all counts coming from gcov to int - this is because gcov's json library
# will pass as scientific notation (i.e. 12+e45)
start_line = int(function_raw["start_line"])
execution_count = int(function_raw["execution_count"])
if function_name not in functions:
functions[function_name] = {
"start_line": start_line,
"execution_count": execution_count
}
else:
functions[function_name]["execution_count"] += execution_count
def emptyBranchSet(branch1, branch2):
return (branch1["count"] == 0 and branch2["count"] == 0)
def matchingBranchSet(branch1, branch2):
return (branch1["count"] == branch2["count"])
def filterExceptionalBranches(branches):
filtered_branches = []
exception_branch = False
for i in range(0, len(branches), 2):
if i+1 >= len(branches):
filtered_branches.append(branches[i])
break
# Filter exceptional branch noise
if branches[i+1]["throw"]:
exception_branch = True
continue
# Filter initializer list noise
if exception_branch and emptyBranchSet(branches[i], branches[i+1]) and len(filtered_branches) >= 2 and matchingBranchSet(filtered_branches[-1], filtered_branches[-2]):
return []
filtered_branches.append(branches[i])
filtered_branches.append(branches[i+1])
return filtered_branches
def distillLine(line_raw, lines, branches, include_exceptional_branches):
line_number = int(line_raw["line_number"])
count = int(line_raw["count"])
if line_number not in lines:
lines[line_number] = count
else:
lines[line_number] += count
# Filter out exceptional branches by default unless requested otherwise
if not include_exceptional_branches:
line_raw["branches"] = filterExceptionalBranches(line_raw["branches"])
# Increment all branch counts
for i, branch in enumerate(line_raw["branches"]):
if line_number not in branches:
branches[line_number] = []
blen = len(branches[line_number])
glen = len(line_raw["branches"])
if blen < glen:
branches[line_number] += [0] * (glen - blen)
branches[line_number][i] += int(branch["count"])
def distillSource(source_raw, sources, test_name, include_exceptional_branches):
source_name = source_raw["file_abs"]
if source_name not in sources:
sources[source_name] = {
test_name: {
"functions": {},
"branches": {},
"lines": {}
}
}
for function in source_raw["functions"]:
distillFunction(function, sources[source_name][test_name]["functions"])
for line in source_raw["lines"]:
distillLine(line, sources[source_name][test_name]["lines"], sources[source_name][test_name]["branches"], include_exceptional_branches)
def dumpToJson(intermediate, output):
with open(output, "w") as f:
json.dump(intermediate, f)
def getGcovFilterOptions(args):
return {
"sources": set([os.path.abspath(s) for s in args.sources]), #Make paths absolute, use set for fast lookups
"include": args.includepost,
"exclude": args.excludepost,
}
def addDicts(dict1, dict2):
"""Add dicts together by value. i.e. addDicts({"a":1,"b":0}, {"a":2}) == {"a":3,"b":0}."""
result = {k:v for k,v in dict1.items()}
for k,v in dict2.items():
if k in result:
result[k] += v
else:
result[k] = v
return result
def addLists(list1, list2):
"""Add lists together by value. i.e. addLists([1,1], [2,2]) == [3,3]."""
# Find big list and small list
blist, slist = list(list2), list(list1)
if len(list1) > len(list2):
blist, slist = slist, blist
# Overlay small list onto big list
for i, b in enumerate(slist):
blist[i] += b
return blist
def combineReports(base, overlay):
for source, scov in overlay["sources"].items():
# Combine Source Coverage
if source not in base["sources"]:
base["sources"][source] = scov
continue
for test_name, tcov in scov.items():
# Combine Source Test Name Coverage
if test_name not in base["sources"][source]:
base["sources"][source][test_name] = tcov
continue
# Drill down and create convenience variable
base_data = base["sources"][source][test_name]
# Combine Line Coverage
base_data["lines"] = addDicts(base_data["lines"], tcov["lines"])
# Combine Branch Coverage
for branch, cov in tcov["branches"].items():
if branch not in base_data["branches"]:
base_data["branches"][branch] = cov
else:
base_data["branches"][branch] = addLists(base_data["branches"][branch], cov)
# Combine Function Coverage
for function, cov in tcov["functions"].items():
if function not in base_data["functions"]:
base_data["functions"][function] = cov
else:
base_data["functions"][function]["execution_count"] += cov["execution_count"]
def parseInfo(path):
"""Parse an lcov .info file into fastcov json."""
fastcov_json = {
"sources": {}
}
with open(path) as f:
for line in f:
if line.startswith("TN:"):
current_test_name = line[3:].strip()
elif line.startswith("SF:"):
current_sf = line[3:].strip()
fastcov_json["sources"][current_sf] = {
current_test_name: {
"functions": {},
"branches": {},
"lines": {},
}
}
current_data = fastcov_json["sources"][current_sf][current_test_name]
elif line.startswith("FN:"):
line_num, function_name = line[3:].strip().split(",")
current_data["functions"][function_name] = {}
current_data["functions"][function_name]["start_line"] = int(line_num)
elif line.startswith("FNDA:"):
count, function_name = line[5:].strip().split(",")
current_data["functions"][function_name]["execution_count"] = int(count)
elif line.startswith("DA:"):
line_num, count = line[3:].strip().split(",")
current_data["lines"][line_num] = int(count)
elif line.startswith("BRDA:"):
branch_tokens = line[5:].strip().split(",")
line_num, count = branch_tokens[0], branch_tokens[-1]
if line_num not in current_data["branches"]:
current_data["branches"][line_num] = []
current_data["branches"][line_num].append(int(count))
return fastcov_json
def convertKeysToInt(report):
for source in report["sources"].keys():
for test_name in report["sources"][source].keys():
report_data = report["sources"][source][test_name]
report_data["lines"] = {int(k):v for k,v in report_data["lines"].items()}
report_data["branches"] = {int(k):v for k,v in report_data["branches"].items()}
def parseAndCombine(paths):
base_report = {}
for path in paths:
if path.endswith(".json"):
with open(path) as f:
report = json.load(f)
elif path.endswith(".info"):
report = parseInfo(path)
else:
logging.error("Currently only fastcov .json and lcov .info supported for combine operations, aborting due to %s...\n", path)
sys.exit(EXIT_CODES["unsupported_coverage_format"])
# In order for sorting to work later when we serialize,
# make sure integer keys are int
convertKeysToInt(report)
if not base_report:
base_report = report
logging.info("Setting {} as base report".format(path))
else:
combineReports(base_report, report)
logging.info("Adding {} to base report".format(path))
return base_report
def getCombineCoverage(args):
logging.info("Performing combine operation")
fastcov_json = parseAndCombine(args.combine)
filterFastcov(fastcov_json, args)
return fastcov_json
def getGcovCoverage(args):
# Need at least python 3.5 because of use of recursive glob
checkPythonVersion(sys.version_info[0:2])
# Need at least gcov 9.0.0 because that's when gcov JSON and stdout streaming was introduced
checkGcovVersion(getGcovVersion(args.gcov))
# Get list of gcda files to process
coverage_files = findCoverageFiles(args.directory, args.coverage_files, args.use_gcno)
# If gcda/gcno filtering is enabled, filter them out now
if args.excludepre:
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
# We "zero" the "counters" by simply deleting all gcda files
if args.zerocounters:
removeFiles(coverage_files)
logging.info("Removed {} .gcda files".format(len(coverage_files)))
sys.exit()
# Fire up one gcov per cpu and start processing gcdas
gcov_filter_options = getGcovFilterOptions(args)
fastcov_json = processGcdas(args, coverage_files, gcov_filter_options)
# Summarize processing results
logging.info("Processed {} .gcov files ({} total, {} skipped)".format(GCOVS_TOTAL - GCOVS_SKIPPED, GCOVS_TOTAL, GCOVS_SKIPPED))
logging.debug("Final report will contain coverage for the following %d source files:\n %s", len(fastcov_json["sources"]), "\n ".join(fastcov_json["sources"]))
return fastcov_json
def dumpFile(fastcov_json, args):
if args.lcov:
dumpToLcovInfo(fastcov_json, args.output)
logging.info("Created lcov info file '{}'".format(args.output))
else:
dumpToJson(fastcov_json, args.output)
logging.info("Created fastcov json file '{}'".format(args.output))
def tupleToDotted(tup):
return ".".join(map(str, tup))
def parseArgs():
parser = argparse.ArgumentParser(description='A parallel gcov wrapper for fast coverage report generation')
parser.add_argument('-z', '--zerocounters', dest='zerocounters', action="store_true", help='Recursively delete all gcda files')
# Enable Branch Coverage
parser.add_argument('-b', '--branch-coverage', dest='branchcoverage', action="store_true", help='Include only the most useful branches in the coverage report.')
parser.add_argument('-B', '--exceptional-branch-coverage', dest='xbranchcoverage', action="store_true", help='Include ALL branches in the coverage report (including potentially noisy exceptional branches).')
parser.add_argument('-A', '--exclude-br-lines-starting-with', dest='exclude_branches_sw', nargs="+", metavar='', default=[], help='Exclude branches from lines starting with one of the provided strings (i.e. assert, return, etc.)')
parser.add_argument('-a', '--include-br-lines-starting-with', dest='include_branches_sw', nargs="+", metavar='', default=[], help='Include only branches from lines starting with one of the provided strings (i.e. if, else, while, etc.)')
parser.add_argument('-X', '--skip-exclusion-markers', dest='skip_exclusion_markers', action="store_true", help='Skip reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
parser.add_argument('-x', '--scan-exclusion-markers', dest='scan_exclusion_markers', action="store_true", help='(Combine operations) Force reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
# Capture untested file coverage as well via gcno
parser.add_argument('-n', '--process-gcno', dest='use_gcno', action="store_true", help='Process both gcno and gcda coverage files. This option is useful for capturing untested files in the coverage report.')
# Filtering Options
parser.add_argument('-s', '--source-files', dest='sources', nargs="+", metavar='', default=[], help='Filter: Specify exactly which source files should be included in the final report. Paths must be either absolute or relative to current directory.')
parser.add_argument('-e', '--exclude', dest='excludepost', nargs="+", metavar='', default=[], help='Filter: Exclude source files from final report if they contain one of the provided substrings (i.e. /usr/include test/, etc.)')
parser.add_argument('-i', '--include', dest='includepost', nargs="+", metavar='', default=[], help='Filter: Only include source files in final report that contain one of the provided substrings (i.e. src/ etc.)')
parser.add_argument('-f', '--gcda-files', dest='coverage_files', nargs="+", metavar='', default=[], help='Filter: Specify exactly which gcda or gcno files should be processed. Note that specifying gcno causes both gcno and gcda to be processed.')
parser.add_argument('-E', '--exclude-gcda', dest='excludepre', nargs="+", metavar='', default=[], help='Filter: Exclude gcda or gcno files from being processed via simple find matching (not regex)')
parser.add_argument('-g', '--gcov', dest='gcov', default='gcov', help='Which gcov binary to use')
parser.add_argument('-d', '--search-directory', dest='directory', default=".", help='Base directory to recursively search for gcda files (default: .)')
parser.add_argument('-c', '--compiler-directory', dest='cdirectory', default=".", help='Base directory compiler was invoked from (default: .) \
This needs to be set if invoking fastcov from somewhere other than the base compiler directory.')
parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=multiprocessing.cpu_count(), help='Number of parallel gcov to spawn (default: {}).'.format(multiprocessing.cpu_count()))
parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \
If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.')
parser.add_argument('-F', '--fallback-encodings', dest='fallback_encodings', nargs="+", metavar='', default=[], help='List of encodings to try if opening a source file with the default fails (i.e. latin1, etc.). This option is not usually needed.')
parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json')
parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)')
parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout')
parser.add_argument('-t', '--test-name', dest='test_name', default="", help='Specify a test name for the coverage. Equivalent to lcov\'s `-t`.')
parser.add_argument('-C', '--add-tracefile', dest='combine', nargs="+", help='Combine multiple coverage files into one. If this flag is specified, fastcov will do a combine operation instead invoking gcov. Equivalent to lcov\'s `-a`.')
parser.add_argument('-V', '--verbose', dest="verbose", action="store_true", help="Print more detailed information about what fastcov is doing")
parser.add_argument('-v', '--version', action="version", version='%(prog)s {version}'.format(version=__version__), help="Show program's version number and exit")
args = parser.parse_args()
return args
def checkPythonVersion(version):
"""Exit if the provided python version is less than the supported version."""
if version < MINIMUM_PYTHON:
sys.stderr.write("Minimum python version {} required, found {}\n".format(tupleToDotted(MINIMUM_PYTHON), tupleToDotted(version)))
sys.exit(EXIT_CODES["python_version"])
def checkGcovVersion(version):
"""Exit if the provided gcov version is less than the supported version."""
if version < MINIMUM_GCOV:
sys.stderr.write("Minimum gcov version {} required, found {}\n".format(tupleToDotted(MINIMUM_GCOV), tupleToDotted(version)))
sys.exit(EXIT_CODES["gcov_version"])
def setupLogging(quiet, verbose):
handler = logging.StreamHandler()
handler.setFormatter(FastcovFormatter("[%(levelname)s]: %(message)s"))
root = logging.getLogger()
root.setLevel(logging.INFO)
root.addHandler(handler)
if not quiet:
logging.disable(level=logging.NOTSET) # Re-enable logging
if verbose:
root.setLevel(logging.DEBUG)
def main():
args = parseArgs()
# Setup logging
setupLogging(args.quiet, args.verbose)
# Get report from appropriate source
if args.combine:
fastcov_json = getCombineCoverage(args)
skip_exclusion_markers = not args.scan_exclusion_markers
else:
fastcov_json = getGcovCoverage(args)
skip_exclusion_markers = args.skip_exclusion_markers
# Scan for exclusion markers
if not skip_exclusion_markers:
scanExclusionMarkers(fastcov_json, args.jobs, args.exclude_branches_sw, args.include_branches_sw, args.minimum_chunk, args.fallback_encodings)
logging.info("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"])))
# Dump to desired file format
dumpFile(fastcov_json, args)
# If there was an error along the way, but we still completed the pipeline...
if EXIT_CODE:
sys.exit(EXIT_CODE)
# Set package version... it's way down here so that we can call tupleToDotted
__version__ = tupleToDotted(FASTCOV_VERSION)
if __name__ == '__main__':
main()
-257
View File
@@ -1,257 +0,0 @@
#!/usr/bin/env perl
# See copyright, etc in below POD section.
######################################################################
use warnings;
use Getopt::Long;
#use Data::Dumper; $Data::Dumper::Indent=1; $Data::Dumper::Sortkeys=1; #Debug
use IO::File;
use IO::Dir;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $VERSION = '0.001';
our $Opt_Widen = 1;
#======================================================================
# main
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"help" => sub { print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval => 0,
output=>\*STDOUT, -noperldoc=>1); },
"narrow!" => sub { $Opt_Widen = 0; },
"version" => sub { print "Version $VERSION\n"; exit(0); },
"widen!" => sub { $Opt_Widen = 1; }, # Default, undocumented
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
)) {
die "%Error: Bad usage, try 'git_untabify --help'\n";
}
read_patch();
#######################################################################
sub read_patch {
my $filename = undef;
my $lineno = 0;
my $hunk = 0;
my $editlines = {};
while (defined(my $line = <STDIN>)) {
chomp $line;
if ($line =~ m!^\+\+\+ b/(.*)!) {
find_edits($editlines);
edit_file($filename, $editlines);
$filename = $1;
$lineno = 0;
$editlines = {};
print "FILE $filename\n" if $Debug;
}
elsif ($line =~ m!^@@ -?[0-9]+,?[0-9]* \+?([0-9]+)!) {
$lineno = $1 - 1;
++$hunk;
print " LINE $1 $line" if $Debug;
}
elsif ($line =~ m!^ !) {
++$lineno;
$editlines->{$lineno} = {line => $line,
hunk => $hunk,
user_edit => 0, };
}
elsif ($line =~ m!^\+!) {
++$lineno;
print " $lineno: $line" if $Debug;
$editlines->{$lineno} = {line => $line,
hunk => $hunk,
user_edit => 1, };
}
}
find_edits($editlines);
edit_file($filename, $editlines);
}
sub find_edits {
my $editlines = shift;
# Expand edit regions so if have edited line, non-edited line, edited
# line, we will tab expand the middle ones.
my %hunk_firstlines;
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_firstlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
my %hunk_lastlines;
foreach my $lineno (sort {$b <=> $a} keys %$editlines) {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_lastlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
if ($Opt_Widen) {
# Expand to include }'s that finish basic block
foreach my $hunk (keys %hunk_lastlines) {
while (my $lineno = $hunk_lastlines{$hunk}) {
++$lineno;
if (($editlines->{$lineno}{line} || "")
=~ /^[+ ]\s+}[ \t};]*$/) {
$hunk_lastlines{$hunk} = $lineno;
} else {
last;
}
}
}
# Expand to always untabify at least 3 lines (so that future diff will
# have non-tabs within a edit hunk distance
foreach my $hunk (keys %hunk_firstlines) {
if ($hunk_firstlines{$hunk} == $hunk_lastlines{$hunk}) {
--$hunk_firstlines{$hunk};
++$hunk_lastlines{$hunk};
}
elsif ($hunk_firstlines{$hunk}+1 == $hunk_lastlines{$hunk}) {
++$hunk_lastlines{$hunk};
}
}
}
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
if (($editlines->{$lineno}{line}||"") =~ /\t/) {
my $hunk = $editlines->{$lineno}{hunk};
if ($hunk_firstlines{$hunk} <= $lineno && $hunk_lastlines{$hunk} >= $lineno) {
$editlines->{$lineno}{editit} = 1;
}
}
}
}
sub edit_file {
my $filename = shift;
my $editlines = shift;
my @editits;
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
push @editits, $lineno if $editlines->{$lineno}{editit};
}
return if $#editits < 0;
if (ignore($filename)) {
print "%Warning: Ignoring $filename\n";
return;
}
print "Edit $filename ",join(",",@editits),"\n";
my $lineno = 0;
my @out;
{
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
while (defined(my $line = $fh->getline)) {
++$lineno;
if ($editlines->{$lineno}{editit}) {
print $line;
push @out, untabify($line);
} else {
push @out, $line;
}
}
$fh->close;
}
{
my $fh = IO::File->new(">${filename}.untab") or die "%Error: $! ${filename}.untab,";
$fh->print(join('',@out));
$fh->close;
my ($dev,$ino,$mode) = stat($filename);
chmod $mode, "${filename}.untab";
}
rename("${filename}.untab", $filename) or die "%Error: $! ${filename}.untab,";
}
sub ignore {
my $filename = shift;
return 1 if ($filename =~ /(Makefile|\.mk)/);
return 1 if ($filename =~ /\.(y|l|out|vcd)$/);
return 1 if ($filename =~ /gtkwave/);
#
return 0 if ($filename =~ /\.(sv|v|vh|svh|h|vc|cpp|pl)$/);
return 0;
}
sub untabify {
my $line = shift;
my $out = "";
my $col = 0;
foreach my $c (split //, $line) {
if ($c eq "\t") {
my $destcol = int(($col+8)/8)*8;
while ($col < $destcol) { ++$col; $out .= " "; }
} else {
$out .= $c;
$col++;
}
}
return $out;
}
#######################################################################
__END__
=pod
=head1 NAME
git_untabify - Pipe a git diff report and untabify differences
=head1 SYNOPSIS
git diff a..b | git_untabify
=head1 DESCRIPTION
Take a patch file, and edit the files in the destination patch list to
untabify the related patch lines.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=item --narrow
Only edit lines which the user edited.
If not provided, also edit other lines within at least a 3 line area around
the edit, and between any edits within the same hunk.
=item --version
Displays program version and exits.
=back
=head1 DISTRIBUTION
Copyright 2005-2020 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
=head1 AUTHORS
Wilson Snyder <[email protected]>
=head1 SEE ALSO
=cut
######################################################################
### Local Variables:
### compile-command: "./git_untabify "
### End:
+1 -1
View File
@@ -84,7 +84,7 @@ maintainer-copy::
clean mostlyclean distclean maintainer-clean:: clean mostlyclean distclean maintainer-clean::
-rm -rf obj_* *.log *.dmp *.vpd core -rm -rf obj_* *.log *.dmp *.vpd core
-rm -f *.o *.d perlxsi.c *_gen_* -rm -f *.o *.d perlxsi.c *_gen_*
-rm -f *__gen* -rm -f *__gen* obj_*
-rm -f .objcache* -rm -f .objcache*
distclean maintainer-clean:: distclean maintainer-clean::
+9 -6
View File
@@ -211,11 +211,13 @@ RAW_OBJS = \
V3LinkCells.o \ V3LinkCells.o \
V3LinkDot.o \ V3LinkDot.o \
V3LinkJump.o \ V3LinkJump.o \
V3LinkInc.o \
V3LinkLValue.o \ V3LinkLValue.o \
V3LinkLevel.o \ V3LinkLevel.o \
V3LinkParse.o \ V3LinkParse.o \
V3LinkResolve.o \ V3LinkResolve.o \
V3Localize.o \ V3Localize.o \
V3MergeCond.o \
V3Name.o \ V3Name.o \
V3Number.o \ V3Number.o \
V3Options.o \ V3Options.o \
@@ -246,6 +248,7 @@ RAW_OBJS = \
V3Undriven.o \ V3Undriven.o \
V3Unknown.o \ V3Unknown.o \
V3Unroll.o \ V3Unroll.o \
V3Waiver.o \
V3Width.o \ V3Width.o \
V3WidthSel.o \ V3WidthSel.o \
@@ -287,21 +290,21 @@ V3Number_test: V3Number_test.o
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp $(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
%.o: %.cpp %.o: %.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
%.o: %.c %.o: %.c
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< $(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
#### Generated files #### Generated files
-1
View File
@@ -50,7 +50,6 @@ protected:
class ActiveNamer : public ActiveBaseVisitor { class ActiveNamer : public ActiveBaseVisitor {
private: private:
typedef std::map<string, AstActive*> ActiveNameMap;
// STATE // STATE
AstScope* m_scopep; // Current scope to add statement to AstScope* m_scopep; // Current scope to add statement to
AstActive* m_iActivep; // For current scope, the IActive we're building AstActive* m_iActivep; // For current scope, the IActive we're building
+2 -8
View File
@@ -89,7 +89,7 @@ private:
} }
// Move the SENTREE for each active up to the global level. // Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical // This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp); AstSenTree* wantp = m_finder.getSenTree(sensesp);
UINFO(4, " lookdone\n"); UINFO(4, " lookdone\n");
if (wantp != sensesp) { if (wantp != sensesp) {
// Move the active's contents to the other active // Move the active's contents to the other active
@@ -108,7 +108,7 @@ private:
// No need to do statements under it, they're already moved. // No need to do statements under it, they're already moved.
// iterateChildren(nodep); // iterateChildren(nodep);
} }
virtual void visit(AstInitial* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
@@ -117,15 +117,9 @@ private:
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstAlways* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE"); nodep->v3fatalSrc("Node should have been under ACTIVE");
} }
virtual void visit(AstFinal* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been deleted");
}
//-------------------- //--------------------
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
-3
View File
@@ -23,9 +23,6 @@
#include "V3GraphDfa.h" #include "V3GraphDfa.h"
#include "V3Stats.h" #include "V3Stats.h"
#include <cstdarg>
#include <iomanip>
//###################################################################### //######################################################################
// Assert class functions // Assert class functions
-3
View File
@@ -23,9 +23,6 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3AssertPre.h" #include "V3AssertPre.h"
#include <cstdarg>
#include <iomanip>
//###################################################################### //######################################################################
// Assert class functions // Assert class functions
+5 -7
View File
@@ -23,7 +23,6 @@
#include "V3Broken.h" #include "V3Broken.h"
#include "V3String.h" #include "V3String.h"
#include <cstdarg>
#include <iomanip> #include <iomanip>
#include <memory> #include <memory>
@@ -727,7 +726,7 @@ void AstNode::deleteNode() {
this->m_op4p = reinterpret_cast<AstNode*>(0x1); this->m_op4p = reinterpret_cast<AstNode*>(0x1);
if ( if (
#if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS) #if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS)
1 true
#else #else
!v3Global.opt.debugLeak() !v3Global.opt.debugLeak()
#endif #endif
@@ -1129,6 +1128,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
*logsp << "No changes since last dump!\n"; *logsp << "No changes since last dump!\n";
} else { } else {
dumpTree(*logsp); dumpTree(*logsp);
editCountSetLast(); // Next dump can indicate start from here
} }
} }
} }
@@ -1139,13 +1139,11 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
// set by other steps if it is called in the middle of other operations // set by other steps if it is called in the middle of other operations
if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp); if (AstNetlist* netp = VN_CAST(this, Netlist)) V3Broken::brokenAll(netp);
} }
// Next dump can indicate start from here
editCountSetLast();
} }
void AstNode::v3errorEndFatal(std::ostringstream& str) const { void AstNode::v3errorEndFatal(std::ostringstream& str) const {
v3errorEnd(str); v3errorEnd(str);
assert(0); assert(0); // LCOV_EXCL_LINE
VL_UNREACHABLE VL_UNREACHABLE
} }
@@ -1154,10 +1152,10 @@ string AstNode::locationStr() const {
const AstNode* backp = this; const AstNode* backp = this;
int itmax = 10000; // Max iterations before giving up on location search int itmax = 10000; // Max iterations before giving up on location search
while (backp) { while (backp) {
if (--itmax < 0) { if (VL_UNCOVERABLE(--itmax < 0)) {
// Likely some circular back link, and V3Ast is trying to report a low-level error // Likely some circular back link, and V3Ast is trying to report a low-level error
UINFO(1, "Ran out of iterations finding locationStr on " << backp << endl); UINFO(1, "Ran out of iterations finding locationStr on " << backp << endl);
return ""; return ""; // LCOV_EXCL_LINE
} }
const AstScope* scopep; const AstScope* scopep;
if ((scopep = VN_CAST_CONST(backp, Scope))) { if ((scopep = VN_CAST_CONST(backp, Scope))) {
+86 -39
View File
@@ -193,12 +193,14 @@ class AstCFuncType {
public: public:
enum en { enum en {
FT_NORMAL, FT_NORMAL,
TRACE_REGISTER,
TRACE_INIT, TRACE_INIT,
TRACE_INIT_SUB, TRACE_INIT_SUB,
TRACE_FULL, TRACE_FULL,
TRACE_FULL_SUB, TRACE_FULL_SUB,
TRACE_CHANGE, TRACE_CHANGE,
TRACE_CHANGE_SUB TRACE_CHANGE_SUB,
TRACE_CLEANUP
}; };
enum en m_e; enum en m_e;
inline AstCFuncType() inline AstCFuncType()
@@ -210,10 +212,7 @@ public:
: m_e(static_cast<en>(_e)) {} : m_e(static_cast<en>(_e)) {}
operator en() const { return m_e; } operator en() const { return m_e; }
// METHODS // METHODS
bool isTrace() const { bool isTrace() const { return m_e != FT_NORMAL; }
return (m_e == TRACE_INIT || m_e == TRACE_INIT_SUB || m_e == TRACE_FULL
|| m_e == TRACE_FULL_SUB || m_e == TRACE_CHANGE || m_e == TRACE_CHANGE_SUB);
}
}; };
inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) { inline bool operator==(const AstCFuncType& lhs, const AstCFuncType& rhs) {
return lhs.m_e == rhs.m_e; return lhs.m_e == rhs.m_e;
@@ -258,7 +257,7 @@ public:
case ET_HIGHEDGE: return ET_LOWEDGE; case ET_HIGHEDGE: return ET_LOWEDGE;
case ET_LOWEDGE: return ET_HIGHEDGE; case ET_LOWEDGE: return ET_HIGHEDGE;
default: UASSERT_STATIC(0, "Inverting bad edgeType()"); default: UASSERT_STATIC(0, "Inverting bad edgeType()");
}; }
return VEdgeType::ET_ILLEGAL; return VEdgeType::ET_ILLEGAL;
} }
const char* ascii() const { const char* ascii() const {
@@ -1081,9 +1080,6 @@ public:
// - Also used to allow parameter passing up/down iterate calls // - Also used to allow parameter passing up/down iterate calls
class WidthVP; class WidthVP;
class LinkVP;
class OrderBlockNU;
class OrderVarNU;
class V3GraphVertex; class V3GraphVertex;
class VSymEnt; class VSymEnt;
@@ -1104,15 +1100,11 @@ public:
explicit VNUser(void* p) { m_u.up = p; } explicit VNUser(void* p) { m_u.up = p; }
~VNUser() {} ~VNUser() {}
// Casters // Casters
WidthVP* c() { return ((WidthVP*)m_u.up); } WidthVP* c() const { return reinterpret_cast<WidthVP*>(m_u.up); }
LinkVP* toLinkVP() { return ((LinkVP*)m_u.up); } VSymEnt* toSymEnt() const { return reinterpret_cast<VSymEnt*>(m_u.up); }
VSymEnt* toSymEnt() { return ((VSymEnt*)m_u.up); } AstNode* toNodep() const { return reinterpret_cast<AstNode*>(m_u.up); }
AstNode* toNodep() { return ((AstNode*)m_u.up); } V3GraphVertex* toGraphVertex() const { return reinterpret_cast<V3GraphVertex*>(m_u.up); }
OrderBlockNU* toOrderBlock() { return ((OrderBlockNU*)m_u.up); } int toInt() const { return m_u.ui; }
OrderVarNU* toOrderVar() { return ((OrderVarNU*)m_u.up); }
V3GraphVertex* toGraphVertex() { return ((V3GraphVertex*)m_u.up); }
inline int toInt() { return m_u.ui; }
static inline VNUser fromZero() { return VNUser(0); }
static inline VNUser fromInt(int i) { return VNUser(i); } static inline VNUser fromInt(int i) { return VNUser(i); }
}; };
@@ -1318,7 +1310,7 @@ public:
class FullValue {}; // for creator type-overload selection class FullValue {}; // for creator type-overload selection
explicit V3Hash(Illegal) { m_both = 0; } explicit V3Hash(Illegal) { m_both = 0; }
// Saving and restoring inside a userp // Saving and restoring inside a userp
explicit V3Hash(VNUser u) { m_both = u.toInt(); } explicit V3Hash(const VNUser& u) { m_both = u.toInt(); }
V3Hash operator+=(const V3Hash& rh) { V3Hash operator+=(const V3Hash& rh) {
setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval())); setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval()));
return *this; return *this;
@@ -1355,12 +1347,12 @@ public:
// Prefetch a node. // Prefetch a node.
// The if() makes it faster, even though prefetch won't fault on null pointers // The if() makes it faster, even though prefetch won't fault on null pointers
#define ASTNODE_PREFETCH(nodep) \ #define ASTNODE_PREFETCH(nodep) \
{ \ do { \
if (nodep) { \ if (nodep) { \
VL_PREFETCH_RD(&((nodep)->m_nextp)); \ VL_PREFETCH_RD(&((nodep)->m_nextp)); \
VL_PREFETCH_RD(&((nodep)->m_iterpp)); \ VL_PREFETCH_RD(&((nodep)->m_iterpp)); \
} \ } \
} } while (false)
class AstNode { class AstNode {
// v ASTNODE_PREFETCH depends on below ordering of members // v ASTNODE_PREFETCH depends on below ordering of members
@@ -1508,6 +1500,7 @@ public:
} }
bool brokeExists() const; bool brokeExists() const;
bool brokeExistsAbove() const; bool brokeExistsAbove() const;
bool brokeExistsBelow() const;
// CONSTRUCTORS // CONSTRUCTORS
virtual ~AstNode() {} virtual ~AstNode() {}
@@ -1788,20 +1781,22 @@ public:
static void dumpTreeFileGdb(const char* filenamep = NULL); static void dumpTreeFileGdb(const char* filenamep = NULL);
// METHODS - queries // METHODS - queries
// Else a $display, etc, that must be ordered with other displays
virtual bool isPure() const { return true; }
// Changes control flow, disable some optimizations // Changes control flow, disable some optimizations
virtual bool isBrancher() const { return false; } virtual bool isBrancher() const { return false; }
// Else a AstTime etc that can't be pushed out // Else a AstTime etc that can't be pushed out
virtual bool isGateOptimizable() const { return true; } virtual bool isGateOptimizable() const { return true; }
// GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf) // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isGateDedupable() const { return isGateOptimizable(); } virtual bool isGateDedupable() const { return isGateOptimizable(); }
// Else a AstTime etc that can't be substituted out // Needs verilated_heavy.h (uses std::string or some others)
virtual bool isSubstOptimizable() const { return true; } virtual bool isHeavy() const { return false; }
// Else a AstTime etc which output can't be predicted from input
virtual bool isPredictOptimizable() const { return true; }
// Else creates output or exits, etc, not unconsumed // Else creates output or exits, etc, not unconsumed
virtual bool isOutputter() const { return false; } virtual bool isOutputter() const { return false; }
// Else a AstTime etc which output can't be predicted from input
virtual bool isPredictOptimizable() const { return true; }
// Else a $display, etc, that must be ordered with other displays
virtual bool isPure() const { return true; }
// Else a AstTime etc that can't be substituted out
virtual bool isSubstOptimizable() const { return true; }
// isUnlikely handles $stop or similar statement which means an above IF // isUnlikely handles $stop or similar statement which means an above IF
// statement is unlikely to be taken // statement is unlikely to be taken
virtual bool isUnlikely() const { return false; } virtual bool isUnlikely() const { return false; }
@@ -1998,6 +1993,43 @@ public:
virtual bool same(const AstNode*) const { return true; } virtual bool same(const AstNode*) const { return true; }
}; };
class AstNodeQuadop : public AstNodeMath {
// Quaternary math
public:
AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs)
: AstNodeMath(t, fl) {
setOp1p(lhs);
setOp2p(rhs);
setOp3p(ths);
setOp4p(fhs);
}
ASTNODE_BASE_FUNCS(NodeQuadop)
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
AstNode* thsp() const { return op3p(); }
AstNode* fhsp() const { return op4p(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
void fhsp(AstNode* nodep) { return setOp4p(nodep); }
// METHODS
// Set out to evaluation of a AstConst'ed
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths, const V3Number& fhs)
= 0;
virtual bool cleanLhs() const = 0; // True if LHS must have extra upper bits zero
virtual bool cleanRhs() const = 0; // True if RHS must have extra upper bits zero
virtual bool cleanThs() const = 0; // True if THS must have extra upper bits zero
virtual bool cleanFhs() const = 0; // True if THS must have extra upper bits zero
virtual bool sizeMattersLhs() const = 0; // True if output result depends on lhs size
virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size
virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size
virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size
virtual int instrCount() const { return widthInstrs(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode*) const { return true; }
};
class AstNodeBiCom : public AstNodeBiop { class AstNodeBiCom : public AstNodeBiop {
// Binary math with commutative properties // Binary math with commutative properties
public: public:
@@ -2090,6 +2122,20 @@ public:
virtual bool same(const AstNode*) const { return true; } virtual bool same(const AstNode*) const { return true; }
}; };
class AstNodeProcedure : public AstNode {
// IEEE procedure: initial, final, always
public:
AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp)
: AstNode(t, fl) {
addNOp2p(bodysp);
}
ASTNODE_BASE_FUNCS(NodeProcedure)
// METHODS
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
class AstNodeStmt : public AstNode { class AstNodeStmt : public AstNode {
// Statement -- anything that's directly under a function // Statement -- anything that's directly under a function
bool m_statement; // Really a statement (e.g. not a function with return) bool m_statement; // Really a statement (e.g. not a function with return)
@@ -2323,9 +2369,8 @@ public:
virtual AstNodeDType* skipRefToEnump() const = 0; virtual AstNodeDType* skipRefToEnump() const = 0;
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthAlignBytes() const = 0; virtual int widthAlignBytes() const = 0;
virtual int
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
widthTotalBytes() const = 0; virtual int widthTotalBytes() const = 0;
virtual bool maybePointedTo() const { return true; } virtual bool maybePointedTo() const { return true; }
// Iff has a non-null refDTypep(), as generic node function // Iff has a non-null refDTypep(), as generic node function
virtual AstNodeDType* virtRefDTypep() const { return NULL; } virtual AstNodeDType* virtRefDTypep() const { return NULL; }
@@ -2429,9 +2474,8 @@ public:
} // op1 = AstMember list } // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); } void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; } bool packed() const { return m_packed; }
bool packedUnsup() const { // packed() but as don't support unpacked, presently all structs
return true; static bool packedUnsup() { return true; }
} // packed() but as don't support unpacked, presently all structs
void isFourstate(bool flag) { m_isFourstate = flag; } void isFourstate(bool flag) { m_isFourstate = flag; }
virtual bool isFourstate() const { return m_isFourstate; } virtual bool isFourstate() const { return m_isFourstate; }
void clearCache() { m_members.clear(); } void clearCache() { m_members.clear(); }
@@ -2440,7 +2484,7 @@ public:
MemberNameMap::const_iterator it = m_members.find(name); MemberNameMap::const_iterator it = m_members.find(name);
return (it == m_members.end()) ? NULL : it->second; return (it == m_members.end()) ? NULL : it->second;
} }
int lsb() const { return 0; } static int lsb() { return 0; }
int msb() const { return dtypep()->width() - 1; } // Packed classes look like arrays int msb() const { return dtypep()->width() - 1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); } VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
}; };
@@ -2482,10 +2526,8 @@ public:
virtual V3Hash sameHash() const { virtual V3Hash sameHash() const {
return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb())); return V3Hash(V3Hash(m_refDTypep), V3Hash(msb()), V3Hash(lsb()));
} }
AstNodeDType* getChildDTypep() const { return childDTypep(); } virtual AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
return VN_CAST(op1p(), NodeDType);
} // op1 = Range of variable
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); } virtual AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
@@ -2680,11 +2722,13 @@ private:
string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
string m_inlinedDots; // Dotted hierarchy flattened out string m_inlinedDots; // Dotted hierarchy flattened out
AstNodeModule* m_packagep; // Package hierarchy AstNodeModule* m_packagep; // Package hierarchy
bool m_pli; // Pli system call ($name)
public: public:
AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp)
: AstNodeStmt(t, fl, statement) : AstNodeStmt(t, fl, statement)
, m_taskp(NULL) , m_taskp(NULL)
, m_packagep(NULL) { , m_packagep(NULL)
, m_pli(false) {
setOp1p(namep); setOp1p(namep);
addNOp3p(pinsp); addNOp3p(pinsp);
} }
@@ -2692,7 +2736,8 @@ public:
: AstNodeStmt(t, fl, statement) : AstNodeStmt(t, fl, statement)
, m_taskp(NULL) , m_taskp(NULL)
, m_name(name) , m_name(name)
, m_packagep(NULL) { , m_packagep(NULL)
, m_pli(false) {
addNOp3p(pinsp); addNOp3p(pinsp);
} }
ASTNODE_BASE_FUNCS(NodeFTaskRef) ASTNODE_BASE_FUNCS(NodeFTaskRef)
@@ -2716,6 +2761,8 @@ public:
void dotted(const string& name) { m_dotted = name; } void dotted(const string& name) { m_dotted = name; }
AstNodeModule* packagep() const { return m_packagep; } AstNodeModule* packagep() const { return m_packagep; }
void packagep(AstNodeModule* nodep) { m_packagep = nodep; } void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
bool pli() const { return m_pli; }
void pli(bool flag) { m_pli = flag; }
// op1 = namep // op1 = namep
AstNode* namep() const { return op1p(); } AstNode* namep() const { return op1p(); }
// op2 = reserved for AstMethodCall // op2 = reserved for AstMethodCall
+151 -136
View File
@@ -24,7 +24,6 @@
#include "V3PartitionGraph.h" // Just for mtask dumping #include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3EmitCBase.h" #include "V3EmitCBase.h"
#include <cstdarg>
#include <iomanip> #include <iomanip>
#include <vector> #include <vector>
@@ -282,16 +281,16 @@ string AstVar::verilogKwd() const {
class AstVar::VlArgTypeRecursed { class AstVar::VlArgTypeRecursed {
public: public:
string m_oref; // To output, reference part before name, "&" bool m_isRef; // Is it a reference?
string m_osuffix; // To output, suffixed after name, "[3]" string m_type; // The base type, e.g.: "Foo_t"s
string m_oprefix; // To output, prefixed before name, "Foo_t" string m_dims; // Array dimensions, e.g.: "[3][2][1]"
void clear() { string render(const string& name) {
m_oref.clear(); string out;
m_osuffix.clear(); out += m_type;
m_oprefix.clear(); out += " ";
} out += m_isRef ? "(&" + name + ")" : name;
string refParen(const string& name) { out += m_dims;
return m_oref.empty() ? name : "(" + m_oref + " " + name + ")"; return out;
} }
}; };
@@ -301,126 +300,86 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string&
string ostatic; string ostatic;
if (isStatic() && namespc.empty()) ostatic = "static "; if (isStatic() && namespc.empty()) ostatic = "static ";
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false); VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep());
string oname; string oname;
if (named) { if (named) {
oname += " ";
if (!namespc.empty()) oname += namespc + "::"; if (!namespc.empty()) oname += namespc + "::";
oname += VIdProtect::protectIf(name(), protect()); oname += VIdProtect::protectIf(name(), protect());
} }
return ostatic + info.m_oprefix + info.refParen(oname) + info.m_osuffix; return ostatic + info.render(oname);
} }
AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool arrayed) const { bool compound) const {
VlArgTypeRecursed info;
info.m_isRef
= isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef()));
dtypep = dtypep->skipRefp(); dtypep = dtypep->skipRefp();
if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) { if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) {
VlArgTypeRecursed key = vlArgTypeRecurse(forFunc, adtypep->keyDTypep(), true); const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true);
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
string out = "VlAssocArray<"; info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">";
out += key.m_oprefix;
if (!key.m_osuffix.empty() || !key.m_oref.empty()) {
out += " " + key.m_osuffix + key.m_oref;
}
out += ", ";
out += sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
out += "> ";
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
} else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { } else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
string out = "VlQueue<"; info.m_type = "VlQueue<" + sub.m_type + ">";
out += sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
out += "> ";
VlArgTypeRecursed info;
info.m_oprefix = out;
return info;
} else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { } else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) {
VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true);
VlArgTypeRecursed info; info.m_type = "VlQueue<" + sub.m_type;
string out = "VlQueue<" + sub.m_oprefix;
if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) {
out += " " + sub.m_osuffix + sub.m_oref;
}
// + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1 // + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1
if (adtypep->boundp()) out += ", " + cvtToStr(adtypep->boundConst() + 1); if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1);
out += "> "; info.m_type += ">";
info.m_oprefix = out;
return info;
} else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) { } else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) {
VlArgTypeRecursed info; info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">";
return info;
} else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) { } else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) {
VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed); if (compound) {
info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix; v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported");
return info;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
string otype;
string oarray;
bool strtype = bdtypep->keyword() == AstBasicDTypeKwd::STRING;
string bitvec;
if (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
bitvec += "/*" + cvtToStr(dtypep->width() - 1) + ":0*/";
} }
if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound);
|| bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) info.m_type = sub.m_type;
otype += "const "; info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims;
} else if (const AstBasicDType* bdtypep = dtypep->basicp()) {
// We don't print msb()/lsb() as multidim packed would require recursion,
// and may confuse users as C++ data is stored always with bit 0 used
const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds())
? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"
: "";
if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) {
otype += "char*"; info.m_type = "const char*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { } else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) {
otype += "VerilatedScope*"; info.m_type = "const VerilatedScope*";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { } else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) {
otype += "double"; info.m_type = "double";
} else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { } else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) {
otype += "float"; info.m_type = "float";
} else if (strtype) { } else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) {
otype += "std::string"; info.m_type = "std::string";
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
otype += "CData" + bitvec; info.m_type = "CData" + bitvec;
} else if (dtypep->widthMin() <= 16) { } else if (dtypep->widthMin() <= 16) {
otype += "SData" + bitvec; info.m_type = "SData" + bitvec;
} else if (dtypep->widthMin() <= VL_IDATASIZE) { } else if (dtypep->widthMin() <= VL_IDATASIZE) {
otype += "IData" + bitvec; info.m_type = "IData" + bitvec;
} else if (dtypep->isQuad()) { } else if (dtypep->isQuad()) {
otype += "QData" + bitvec; info.m_type = "QData" + bitvec;
} else if (dtypep->isWide()) { } else if (dtypep->isWide()) {
if (arrayed) { if (compound) {
otype += "VlWide<" + cvtToStr(dtypep->widthWords()) + "> "; info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> ";
} else { } else {
otype += "WData" + bitvec; // []'s added later info.m_type += "WData" + bitvec; // []'s added later
oarray += "[" + cvtToStr(dtypep->widthWords()) + "]"; info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]";
} }
} }
string oref;
if (isDpiOpenArray()
|| (forFunc
&& (isWritable() || direction() == VDirection::REF
|| direction() == VDirection::CONSTREF || (strtype && isNonOutput())))) {
oref = "&";
}
VlArgTypeRecursed info;
info.m_oprefix = otype;
info.m_osuffix = oarray;
info.m_oref = oref;
// UINFO(9, "vlArgRec "<<"oprefix="<<info.m_oprefix<<" osuffix="<<info.m_osuffix
// <<" oref="<<info.m_oref<<" "<<dtypep);
return info;
} else { } else {
v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName()); v3fatalSrc("Unknown data type in var type emitter: " << dtypep->prettyName());
} }
UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type");
if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; }
return info;
} }
string AstVar::vlEnumType() const { string AstVar::vlEnumType() const {
@@ -472,29 +431,52 @@ string AstVar::vlEnumDir() const {
return out; return out;
} }
string AstVar::vlPropInit() const { string AstVar::vlPropDecl(string propName) const {
string out; string out;
out = vlEnumType(); // VLVT_UINT32 etc
out += ", " + vlEnumDir(); // VLVD_IN etc std::vector<int> ulims; // Unpacked dimension limits
if (AstBasicDType* bdtypep = basicp()) { for (const AstNodeDType* dtp = dtypep(); dtp;) {
out += ", VerilatedVarProps::Packed()";
out += ", " + cvtToStr(bdtypep->left()) + ", " + cvtToStr(bdtypep->right());
}
bool first = true;
for (AstNodeDType* dtp = dtypep(); dtp;) {
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstNodeArrayDType* adtypep = VN_CAST(dtp, NodeArrayDType)) { if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) {
if (first) { ulims.push_back(adtypep->declRange().left());
out += ", VerilatedVarProps::Unpacked()"; ulims.push_back(adtypep->declRange().right());
first = false;
}
out += ", " + cvtToStr(adtypep->declRange().left()) + ", "
+ cvtToStr(adtypep->declRange().right());
dtp = adtypep->subDTypep(); dtp = adtypep->subDTypep();
} else { } else {
break; // AstBasicDType - nothing below break; // AstBasicDType - nothing below
} }
} }
if (!ulims.empty()) {
out += "static const int " + propName + "__ulims[";
out += cvtToStr(ulims.size());
out += "] = {";
std::vector<int>::const_iterator it = ulims.begin();
out += cvtToStr(*it);
while (++it != ulims.end()) {
out += ", ";
out += cvtToStr(*it);
}
out += "};\n";
}
out += "static const VerilatedVarProps ";
out += propName;
out += "(";
out += vlEnumType(); // VLVT_UINT32 etc
out += ", " + vlEnumDir(); // VLVD_IN etc
if (const AstBasicDType* const bdtypep = basicp()) {
out += ", VerilatedVarProps::Packed()";
out += ", " + cvtToStr(bdtypep->left());
out += ", " + cvtToStr(bdtypep->right());
}
if (!ulims.empty()) {
out += ", VerilatedVarProps::Unpacked()";
out += ", " + cvtToStr(ulims.size() / 2);
out += ", " + propName + "__ulims";
}
out += ");\n";
return out; return out;
} }
@@ -746,6 +728,14 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) {
return nodep; return nodep;
} }
const char* AstJumpBlock::broken() const {
BROKEN_RTN(!labelp()->brokeExistsBelow());
return NULL;
}
void AstJumpBlock::cloneRelink() {
if (m_labelp->clonep()) m_labelp = m_labelp->clonep();
}
const char* AstScope::broken() const { const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists()); BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists()); BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
@@ -753,7 +743,6 @@ const char* AstScope::broken() const {
BROKEN_RTN(m_modp && !m_modp->brokeExists()); BROKEN_RTN(m_modp && !m_modp->brokeExists());
return NULL; return NULL;
} }
void AstScope::cloneRelink() { void AstScope::cloneRelink() {
if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep(); if (m_aboveScopep && m_aboveScopep->clonep()) m_aboveScopep->clonep();
if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep(); if (m_aboveCellp && m_aboveCellp->clonep()) m_aboveCellp->clonep();
@@ -761,7 +750,6 @@ void AstScope::cloneRelink() {
static_cast<AstNode*>(m_modp)->clonep(); static_cast<AstNode*>(m_modp)->clonep();
} }
} }
string AstScope::nameDotless() const { string AstScope::nameDotless() const {
string out = shortName(); string out = shortName();
string::size_type pos; string::size_type pos;
@@ -780,7 +768,6 @@ string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
if (out.substr(0, 1) == ".") out.replace(0, 1, ""); if (out.substr(0, 1) == ".") out.replace(0, 1, "");
return AstNode::prettyName(out); return AstNode::prettyName(out);
} }
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const { string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
string out; string out;
for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) { for (AstText* textp = scopeTextp; textp; textp = VN_CAST(textp->nextp(), Text)) {
@@ -977,27 +964,37 @@ void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
//====================================================================== //======================================================================
// Per-type Debugging // Per-type Debugging
// Render node address for dumps. By default this is just the address
// printed as hex, but with --dump-tree-addrids we map addresses to short
// strings with a bijection to aid human readability. Observe that this might
// not actually be a unique identifier as the address can get reused after a
// node has been freed.
static std::string nodeAddr(const AstNode* nodep) {
return v3Global.opt.dumpTreeAddrids() ? v3Global.ptrToId(nodep) : cvtToHex(nodep);
}
void AstNode::dump(std::ostream& str) const { void AstNode::dump(std::ostream& str) const {
str << typeName() << " " str << typeName() << " "
<< cvtToHex(this) << nodeAddr(this)
//<<" "<<cvtToHex(this)->m_backp //<< " " << nodeAddr(m_backp)
<< " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">") << " <e" << std::dec << editCount() << ((editCount() >= editCountLast()) ? "#>" : ">")
<< " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno() << "}"; << " {" << fileline()->filenameLetters() << std::dec << fileline()->lastLineno()
if (user1p()) str << " u1=" << cvtToHex(user1p()); << fileline()->firstColumnLetters() << "}";
if (user2p()) str << " u2=" << cvtToHex(user2p()); if (user1p()) str << " u1=" << nodeAddr(user1p());
if (user3p()) str << " u3=" << cvtToHex(user3p()); if (user2p()) str << " u2=" << nodeAddr(user2p());
if (user4p()) str << " u4=" << cvtToHex(user4p()); if (user3p()) str << " u3=" << nodeAddr(user3p());
if (user5p()) str << " u5=" << cvtToHex(user5p()); if (user4p()) str << " u4=" << nodeAddr(user4p());
if (user5p()) str << " u5=" << nodeAddr(user5p());
if (hasDType()) { if (hasDType()) {
// Final @ so less likely to by accident read it as a nodep // Final @ so less likely to by accident read it as a nodep
if (dtypep() == this) { if (dtypep() == this) {
str << " @dt=this@"; str << " @dt=this@";
} else { } else {
str << " @dt=" << cvtToHex(dtypep()) << "@"; str << " @dt=" << nodeAddr(dtypep()) << "@";
} }
if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); } if (AstNodeDType* dtp = dtypep()) { dtp->dumpSmall(str); }
} else { // V3Broken will throw an error } else { // V3Broken will throw an error
if (dtypep()) str << " %Error-dtype-exp=null,got=" << cvtToHex(dtypep()); if (dtypep()) str << " %Error-dtype-exp=null,got=" << nodeAddr(dtypep());
} }
if (name() != "") { if (name() != "") {
if (VN_IS(this, Const)) { if (VN_IS(this, Const)) {
@@ -1142,6 +1139,15 @@ void AstJumpGo::dump(std::ostream& str) const {
str << "%Error:UNLINKED"; str << "%Error:UNLINKED";
} }
} }
void AstJumpLabel::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " -> ";
if (blockp()) {
blockp()->dump(str);
} else {
str << "%Error:UNLINKED";
}
}
void AstMemberSel::dump(std::ostream& str) const { void AstMemberSel::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " -> "; str << " -> ";
@@ -1218,12 +1224,16 @@ void AstRange::dump(std::ostream& str) const {
} }
void AstRefDType::dump(std::ostream& str) const { void AstRefDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str); this->AstNodeDType::dump(str);
if (defp()) { if (typedefp() || subDTypep()) {
static bool s_recursing = false; static bool s_recursing = false;
if (!s_recursing) { // Prevent infinite dump if circular typedefs if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true; s_recursing = true;
str << " -> "; str << " -> ";
defp()->dump(str); if (typedefp()) {
typedefp()->dump(str);
} else if (subDTypep()) {
subDTypep()->dump(str);
}
s_recursing = false; s_recursing = false;
} }
} else { } else {
@@ -1239,7 +1249,7 @@ void AstNodeDType::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (generic()) str << " [GENERIC]"; if (generic()) str << " [GENERIC]";
if (AstNodeDType* dtp = virtRefDTypep()) { if (AstNodeDType* dtp = virtRefDTypep()) {
str << " refdt=" << cvtToHex(dtp); str << " refdt=" << nodeAddr(dtp);
dtp->dumpSmall(str); dtp->dumpSmall(str);
} }
} }
@@ -1384,7 +1394,7 @@ void AstVarScope::dump(std::ostream& str) const {
} }
void AstVarXRef::dump(std::ostream& str) const { void AstVarXRef::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) { if (lvalue()) {
str << " [LV] => "; str << " [LV] => ";
} else { } else {
@@ -1402,7 +1412,7 @@ void AstVarXRef::dump(std::ostream& str) const {
} }
void AstVarRef::dump(std::ostream& str) const { void AstVarRef::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
if (lvalue()) { if (lvalue()) {
str << " [LV] => "; str << " [LV] => ";
} else { } else {
@@ -1454,7 +1464,7 @@ void AstParseRef::dump(std::ostream& str) const {
} }
void AstPackageRef::dump(std::ostream& str) const { void AstPackageRef::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> "; str << " -> ";
if (packagep()) { if (packagep()) {
packagep()->dump(str); packagep()->dump(str);
@@ -1462,7 +1472,10 @@ void AstPackageRef::dump(std::ostream& str) const {
str << "UNLINKED"; str << "UNLINKED";
} }
} }
void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstDot::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (colon()) str << "[::]";
}
void AstActive::dump(std::ostream& str) const { void AstActive::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
str << " => "; str << " => ";
@@ -1474,7 +1487,7 @@ void AstActive::dump(std::ostream& str) const {
} }
void AstNodeFTaskRef::dump(std::ostream& str) const { void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (packagep()) { str << " pkg=" << cvtToHex(packagep()); } if (packagep()) { str << " pkg=" << nodeAddr(packagep()); }
str << " -> "; str << " -> ";
if (dotted() != "") { str << ".=" << dotted() << " "; } if (dotted() != "") { str << ".=" << dotted() << " "; }
if (taskp()) { if (taskp()) {
@@ -1506,6 +1519,8 @@ void AstBegin::dump(std::ostream& str) const {
} }
void AstCoverDecl::dump(std::ostream& str) const { void AstCoverDecl::dump(std::ostream& str) const {
this->AstNode::dump(str); this->AstNode::dump(str);
if (!page().empty()) str << " page=" << page();
if (!linescov().empty()) str << " lc=" << linescov();
if (this->dataDeclNullp()) { if (this->dataDeclNullp()) {
str << " -> "; str << " -> ";
this->dataDeclNullp()->dump(str); this->dataDeclNullp()->dump(str);
+345 -125
View File
@@ -319,6 +319,7 @@ public:
, m_packagep(NULL) {} , m_packagep(NULL) {}
ASTNODE_NODE_FUNCS(Class) ASTNODE_NODE_FUNCS(Class)
virtual string verilogKwd() const { return "class"; } virtual string verilogKwd() const { return "class"; }
virtual bool isHeavy() const { return true; }
virtual bool maybePointedTo() const { return true; } virtual bool maybePointedTo() const { return true; }
virtual void dump(std::ostream& str) const; virtual void dump(std::ostream& str) const;
virtual const char* broken() const { virtual const char* broken() const {
@@ -345,19 +346,18 @@ public:
}; };
class AstClassExtends : public AstNode { class AstClassExtends : public AstNode {
// Children: AstClassRefDType during early parse, then moves to dtype // Children: List of AstParseRef for packages/classes
// during early parse, then moves to dtype
public: public:
AstClassExtends(FileLine* fl, AstNodeDType* dtp) AstClassExtends(FileLine* fl, AstNode* classOrPkgsp)
: ASTGEN_SUPER(fl) { : ASTGEN_SUPER(fl) {
childDTypep(dtp); // Only for parser setNOp1p(classOrPkgsp); // Only for parser
} }
ASTNODE_NODE_FUNCS(ClassExtends) ASTNODE_NODE_FUNCS(ClassExtends)
virtual string verilogKwd() const { return "extends"; } virtual string verilogKwd() const { return "extends"; }
virtual bool hasDType() const { return true; } virtual bool hasDType() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* classOrPkgsp() const { return VN_CAST(op1p(), NodeDType); }
// op1 = Type assigning to void classOrPkgsp(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstClass* classp() const; // Class being extended (after link) AstClass* classp() const; // Class being extended (after link)
}; };
@@ -541,6 +541,7 @@ public:
virtual string prettyDTypeName() const; virtual string prettyDTypeName() const;
virtual void dumpSmall(std::ostream& str) const; virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable // op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
@@ -603,6 +604,7 @@ public:
virtual string prettyDTypeName() const; virtual string prettyDTypeName() const;
virtual void dumpSmall(std::ostream& str) const; virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable // op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
@@ -815,6 +817,7 @@ public:
BROKEN_RTN(dtypep() != this); BROKEN_RTN(dtypep() != this);
return NULL; return NULL;
} }
virtual bool isHeavy() const { return keyword() == AstBasicDTypeKwd::STRING; }
AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable AstRange* rangep() const { return VN_CAST(op1p(), Range); } // op1 = Range of variable
void rangep(AstRange* nodep) { setNOp1p(nodep); } void rangep(AstRange* nodep) { setNOp1p(nodep); }
void setSignedState(const VSigning& signst) { void setSignedState(const VSigning& signst) {
@@ -832,8 +835,8 @@ public:
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
// (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthAlignBytes() const; virtual int widthAlignBytes() const;
virtual int // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,... virtual int widthTotalBytes() const;
virtual bool isFourstate() const { return keyword().isFourstate(); } virtual bool isFourstate() const { return keyword().isFourstate(); }
AstBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead AstBasicDTypeKwd keyword() const { // Avoid using - use isSomething accessors instead
return m.m_keyword; return m.m_keyword;
@@ -855,9 +858,8 @@ public:
bool isDpiPrimitive() const { // DPI uses a primitive type bool isDpiPrimitive() const { // DPI uses a primitive type
return !isDpiBitVec() && !isDpiLogicVec(); return !isDpiBitVec() && !isDpiLogicVec();
} }
const VNumRange& nrange() const { // Generally the msb/lsb/etc funcs should be used instead
return m.m_nrange; const VNumRange& nrange() const { return m.m_nrange; }
} // Generally the msb/lsb/etc funcs should be used instead
int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); } int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); }
int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); } int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); }
int left() const { return littleEndian() ? lsb() : msb(); } // How to show a declaration int left() const { return littleEndian() ? lsb() : msb(); } // How to show a declaration
@@ -1067,6 +1069,7 @@ public:
virtual void dumpSmall(std::ostream& str) const; virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual string prettyDTypeName() const; virtual string prettyDTypeName() const;
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable // op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
@@ -1095,25 +1098,24 @@ public:
class AstRefDType : public AstNodeDType { class AstRefDType : public AstNodeDType {
private: private:
// Pre-Width must reference the Typeref, not what it points to, as some child
// types like AstBracketArrayType will disappear and can't lose the handle
AstTypedef* m_typedefp; // referenced type
// Post-width typedefs are removed and point to type directly
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
string m_name; // Name of an AstTypedef string m_name; // Name of an AstTypedef
AstNodeModule* m_packagep; // Package hierarchy AstNodeModule* m_packagep; // Package hierarchy
public: public:
AstRefDType(FileLine* fl, const string& name) AstRefDType(FileLine* fl, const string& name)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl)
, m_typedefp(NULL)
, m_refDTypep(NULL) , m_refDTypep(NULL)
, m_name(name) , m_name(name)
, m_packagep(NULL) {} , m_packagep(NULL) {}
AstRefDType(FileLine* fl, AstNodeDType* defp)
: ASTGEN_SUPER(fl)
, m_refDTypep(defp)
, m_packagep(NULL) {
dtypeFrom(defp->dtypep());
widthFromSub(subDTypep());
}
class FlagTypeOfExpr {}; // type(expr) for parser only class FlagTypeOfExpr {}; // type(expr) for parser only
AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl)
, m_typedefp(NULL)
, m_refDTypep(NULL) , m_refDTypep(NULL)
, m_packagep(NULL) { , m_packagep(NULL) {
setOp2p(typeofp); setOp2p(typeofp);
@@ -1121,47 +1123,53 @@ public:
ASTNODE_NODE_FUNCS(RefDType) ASTNODE_NODE_FUNCS(RefDType)
// METHODS // METHODS
virtual const char* broken() const { virtual const char* broken() const {
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
return NULL; return NULL;
} }
virtual void cloneRelink() { virtual void cloneRelink() {
if (m_typedefp && m_typedefp->clonep()) { m_typedefp = m_typedefp->clonep(); }
if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); } if (m_refDTypep && m_refDTypep->clonep()) { m_refDTypep = m_refDTypep->clonep(); }
} }
virtual bool same(const AstNode* samep) const { virtual bool same(const AstNode* samep) const {
const AstRefDType* asamep = static_cast<const AstRefDType*>(samep); const AstRefDType* asamep = static_cast<const AstRefDType*>(samep);
return (m_refDTypep == asamep->m_refDTypep && m_name == asamep->m_name return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep
&& m_packagep == asamep->m_packagep); && m_name == asamep->m_name && m_packagep == asamep->m_packagep);
} }
virtual bool similarDType(AstNodeDType* samep) const { virtual bool similarDType(AstNodeDType* samep) const {
return skipRefp()->similarDType(samep->skipRefp()); return skipRefp()->similarDType(samep->skipRefp());
} }
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep), V3Hash(m_packagep)); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_typedefp), V3Hash(m_packagep)); }
virtual void dump(std::ostream& str = std::cout) const; virtual void dump(std::ostream& str = std::cout) const;
virtual string name() const { return m_name; } virtual string name() const { return m_name; }
virtual string prettyDTypeName() const { virtual string prettyDTypeName() const {
return subDTypep() ? subDTypep()->name() : prettyName(); return subDTypep() ? subDTypep()->name() : prettyName();
} }
virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; } virtual AstBasicDType* basicp() const { return subDTypep() ? subDTypep()->basicp() : NULL; }
AstNodeDType* subDTypep() const {
if (typedefp()) return typedefp()->subDTypep();
return refDTypep(); // Maybe NULL
}
virtual AstNodeDType* skipRefp() const { virtual AstNodeDType* skipRefp() const {
// Skip past both the Ref and the Typedef // Skip past both the Ref and the Typedef
if (defp()) { if (subDTypep()) {
return defp()->skipRefp(); return subDTypep()->skipRefp();
} else { } else {
v3fatalSrc("Typedef not linked"); v3fatalSrc("Typedef not linked");
return NULL; return NULL;
} }
} }
virtual AstNodeDType* skipRefToConstp() const { virtual AstNodeDType* skipRefToConstp() const {
if (defp()) { if (subDTypep()) {
return defp()->skipRefToConstp(); return subDTypep()->skipRefToConstp();
} else { } else {
v3fatalSrc("Typedef not linked"); v3fatalSrc("Typedef not linked");
return NULL; return NULL;
} }
} }
virtual AstNodeDType* skipRefToEnump() const { virtual AstNodeDType* skipRefToEnump() const {
if (defp()) { if (subDTypep()) {
return defp()->skipRefToEnump(); return subDTypep()->skipRefToEnump();
} else { } else {
v3fatalSrc("Typedef not linked"); v3fatalSrc("Typedef not linked");
return NULL; return NULL;
@@ -1171,15 +1179,13 @@ public:
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); } virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
void name(const string& flag) { m_name = flag; } void name(const string& flag) { m_name = flag; }
// op1 = Range of variable // op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return defp()->skipRefp(); } AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); }
AstNodeDType* defp() const { AstTypedef* typedefp() const { return m_typedefp; }
return m_refDTypep; void typedefp(AstTypedef* nodep) { m_typedefp = nodep; }
} // Code backward compatibility name for refDTypep
AstNodeDType* refDTypep() const { return m_refDTypep; } AstNodeDType* refDTypep() const { return m_refDTypep; }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); } virtual AstNodeDType* virtRefDTypep() const { return refDTypep(); }
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
virtual AstNodeDType* subDTypep() const { return m_refDTypep; }
AstNodeModule* packagep() const { return m_packagep; } AstNodeModule* packagep() const { return m_packagep; }
void packagep(AstNodeModule* nodep) { m_packagep = nodep; } void packagep(AstNodeModule* nodep) { m_packagep = nodep; }
AstNode* typeofp() const { return op2p(); } AstNode* typeofp() const { return op2p(); }
@@ -1902,11 +1908,11 @@ public:
VDirection declDirection() const { return m_declDirection; } VDirection declDirection() const { return m_declDirection; }
void varType(AstVarType type) { m_varType = type; } void varType(AstVarType type) { m_varType = type; }
void varType2Out() { void varType2Out() {
m_tristate = 0; m_tristate = false;
m_direction = VDirection::OUTPUT; m_direction = VDirection::OUTPUT;
} }
void varType2In() { void varType2In() {
m_tristate = 0; m_tristate = false;
m_direction = VDirection::INPUT; m_direction = VDirection::INPUT;
} }
AstBasicDTypeKwd declKwd() const { return m_declKwd; } AstBasicDTypeKwd declKwd() const { return m_declKwd; }
@@ -1918,7 +1924,7 @@ public:
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const; string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const;
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
string vlPropInit() const; // Return VerilatorVarProps initializer string vlPropDecl(string propName) const; // Return VerilatorVarProps declaration
void combineType(AstVarType type); void combineType(AstVarType type);
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable // op1 = Range of variable
@@ -2078,7 +2084,7 @@ public:
private: private:
class VlArgTypeRecursed; class VlArgTypeRecursed;
VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep,
bool arrayed) const; bool compound = false) const;
}; };
class AstDefParam : public AstNode { class AstDefParam : public AstNode {
@@ -2867,9 +2873,11 @@ public:
class AstDot : public AstNode { class AstDot : public AstNode {
// A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef
// These are eliminated in the link stage // These are eliminated in the link stage
bool m_colon; // Is a "::" instead of a "." (lhs must be package/class)
public: public:
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp) AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER(fl) { : ASTGEN_SUPER(fl)
, m_colon(colon) {
setOp1p(lhsp); setOp1p(lhsp);
setOp2p(rhsp); setOp2p(rhsp);
} }
@@ -2877,23 +2885,28 @@ public:
// For parser, make only if non-null package // For parser, make only if non-null package
static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) { static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) {
if (!packagep) return rhsp; if (!packagep) return rhsp;
return new AstDot(fl, new AstPackageRef(fl, packagep), rhsp); return new AstDot(fl, true, new AstPackageRef(fl, packagep), rhsp);
} }
virtual void dump(std::ostream& str) const; virtual void dump(std::ostream& str) const;
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); }
AstNode* lhsp() const { return op1p(); } AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); } AstNode* rhsp() const { return op2p(); }
bool colon() const { return m_colon; }
}; };
class AstUnbounded : public AstNode { class AstUnbounded : public AstNodeMath {
// A $ in the parser, used for unbounded and queues // A $ in the parser, used for unbounded and queues
// Due to where is used, treated as Signed32
public: public:
explicit AstUnbounded(FileLine* fl) explicit AstUnbounded(FileLine* fl)
: ASTGEN_SUPER(fl) {} : ASTGEN_SUPER(fl) {
dtypeSetSigned32();
}
ASTNODE_NODE_FUNCS(Unbounded) ASTNODE_NODE_FUNCS(Unbounded)
virtual string emitVerilog() { return "$"; } virtual string emitVerilog() { return "$"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return true; }
}; };
//###################################################################### //######################################################################
@@ -3076,25 +3089,34 @@ public:
bool hasCombo() const; // Includes a COMBO SenItem bool hasCombo() const; // Includes a COMBO SenItem
}; };
class AstAlways : public AstNode { class AstFinal : public AstNodeProcedure {
public:
AstFinal(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl, bodysp) {}
ASTNODE_NODE_FUNCS(Final)
};
class AstInitial : public AstNodeProcedure {
public:
AstInitial(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl, bodysp) {}
ASTNODE_NODE_FUNCS(Initial)
};
class AstAlways : public AstNodeProcedure {
VAlwaysKwd m_keyword; VAlwaysKwd m_keyword;
public: public:
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl, bodysp)
, m_keyword(keyword) { , m_keyword(keyword) {
addNOp1p(sensesp); addNOp1p(sensesp);
addNOp2p(bodysp);
} }
ASTNODE_NODE_FUNCS(Always) ASTNODE_NODE_FUNCS(Always)
// //
virtual void dump(std::ostream& str) const; virtual void dump(std::ostream& str) const;
AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list
AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
VAlwaysKwd keyword() const { return m_keyword; } VAlwaysKwd keyword() const { return m_keyword; }
// Special accessors
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
}; };
class AstAlwaysPublic : public AstNodeStmt { class AstAlwaysPublic : public AstNodeStmt {
@@ -3300,14 +3322,17 @@ private:
string m_page; string m_page;
string m_text; string m_text;
string m_hier; string m_hier;
int m_column; string m_linescov;
int m_offset; // Offset column numbers to uniq-ify IFs
int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment int m_binNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
public: public:
AstCoverDecl(FileLine* fl, int column, const string& page, const string& comment) AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov,
int offset)
: ASTGEN_SUPER(fl) { : ASTGEN_SUPER(fl) {
m_text = comment;
m_page = page; m_page = page;
m_column = column; m_text = comment;
m_linescov = linescov;
m_offset = offset;
m_binNum = 0; m_binNum = 0;
m_dataDeclp = NULL; m_dataDeclp = NULL;
} }
@@ -3325,10 +3350,11 @@ public:
virtual void dump(std::ostream& str) const; virtual void dump(std::ostream& str) const;
virtual int instrCount() const { return 1 + 2 * instrCountLd(); } virtual int instrCount() const { return 1 + 2 * instrCountLd(); }
virtual bool maybePointedTo() const { return true; } virtual bool maybePointedTo() const { return true; }
int column() const { return m_column; }
void binNum(int flag) { m_binNum = flag; } void binNum(int flag) { m_binNum = flag; }
int binNum() const { return m_binNum; } int binNum() const { return m_binNum; }
int offset() const { return m_offset; }
const string& comment() const { return m_text; } // text to insert in code const string& comment() const { return m_text; } // text to insert in code
const string& linescov() const { return m_linescov; }
const string& page() const { return m_page; } const string& page() const { return m_page; }
const string& hier() const { return m_hier; } const string& hier() const { return m_hier; }
void hier(const string& flag) { m_hier = flag; } void hier(const string& flag) { m_hier = flag; }
@@ -3336,8 +3362,8 @@ public:
virtual V3Hash sameHash() const { return V3Hash(); } virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { virtual bool same(const AstNode* samep) const {
const AstCoverDecl* asamep = static_cast<const AstCoverDecl*>(samep); const AstCoverDecl* asamep = static_cast<const AstCoverDecl*>(samep);
return (fileline() == asamep->fileline() && hier() == asamep->hier() return (fileline() == asamep->fileline() && linescov() == asamep->linescov()
&& comment() == asamep->comment() && column() == asamep->column()); && hier() == asamep->hier() && comment() == asamep->comment());
} }
virtual bool isPredictOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; }
void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; } void dataDeclp(AstCoverDecl* nodep) { m_dataDeclp = nodep; }
@@ -3626,6 +3652,7 @@ public:
virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; } virtual string emitVerilog() { return "%f" + verilogKwd() + "(%l)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; }
virtual bool isOutputter() const { return true; } virtual bool isOutputter() const { return true; }
virtual bool cleanOut() const { return true; } virtual bool cleanOut() const { return true; }
@@ -3777,6 +3804,7 @@ public:
ASTNODE_NODE_FUNCS(FOpen) ASTNODE_NODE_FUNCS(FOpen)
virtual string verilogKwd() const { return "$fopen"; } virtual string verilogKwd() const { return "$fopen"; }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; } virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; } virtual bool isOutputter() const { return true; }
@@ -3788,6 +3816,28 @@ public:
AstNode* modep() const { return op3p(); } AstNode* modep() const { return op3p(); }
}; };
class AstFOpenMcd : public AstNodeStmt {
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
public:
AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep)
: ASTGEN_SUPER(fl) {
setOp1p(filep);
setOp2p(filenamep);
}
ASTNODE_NODE_FUNCS(FOpenMcd)
virtual string verilogKwd() const { return "$fopen"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool isUnlikely() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op1p(); }
AstNode* filenamep() const { return op2p(); }
};
class AstFFlush : public AstNodeStmt { class AstFFlush : public AstNodeStmt {
// Parents: stmtlist // Parents: stmtlist
// Children: file which must be a varref // Children: file which must be a varref
@@ -4009,6 +4059,7 @@ public:
setNOp4p(msbp); setNOp4p(msbp);
} }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; } virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; } virtual bool isOutputter() const { return true; }
@@ -4099,6 +4150,7 @@ public:
virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; } virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
virtual bool isHeavy() const { return true; }
virtual bool isPredictOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; }
virtual bool cleanOut() const { return true; } virtual bool cleanOut() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); } virtual V3Hash sameHash() const { return V3Hash(); }
@@ -4283,44 +4335,81 @@ public:
void priorityPragma(bool flag) { m_priorityPragma = flag; } void priorityPragma(bool flag) { m_priorityPragma = flag; }
}; };
class AstJumpLabel : public AstNodeStmt { class AstJumpBlock : public AstNodeStmt {
// Jump point declaration // Block of code including a JumpGo and JumpLabel
// Separate from AstJumpGo; as a declaration can't be deleted
// Parents: {statement list} // Parents: {statement list}
// Children: {statement list, with JumpGo below} // Children: {statement list, with JumpGo and JumpLabel below}
private: private:
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
public: public:
AstJumpLabel(FileLine* fl, AstNode* stmtsp) // After construction must call ->labelp to associate with appropriate label
AstJumpBlock(FileLine* fl, AstNode* stmtsp)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl)
, m_labelNum(0) { , m_labelNum(0) {
addNOp1p(stmtsp); addNOp1p(stmtsp);
} }
virtual const char* broken() const;
virtual void cloneRelink();
ASTNODE_NODE_FUNCS(JumpBlock)
virtual int instrCount() const { return 0; } virtual int instrCount() const { return 0; }
ASTNODE_NODE_FUNCS(JumpLabel)
virtual bool maybePointedTo() const { return true; } virtual bool maybePointedTo() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); } virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; } virtual bool same(const AstNode* samep) const { return true; }
// op1 = Statements // op1 = Statements
AstNode* stmtsp() const { return op1p(); } // op1 = List of statements AstNode* stmtsp() const { return op1p(); } // op1 = List of statements
void addStmtsp(AstNode* nodep) { addNOp1p(nodep); } void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
AstNode* endStmtsp() const { return op2p(); } // op1 = List of end-of-block
void addEndStmtsp(AstNode* nodep) { addNOp2p(nodep); }
int labelNum() const { return m_labelNum; } int labelNum() const { return m_labelNum; }
void labelNum(int flag) { m_labelNum = flag; } void labelNum(int flag) { m_labelNum = flag; }
AstJumpLabel* labelp() const { return m_labelp; }
void labelp(AstJumpLabel* labelp) { m_labelp = labelp; }
};
class AstJumpLabel : public AstNodeStmt {
// Jump point declaration
// Parents: {statement list with JumpBlock above}
// Children: none
private:
AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration
public:
AstJumpLabel(FileLine* fl, AstJumpBlock* blockp)
: ASTGEN_SUPER(fl)
, m_blockp(blockp) {}
ASTNODE_NODE_FUNCS(JumpLabel)
virtual bool maybePointedTo() const { return true; }
virtual const char* broken() const {
BROKEN_RTN(!blockp()->brokeExistsAbove());
BROKEN_RTN(blockp()->labelp() != this);
return NULL;
}
virtual void cloneRelink() {
if (m_blockp->clonep()) m_blockp = m_blockp->clonep();
}
virtual void dump(std::ostream& str) const;
virtual int instrCount() const { return 0; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const {
return blockp() == static_cast<const AstJumpLabel*>(samep)->blockp();
}
AstJumpBlock* blockp() const { return m_blockp; }
}; };
class AstJumpGo : public AstNodeStmt { class AstJumpGo : public AstNodeStmt {
// Jump point; branch up to the JumpLabel // Jump point; branch down to a JumpLabel
// Parents: {statement list} // No support for backward jumps at present
// Parents: {statement list with JumpBlock above}
// Children: none
private: private:
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
public: public:
AstJumpGo(FileLine* fl, AstJumpLabel* labelp) AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
: ASTGEN_SUPER(fl) { : ASTGEN_SUPER(fl)
m_labelp = labelp; , m_labelp(labelp) {}
} ASTNODE_NODE_FUNCS(JumpGo);
ASTNODE_NODE_FUNCS(JumpGo)
virtual const char* broken() const { virtual const char* broken() const {
BROKEN_RTN(!labelp()->brokeExistsAbove()); BROKEN_RTN(!labelp()->brokeExistsBelow());
return NULL; return NULL;
} }
virtual void cloneRelink() { virtual void cloneRelink() {
@@ -4330,7 +4419,6 @@ public:
virtual int instrCount() const { return instrCountBranch(); } virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(labelp()); } virtual V3Hash sameHash() const { return V3Hash(labelp()); }
virtual bool same(const AstNode* samep) const { virtual bool same(const AstNode* samep) const {
// Also same if identical tree structure all the way down, but hard to detect
return labelp() == static_cast<const AstJumpGo*>(samep)->labelp(); return labelp() == static_cast<const AstJumpGo*>(samep)->labelp();
} }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
@@ -4433,28 +4521,6 @@ public:
void joinType(const VJoinType& flag) { m_joinType = flag; } void joinType(const VJoinType& flag) { m_joinType = flag; }
}; };
class AstInitial : public AstNode {
public:
AstInitial(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
addNOp1p(bodysp);
}
ASTNODE_NODE_FUNCS(Initial)
AstNode* bodysp() const { return op1p(); } // op1 = Expressions to evaluate
// Special accessors
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
class AstFinal : public AstNode {
public:
AstFinal(FileLine* fl, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
addNOp1p(bodysp);
}
ASTNODE_NODE_FUNCS(Final)
AstNode* bodysp() const { return op1p(); } // op1 = Expressions to evaluate
};
class AstInside : public AstNodeMath { class AstInside : public AstNodeMath {
public: public:
AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp)
@@ -4761,35 +4827,36 @@ class AstTraceDecl : public AstNodeStmt {
// Trace point declaration // Trace point declaration
// Separate from AstTraceInc; as a declaration can't be deleted // Separate from AstTraceInc; as a declaration can't be deleted
// Parents: {statement list} // Parents: {statement list}
// Children: none // Children: expression being traced
private: private:
string m_showname; // Name of variable
uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines uint32_t m_code; // Trace identifier code; converted to ASCII by trace routines
VNumRange m_bitRange; // Property of var the trace details const string m_showname; // Name of variable
VNumRange m_arrayRange; // Property of var the trace details const VNumRange m_bitRange; // Property of var the trace details
uint32_t m_codeInc; // Code increment const VNumRange m_arrayRange; // Property of var the trace details
AstVarType m_varType; // Type of variable (for localparam vs. param) const uint32_t m_codeInc; // Code increment
AstBasicDTypeKwd m_declKwd; // Keyword at declaration time const AstVarType m_varType; // Type of variable (for localparam vs. param)
VDirection m_declDirection; // Declared direction input/output etc const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
bool m_isScoped; // Uses run-time scope (for interfaces) const VDirection m_declDirection; // Declared direction input/output etc
const bool m_isScoped; // Uses run-time scope (for interfaces)
public: public:
AstTraceDecl(FileLine* fl, const string& showname, AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc AstVar* varp, // For input/output state etc
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange, AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
bool isScoped) bool isScoped)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl)
, m_code(0)
, m_showname(showname) , m_showname(showname)
, m_bitRange(bitRange) , m_bitRange(bitRange)
, m_arrayRange(arrayRange) , m_arrayRange(arrayRange)
, m_codeInc(
((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
* (VL_EDATASIZE / 32))) // A code is always 32-bits
, m_varType(varp->varType())
, m_declKwd(varp->declKwd())
, m_declDirection(varp->declDirection())
, m_isScoped(isScoped) { , m_isScoped(isScoped) {
dtypeFrom(valuep); dtypeFrom(valuep);
m_code = 0; addNOp1p(valuep);
m_codeInc
= ((arrayRange.ranged() ? arrayRange.elements() : 1) * valuep->dtypep()->widthWords()
* (VL_EDATASIZE / (8 * sizeof(uint32_t)))); // A code is always 32-bits
m_varType = varp->varType();
m_declKwd = varp->declKwd();
m_declDirection = varp->declDirection();
} }
virtual int instrCount() const { return 100; } // Large... virtual int instrCount() const { return 100; } // Large...
ASTNODE_NODE_FUNCS(TraceDecl) ASTNODE_NODE_FUNCS(TraceDecl)
@@ -4808,20 +4875,25 @@ public:
AstBasicDTypeKwd declKwd() const { return m_declKwd; } AstBasicDTypeKwd declKwd() const { return m_declKwd; }
VDirection declDirection() const { return m_declDirection; } VDirection declDirection() const { return m_declDirection; }
bool isScoped() const { return m_isScoped; } bool isScoped() const { return m_isScoped; }
AstNode* valuep() const { return op1p(); }
}; };
class AstTraceInc : public AstNodeStmt { class AstTraceInc : public AstNodeStmt {
// Trace point; incremental change detect and dump // Trace point dump
// Parents: {statement list} // Parents: {statement list}
// Children: incremental value // Children: op1: things to emit before this node,
// op2: expression being traced (from decl)
private: private:
AstTraceDecl* m_declp; // [After V3Trace] Pointer to declaration AstTraceDecl* m_declp; // Pointer to declaration
const bool m_full; // Is this a full vs incremental dump
public: public:
AstTraceInc(FileLine* fl, AstTraceDecl* declp, AstNode* valuep) AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full)
: ASTGEN_SUPER(fl) { : ASTGEN_SUPER(fl)
, m_declp(declp)
, m_full(full) {
dtypeFrom(declp); dtypeFrom(declp);
m_declp = declp; addOp2p(declp->valuep()->cloneTree(true));
addNOp2p(valuep);
} }
ASTNODE_NODE_FUNCS(TraceInc) ASTNODE_NODE_FUNCS(TraceInc)
virtual const char* broken() const { virtual const char* broken() const {
@@ -4843,13 +4915,11 @@ public:
virtual bool isOutputter() const { return true; } virtual bool isOutputter() const { return true; }
// but isPure() true // but isPure() true
// op1 = Statements before the value // op1 = Statements before the value
AstNode* precondsp() const { AstNode* precondsp() const { return op1p(); }
return op1p();
} // op1 = prepare statements for condition (exec every loop)
void addPrecondsp(AstNode* newp) { addOp1p(newp); } void addPrecondsp(AstNode* newp) { addOp1p(newp); }
// op2 = Value to trace
AstTraceDecl* declp() const { return m_declp; } // Where defined
AstNode* valuep() const { return op2p(); } AstNode* valuep() const { return op2p(); }
AstTraceDecl* declp() const { return m_declp; }
bool full() const { return m_full; }
}; };
class AstActive : public AstNode { class AstActive : public AstNode {
@@ -5397,6 +5467,33 @@ public:
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual int instrCount() const { return widthInstrs() * 16; } virtual int instrCount() const { return widthInstrs() * 16; }
}; };
class AstCountBits : public AstNodeQuadop {
// Number of bits set in vector
public:
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p)
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), ctrl1p->cloneTree(false)) {}
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p)
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {}
AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p)
: ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {}
ASTNODE_NODE_FUNCS(CountBits)
virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1,
const V3Number& ctrl2, const V3Number& ctrl3) {
out.opCountBits(expr, ctrl1, ctrl2, ctrl3);
}
virtual string emitVerilog() { return "%f$countbits(%l, %r, %f, %o)"; }
virtual string emitC() { return ""; }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool cleanThs() const { return true; }
virtual bool cleanFhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; }
virtual bool sizeMattersFhs() const { return false; }
virtual int instrCount() const { return widthInstrs() * 16; }
};
class AstCountOnes : public AstNodeUniop { class AstCountOnes : public AstNodeUniop {
// Number of bits set in vector // Number of bits set in vector
public: public:
@@ -5426,6 +5523,24 @@ public:
virtual bool cleanLhs() const { return false; } virtual bool cleanLhs() const { return false; }
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
}; };
class AstIsUnbounded : public AstNodeUniop {
// True if is unmbounded ($)
public:
AstIsUnbounded(FileLine* fl, AstNode* lhsp)
: ASTGEN_SUPER(fl, lhsp) {
dtypeSetLogicBool();
}
ASTNODE_NODE_FUNCS(IsUnbounded)
virtual void numberOperate(V3Number& out, const V3Number&) {
// Any constant isn't unbounded
out.setZero();
}
virtual string emitVerilog() { return "%f$isunbounded(%l)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool sizeMattersLhs() const { return false; }
};
class AstOneHot : public AstNodeUniop { class AstOneHot : public AstNodeUniop {
// True if only single bit set in vector // True if only single bit set in vector
public: public:
@@ -5967,6 +6082,7 @@ public:
virtual bool cleanOut() const { return true; } virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; } virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual bool isHeavy() const { return true; }
FmtType format() const { return m_fmt; } FmtType format() const { return m_fmt; }
}; };
@@ -7133,6 +7249,106 @@ public:
virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; } virtual int instrCount() const { return widthInstrs() * instrCountMul() * 10; }
virtual bool signedFlavor() const { return true; } virtual bool signedFlavor() const { return true; }
}; };
class AstPreAdd : public AstNodeTriop {
// Pre-increment/add
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only ++ not +=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PreAdd)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(++%r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstPreSub : public AstNodeTriop {
// Pre-decrement/subtract
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only -- not -=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PreSub)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(--%r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstPostAdd : public AstNodeTriop {
// Post-increment/add
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only ++ not +=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PostAdd)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(%r++)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstPostSub : public AstNodeTriop {
// Post-decrement/subtract
// Parents: MATH
// Children: lhsp: AstConst (1) as currently support only -- not -=
// Children: rhsp: tree with AstVarRef that is value to read before operation
// Children: thsp: tree with AstVarRef LValue that is stored after operation
public:
AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp)
: ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {}
ASTNODE_NODE_FUNCS(PostSub)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs,
const V3Number& ths) {
V3ERROR_NA; // Need to modify lhs
}
virtual string emitVerilog() { return "%k(%r--)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return false; }
virtual bool cleanLhs() const { return false; }
virtual bool cleanRhs() const { return false; }
virtual bool cleanThs() const { return false; }
virtual bool sizeMattersLhs() const { return true; }
virtual bool sizeMattersRhs() const { return true; }
virtual bool sizeMattersThs() const { return true; }
};
class AstEqCase : public AstNodeBiCom { class AstEqCase : public AstNodeBiCom {
public: public:
AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
@@ -7500,6 +7716,7 @@ public:
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; } virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; } virtual bool sizeMattersThs() const { return false; }
virtual bool isHeavy() const { return true; }
}; };
class AstGetcN : public AstNodeBiop { class AstGetcN : public AstNodeBiop {
@@ -7525,6 +7742,7 @@ public:
virtual bool cleanRhs() const { return true; } virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; } virtual bool sizeMattersRhs() const { return false; }
virtual bool isHeavy() const { return true; }
}; };
class AstGetcRefN : public AstNodeBiop { class AstGetcRefN : public AstNodeBiop {
@@ -7543,13 +7761,14 @@ public:
V3ERROR_NA; V3ERROR_NA;
} }
virtual string emitVerilog() { return "%k%l[%r]"; } virtual string emitVerilog() { return "%k%l[%r]"; }
virtual string emitC() { V3ERROR_NA; } virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitSimpleOperator() { return ""; } virtual string emitSimpleOperator() { return ""; }
virtual bool cleanOut() const { return true; } virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; } virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; } virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; } virtual bool sizeMattersRhs() const { return false; }
virtual bool isHeavy() const { return true; }
}; };
class AstSubstrN : public AstNodeTriop { class AstSubstrN : public AstNodeTriop {
@@ -7575,6 +7794,7 @@ public:
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; } virtual bool sizeMattersRhs() const { return false; }
virtual bool sizeMattersThs() const { return false; } virtual bool sizeMattersThs() const { return false; }
virtual bool isHeavy() const { return true; }
}; };
class AstCompareNN : public AstNodeBiop { class AstCompareNN : public AstNodeBiop {
@@ -7607,6 +7827,7 @@ public:
virtual bool cleanRhs() const { return true; } virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; } virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; } virtual bool sizeMattersRhs() const { return false; }
virtual bool isHeavy() const { return true; }
}; };
class AstPast : public AstNodeMath { class AstPast : public AstNodeMath {
@@ -7675,11 +7896,10 @@ public:
virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); }
virtual int instrCount() const { return widthInstrs(); } virtual int instrCount() const { return widthInstrs(); }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const {
return VN_CAST(op1p(), NodeDType);
} // op1 = Type assigning to
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
// op1 = Type assigning to
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc
}; };
class AstPatMember : public AstNodeMath { class AstPatMember : public AstNodeMath {
-3
View File
@@ -30,12 +30,9 @@
#include "V3Global.h" #include "V3Global.h"
#include "V3Begin.h" #include "V3Begin.h"
#include "V3Inst.h"
#include "V3Ast.h" #include "V3Ast.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
#include <vector>
//###################################################################### //######################################################################
-1
View File
@@ -30,7 +30,6 @@
#include "V3Branch.h" #include "V3Branch.h"
#include "V3Ast.h" #include "V3Ast.h"
#include <cstdarg>
#include <map> #include <map>
//###################################################################### //######################################################################
+20 -5
View File
@@ -32,7 +32,6 @@
#include "V3AstConstOnly.h" #include "V3AstConstOnly.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
#include VL_INCLUDE_UNORDERED_MAP #include VL_INCLUDE_UNORDERED_MAP
//###################################################################### //######################################################################
@@ -131,6 +130,14 @@ public:
if (!(iter->second & FLAG_LINKABLE)) return false; if (!(iter->second & FLAG_LINKABLE)) return false;
return true; return true;
} }
static bool okIfAbove(const AstNode* nodep) {
// Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if ((iter->second & FLAG_UNDER_NOW)) return false;
return true;
}
static bool okIfBelow(const AstNode* nodep) { static bool okIfBelow(const AstNode* nodep) {
// Must be linked to and below current node // Must be linked to and below current node
if (!okIfLinkedTo(nodep)) return false; if (!okIfLinkedTo(nodep)) return false;
@@ -142,19 +149,22 @@ public:
static void prepForTree() { static void prepForTree() {
#ifndef VL_LEAK_CHECKS #ifndef VL_LEAK_CHECKS
s_nodes.clear(); s_nodes.clear();
#endif #else
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) { for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
it->second &= ~FLAG_IN_TREE; it->second &= ~FLAG_IN_TREE;
it->second &= ~FLAG_LINKABLE; it->second &= ~FLAG_LINKABLE;
} }
#endif
} }
static void doneWithTree() { static void doneWithTree() {
for (int backs = 0; backs < 2; for (int backs = 0; backs < 2;
backs++) { // Those with backp() are probably under one leaking without backs++) { // Those with backp() are probably under one leaking without
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) { for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE) // LCOV_EXCL_START
&& !(it->second & FLAG_LEAKED) if (VL_UNCOVERABLE((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
&& (it->first->backp() ? backs == 1 : backs == 0)) { && !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs == 1 : backs == 0))) {
// Use only AstNode::dump instead of the virtual one, as there // Use only AstNode::dump instead of the virtual one, as there
// may be varp() and other cross links that are bad. // may be varp() and other cross links that are bad.
if (v3Global.opt.debugCheck()) { if (v3Global.opt.debugCheck()) {
@@ -173,6 +183,7 @@ public:
} }
it->second |= FLAG_LEAKED; it->second |= FLAG_LEAKED;
} }
// LCOV_EXCL_STOP
} }
} }
} }
@@ -193,6 +204,10 @@ bool AstNode::brokeExistsAbove() const {
// Called by node->broken() routines to do table lookup // Called by node->broken() routines to do table lookup
return BrokenTable::okIfBelow(this); return BrokenTable::okIfBelow(this);
} }
bool AstNode::brokeExistsBelow() const {
// Called by node->broken() routines to do table lookup
return BrokenTable::okIfAbove(this);
}
//###################################################################### //######################################################################
-6
View File
@@ -32,10 +32,7 @@
#include "V3CCtors.h" #include "V3CCtors.h"
#include <algorithm> #include <algorithm>
#include <cmath>
#include <cstdarg>
#include <map> #include <map>
#include <vector>
class V3CCtorsVisitor { class V3CCtorsVisitor {
private: private:
@@ -49,7 +46,6 @@ private:
int m_funcNum; // Function number being built int m_funcNum; // Function number being built
public: public:
AstCFunc* builtFuncp() const { return m_tlFuncp; }
void add(AstNode* nodep) { void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) { if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_funcp = NULL; m_funcp = NULL;
@@ -146,13 +142,11 @@ void V3CCtors::cctorsAll() {
modp = VN_CAST(modp->nextp(), NodeModule)) { modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn // Process each module in turn
{ {
AstCFunc* varResetFuncp;
V3CCtorsVisitor var_reset( V3CCtorsVisitor var_reset(
modp, "_ctor_var_reset", modp, "_ctor_var_reset",
(VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""), (VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""),
(VN_IS(modp, Class) ? "vlSymsp" : ""), (VN_IS(modp, Class) ? "vlSymsp" : ""),
(VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : "")); (VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : ""));
varResetFuncp = var_reset.builtFuncp();
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstVar* varp = VN_CAST(np, Var)) { if (AstVar* varp = VN_CAST(np, Var)) {
+1 -1
View File
@@ -218,7 +218,7 @@ public:
//###################################################################### //######################################################################
// Class class functions // Class class functions
void V3CUse::cUseAll(AstNetlist* nodep) { void V3CUse::cUseAll() {
UINFO(2, __FUNCTION__ << ": " << endl); UINFO(2, __FUNCTION__ << ": " << endl);
// Call visitor separately for each module, so visitor state is cleared // Call visitor separately for each module, so visitor state is cleared
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
+1 -1
View File
@@ -27,7 +27,7 @@
class V3CUse { class V3CUse {
public: public:
static void cUseAll(AstNetlist* nodep); static void cUseAll();
}; };
#endif // Guard #endif // Guard
+4 -5
View File
@@ -43,7 +43,6 @@
#include "V3Stats.h" #include "V3Stats.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in #define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant #define CASE_BARF 999999 // Magic width when non-constant
@@ -96,7 +95,7 @@ private:
} else if (VN_IS(m_caseExprp, Case) } else if (VN_IS(m_caseExprp, Case)
&& (VN_CAST(m_caseExprp, Case)->casez() && (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) { || VN_CAST(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isUnknown()) { if (nodep->num().isAnyX()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, " nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
"(perhaps intended ?/z in constant)"); "(perhaps intended ?/z in constant)");
} }
@@ -281,13 +280,13 @@ private:
// IF(msb-1, 01, 00)) // IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack(); AstNode* cexprp = nodep->exprp()->unlinkFrBack();
if (debug() >= 9) { if (debug() >= 9) { // LCOV_EXCL_START
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) { for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
if (AstNode* itemp = m_valueItem[i]) { if (AstNode* itemp = m_valueItem[i]) {
UINFO(9, "Value " << std::hex << i << " " << itemp << endl); UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
} }
} }
} } // LCOV_EXCL_STOP
// Handle any assertions // Handle any assertions
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered); replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
@@ -460,7 +459,7 @@ private:
// Xs in case or casez are impossible due to two state simulations // Xs in case or casez are impossible due to two state simulations
if (casep->casex()) { if (casep->casex()) {
} else if (casep->casez() || casep->caseInside()) { } else if (casep->casez() || casep->caseInside()) {
if (itemp->num().isUnknown()) return true; if (itemp->num().isAnyX()) return true;
} else { } else {
if (itemp->num().isFourState()) return true; if (itemp->num().isFourState()) return true;
} }
+9 -1
View File
@@ -45,7 +45,6 @@
#include "V3Ast.h" #include "V3Ast.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
//###################################################################### //######################################################################
// Cast state, as a visitor of each AstNode // Cast state, as a visitor of each AstNode
@@ -128,6 +127,15 @@ private:
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp()); if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
} }
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()
| nodep->fhsp()->user1());
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
if (nodep->sizeMattersFhs()) ensureCast(nodep->fhsp());
}
virtual void visit(AstCCast* nodep) VL_OVERRIDE { virtual void visit(AstCCast* nodep) VL_OVERRIDE {
iterateChildren(nodep); iterateChildren(nodep);
ensureLower32Cast(nodep); ensureLower32Cast(nodep);
+3 -6
View File
@@ -33,12 +33,9 @@
#include "V3File.h" #include "V3File.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
#include <deque> #include <deque>
#include <iomanip> #include <iomanip>
#include <list>
#include <memory> #include <memory>
#include <vector>
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic #define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
@@ -258,7 +255,7 @@ private:
iterateChildren(nodep); iterateChildren(nodep);
m_logicVertexp = NULL; m_logicVertexp = NULL;
if (0 && debug() >= 9) { if (false && debug() >= 9) {
UINFO(9, "Trace Logic:\n"); UINFO(9, "Trace Logic:\n");
nodep->dumpTree(cout, "-log1: "); nodep->dumpTree(cout, "-log1: ");
} }
@@ -298,7 +295,7 @@ private:
static bool told_file = false; static bool told_file = false;
nodep->v3warnCode(code, msg); nodep->v3warnCode(code, msg);
if (!told_file) { if (!told_file) {
told_file = 1; told_file = true;
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl; std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
} }
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl; *m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
@@ -732,7 +729,7 @@ private:
// Ignores // Ignores
virtual void visit(AstInitial*) VL_OVERRIDE {} virtual void visit(AstInitial*) VL_OVERRIDE {}
virtual void visit(AstTraceInc*) VL_OVERRIDE {} virtual void visit(AstTraceDecl*) VL_OVERRIDE {}
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} virtual void visit(AstCoverToggle*) VL_OVERRIDE {}
virtual void visit(AstNodeDType*) VL_OVERRIDE {} virtual void visit(AstNodeDType*) VL_OVERRIDE {}
-2
View File
@@ -35,8 +35,6 @@
#include "V3EmitCBase.h" #include "V3EmitCBase.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
#include <set>
//###################################################################### //######################################################################
+13 -1
View File
@@ -31,7 +31,6 @@
#include "V3Ast.h" #include "V3Ast.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
//###################################################################### //######################################################################
// Clean state, as a visitor of each AstNode // Clean state, as a visitor of each AstNode
@@ -160,6 +159,15 @@ private:
if (nodep->cleanThs()) ensureClean(nodep->thsp()); if (nodep->cleanThs()) ensureClean(nodep->thsp());
// no setClean.. must do it in each user routine. // no setClean.. must do it in each user routine.
} }
void operandQuadop(AstNodeQuadop* nodep) {
iterateChildren(nodep);
computeCppWidth(nodep);
if (nodep->cleanLhs()) { ensureClean(nodep->lhsp()); }
if (nodep->cleanRhs()) { ensureClean(nodep->rhsp()); }
if (nodep->cleanThs()) { ensureClean(nodep->thsp()); }
if (nodep->cleanFhs()) { ensureClean(nodep->fhsp()); }
// no setClean.. must do it in each user routine.
}
// VISITORS // VISITORS
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE { virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
@@ -192,6 +200,10 @@ private:
operandBiop(nodep); operandBiop(nodep);
setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp())); setClean(nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
} }
virtual void visit(AstNodeQuadop* nodep) VL_OVERRIDE {
operandQuadop(nodep);
setClean(nodep, nodep->cleanOut());
}
virtual void visit(AstNodeMath* nodep) VL_OVERRIDE { virtual void visit(AstNodeMath* nodep) VL_OVERRIDE {
iterateChildren(nodep); iterateChildren(nodep);
computeCppWidth(nodep); computeCppWidth(nodep);
-4
View File
@@ -36,7 +36,6 @@
#include "V3EmitCBase.h" #include "V3EmitCBase.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
//###################################################################### //######################################################################
// Clock state, as a visitor of each AstNode // Clock state, as a visitor of each AstNode
@@ -48,9 +47,6 @@ private:
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created. // AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
AstUser1InUse m_inuser1; AstUser1InUse m_inuser1;
// TYPES
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
// STATE // STATE
AstNodeModule* m_modp; // Current module AstNodeModule* m_modp; // Current module
AstTopScope* m_topScopep; // Current top scope AstTopScope* m_topScopep; // Current top scope
+34 -24
View File
@@ -40,7 +40,6 @@
#include "V3Ast.h" #include "V3Ast.h"
#include <algorithm> #include <algorithm>
#include <cstdarg>
#include <map> #include <map>
#include <vector> #include <vector>
@@ -57,15 +56,6 @@ protected:
// METHODS // METHODS
virtual ~CombBaseVisitor() {} virtual ~CombBaseVisitor() {}
VL_DEBUG_FUNC; // Declare debug() VL_DEBUG_FUNC; // Declare debug()
//***** optimization levels
static bool emptyFunctionDeletion() { return true; }
static bool duplicateFunctionCombine() { return true; }
// Note this is disabled, it still needed work
// Also repair it for DPI functions; when make __common need to ensure proper
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
// get split between functions causing the text to have a dangling reference.
bool statementCombine() { return false; } // duplicateFunctionCombine();
}; };
//###################################################################### //######################################################################
@@ -86,11 +76,10 @@ public:
} else { } else {
UINFO(4, " Remove " << oldfuncp << endl); UINFO(4, " Remove " << oldfuncp << endl);
} }
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange // Note: m_callMmap modified in loop, so not using equal_range.
= m_callMmap.equal_range(oldfuncp); for (CallMmap::iterator it = m_callMmap.find(oldfuncp); it != m_callMmap.end();
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) { it = m_callMmap.find(oldfuncp)) {
CallMmap::iterator eqit = nextit++; AstCCall* callp = it->second;
AstCCall* callp = eqit->second;
if (!callp->user3()) { // !already done if (!callp->user3()) { // !already done
UINFO(4, " Called " << callp << endl); UINFO(4, " Called " << callp << endl);
UASSERT_OBJ(callp->funcp() == oldfuncp, callp, UASSERT_OBJ(callp->funcp() == oldfuncp, callp,
@@ -105,8 +94,13 @@ public:
} }
callp->user3(true); // Dead now callp->user3(true); // Dead now
VL_DO_DANGLING(pushDeletep(callp), callp); VL_DO_DANGLING(pushDeletep(callp), callp);
m_callMmap.erase(eqit); // Fix the table
} }
// It is safe to unconditionally remove this entry here as the above
// 'if' would never be entered again for this entry (we set user3).
// The only other place where m_callMmap is looked up is deleteCall
// below, but that is only ever called straight after an addCall
// of the node being deleted, so it won't miss this entry.
m_callMmap.erase(it); // Fix the table
} }
} }
// METHODS // METHODS
@@ -182,7 +176,6 @@ private:
CombineState m_state; // Major state CombineState m_state; // Major state
AstNodeModule* m_modp; // Current module AstNodeModule* m_modp; // Current module
AstCFunc* m_funcp; // Current function AstCFunc* m_funcp; // Current function
V3Hash m_lowerHash; // Hash of the statement we're building
CombCallVisitor m_call; // Tracking of function call users CombCallVisitor m_call; // Tracking of function call users
int m_modNFuncs; // Number of functions made int m_modNFuncs; // Number of functions made
AstNode* m_walkLast1p; // Final node that is the same in duplicate list AstNode* m_walkLast1p; // Final node that is the same in duplicate list
@@ -195,6 +188,7 @@ private:
m_hashed.hashAndInsert(nodep); m_hashed.hashAndInsert(nodep);
// UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl); // UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl);
} }
#ifdef VL_COMBINE_STATEMENTS
void hashFunctions(AstCFunc* nodep) { void hashFunctions(AstCFunc* nodep) {
// Compute hash of all statement trees in the function // Compute hash of all statement trees in the function
CombineState oldState = m_state; CombineState oldState = m_state;
@@ -204,6 +198,7 @@ private:
} }
m_state = oldState; m_state = oldState;
} }
#endif
void walkEmptyFuncs() { void walkEmptyFuncs() {
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
AstNode* node1p = it->second; AstNode* node1p = it->second;
@@ -251,6 +246,8 @@ private:
oldfuncp->unlinkFrBack(); oldfuncp->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp);
} }
#ifdef VL_COMBINE_STATEMENTS
void replaceOnlyCallFunc(AstCCall* nodep) { void replaceOnlyCallFunc(AstCCall* nodep) {
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) { if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
// oldfuncp->dumpTree(cout, "MAYDEL: "); // oldfuncp->dumpTree(cout, "MAYDEL: ");
@@ -343,7 +340,7 @@ private:
// Grab statement bodies // Grab statement bodies
AstNRelinker relink1Handle; AstNRelinker relink1Handle;
AstNRelinker relink2Handle; AstNRelinker relink2Handle;
for (AstNode *nextp, *walkp = node1p; 1; walkp = nextp) { for (AstNode *nextp, *walkp = node1p; true; walkp = nextp) {
nextp = walkp->nextp(); nextp = walkp->nextp();
if (walkp == node1p) { if (walkp == node1p) {
walkp->unlinkFrBack(&relink1Handle); walkp->unlinkFrBack(&relink1Handle);
@@ -353,7 +350,7 @@ private:
} }
if (walkp == last1p) break; if (walkp == last1p) break;
} }
for (AstNode *nextp, *walkp = node2p; 1; walkp = nextp) { for (AstNode *nextp, *walkp = node2p; true; walkp = nextp) {
nextp = walkp->nextp(); nextp = walkp->nextp();
if (walkp == node2p) { if (walkp == node2p) {
walkp->unlinkFrBack(&relink2Handle); walkp->unlinkFrBack(&relink2Handle);
@@ -381,6 +378,7 @@ private:
VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p); VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p);
VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p); VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p);
} }
#endif
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
@@ -404,15 +402,21 @@ private:
m_state = STATE_IDLE; m_state = STATE_IDLE;
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine"); if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
// Walk the hashes removing empty functions // Walk the hashes removing empty functions
if (emptyFunctionDeletion()) walkEmptyFuncs(); walkEmptyFuncs();
// Walk the hashes looking for duplicate functions // Walk the hashes looking for duplicate functions
if (duplicateFunctionCombine()) walkDupFuncs(); walkDupFuncs();
// Walk the statements looking for large replicated code sections // Walk the statements looking for large replicated code sections
if (statementCombine()) { // Note this is disabled, it still needed work
// Also repair it for DPI functions; when make __common need to ensure proper
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
// get split between functions causing the text to have a dangling reference.
#ifdef VL_COMBINE_STATEMENTS
{
m_state = STATE_DUP; m_state = STATE_DUP;
iterateChildren(nodep); iterateChildren(nodep);
m_state = STATE_IDLE; m_state = STATE_IDLE;
} }
#endif
m_modp = NULL; m_modp = NULL;
} }
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
@@ -420,9 +424,12 @@ private:
if (!nodep->dontCombine()) { if (!nodep->dontCombine()) {
if (m_state == STATE_HASH) { if (m_state == STATE_HASH) {
hashStatement(nodep); // Hash the entire function - it might be identical hashStatement(nodep); // Hash the entire function - it might be identical
} else if (m_state == STATE_DUP) { }
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP) {
iterateChildren(nodep); iterateChildren(nodep);
} }
#endif
} }
m_funcp = NULL; m_funcp = NULL;
} }
@@ -433,9 +440,12 @@ private:
} }
if (m_state == STATE_HASH && m_funcp) { if (m_state == STATE_HASH && m_funcp) {
hashStatement(nodep); hashStatement(nodep);
} else if (m_state == STATE_DUP && m_funcp) { }
#ifdef VL_COMBINE_STATEMENTS
else if (m_state == STATE_DUP && m_funcp) {
walkDupCodeStart(nodep); walkDupCodeStart(nodep);
} }
#endif
} }
//-------------------- //--------------------
+1 -1
View File
@@ -335,7 +335,7 @@ public:
// UINFO(9, " Hit " << *m_lastIt << endl); // UINFO(9, " Hit " << *m_lastIt << endl);
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on); filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
} }
if (0 && debug() >= 9) { if (false && debug() >= 9) {
for (IgnLines::const_iterator it = m_lastIgnore.it; it != m_ignLines.end(); ++it) { for (IgnLines::const_iterator it = m_lastIgnore.it; it != m_ignLines.end(); ++it) {
UINFO(9, " NXT " << *it << endl); UINFO(9, " NXT " << *it << endl);
} }
+1 -1
View File
@@ -43,7 +43,7 @@ public:
static void applyModule(AstNodeModule* modulep); static void applyModule(AstNodeModule* modulep);
static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp); static void applyFTask(AstNodeModule* modulep, AstNodeFTask* ftaskp);
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp); static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& match); static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
}; };
#endif // Guard #endif // Guard

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