Compare commits

...
273 Commits
Author SHA1 Message Date
Wilson Snyder dfcd412e5f Version bump 2019-10-06 09:40:36 -04:00
Wilson Snyder 307549e8a6 Internals: Fix some cppcheck warnings. 2019-10-06 08:20:02 -04:00
Wilson Snyder 09b79a731a Fix more output spacing issues. 2019-10-05 21:52:33 -04:00
Wilson Snyder 4544a2fd99 Fix extra declaration of trace() in submodules. 2019-10-05 20:16:33 -04:00
Wilson Snyder e09c918198 Fix indentation broke in 977a767477. 2019-10-05 18:00:45 -04:00
Wilson Snyder 9bf6135f6d Remove some output tabs. 2019-10-05 17:35:08 -04:00
Wilson Snyder d472ef63e9 Internals: Cleanup some misnamed classes. No functional change. 2019-10-05 08:17:21 -04:00
Wilson Snyder f1c04b5d25 Fix extra space in mtask comment. No functional change. 2019-10-04 22:54:57 -04:00
Wilson Snyder 1cf29c4d20 Fix truncation of comments, broke in f133c4d0b3. 2019-10-04 22:54:17 -04:00
Maarten De Braekeleer 977a767477 Avoid tabs in C output.
Signed-off-by: Wilson Snyder <[email protected]>
2019-10-04 21:10:53 -04:00
Wilson Snyder 771a301f66 Commentary: Remove newlines, upsets some patches. No functional change. 2019-10-04 20:17:11 -04:00
Wilson Snyder a9954a71c3 Fix case statements with strings, bug1536. 2019-10-04 19:13:39 -04:00
Wilson Snyder 967dc24fda Commentary 2019-10-04 17:42:34 -04:00
Wilson Snyder e1e45cf13c Internals: Move option checks to notify(). 2019-10-03 22:18:29 -04:00
Wilson Snyder bd89c71694 Internals: Refactor to avoid V3Global requirements in V3String. No functional change intended. 2019-10-02 21:38:16 -04:00
Stefan Wallentowitz 633131b984 Return vpiModule when it is the scope.
Return the vpiModule when it is searched for by name and not the vpiScope,
now that we actually have it (one step further to supporting vpiModule in
complete).

Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-10-02 18:47:12 -04:00
Wilson Snyder 99db18b6c3 Commentary 2019-10-02 18:47:06 -04:00
Todd Strader 961a8e190f Internals: Remove rogue character. 2019-10-02 08:52:26 -04:00
Stefan Wallentowitz 045ff25f80 Support vpiModule, bug1469.
Add very basic support for vpiModule. Basically it allows to traverse
the module tree to find a variable etc. It does not support more than
vpi_iterate and vpi_scan for vpiModule along basic operations like
vpi_get_str on vpiModule.

The support is added non-intrusively to non-VPI verilator runs. It
essentially:

 - Tracks the creation of cell instances and keeps them alive until
   the emit phase. They are there converted to scopes if modules.

 - Emits empty (don't add anything during construction)
   VerilatedScopes for all inlined modules, only for those inlined
   modules that are on the hierarchical path to public variables.

 - Adds VerilatedHierarchy as abstraction to structure of the
   scopes. It is only created for VPI designs. It allows to traverse
   the hierarchy from the top (NULL).

Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-10-01 21:57:45 -04:00
Wilson Snyder 66209d1114 Tests: Less verbose status. 2019-10-01 21:32:38 -04:00
Todd Strader 3f1fe2d18a Internals: Travis CI environment. 2019-10-01 06:05:11 -04:00
Wilson Snyder 8b6fb26272 Return good exit status on --help. 2019-09-30 23:15:10 -04:00
Wilson Snyder 881362bb04 Fix clang compile warnings. 2019-09-30 21:55:31 -04:00
Wilson Snyder 239ef1ae6d Fix misc bad-syntax crashes, bug1533. 2019-09-30 20:00:30 -04:00
Wilson Snyder 9eaec3b5c1 Fix misc bad-syntax crashes, bug1530. 2019-09-30 19:48:01 -04:00
Wilson Snyder dd4aa948ae Tests: Have driver report ETA. 2019-09-30 19:22:36 -04:00
Wilson Snyder 12fa085b26 Fix misc bad-syntax crashes, bug1529. 2019-09-30 19:22:14 -04:00
Wilson Snyder 9d6b0d7dd6 Tests: Fix broken contributors check. 2019-09-30 18:56:04 -04:00
Wilson Snyder a1405dac8e Fix misc bad-syntax crashes, bug1532. 2019-09-30 18:50:27 -04:00
Todd Strader cb115e1a15 Commentary 2019-09-30 09:33:17 -04:00
Wilson Snyder 1c7eb89df5 Commentary: Update contributing indentation. 2019-09-29 17:11:13 -04:00
Wilson Snyder 6e91f82a7d Commentary: Fix logo rendering 2019-09-29 17:09:03 -04:00
Wilson Snyder 17123cd0e0 Add contributing document. Convert internals to asciidoc format. Part of last commit. 2019-09-29 17:05:13 -04:00
Wilson Snyder 3f0c5b7550 WIP 2019-09-29 17:03:07 -04:00
Wilson Snyder f6e0e9adec Internals: Use SHA256 instead of insecure SHA1. 2019-09-28 13:32:28 -04:00
Wilson Snyder dea1531f40 Commentary 2019-09-28 11:38:23 -04:00
Wilson Snyder edcfaa888d Commentary 2019-09-28 11:13:30 -04:00
Todd Strader 28b9db1903 Add AstVFile and AstTextBlock, towards bug1490. 2019-09-27 04:24:38 -04:00
Todd Strader 9e64be71a7 Add XSim user run flags 2019-09-27 01:12:53 -04:00
Stefan Wallentowitz 99a8845a96 Fix VerilatedVpioVar vpiMemory/vpiReg accessor, bug1528.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-27 00:01:09 -04:00
Wilson Snyder be4692772c Ignore MCD fopenw with --bbox-unsup. 2019-09-26 23:37:22 -04:00
Wilson Snyder 4f315d9078 Fix ugly error on interface misuse, bug1525. 2019-09-25 21:53:01 -04:00
Wilson Snyder f133c4d0b3 Fix mis-indenting AstComments with C++ symbols. 2019-09-24 19:07:22 -04:00
Wilson Snyder 8490046028 Internals: AstComment optional suppression of at. No functional change intended. 2019-09-23 18:44:45 -04:00
Lukasz Dalek d6ac351dcb Add --public-flat-rw switch, bug1511.
This switch exposes VARs, PORTs and WIREs to C++ code. It must be use
with care as it has a significant performance impact and may result in
mis-simulation of generated clocks. Anyhow, it is prefered over
--public and useful for VPI.

Signed-off-by: Lukasz Dalek <[email protected]>
Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-23 07:56:07 -04:00
Stefan Wallentowitz 502bd6cbd6 Tests: Set VM_PREFIX from test script.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-21 08:26:34 -04:00
Philipp Wagner d7b6b53c4d Make callCbs() public.
VerilatedVpi::callCbs() can be used by the user to signal
simulation-related callbacks, e.g.
VerilatedVpi::callCbs(cbStartOfSimulation).

The information if any callbacks have been called may be important to
drive an evaluation until no further changes are observed.

Signed-off-by: Lukasz Dalek <[email protected]>
Signed-off-by: Philipp Wagner <[email protected]>
Signed-off-by: Stefan Wallentowitz <[email protected]>
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-21 07:43:20 -04:00
Stefan Wallentowitz 96725b3431 Tests: To allow reuse of cpp files, allow to set the PLI filename.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-19 18:46:45 -04:00
Stefan Wallentowitz 8686ed9b00 Fix vpiType accessor, bug1510.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-18 12:24:19 -04:00
Stefan Wallentowitz 32e1207782 Fix vpiType accessor, bug1509.
Signed-off-by: Wilson Snyder <[email protected]>
2019-09-18 07:22:59 -04:00
Wilson Snyder 900115bb2d Fix false warning on backward indexing, bug1507. 2019-09-17 15:17:23 -04:00
Wilson Snyder 3469c78153 Fix bad module name. 2019-09-16 21:09:18 -04:00
Wilson Snyder baa634343b Fix config_rev revision detection on old versions. 2019-09-13 07:20:26 -04:00
Wilson Snyder 1471f5691a Fix error on multidimensional cells, bug1505. 2019-09-12 19:06:26 -04:00
Wilson Snyder e556269692 Commentary - Spelling fixes 2019-09-12 07:22:22 -04:00
Todd Strader d1af69f91d Produce man files with 'make all' 2019-09-11 10:01:18 -04:00
Wilson Snyder fa904f386c Commentary - Spelling fixes 2019-09-09 07:50:21 -04:00
Todd Strader a4daae66de -LDLIBS isn't an option 2019-09-06 13:04:47 -04:00
Todd Strader c813026566 Make Syms file honor --output-split-cfuncs, bug1499. 2019-09-04 06:15:41 -04:00
Wilson Snyder 314cd92129 Support $fseek, $ftell, $frewind, bug1496. 2019-09-03 21:28:15 -04:00
Wilson Snyder 3bc260c55d Fix make test with no VERILATOR_ROOT, bug1494. 2019-09-01 11:15:42 -04:00
Wilson Snyder 4c0f95af10 devel release 2019-08-29 19:12:47 -04:00
Wilson Snyder 35fe205fd6 Version bump 2019-08-29 18:58:38 -04:00
Todd Strader 70cf2582d6 Add XSim support to driver.pl, bug1493. 2019-08-29 17:00:49 -04:00
Todd Strader ec620387af Add --dpi-hdr-only, bug1491. 2019-08-27 21:36:59 -04:00
Wilson Snyder e1e4bde125 Remove old V3ClkGater code 2019-08-27 17:51:06 -04:00
Todd Strader b947391662 Retain widthSized when simulating 2019-08-12 15:38:58 -04:00
Wilson Snyder edc0f442e4 Tests: Add tests for bug1487. 2019-08-09 05:45:44 -04:00
Wilson Snyder 562b9551bf Internals: Remove some unused arguments. No functional change intended. 2019-08-09 04:12:49 -04:00
Wilson Snyder f74af949da Remove trailing spaces. 2019-08-08 17:53:49 -04:00
Wilson Snyder 81e806e895 Fix elaboration time errors, bug1429. 2019-08-04 22:34:54 -04:00
Wilson Snyder 7d4958264a Support arbitrary-argument $warning/$info etc 2019-08-04 21:50:08 -04:00
Wilson Snyder 88b87429dc Tests: Add elaboration info test. 2019-08-04 21:31:06 -04:00
Wilson Snyder 429f463032 Don't check SYSTEMC environment, for part of CMake support, bug1363. 2019-08-04 20:21:58 -04:00
Wilson Snyder af4a39603c Makefile: Run hello world before other examples. 2019-08-04 20:20:29 -04:00
Wilson Snyder a13d230d8c Tests: Less verbosity 2019-08-04 15:04:34 -04:00
Wilson Snyder b7bd5956ea Concats should be unsigned 2019-08-04 14:48:17 -04:00
Wilson Snyder 1a36e05cc6 Fix core dump on v3Number replace'ed assertions. 2019-08-04 14:14:28 -04:00
Wilson Snyder 71265a8ec9 Internals: Rename unsized functions. No functional change. 2019-08-04 12:39:35 -04:00
Wilson Snyder 3a720204c2 Internals: Remove m_logicMap as m_detailedMap covers it. No functional change intended. 2019-08-04 08:16:24 -04:00
Wilson Snyder a95f58749f Fix internal error on gate optimization of assign, bug1475. 2019-08-03 21:49:39 -04:00
Wilson Snyder 9e58ede480 Internals: Rename V3Hashed functions for future commit. No functional change. 2019-08-03 19:05:59 -04:00
Wilson Snyder cf2ac30f66 Fix date. 2019-08-02 21:39:32 -04:00
Wilson Snyder 68b22a4a3d Tests: Summarize any skips. 2019-07-30 22:20:37 -04:00
Wilson Snyder 875dc9a27e --debug doesn't take an arg 2019-07-30 18:40:38 -04:00
Maarten De Braekeleer 1332446f2a Spelling fixes.
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-30 18:27:36 -04:00
Wilson Snyder 6b798830c9 Fix spacing 2019-07-29 21:07:37 -04:00
Wilson Snyder ffa23b59b8 Tests: Add iff test, bug1482. 2019-07-26 19:31:02 -04:00
Maarten De Braekeleer 7d27461054 Spelling fixes.
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-26 12:58:13 -04:00
Maarten De Braekeleer b3f318d8ab Add contributor certification. 2019-07-26 12:57:42 -04:00
Todd Strader 4a14788c9b When showing an error, show the instance location 2019-07-26 12:52:38 -04:00
Wilson Snyder 5560da2934 Commentary 2019-07-26 06:24:26 -04:00
Todd Strader 43ce048f9e Add rr support 2019-07-25 21:34:09 -04:00
Todd Strader b045111a67 Refactor SimulateVisitor to use AstConst 2019-07-23 13:58:17 -04:00
Todd Strader 654571bd1c V3Number cleanup 2019-07-22 15:07:08 -04:00
Todd Strader a3fd105acb Add more Travis coverage 2019-07-18 05:31:02 -04:00
Wilson Snyder 97561bf064 When showing an error, show source code. 2019-07-14 21:42:03 -04:00
Wilson Snyder a4820fc700 Misc minor error cleanups from show-source branch. 2019-07-14 20:59:56 -04:00
Wilson Snyder ee469eedaf Fix some errors reporting wrong objects. 2019-07-14 15:06:49 -04:00
Wilson Snyder a49d819437 Tests: Default test_regress to quiet 2019-07-14 15:04:19 -04:00
Wilson Snyder cbb9288cb1 Fix some errors reporting wrong objects. 2019-07-14 12:21:39 -04:00
Wilson Snyder 173efbc829 Offer suggestions on bad identifier errors. 2019-07-14 10:08:53 -04:00
Wilson Snyder 0fef3b02ec Fix some parse tokens having wrong fileline. 2019-07-13 12:01:26 -04:00
Wilson Snyder d1ee6689c4 Internals: Make V3LanguageWords a singleton. 2019-07-13 08:57:42 -04:00
Wilson Snyder b3eab9d78a Tests: Move t_math_synmul to extended tests. 2019-07-12 19:35:28 -04:00
Wilson Snyder defd05bdd7 Tests: Fix driver checking threads/gcc for extended tests. 2019-07-12 19:35:10 -04:00
Wilson Snyder a7e5cccf33 In errors, single quote signals and other from-user data. 2019-07-11 22:36:32 -04:00
Wilson Snyder 0f857ce423 In errors, single quote signals and other from-user data. 2019-07-11 22:09:30 -04:00
Wilson Snyder 83cf1882de Quote reserved word messages, and related internal cleanups. 2019-07-11 20:49:35 -04:00
Wilson Snyder e17543d6d8 Tests: Fill in some missing error coverage holes. 2019-07-11 20:18:36 -04:00
Wilson Snyder dacf45fea9 Fix error message continuations to avoid linenumber repetition 2019-07-11 19:15:40 -04:00
Wilson Snyder 13a20c5ee9 Internals: Fix inserted tabs. 2019-07-11 07:05:33 -04:00
Wilson Snyder 58dfe9d071 Internals: Detab and fix spacing style issues. No functional change.
When diff, recommend using "git diff --ignore-all-space"
When merging, recommend using "git merge -Xignore-all-space"
2019-07-11 06:57:49 -04:00
Wilson Snyder 6c5cc885a6 Internals: Cleanup FileLine constructors. No functional change intended. 2019-07-10 22:04:58 -04:00
Sebastien Van Cauwenberghe 2c44ab61ac Fix GDB returning wrong error code on Fedora 30
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-10 06:47:20 -04:00
Sebastien Van Cauwenberghe 0847ea57ae Docs: Add name to contributors
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-10 06:46:28 -04:00
Wilson Snyder 9af84c71f5 Internals: More UASSERT_OBJ conversions. No functional change intended. 2019-07-07 09:01:36 -04:00
Wilson Snyder 4ce77d3e68 Header mentions public use. 2019-07-07 09:00:57 -04:00
Philipp Wagner 3c67791624 docs: Document parse-order-dependency for config files, bug1474
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-06 18:09:23 -04:00
Philipp Wagner a281c00752 docs: Contributor signoff
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-06 18:08:22 -04:00
Wilson Snyder 2ca418288d Fix enum values not being sized based on parent, bug1442. 2019-07-06 16:26:44 -04:00
Wilson Snyder bea34d0ced Internals: Misc enum cleanups. No functional change. 2019-07-06 15:50:25 -04:00
Wilson Snyder a5f2ce0dad Tests: Disable t_leak on Travis-CI. 2019-07-06 13:47:17 -04:00
Gianfranco Costamagna 07ae7146e3 Honour system flags, this makes debug flags being injected correctly.
Signed-off-by: Wilson Snyder <[email protected]>
2019-07-06 13:02:36 -04:00
Wilson Snyder 8548ecfdac Internals: Add UASSERT_OBJ macro to replace hand-done ifs. No functional change intended.
This makes it easier to filter out correctly zero code-coverage lines.
2019-07-06 12:57:50 -04:00
Wilson Snyder 7e54ff1b37 Additional lcov code coverage. 2019-07-05 22:30:19 -04:00
Wilson Snyder a4b9745e6e Fix lifetime opt dropping 2019-07-05 22:30:19 -04:00
Wilson Snyder 8612ba2b8d Internals: Commentary and fix gate debug glibc warning 2019-07-05 22:30:19 -04:00
Todd Strader fea6e047e2 Add Travis badge 2019-07-05 05:26:08 -04:00
Wilson Snyder 01ef7122e9 Internals: Add lcov code coverage markers. 2019-06-30 22:37:03 -04:00
Wilson Snyder ac43e7322b Internals: Remove dead code. 2019-06-30 22:11:56 -04:00
Wilson Snyder 02a3f2089f Include filenames in savable error. 2019-06-30 22:01:53 -04:00
Wilson Snyder 33ad834106 Tests: Close some test coverage holes. 2019-06-30 22:00:18 -04:00
Wilson Snyder efe739c52f Tests: Cover --error-limit and update docs (found via coverage). 2019-06-30 21:36:57 -04:00
Wilson Snyder 5cd531a5e0 Tests: Fix glib warning 2019-06-30 21:35:55 -04:00
Wilson Snyder 0e8dfdbb71 Tests: Less verbosity. 2019-06-30 17:45:42 -04:00
Wilson Snyder ec32a9b976 Tests: Close some test coverage holes. 2019-06-30 17:38:41 -04:00
Wilson Snyder 1aae6df669 Internals: Run graph self tests on --debug-self-test 2019-06-30 17:36:58 -04:00
Wilson Snyder f7641d2ecc Change MULTITOP to warning to help linting, see manual. 2019-06-30 16:46:48 -04:00
Wilson Snyder 5f27c41ee3 Test driver: Cleanup rerun flags & status. 2019-06-29 21:36:33 -04:00
Wilson Snyder 51df77099a Test driver: With --quiet print summary every 15sec or Travis barfs. 2019-06-29 15:58:00 -04:00
Wilson Snyder b8b7e5c978 Test driver: Add --rerun and --quiet options 2019-06-29 15:24:56 -04:00
Wilson Snyder dddcfeb482 Test driver: Move one_test, no functional change. 2019-06-29 13:37:01 -04:00
Wilson Snyder 8d63f83177 Tests: Reduce verbosity unless use --verbose 2019-06-29 13:11:30 -04:00
Wilson Snyder d43e9aa2c5 Fix not in array context on non-power-of-two slices, msg2946. 2019-06-29 11:30:38 -04:00
Wilson Snyder a2c1b7f827 Tests: Fix t_flag_csplit skip on old make. 2019-06-29 08:25:50 -04:00
Wilson Snyder 2fff92fe78 Tests: Add array MDA test. 2019-06-29 08:12:00 -04:00
Wilson Snyder ba9af4aabf For internal messages, use <command-line> and <built-in> to match GCC. 2019-06-29 07:39:34 -04:00
Wilson Snyder ef02678305 tests: Fix default make test, broke earlier commit. 2019-06-29 07:22:19 -04:00
Wilson Snyder 6990db70fa Avoid unique internal fileline in selftest. 2019-06-28 22:34:01 -04:00
Wilson Snyder af5616c077 Fix line number in dup vars. 2019-06-28 22:34:01 -04:00
Todd Strader 009f053d6e Add initial Travis CI config 2019-06-27 11:26:25 -04:00
Wilson Snyder 6903c52ef7 Tests: Add coverage of missing include error. 2019-06-26 19:12:57 -04:00
Wilson Snyder aa65dfb1bc Tests: Use only 2 threads for t_gantt. 2019-06-26 19:06:52 -04:00
Wilson Snyder 84a2cd0ec7 Remove some old DIRPROJECT dead code. 2019-06-26 18:50:38 -04:00
Wilson Snyder 8e7559c6c9 Show included-from filenames in warnings, bug1439. 2019-06-22 17:01:39 -04:00
Wilson Snyder 951521320a Warnings: Suppress dup lines, and use lowercase note: to match gcc 2019-06-22 16:12:17 -04:00
Wilson Snyder abc0eb92a0 Debug: Show only first line of suppressed warnings 2019-06-22 14:25:31 -04:00
Wilson Snyder c514bb26e8 Always internal module wrapper TOP. 2019-06-22 13:43:49 -04:00
Wilson Snyder 5cb6474cc6 Fix not reporting some duplicate signals/ports, bug1462. 2019-06-22 12:43:48 -04:00
Wilson Snyder b8eb6368e9 Tests: Fix up duplicate var declarations. 2019-06-22 12:32:13 -04:00
Wilson Snyder 6239deb1df Tests: Disable t_flag_csplit with old make. 2019-06-19 08:44:40 -04:00
Wilson Snyder 89c2a6070a devel release 2019-06-16 10:01:09 -04:00
Wilson Snyder c53ea10c75 Version bump 2019-06-16 09:30:56 -04:00
Wilson Snyder 8fa54b1c4d Add .gitattributes 2019-06-15 21:49:49 -04:00
Wilson Snyder e5fae03364 docs: Move license files back to top out of docs to appease github. 2019-06-15 21:41:38 -04:00
Wilson Snyder 081fd3b789 Rename to LICENSE to appease github 2019-06-15 17:57:40 -04:00
Wilson Snyder 0edd3c9e95 Tests: Support remote test obj_ 2019-06-15 16:37:58 -04:00
Wilson Snyder 659c7b78d5 Warn only once if too few CPUs. 2019-06-15 09:17:51 -04:00
Wilson Snyder 34ef3c9c38 Internals: Assert V3Number ops have different pointers. 2019-06-15 08:10:17 -04:00
Wilson Snyder 90af180ec1 Fix constant function return of function var, bug1467. 2019-06-15 08:03:39 -04:00
Wilson Snyder 0d71c1154d Fix overshift error to have user's source line. 2019-06-15 07:44:03 -04:00
Alex Chadwick 5da5e32e86 Fix --savable invalid C++ on packed arrays, bug1465.
Signed-off-by: Wilson Snyder <[email protected]>
2019-06-14 18:42:27 -04:00
Wilson Snyder ea59a39661 Commentary 2019-06-13 20:53:39 -04:00
Wilson Snyder f5ca1a04cc Docs: Rewrite README 2019-06-13 20:51:06 -04:00
Wilson Snyder b6c905dffc Move files into docs directory. 2019-06-13 07:19:44 -04:00
Wilson Snyder e4a3f9b38c Tests: Remove tabs from golden-output tests. No functional change. 2019-06-12 22:41:51 -04:00
Wilson Snyder b3e2d26e35 Tests: Remove tabs from golden-output tests. No functional change. 2019-06-12 22:22:36 -04:00
Wilson Snyder 79e9fbaeb7 Tests: Add additional .out files instead of expects. 2019-06-12 21:49:40 -04:00
Wilson Snyder f5f5cd522b Tests: Make standard lint() to replace inconsistent compile() 2019-06-12 21:05:02 -04:00
Wilson Snyder e713c8ce57 Fix not reporting some duplicate signals, bug1462. 2019-06-12 19:17:10 -04:00
Wilson Snyder 94ed817897 Fix debug over-verbosity. 2019-06-12 19:11:26 -04:00
Wilson Snyder ff360738b5 XML: Remove extranious space on dtypes. 2019-06-12 07:19:14 -04:00
Wilson Snyder f7f73a0825 Internals: Standardize internal FileLine filenames. 2019-06-12 07:00:56 -04:00
Wilson Snyder 2cedd14d43 Fix build error on MinGW, bug1460. 2019-06-11 21:38:17 -04:00
Wilson Snyder 77c2d49d1a Internals: Move code out of verilog.y. No functional change. 2019-06-11 21:19:44 -04:00
Wilson Snyder dd8d5ef687 Internals: Move code out of verilog.l. No functional change. 2019-06-11 21:03:03 -04:00
Wilson Snyder cfb05cd70a Whitespace cleanup. No functional change. 2019-06-11 20:20:04 -04:00
Todd Strader 6f2f668449 Fix dotted references to type parameter sizes, bug1458.
Signed-off-by: Wilson Snyder <[email protected]>
2019-06-11 19:00:24 -04:00
Wilson Snyder 6ffbb7cabf Internals: Remove extra semicolons. No functional change. 2019-06-11 18:31:06 -04:00
Wilson Snyder 6c1782e4de Add contributors and test. 2019-06-10 20:29:58 -04:00
Todd Strader 10e3cc6e3b Tests: Better checking for type param hash fix.
Signed-off-by: Wilson Snyder <[email protected]>
2019-06-06 19:57:31 -04:00
Todd Strader 34424e70d8 Fix sameHash error on type parameters, bug1456.
Signed-off-by: Wilson Snyder <[email protected]>
2019-06-05 20:39:42 -04:00
Wilson Snyder 38ad8727af Tests: Remove CRs. 2019-06-04 20:37:16 -04:00
Wilson Snyder 4e115d4b69 Fix performance when mulithreaded on 1 CPU, bug1455. 2019-06-03 19:13:03 -04:00
Wilson Snyder f6f8073058 Support logical equivalence operator <->. 2019-06-01 19:40:06 -04:00
Wilson Snyder 902ba752a3 Move many unsupported errors from lex to parser so can --bbox-unsup ignore them. 2019-05-31 21:05:50 -04:00
Wilson Snyder 97d9de3dad Support deferred assertions, bug1449. 2019-05-31 07:33:57 -04:00
Todd Strader 97fef7c60b Tests: Fix t_dist_whitespace.pl --golden, bug1451
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-30 20:36:13 -04:00
Wilson Snyder a58e7d94ec Error continuation lines no longer have %Error prefix. 2019-05-30 20:30:59 -04:00
Wilson Snyder c0be8bcefb Internals: Remove some pointless V3Number temporaries. No functional change intended. 2019-05-29 23:18:47 -04:00
Wilson Snyder 8846b365f4 Fix some memory leaks in V3Const/V3Unroll. 2019-05-29 22:43:26 -04:00
Kanad Kanhere 72eb361131 Fix invalid XML output due to special chars, bug1444.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-29 18:41:03 -04:00
Wilson Snyder b83b606267 Internals: Detab and fix spacing style issues. No functional change.
When diff, recommend using "git diff --ignore-all-space"
When merging, recommend using "git merge -Xignore-all-space"
2019-05-19 16:13:13 -04:00
Wilson Snyder 59d7d9e8c3 Fix real parameter assignment, bug1427. 2019-05-17 20:50:57 -04:00
Kanad Kanhere 3411279294 Internals: Relocate quoteNameControls, part of bug1444.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-16 21:44:01 -04:00
Wilson Snyder 8d6bea8975 nodist: Fix git_untabify --narrow. 2019-05-16 21:32:50 -04:00
Wilson Snyder 01725f662f Fix $display with string without %s, bug1441. 2019-05-16 21:21:38 -04:00
Wilson Snyder d841e68f4f Fix parameter function string returns, bug1441. 2019-05-16 21:16:20 -04:00
Wilson Snyder 13ecb8e177 Fix fault on with %t, bug1443. 2019-05-16 19:35:10 -04:00
Todd Strader 26436cf4dd Tests: Fix files ignored by t_dist_manifest, bug1438.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-15 19:02:17 -04:00
Wilson Snyder 96c70ea2df Internals: Fix some long lines in include files. No functional change.
When merging, recommend using "git merge -Xignore-all-space"
2019-05-14 22:49:32 -04:00
Wilson Snyder c8849094fc Fix spacing of last commit. 2019-05-14 22:05:37 -04:00
Wilson Snyder afea6d84e3 Mark infrequently called functions with GCC cold attribute. 2019-05-14 22:03:50 -04:00
Wilson Snyder 1fb0af7fba Internals: Fix some -Wsuggest-attribute=const suggestions. 2019-05-14 21:46:19 -04:00
Wilson Snyder 8ad1a68420 Fix OSX compile issue with -Winvalid-noreturn, bug1440. 2019-05-14 20:51:28 -04:00
Wilson Snyder 6ef7d5f0fd Internals: Fix spacing of last commit 2019-05-14 06:56:20 -04:00
Todd Strader d0fbdfac07 Add --quiet-exit, bug1436.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-14 06:47:51 -04:00
Sergey Kvachonok 16997d153f Fix sign-compare warning in verilated.cpp, bug1437.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-14 06:07:16 -04:00
Wilson Snyder 7777d10e9b Tests: Check for and remove trailing newlines 2019-05-13 19:47:52 -04:00
Wilson Snyder 00214f738f Tests: New scope-relevant tests, towards bug1305. 2019-05-13 19:31:24 -04:00
Wilson Snyder 07e6bc17db Fix error message showing pointer 2019-05-13 19:31:00 -04:00
Wilson Snyder afdfa4df87 Support VerilatedFstC set_time_unit, bug1433. 2019-05-12 08:19:49 -04:00
Wilson Snyder 1f714c6813 Commentary: Spelling fixes. 2019-05-11 18:42:27 -04:00
Wilson Snyder 5df3032b11 gtkwave: Merge from upstream. 2019-05-09 20:38:48 -04:00
Todd Strader eac3458647 Internals: V3Number tracks node information, part of bug1305.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-09 20:03:19 -04:00
Wilson Snyder 00efa05b50 devel release 2019-05-08 21:39:23 -04:00
Wilson Snyder cc1d380864 Version bump 2019-05-08 21:15:56 -04:00
Wilson Snyder f96942a526 Internals: Detab and fix spacing style issues in include files. No functional change.
When merging, recommend using "git merge -Xignore-all-space"
2019-05-08 21:13:38 -04:00
Wilson Snyder b23fc06388 Internals: Detab and fix spacing style issues in some include files. No functional change. 2019-05-07 23:30:24 -04:00
Wilson Snyder f818ddc71c Internals: Detab and fix spacing style issues in tests and scripts. No functional change. 2019-05-07 22:34:09 -04:00
Wilson Snyder 37c8cc82b2 Auto-extend and WIDTH warn on unsized X/Zs, bug1423. 2019-05-07 21:57:38 -04:00
Wilson Snyder 03ebd5554f Fix table compile error with multiinterfaces, bug1431. 2019-05-06 19:33:54 -04:00
Wilson Snyder a2a7021914 Reorder VCD codes for better viewer packing. 2019-05-06 18:55:38 -04:00
Wilson Snyder c6650f88e1 Internals: Remove some uses of AstConst taking V3Number. No functional change intended. 2019-05-03 21:21:18 -04:00
Wilson Snyder 55a25674a2 Add --trace-fst-thread. 2019-05-02 20:33:05 -04:00
Wilson Snyder 05c3d520a6 Test: Ignore tabs on new .out 2019-05-02 20:32:50 -04:00
Wilson Snyder 6b3304320b For FST tracing use LZ4 compression. 2019-05-02 19:55:16 -04:00
Wilson Snyder 8d15276625 Tests: Use golden_filename consistently. 2019-05-02 19:02:40 -04:00
Todd Strader 354f107fed Tests: Converting tests to golden files for bug1305.
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-02 18:45:32 -04:00
Wilson Snyder 1ff55c20e0 Support "'dx" constants, bug1423. 2019-05-01 20:02:28 -04:00
Todd Strader 9583f0d3cc Add .git file (not directory) to MANIFEST.SKIP for git worktrees
Signed-off-by: Wilson Snyder <[email protected]>
2019-05-01 19:48:27 -04:00
Wilson Snyder 3acb85a005 Fix FST enums not displaying, bug1426. 2019-05-01 19:18:45 -04:00
Wilson Snyder 08d041cb93 Add error when use parameters without value, bug1424. 2019-04-30 19:16:41 -04:00
Wilson Snyder 274b2002c2 Fix GTKWave register warning, bug1421. 2019-04-29 05:28:30 -04:00
Todd Strader 681e91f9d8 Fix FST documentation, bug1419.
Signed-off-by: Wilson Snyder <[email protected]>
2019-04-28 17:53:58 -04:00
Wilson Snyder 6e333bd9ab Fix test problems when missing fst2vcd, bug1417. 2019-04-10 20:51:38 -04:00
Larry Lee 6a331e37fc Fix missing VL_SHIFTL_ errors, bug1412, bug1415.
Signed-off-by: Wilson Snyder <[email protected]>
2019-04-05 19:32:25 -04:00
Sergey Kvachonok d8a020905a Fix MinGW GCC 6 printf formats, bug1413.
Signed-off-by: Wilson Snyder <[email protected]>
2019-04-02 18:24:36 -04:00
Wilson Snyder efa6f4cd95 Fix extraction, part of fix missing VL_SHIFTL_QQW error, bug1412. 2019-03-28 19:46:39 -04:00
Larry Lee ca537dc3ed Fix missing VL_SHIFTL_QQW error, bug1412.
Signed-off-by: Wilson Snyder <[email protected]>
2019-03-28 19:11:46 -04:00
Wilson Snyder 3b64f54cea Support '#' comments in , bug1411. 2019-03-27 07:40:14 -04:00
Wilson Snyder 32c1e38b84 devel release 2019-03-23 21:14:30 -04:00
Wilson Snyder a7aa8820e1 Version bump 2019-03-23 21:00:07 -04:00
Wilson Snyder 2582a83376 Unsupported error on select of concatenation 2019-03-13 19:52:23 -04:00
Wilson Snyder 0094cd7a81 Internals: Spacing fixes. No functional change. 2019-03-13 19:47:47 -04:00
Wilson Snyder d9b33d74a4 Support void' cast on functions called as tasks, bug1383. 2019-03-10 15:12:20 -04:00
Wilson Snyder 539a773ea7 Add IGNOREDRETURN warning. 2019-03-10 14:57:01 -04:00
Wilson Snyder b1831d7e33 Fix +1364-1995ext flags applying too late, bug1384. 2019-03-10 14:09:22 -04:00
Wilson Snyder b8ccb7a4c1 Fix maintainer test when no Parallel::Forker, msg2630. 2019-03-10 12:14:58 -04:00
Wilson Snyder 0eb75a41bb Fix perl 5.38 warning. 2019-03-10 12:14:02 -04:00
Wilson Snyder 4cc47e3297 Tests: Cleanup spacing/style. No functional change. 2019-03-10 09:25:23 -04:00
Wilson Snyder 7bf3366041 Support . 2019-03-07 20:56:53 -05:00
Wilson Snyder c4b9f4bccf Tests: Remove old verilator_file_descriptor 2019-03-07 18:29:44 -05:00
Wilson Snyder 455c552132 Fix MSVC compile error, bug1406. 2019-03-04 20:29:01 -05:00
Wilson Snyder f26fb51509 Commentary, bug1339. 2019-03-01 20:14:48 -05:00
Wilson Snyder ab3c6576ed Report PORTSHORT errors on concat constants, bug 1400. 2019-02-27 21:06:07 -05:00
Wilson Snyder d1bd994113 Commentary, bug1399. 2019-02-26 18:56:13 -05:00
Wilson Snyder d1548b1161 Commentary 2019-02-26 18:24:46 -05:00
Wilson Snyder 8a43f41ed6 Fix $value$plus$args missing verilated_heavy.h. 2019-02-15 18:33:52 -05:00
Wilson Snyder 42759e4011 Fix VERILATOR_GDB being ignored, msg2860. 2019-02-12 18:20:40 -05:00
Wilson Snyder 27fa19eb94 Add +verilator+seed, bug1396. 2019-02-04 20:28:17 -05:00
Wilson Snyder 426ed8589b devel release 2019-01-28 07:30:42 -05:00
996 changed files with 54349 additions and 48992 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-modernize*,-hicpp*,-and
WarningsAsErrors: ''
HeaderFilterRegex: ''
FormatStyle: none
CheckOptions:
CheckOptions:
- key: google-readability-braces-around-statements.ShortStatementLines
value: '2'
- key: google-readability-namespace-comments.SpacesBeforeComments
+4
View File
@@ -0,0 +1,4 @@
*.v linguist-language=SystemVerilog
*.vh linguist-language=SystemVerilog
*.sv linguist-language=SystemVerilog
nodist linguist-detectable=false
+111
View File
@@ -0,0 +1,111 @@
# DESCRIPTION: Travis-CI config
#
# Copyright 2003-2019 by Todd Strader. Verilator 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.
language: cpp
matrix:
include:
# Non-cron build will just run on whatever linux flavor we get
- if: type != cron
os: linux
compiler: gcc
env:
- SCENARIOS=--dist
- if: type != cron
os: linux
compiler: gcc
env:
- SCENARIOS=--vlt
- if: type != cron
os: linux
compiler: gcc
env:
- SCENARIOS=--vltmt
# Cron builds try different OS/compiler combinations
- if: type = cron
dist: xenial
compiler: gcc
env:
- SCENARIOS=--dist
- if: type = cron
dist: xenial
compiler: gcc
env:
- SCENARIOS=--vlt
- if: type = cron
dist: xenial
compiler: gcc
env:
- SCENARIOS=--vltmt
- if: type = cron
dist: xenial
compiler: clang
env:
- SCENARIOS=--dist
- if: type = cron
dist: xenial
compiler: clang
env:
- SCENARIOS=--vlt
- if: type = cron
dist: xenial
compiler: clang
env:
- SCENARIOS=--vltmt
# - if: type = cron
# os: osx
# compiler: gcc
# env:
# - SCENARIOS=--dist
# - if: type = cron
# os: osx
# compiler: gcc
# env:
# - SCENARIOS=--vlt
# - if: type = cron
# os: osx
# compiler: gcc
# env:
# - SCENARIOS=--vltmt
- if: type = cron
dist: trusty
compiler: gcc
env:
- SCENARIOS=--dist
- if: type = cron
dist: trusty
compiler: gcc
env:
- SCENARIOS=--vlt
- if: type = cron
dist: trusty
compiler: gcc
env:
- SCENARIOS=--vltmt
cache: ccache
# Some tests require gdb
addons:
apt:
packages:
- gdb
before_install:
# Perl modules needed for testing
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker Bit::Vector
before_script:
- export VLT_JOBS=$((`nproc` + 1))
- export OBJCACHE=ccache
- export VERILATOR_ROOT=`pwd`
- autoconf
script:
- >
./configure --enable-maintainer-mode --enable-longtests &&
make -j $VLT_JOBS &&
make test_regress DRIVER_FLAGS="-j 0 --quiet --rerun"
after_script:
- ccache -s
-674
View File
@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+143 -1
View File
@@ -2,6 +2,148 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.020 2019-10-06
*** Support $fseek, $ftell, $frewind, bug1496. [Howard Su]
*** Add --public-flat-rw, bug1511. [Stefan Wallentowitz]
*** Support vpiModule, bug1469. [Stefan Wallentowitz]
**** Make Syms file honor --output-split-cfuncs, bug1499. [Todd Strader]
**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy]
**** Fix error on multidimensional cells, bug1505. [Anderson Ignacio Da Silva]
**** Fix config_rev revision detection on old versions.
**** Fix false warning on backward indexing, bug1507. [Hao Shi]
**** Fix vpiType accessor, bug1509, bug1510. [Stefan Wallentowitz]
**** Fix ugly error on interface misuse, bug1525. [Bogdan Vukobratovic]
**** Fix misc bad-syntax crashes, bug1529-bug1533. [Eric Rippey]
**** Fix case statements with strings, bug1536. [Philipp Wagner]
* Verilator 4.018 2019-08-29
** When showing an error, show source code and offer suggestions of replacements.
** When showing an error, show the instance location, bug1305. [Todd Strader]
*** Add --rr, bug1481. [Todd Strader]
*** Change MULTITOP to warning to help linting, see manual.
*** Add XSim support to driver.pl, bug1493. [Todd Strader]
**** Show included-from filenames in warnings, bug1439. [Todd Strader]
**** Fix elaboration time errors, bug1429. [Udi Finkelstein]
**** Fix not reporting some duplicate signals/ports, bug1462. [Peter Gerst]
**** Fix not in array context on non-power-of-two slices, msg2946. [Yu Sheng Lin]
**** Fix system compile flags injection. [Gianfranco Costamagna]
**** Fix enum values not being sized based on parent, bug1442. [Dan Petrisko]
**** Fix internal error on gate optimization of assign, bug1475. [Oyvind Harboe]
**** Add --dpi-hdr-only, bug1491. [Todd Strader]
* Verilator 4.016 2019-06-16
*** Add --quiet-exit, bug1436. [Todd Strader]
**** Error continuation lines no longer have %Error prefix.
**** Support logical equivalence operator <->.
**** Support VerilatedFstC set_time_unit, bug1433. [Pieter Kapsenberg]
**** Support deferred assertions, bug1449. [Charles Eddleston]
**** Mark infrequently called functions with GCC cold attribute.
**** Fix sign-compare warning in verilated.cpp, bug1437. [Sergey Kvachonok]
**** Fix fault on $realtime with %t, bug1443. [Julien Margetts]
**** Fix $display with string without %s, bug1441. [Denis Rystsov]
**** Fix parameter function string returns, bug1441. [Denis Rystsov]
**** Fix invalid XML output due to special chars, bug1444. [Kanad Kanhere]
**** Fix performance when mulithreaded on 1 CPU, bug1455. [Stefan Wallentowitz]
**** Fix type and real parameter issues, bug1427, bug1456, bug1458. [Todd Strader]
**** Fix build error on MinGW, bug1460. [Richard Myers]
**** Fix not reporting some duplicate signals, bug1462. [Peter Gerst]
**** Fix --savable invalid C++ on packed arrays, bug1465. [Alex Chadwick]
**** Fix constant function return of function var, bug1467. [Roman Popov]
* Verilator 4.014 2019-05-08
*** Add --trace-fst-thread.
**** Support '#' comments in $readmem, bug1411. [Frederick Requin]
**** Support "'dx" constants, bug1423. [Udi Finkelstein]
**** For FST tracing use LZ4 compression. [Tony Bybell]
**** Add error when use parameters without value, bug1424. [Peter Gerst]
**** Auto-extend and WIDTH warn on unsized X/Zs, bug1423. [Udi Finkelstein]
**** Fix missing VL_SHIFTL_ errors, bug1412, bug1415. [Larry Lee]
**** Fix MinGW GCC 6 printf formats, bug1413. [Sergey Kvachonok]
**** Fix test problems when missing fst2vcd, bug1417. [Todd Strader]
**** Fix GTKWave register warning, bug1421. [Pieter Kapsenberg]
**** Fix FST enums not displaying, bug1426. [Danilo Ramos]
**** Fix table compile error with multiinterfaces, bug1431. [Bogdan Vukobratovic]
* Verilator 4.012 2019-3-23
*** Add +verilator+seed, bug1396. [Stan Sokorac]
*** Support $fread. [Leendert van Doorn]
*** Support void' cast on functions called as tasks, bug1383. [Al Grant]
*** Add IGNOREDRETURN warning, bug1383.
**** Report PORTSHORT errors on concat constants, bug 1400. [Will Korteland]
**** Fix VERILATOR_GDB being ignored, msg2860. [Yu Sheng Lin]
**** Fix $value$plus$args missing verilated_heavy.h. [Yi-Chung Chen]
**** Fix MSVC compile error, bug1406. [Benjamin Gartner]
**** Fix maintainer test when no Parallel::Forker, msg2630. [Enzo Chi]
**** Fix +1364-1995ext flags applying too late, bug1384. [Al Grant]
* Verilator 4.010 2019-01-27
@@ -3196,7 +3338,7 @@ of input ports exists for tracing.
* Verilator 0.0 1994/7/8
**** First code written.
----------------------------------------------------------------------
This uses outline mode in Emacs. See C-h m [M-x describe-mode].
+1 -1
View File
@@ -1,7 +1,7 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+4 -1
View File
@@ -1,5 +1,6 @@
\.clang-tidy
\.git/
\.git$
\.svn/
\.(bak|old)/
\.(bak|old)$
@@ -13,6 +14,7 @@
.*\.key
.*\.vcd
.*\.1
\.travis\.yml
/obj_dir/
/obj_dbg/
/obj_nc/
@@ -27,6 +29,8 @@
^Makefile$
bin/verilator_bin.*
bin/verilator_coverage_bin.*
docs/Makefile$
docs/doxygen-doc/.*
src/Makefile$
src/Makefile_obj$
include/verilated.mk$
@@ -46,7 +50,6 @@ nodist/
/simv.daidir/
/vc_hdrs.h$
/csrc/
doxygen-doc/.*
obj_dir/.*
TAGS
.*~
+35 -57
View File
@@ -83,7 +83,7 @@ infodir = @infodir@
pkgdatadir = @pkgdatadir@
# Directory in which to install pkgconfig file
# Generall ${prefix}/share/pkgconfig
# Generally ${prefix}/share/pkgconfig
pkgconfigdir = @pkgconfigdir@
# Directory in which to install data across multiple architectures
@@ -107,16 +107,17 @@ SUBDIRS = src test_regress \
examples/hello_world_c examples/hello_world_sc \
examples/tracing_c examples/tracing_sc \
INFOS = README README.html README.pdf internals.txt internals.html \
internals.pdf verilator.txt verilator.html verilator.pdf \
$(VL_INST_MAN_FILES)
INFOS = README README.html README.pdf \
verilator.txt verilator.html verilator.pdf
# Files that can be generated, but should be up to date for a distribution.
DISTDEP = info Makefile
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
DISTFILES_INC = $(INFOS) .gitignore \
*.in *.ac \
Changes TODO \
Artistic \
Changes \
LICENSE \
MANIFEST.SKIP \
bin/verilator \
bin/verilator_coverage \
@@ -124,7 +125,15 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
bin/verilator_gantt \
bin/verilator_includer \
bin/verilator_profcfunc \
doxygen-mainpage doxygen.config verilator_logo.png \
docs/.gitignore \
docs/CONTRIBUTING.adoc \
docs/CONTRIBUTORS \
docs/Makefile.in \
docs/TODO \
docs/doxygen-mainpage \
docs/doxygen.config \
docs/internals.adoc \
docs/verilator_logo.png \
install-sh configure *.pod \
include/*.[chv]* \
include/*.in \
@@ -172,12 +181,21 @@ INST_PROJ_BIN_FILES = \
DISTFILES := $(DISTFILES_INC)
EXAMPLES_FIRST = \
examples/hello_world_c \
examples/hello_world_sc \
EXAMPLES = $(EXAMPLES_FIRST) $(filter-out $(EXAMPLES_FIRST), $(sort $(wildcard examples/*)))
ifeq ($(OBJCACHE_JOBS),)
ifneq ($(OBJCACHE_HOSTS),)
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
endif
endif
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_gantt.1 verilator_profcfunc.1
default: all
all: all_nomsg msg_test
all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
@@ -218,13 +236,15 @@ test_regress: all_nomsg
$(MAKE) -C test_regress
examples: all_nomsg
for p in examples/* ; do \
for p in $(EXAMPLES) ; do \
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
done
.PHONY: docs
docs: info
info: $(INFOS)
# Use --no-split to avoid creating filenames > 14 chars.
%.1: ${srcdir}/bin/%
pod2man $< $@
@@ -259,31 +279,12 @@ README.pdf: README.pod Makefile $(POD2LATEXFIX)
pdflatex README.tex
-rm -f README.toc README.aux README.idx README.out
internals.txt: internals.pod
-rm -f $@
$(POD2TEXT) --loose $< > $@
internals.html: internals.pod
pod2html $< >$@
# PDF needs DIST variables; but having configure.ac as dependency isn't detected
internals.pdf: internals.pod Makefile $(POD2LATEXFIX)
pod2latex --full --out internals.tex $<
$(PERL) $(POD2LATEXFIX) "$(DISTTITLE) Internals Manual" "${DISTDATE}" < internals.tex > internals2.tex
mv internals2.tex internals.tex
pdflatex internals.tex
pdflatex internals.tex
-rm -f internals.toc internals.aux internals.idx internals.out
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \
verilator_coverage verilator_gantt verilator_includer verilator_profcfunc
# Some scripts go into both the search path and pkgdatadir,
# so they can be found by the user, and under $VERILATOR_ROOT.
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_gantt.1 verilator_profcfunc.1
VL_INST_INC_BLDDIR_FILES = \
include/verilated_config.h \
include/verilated.mk \
@@ -367,34 +368,9 @@ install-here: installman ftp
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
DISTNAMEREV = $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q ${srcdir}/src/config_rev.h)
DIRPROJECT := $(shell project_dir --project)
VERILATOR_CAD_DIR = $(CAD_DIR)/verilator/$(DISTNAMEREV)/$(DIRPROJECT_ARCH)
INST_PROJ_CVS = cp_if_cvs_diff
install-project: dist
@echo "Install-project to $(DIRPROJECT)"
strip bin/verilator_bin*
strip bin/verilator_coverage_bin*
$(MAKE) install-project-quick
for p in $(VL_INST_MAN_FILES) ; do \
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
done
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
rm $(DISTNAME).tgz
install-project-quick:
ifeq ($(CFG_WITH_DEFENV),yes)
@echo "%Error: Reconfigure with './configure --disable-defenv' to avoid hardcoded paths."
false
endif
@echo "Install-project-quick (no strip) to $(DIRPROJECT)"
for p in $(INST_PROJ_FILES) ; do \
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p; \
done
for p in $(INST_PROJ_BIN_FILES) ; do \
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p-$(DIRPROJECT_ARCH); \
done
install-cadtools: dist
@echo "Install-project to $(CAD_DIR)"
strip bin/verilator_bin*
@@ -435,7 +411,8 @@ CPPCHECK_H = $(wildcard \
$(srcdir)/src/*.h )
CPPCHECK = src/cppcheck_filtered
CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
--suppress=nullPointerRedundantCheck
CPPCHECK_FLAGS += --xml
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
@@ -511,11 +488,12 @@ clean mostlyclean distclean maintainer-clean::
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx
rm -f *.ev *.evs *.ov *.ovs *.cv *.cvs *.ma *.mas
rm -f *.tex
rm -rf test_*/obj_dir
rm -rf examples/*/obj_dir examples/*/logs
rm -rf test_*/obj_dir
rm -rf nodist/obj_dir
distclean maintainer-clean::
rm -f *.info* *.1 $(INFOS)
rm -f *.info* *.1 $(INFOS) $(VL_INST_MAN_FILES)
rm -f Makefile config.status config.cache config.log TAGS
rm -f verilator_bin* verilator_coverage_bin*
rm -f bin/verilator_bin* bin/verilator_coverage_bin*
@@ -530,7 +508,7 @@ TAGS: $(TAGFILES)
.PHONY: doxygen
doxygen:
$(DOXYGEN) doxygen.config
$(MAKE) -C docs doxygen
######################################################################
# Test targets
+146 -73
View File
@@ -3,32 +3,19 @@
=pod
=for html <a href="https://travis-ci.com/verilator/verilator"><img src="https://travis-ci.com/verilator/verilator.svg?branch=master"></a>
=head1 NAME
This is the Verilator package README file.
Welcome to Verilator. This is the Verilator package's README file.
=head1 DISTRIBUTION
http://www.veripool.org/verilator
This package is Copyright 2003-2019 by Wilson Snyder. (Report bugs to
L<http://www.veripool.org/>.)
Verilator 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. (See the documentation for more
details.)
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
This document describes how to initially install Verilator. For more
general information please see L<http://verilator.org>.
=head1 DESCRIPTION
Verilator converts synthesizable (generally not behavioral) Verilog code
into C++ or SystemC code. It is not a complete simulator, just a
translator.
Verilator is a simulator which "Verilates" synthesizable (generally not
behavioral) Verilog code into "Verilated" C++ or SystemC code.
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
reads the specified Verilog code, lints it, and optionally adds coverage
@@ -45,27 +32,77 @@ The resulting executable will perform the actual simulation.
Verilator is developed and has primary testing on Ubuntu. Versions have
also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
with minor porting on any Linix-ish platform. Verilator also works on
with minor porting on any Linux-ish platform. Verilator also works on
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
output (not Verilator itself) compiles under MSVC++ 2008 and newer.
output (not Verilator itself) compiles under all the options above, plus
MSVC++ 2008 and newer.
=head1 INSTALLATION
For more details see
The following are detailed installation instructions.
Alternatively, for a quick summary please see
L<http://www.veripool.org/projects/verilator/wiki/Installing>.
If you will be modifying Verilator, you should use the "git" method as it
will let you track changes.
=over 4
=item
The latest version is available at L<http://www.veripool.org/verilator>.
Obtain binary or sources:
Download the latest package from that site, and decompress.
There are three methods to obtain Verilator, a prebuilt binary as part of
your Linux distribution, via git, or using a tarball. If you will be
modifying Verilator, you should use the "git" method as it will let you
track changes and hopefully contribute in the future.
tar xvzf verilator_version.tgz
=over 4
=item
Prebuilt binary:
You may install a binary on Ubuntu or other distributions using a package
manager. This is unlikely to be the most recent version.
apt-get install verilator
You may now skip the remaining installation steps.
=item
Git:
Get the sources from the repository.
git clone http://git.veripool.org/git/verilator # Only first time
## Note the URL above is not a page you can see with a browser, it's for git only
=item
Tarball:
Get a recent tarball package from L<http://www.veripool.org/verilator>.
Click the "Download" tab, scroll down to the latest package
(i.e. verilator-#.###.tgz), download it, and decompress with:
tar xvzf verilator_#-###.tgz
=back
=item
Install prerequisites:
=over 4
=item
To use Verilator you will need the C<perl>, C<make> (or C<gmake>), and
C<g++> (or C<clang>) packages. To compile Verilator in addition to the above you need the C<flex>,
C<bison> and C<texi2html> packages installed.
sudo apt-get install git make autoconf g++ flex bison # First time prerequisites
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)
=item
@@ -78,22 +115,32 @@ instead.)
=item
To use Verilator you will need the C<perl>, C<make> (or C<gmake>), and
C<g++> (or C<clang>) packages.
To use Verilator FST tracing you will need the C<gtkwave> and C<libgz> (on
To use Verilator FST tracing you will need the C<gtkwave> and C<libgz> (and on
Ubuntu C<zlibc> C<zlib1g> C<zlib1g-dev>) packages installed.
To compile Verilator in addition to the above you need the C<flex>,
C<bison> and C<texi2html> packages installed.
=back
=item
C<cd> to the Verilator directory containing this README.
Prepare for building:
cd verilator # Needed if not already in the package
unsetenv VERILATOR_ROOT # For csh; ignore error if on bash
unset VERILATOR_ROOT # For bash; ignore error if on bash
# If using git:
git pull # Make sure we're up-to-date
git tag # See what versions exist
#git checkout master # Use development branch (e.g. recent bug fix)
#git checkout stable # Use most recent release
#git checkout v{version} # Switch to specified release version
#
autoconf # Create ./configure script
=item
You now have to decide how you're going to eventually install the kit.
Installation Choices
You have to decide how you're going to eventually install the kit.
Note Verilator builds the current value of VERILATOR_ROOT, SYSTEMC_INCLUDE,
and SYSTEMC_LIBDIR as defaults into the executable, so try to have them
@@ -103,25 +150,32 @@ correct before configuring.
=item 1.
Our personal favorite is to always run Verilator from the kit directory.
This allows the easiest experimentation and upgrading. It's also how most
EDA tools operate; to run you point to the tarball, no install is needed.
Our personal favorite is to always run Verilator from its git directory.
This allows the easiest experimentation and upgrading, and allows many
versions of Verilator to co-exist on a system. To run you point to the
program's files, no install is needed.
export VERILATOR_ROOT=`pwd` # if your shell is bash
setenv VERILATOR_ROOT `pwd` # if your shell is csh
./configure
Note after installing (below steps), a calling program should set the
environment variable VERILATOR_ROOT to point to this git directory, then
execute $VERILATOR_ROOT/bin/verilator, which will find the path to all
needed files.
=item 2.
To install globally onto a "cad" disk with multiple versions of every tool,
and add it to path using Modules/modulecmd:
You may eventually be installing onto a project/company-wide "CAD" tools
disk that may support multiple versions of every tool.
unset VERILATOR_ROOT # if your shell is bash
unsetenv VERILATOR_ROOT # if your shell is csh
# For the tarball, use the version number instead of git describe
./configure --prefix /CAD_DISK/verilator/`git describe | sed "s/verilator_//"`
After installing you'll want a module file like the following:
Note after installing (below steps), if you use C<modulecmd>, you'll want a
module file like the following:
set install_root /CAD_DISK/verilator/{version-number-used-above}
unsetenv VERILATOR_ROOT
@@ -131,50 +185,49 @@ and add it to path using Modules/modulecmd:
=item 3.
The next option is to install it globally, using the normal system paths:
The next option is to eventually install it globally, using the normal system paths:
unset VERILATOR_ROOT # if your shell is bash
unsetenv VERILATOR_ROOT # if your shell is csh
./configure
Then after installing (below) the binary directories should already be in
your PATH.
=item 4.
Alternatively you can configure a prefix that install will populate, as
most GNU tools support:
Finally, you may eventually install it into a specific installation prefix,
as most GNU tools support:
unset VERILATOR_ROOT # if your shell is bash
unsetenv VERILATOR_ROOT # if your shell is csh
./configure --prefix /opt/verilator-VERSION
Then after installing you will need to add /opt/verilator-VERSION/bin to
Then after installing (below steps) you will need to add /opt/verilator-VERSION/bin to
PATH.
=back
Note all of the options above did:
./configure ... some options ...
Add to this line C<--enable-longtests> for more complete developer tests.
Additional packages may be required for these tests.
=item
Type C<make> to compile Verilator.
=item
Type C<make test> to check the compilation.
Configure with C<--enable-longtests> for more complete developer tests.
Additional packages may be required for these tests.
You may get a error about a typedef conflict for uint32_t. Edit
verilated.h to change the typedef to work, probably to @samp{typedef
unsigned long uint32_t;}.
=item
If you used the VERILATOR_ROOT scheme you're done. Programs should set the
environment variable VERILATOR_ROOT to point to this distribution, then
execute $VERILATOR_ROOT/bin/verilator, which will find the path to all
needed files.
If you used the prefix scheme, now do a C<make install>.
If you used the prefix scheme, now do a C<make install>. To run verilator,
have the verilator binary directory in your PATH (this should already be
true if using the default configure), and make sure VERILATOR_ROOT is not
set.
=item
You may now wish to consult the examples directory. Type C<make> inside any
example directory to run the example.
@@ -187,25 +240,45 @@ Detailed documentation and the man page can be seen by running:
bin/verilator --help
or reading verilator.txt in the same directory as this README.
or reading verilator.pdf in the same directory as this README.
=head1 DIRECTORY STRUCTURE
or see L<https://www.veripool.org/ftp/verilator_doc.pdf> (which is the most
recent version and thus may differ in some respects from the version you installed).
The directories in the kit after de-taring are as follows:
=head1 PACKAGE DIRECTORY STRUCTURE
The directories in the package directory are as follows:
Changes => Version history
bin/verilator => Compiler Wrapper invoked to Verilate code
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
include/verilated*.h => Global headers
include/verilated.v => Stub defines for linting
include/verilated.mk => Common makefile
src/ => Translator source code
docs/ => Additional documentation
examples/hello_world_c => Example simple Verilog->C++ conversion
examples/hello_world_sc => Example simple Verilog->SystemC conversion
examples/tracing_c => Example Verilog->C++ with tracing
examples/tracing_sc => Example Verilog->SystemC with tracing
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
include/verilated*.h => Global headers
include/verilated.mk => Common Makefile
include/verilated.v => Stub defines for linting
src/ => Translator source code
test_regress => Internal tests
verilator.pdf => Primary documentation
verilator.txt => Primary documentation (text)
=head1 LIMITATIONS
For files created after Verilation, see the manual.
See verilator.txt (or execute C<bin/verilator --help>) for limitations.
=head1 DISTRIBUTION
This package is Copyright 2003-2019 by Wilson Snyder. (Report bugs to
L<http://www.veripool.org/>.)
Verilator 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. (See the documentation for more
details.)
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
+192 -88
View File
@@ -17,13 +17,6 @@ eval 'exec perl -wS $0 ${1+"$@"}'
require 5.006_001;
use warnings;
BEGIN {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
use Getopt::Long;
use FindBin qw($RealBin $RealScript);
use IO::File;
@@ -41,7 +34,9 @@ autoflush STDERR 1;
$Debug = 0;
my $opt_gdb;
my $opt_rr;
my $opt_gdbbt;
my $opt_quiet_exit;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
@@ -58,17 +53,19 @@ foreach my $sw (@ARGV) {
}
Getopt::Long::config("no_auto_abbrev","pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Switches
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
# Additional parameters
"<>" => sub {}, # Ignored
)) {
if (! GetOptions(
# Major operating modes
"help" => \&usage,
"debug" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Switches
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"quiet-exit!" => \$opt_quiet_exit,
"rr!" => \$opt_rr,
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
@@ -85,7 +82,7 @@ if ($opt_gdbbt && !gdb_works()) {
my @quoted_sw = map {sh_escape($_)} @Opt_Verilator_Sw;
if ($opt_gdb) {
# Generic GDB interactive
run (("gdb"||$ENV{VERILATOR_GDB})
run (($ENV{VERILATOR_GDB}||"gdb")
." ".verilator_bin()
# Note, uncomment to set breakpoints before running:
# ." -ex 'break main'"
@@ -98,6 +95,10 @@ if ($opt_gdb) {
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt'");
} elsif ($opt_rr) {
# Record with rr
run ("rr record ".verilator_bin()
." ".join(' ', @quoted_sw));
} elsif ($opt_gdbbt && $Debug) {
# Run under GDB to get gdbbt
run ("gdb"
@@ -105,7 +106,7 @@ if ($opt_gdb) {
." --batch --quiet --return-child-result"
." -ex \"run ".join(' ', @quoted_sw)."\""
." -ex 'set width 0'"
." -ex 'bt'");
." -ex 'bt' -ex 'quit'");
} else {
# Normal, non gdb
run(verilator_bin()." ".join(' ',@quoted_sw));
@@ -114,7 +115,7 @@ if ($opt_gdb) {
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
}
sub debug {
@@ -164,7 +165,8 @@ sub gdb_works {
." --batch-silent --quiet --return-child-result"
." -ex 'run -n'" # `echo -n`
." -ex 'set width 0'"
." -ex 'bt'");
." -ex 'bt'"
." -ex 'quit'");
my $status = $?;
return $status==0;
}
@@ -185,9 +187,9 @@ sub run {
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 4 # SIGILL
|| ($status & 127) == 8 # SIGFPA
|| ($status & 127) == 11) { # SIGSEGV
if (($status & 127) == 4 # SIGILL
|| ($status & 127) == 8 # SIGFPA
|| ($status & 127) == 11) { # SIGSEGV
warn "%Error: Verilator internal fault, sorry. Consider trying --debug --gdbbt\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator aborted. Consider trying --debug --gdbbt\n" if !$Debug;
@@ -195,7 +197,14 @@ sub run {
warn "%Error: Verilator threw signal $status. Consider trying --debug --gdbbt\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
if ($opt_quiet_exit) {
# Same return code as die
exit $! if $!; # errno
exit $? >> 8 if $? >> 8; # child exit status
exit 255; # last resort
} else {
die "%Error: Command Failed $command\n";
}
}
}
@@ -289,6 +298,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--debugi-<srcfile> <level> Enable debugging a source file at a level
--default-language <lang> Default language to parse
+define+<var>=<value> Set preprocessor define
--dpi-hdr-only Only produce the DPI header file
--dump-defines Show preprocessor defines with -E
--dump-tree Enable dumping .tree files
--dump-treei <level> Enable dumping .tree files at a level
@@ -311,7 +321,6 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--inhibit-sim Create function to turn off sim
--inline-mult <value> Tune module inlining
-LDFLAGS <flags> Linker pre-object flags for makefile
-LDLIBS <flags> Linker library flags for makefile
--l2-name <value> Verilog scope name of the top module
--language <lang> Default language standard to parse
+libext+<ext>+[ext]... Extensions for finding modules
@@ -345,10 +354,13 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--prof-threads Enable generating gantt chart data for threads
--private Debugging; see docs
--public Debugging; see docs
--public-flat-rw Mark all variables, etc as public_flat_rw
-pvalue+<name>=<value> Overwrite toplevel parameter
--quiet-exit Don't print the command on failure
--relative-includes Resolve includes relative to current file
--no-relative-cfuncs Disallow 'this->' in generated functions
--report-unoptflat Extra diagnostics for UNOPTFLAT
--rr Run Verilator and record with rr
--savable Enable model save-restore
--sc Create SystemC output
--stats Create statistics file
@@ -361,6 +373,7 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--top-module <topname> Name of top level input module
--trace Enable waveform creation
--trace-fst Enable FST waveform creation
--trace-fst-thread Enable FST threaded waveform creation
--trace-depth <levels> Depth of tracing
--trace-max-array <depth> Maximum bit width for tracing
--trace-max-width <width> Maximum array depth for tracing
@@ -399,7 +412,8 @@ detailed descriptions in L</"RUNTIME ARGUMENTS"> for more information.
+verilator+prof+threads+file+I<filename> Set profile filename
+verilator+prof+threads+start+I<value> Set profile starting point
+verilator+prof+threads+window+I<value> Set profile duration
+verilator+rand+reset+<value> Set random reset technique
+verilator+rand+reset+I<value> Set random reset technique
+verilator+seed+I<value> Set random seed
+verilator+V Verbose version and config
+verilator+version Show version and exit
@@ -728,6 +742,11 @@ Defines the given preprocessor symbol, or multiple symbols if separated by
plusses. Similar to -D; +define is fairly standard across Verilog tools
while -D is an alias for GCC compatibility.
=item --dpi-hdr-only
Only generate the DPI header file. This option has no effect on the name
or location of the file.
=item --dump-defines
With -E, suppress normal output, and instead print a list of all defines
@@ -763,8 +782,8 @@ will also go to standard out.
=item --error-limit I<value>
After this number of errors or warnings are encountered, exit. Defaults to
50.
After this number of errors are encountered, exit. Warnings are not
counted in this limit. Defaults to 50.
=item --exe
@@ -1022,15 +1041,15 @@ developers.
=item --output-split I<bytes>
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 at the next function boundary. In addition, any slow routines will
be placed into __Slow files. This accelerates compilation by as
optimization can be disabled on the slow routines, and the remaining files
can be compiled on parallel machines. Using --output-split should have
only a trivial impact on performance. With GCC 3.3 on a 2GHz Opteron,
--output-split 20000 will result in splitting into approximately
one-minute-compile chunks.
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
at the next function boundary. In addition, any infrequently executed
"cold" routines will be placed into __Slow files. This accelerates
compilation by as optimization can be disabled on the routines in __Slow,
and the remaining files can be compiled on parallel machines. Using
--output-split should have only a trivial impact on performance. With GCC
3.3 on a 2GHz Opteron, --output-split 20000 will result in splitting into
approximately one-minute-compile chunks.
=item --output-split-cfuncs I<statements>
@@ -1150,11 +1169,25 @@ inlining. This will also turn off inlining as if all modules had a
/*verilator public_module*/, unless the module specifically enabled it with
/*verilator inline_module*/.
=item --public-flat-rw
Declares all variables, ports and wires public as if they had /*verilator
public_flat_rw*/ comments. This will make them VPI accessible by their
flat name, but not turn off module inlining. This is particularly useful
in combination with --vpi. This may also in some rare cases result in
mis-simulation of generated clocks. Instead of this global switch, marking
only those signals that need public_flat_rw is typically significantly
better performing.
=item -pvalue+I<name>=I<value>
Overwrites the given parameter(s) of the toplevel module. See -G for a
detailed description.
=item --quiet-exit
When exiting due to an error, do not display the "Command Failed" message.
=item --relative-includes
When a file references an include file, resolve the filename relative to
@@ -1182,6 +1215,10 @@ printing. For example:
will generate a PDF Vt_unoptflat_simple_2_35_unoptflat.dot.pdf from the DOT
file.
=item --rr
Run Verilator and record with rr. See: rr-project.org.
=item --savable
Enable including save and restore functions in the generated model.
@@ -1271,7 +1308,7 @@ good value.
When the input Verilog contains more than one top level module, specifies
the name of the top level Verilog module to become the top, and sets the
default for if --prefix is not used. This is not needed with standard
designs with only one top.
designs with only one top. See also the MULTITOP warning section.
=item --trace
@@ -1290,7 +1327,14 @@ even when waveforms are not turned on during model execution.
=item --trace-fst
Enable FST waveform tracing in the model. This overrides C<--trace>.
Enable FST waveform tracing in the model. This overrides C<--trace> and
C<--trace-fst-thread>. See also C<--trace-fst-thread>.
=item --trace-fst-thread
Enable FST waveform tracing in the model, using a separate thread. This is
typically faster in runtime but slower in total computes than
C<--trace-fst>. This overrides C<--trace> and C<--trace-fst>.
=item --trace-depth I<levels>
@@ -1455,10 +1499,10 @@ Enable all code style related warning messages. This is equivalent to
=item --x-assign unique
Controls the two-state value that is replaced when an assignment to X is
encountered. --x-assign=fast, the default, converts all Xs to whatever is
best for performance. --x-assign=0 converts all Xs to 0s, and is also fast.
--x-assign=1 converts all Xs to 1s, this is nearly as fast as 0, but more
likely to find reset bugs as active high logic will fire. --x-assign=unique
encountered. C<--x-assign fast>, the default, converts all Xs to whatever is
best for performance. C<--x-assign 0> converts all Xs to 0s, and is also fast.
C<--x-assign 1> converts all Xs to 1s, this is nearly as fast as 0, but more
likely to find reset bugs as active high logic will fire. C<--x-assign unique>
will call a function to determine the value, this allows randomization of
all Xs to find reset bugs and is the slowest, but safest for finding reset
bugs in code.
@@ -1483,13 +1527,13 @@ variables are controlled with --x-initial.
Controls the two-state value that is used to initialize variables that are
not otherwise initialized.
--x-initial=0, initializes all otherwise uninitialized variables to zero.
C<--x-initial 0>, initializes all otherwise uninitialized variables to zero.
--x-initial=unique, the default, initializes variables using a function,
C<--x-initial unique>, the default, initializes variables using a function,
which determines the value to use each initialization. This gives greatest
flexibility and allows finding reset bugs. See L</"Unknown states">.
--x-initial=fast, is best for performance, and initializes all variables to
C<--x-initial fast>, is best for performance, and initializes all variables to
a state Verilator determines is optimal. This may allow further code
optimizations, but will likely hide any code bugs relating to missing
resets.
@@ -1524,7 +1568,7 @@ ensure that X E<rarr> 1 triggers a C<posedge>.
B<Note.> Some users have reported that using this option can affect
convergence, and that it may be necessary to use --converge-limit to
increase the number of convergence iterations. This may be another
indication of problems with the modelled design that should be addressed.
indication of problems with the modeled design that should be addressed.
=item --xml-only
@@ -1595,10 +1639,15 @@ posedge eval() and one negedge eval().
=item +verilator+rand+reset+I<value>
When a model was Verilated using "-x-inital unique", sets the
When a model was Verilated using "-x-initial unique", sets the
initialization technique. 0 = Reset to zeros. 1 = Reset to all-ones. 2 =
Randomize. See L</"Unknown states">.
=item +verilator+seed+I<value>
For $random and "-x-initial unique", set the random seed value. If zero or
not specified picks a value from the system random number generator.
=item +verilator+V
Shows the verbose version, including configuration information.
@@ -1698,7 +1747,7 @@ This is an example similar to the above, but using SystemC.
#include "Vour.h"
int sc_main(int argc, char **argv) {
Verilated::commandArgs(argc, argv);
sc_clock clk ("clk",10, 0.5, 3, true);
sc_clock clk ("clk", 10, 0.5, 3, true);
Vour* top;
top = new Vour("top");
top->clk(clk);
@@ -1759,8 +1808,8 @@ the examples directory in the distribution.
=head1 BENCHMARKING & OPTIMIZATION
For best performance, run Verilator with the "-O3 --x-assign=fast
--x-initial=fast --noassert" flags. The -O3 flag will require longer
compile times, and --x-assign=fast --x-initial=fast may increase the risk
--x-initial fast --noassert" flags. The -O3 flag will require longer
compile times, and "--x-assign fast --x-initial fast" may increase the risk
of reset bugs in trade for performance; see the above documentation for
these flags.
@@ -1843,7 +1892,7 @@ For -cc and -sc mode, it also creates:
{prefix}.cpp // Top level C++ file
{prefix}.h // Top level header
{prefix}__Slow{__n}.cpp // Constructors and infrequent routines
{prefix}__Slow{__n}.cpp // Constructors and infrequent cold routines
{prefix}{__n}.cpp // Additional top C++ files (--output-split)
{prefix}{each_verilog_module}.cpp // Lower level internal C++ files
{prefix}{each_verilog_module}.h // Lower level internal header files
@@ -2068,7 +2117,7 @@ command line, or the link), you'd then:
#include "svdpi.h"
#include "Vour__Dpi.h"
int add (int a, int b) { return a+b; }
int add(int a, int b) { return a+b; }
=head2 DPI System Task/Functions
@@ -2118,7 +2167,7 @@ respect to that top level module, then the scope could be set with
#include "svdpi.h"
...
svSetScope (svGetScopeFromName ("dut"));
svSetScope(svGetScopeFromName("dut"));
(Remember that Verilator adds a "V" to the top of the module hierarchy.)
@@ -2132,7 +2181,7 @@ comments within the svdpi.h header for more information.
Verilator allows writing $display like functions using this syntax:
import "DPI-C" function void
\$my_display (input string formatted /*verilator sformat*/ );
\$my_display(input string formatted /*verilator sformat*/ );
The /*verilator sformat*/ indicates that this function accepts a $display
like format specifier followed by any number of arguments to satisfy the
@@ -2240,7 +2289,7 @@ accesses the above signal "readme" would be:
#include "verilated_vpi.h" // Required to get definitions
vluint64_t main_time = 0; // See comments in first example
double sc_time_stamp () { return main_time; }
double sc_time_stamp() { return main_time; }
void read_and_check() {
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
@@ -2339,9 +2388,12 @@ provides one of those threads, and the generated model will create and
manage the other N-1 threads. It's the client's responsibility not to
oversubscribe the available CPU cores. Under CPU oversubscription, the
Verilated model should not livelock nor deadlock, however, you can expect
performance to be far worse than it would be with proper stoichiometry of
performance to be far worse than it would be with proper ratio of
threads and CPU cores.
With --trace-fst-thread, tracing occurs in a separate thread from the main
simulation thread(s). This option is orthogonal to --threads.
The remainder of this section describe behavior with --threads 1 or
--threads N (not --no-threads).
@@ -2387,7 +2439,7 @@ completing after the $stop or $finish.
If using --coverage, the coverage routines are fully thread safe.
If using --dpi, Verilator assumes pure DPI imports are thread safe,
balancing performance versus saftey. See --threads-dpi.
balancing performance versus safety. See --threads-dpi.
If using --savable, the save/restore classes are not multithreaded and are
must be called only by the eval thread.
@@ -2420,6 +2472,10 @@ Configuration files are parsed after the normal Verilog preprocessing, so
`ifdefs, `defines, and comments may be used as if it were normal Verilog
code.
Note that file or line-specific configuration only applies to files read
after the configuration file. It is therefore recommended to pass the
configuration file to Verilator as first file.
The grammar of configuration commands is as follows:
=over 4
@@ -2871,7 +2927,8 @@ signal should be declared public_flat (see above), but read-only.
Used after an input, output, register, or wire declaration to indicate the
signal should be declared public_flat_rd (see above), and also writable,
where writes should be considered to have the timing specified by the given
sensitivity edge list.
sensitivity edge list. Set for all variables, ports and wires using the
--public-flat-rw switch.
=item /*verilator public_module*/
@@ -2892,7 +2949,7 @@ clock pins to be sc_clocks and this is no longer needed.
Used after a port declaration. It sets the port to be of sc_bv<I<width>>
type, instead of bool, vluint32_t or vluint64_t. This may be useful if
the port width is parametrized and different of such modules interface
the port width is parameterized and different of such modules interface
a templated module (such as a transactor) or for other reasons. In general
you should avoid using this attribute when not necessary as with increasing
usage of sc_bv the performance increases significantly.
@@ -3018,9 +3075,10 @@ from a four state simulator. An === comparison to X will always be false,
so that Verilog code which checks for uninitialized logic will not fire.
Assigning a variable to a X will actually assign the variable to a random
value (see the --x-assign switch.) Thus if the value is actually used, the
random value should cause downstream errors. Integers also randomize, even
though the Verilog 2001 specification says they initialize to zero.
value (see the --x-assign switch and +verilator+rand+reset runtime switch.)
Thus if the value is actually used, the random value should cause
downstream errors. Integers also randomize, even though the Verilog 2001
specification says they initialize to zero.
All variables, depending on --x-initial setting, are typically randomly
initialized using a function. By running several random simulation runs
@@ -3282,7 +3340,7 @@ $value$plusargs.
Not supported as Verilator needs to determine all formatting at compile
time. Generally you can just ifdef them out for no ill effect. Note also
VL_TIME_MULTIPLER can be defined at compile time to move the decimal point
VL_TIME_MULTIPLIER can be defined at compile time to move the decimal point
when displaying all times, model wide.
=back
@@ -3398,7 +3456,7 @@ it's a bit slower than a non-delayed assignment.) Here's an example
always @ (posedge clk)
if (~reset_l) begin
for (i=0; i<`ARRAY_SIZE; i++) begin
array[i] = 0; // Non-delayed for verilator
array[i] = 0; // Non-delayed for verilator
end
This message is only seen on large or complicated loops because Verilator
@@ -3573,6 +3631,19 @@ code to a case statement, or a SystemVerilog 'unique if' or 'priority if'.
Disabled by default as this is a code style warning; it will simulate
correctly.
=item IGNOREDRETURN
Warns that a non-void function is being called as a task, and hence the
return value is being ignored.
This warning is required by IEEE. The portable way to suppress this warning
(in SystemVerilog) is to use a void cast, e.g.
void'(function_being_called_as_task());
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
=item IMPERFECTSCH
Warns that the scheduling of the model is not absolutely perfect, and some
@@ -3680,14 +3751,31 @@ correctly.
=item MULTITOP
Error that there are multiple top level modules, that is modules not
instantiated by any other module. Verilator only supports a single top
level, if you need more, create a module that wraps all of the top modules.
Warns that there are multiple top level modules, that is modules not
instantiated by any other module, and both modules were put on the command
line (not in a library). Three likely cases:
Often this error is because some low level cell is being read in, but is
not really needed. The best solution is to insure that each module is in a
unique file by the same name. Otherwise, make sure all library files are
read in as libraries with -v, instead of automatically with -y.
1. A single module is intended to be the top. This warning then occurs
because some low level cell is being read in, but is not really needed as
part of the design. The best solution for this situation is to ensure that
only the top module is put on the command line without any flags, and all
remaining library files are read in as libraries with -v, or are
automatically resolved by having filenames that match the module names.
2. A single module is intended to be the top, the name of it is known, and
all other modules should be ignored if not part of the design. The best
solution is to use the --top-module option to specify the top module's
name. All other modules that are not part of the design will be for the
most part ignored (they must be clean in syntax and their contents will be
removed as part of the Verilog module elaboration process.)
3. Multiple modules are intended to be design tops, e.g. when linting a
library file. As multiple modules are desired, disable the MULTITOP
warning. All input/outputs will go uniquely to each module, with any
conflicting and identical signal names being uniquified by adding a prefix
based on the top module name followed by __02E (a Verilator-encoded ASCII
".'). This renaming is done even if the two modules' signals seem
identical, e.g. multiple modules with a "clk" input.
=item PINCONNECTEMPTY
@@ -3863,7 +3951,7 @@ Often UNOPTFLAT is caused by logic that isn't truly circular as viewed by
synthesis which analyzes interconnection per-bit, but is circular to
simulation which analyzes per-bus:
wire [2:0] x = {x[1:0],shift_in};
wire [2:0] x = {x[1:0], shift_in};
This statement needs to be evaluated multiple times, as a change in
"shift_in" requires "x" to be computed 3 times before it becomes stable.
@@ -3872,12 +3960,12 @@ causes the warning.
For significantly better performance, split this into 2 separate signals:
wire [2:0] xout = {x[1:0],shift_in};
wire [2:0] xout = {x[1:0], shift_in};
and change all receiving logic to instead receive "xout". Alternatively,
change it to
wire [2:0] x = {xin[1:0],shift_in};
wire [2:0] x = {xin[1:0], shift_in};
and change all driving logic to instead drive "xin".
@@ -3993,7 +4081,7 @@ Concatenate leading zeros when doing arithmetic. In the statement
The best fix, which clarifies intent and will also make all tools happy is:
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0,carry[0]};
wire [5:0] plus_one = from[5:0] + 6'd1 + {5'd0, carry[0]};
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
@@ -4005,12 +4093,12 @@ has an indeterminate width. In most cases this violates the Verilog rule
that widths inside concatenates and replicates must be sized, and should be
fixed in the code.
wire [63:0] concat = {1,2};
wire [63:0] concat = {1, 2};
An example where this is technically legal (though still bad form) is:
parameter PAR = 1;
wire [63:0] concat = {PAR,PAR};
wire [63:0] concat = {PAR, PAR};
The correct fix is to either size the 1 ("32'h1"), or add the width to the
parameter definition ("parameter [31:0]"), or add the width to the
@@ -4076,17 +4164,32 @@ code to add appropriate prints to see what is going on.
=over 4
=item Does it run under Windows?
=item Can I contribute?
Please contribute! Just file an issue asking for a merge, or ask on the
forums if looking for something to help on. For more information see our
contributor agreement.
=item How commonly is Verilator used?
Verilator is used by many of the largest silicon design companies, and all
the way down to college projects. Verilator is a "big 4" simulator,
meaning one of the 4 main SystemVerilog simulators available, namely the
commercial products Synopsys' VCS (tm), Mentor's ModelSim (tm), Cadence
Incisive/NC-Verilog/NC-Sim, and the open-source Verilator. The three
commercial choices are commonly collectively called the "big 3" simulators.
=item Does Verilator run under Windows?
Yes, using Cygwin. Verilated output also compiles under Microsoft Visual
C++ Version 7 or newer, but this is not tested every release.
C++, but this is not tested every release.
=item Can you provide binaries?
Verilator is available as a RPM for Debian/Ubuntu, SuSE, Fedora, and
perhaps other systems; this is done by porters and may slightly lag the
primary distribution. If there isn't a binary build for your distribution,
how about you set one up? Please contact the authors for assistance.
Verilator is available as a RPM for Debian/Ubuntu, SuSE, Fedora, and other
distributions; this is done by porters and may slightly lag the primary
distribution. If there isn't a binary build for your distribution, how
about you set one up? Please contact the authors for assistance.
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
@@ -4130,7 +4233,7 @@ placed under the Verilator copyright and LGPL/Artistic license. Small test
cases will be released into the public domain so they can be used anywhere,
and large tests under the LGPL/Artistic, unless requested otherwise.
=item Why is Verilation so slow?
=item Why is running Verilator (to create a model) so slow?
Verilator needs more memory than the resulting simulator will require, as
Verilator creates internally all of the state of the resulting generated
@@ -4213,7 +4316,8 @@ trace file if you want all data to land in the same output file.
FST a format by GTKWave.
This version provides a basic FST support.
To dump FST format, add the --trace switch to Verilator and change the include path in the testbench to:
To dump FST format, add the --trace-fst switch to Verilator and change the include
path in the testbench to:
#include "verilated_fst_c.h"
VerilatedFstC* tfp = new VerilatedFstC;
+37 -44
View File
@@ -17,13 +17,6 @@ eval 'exec perl -wS $0 ${1+"$@"}'
require 5.006_001;
use warnings;
BEGIN {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
use Getopt::Long;
use FindBin qw($RealBin $RealScript);
use IO::File;
@@ -56,12 +49,12 @@ foreach my $sw (@ARGV) {
Getopt::Long::config("no_auto_abbrev","pass_through");
if (! GetOptions (
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Additional parameters
"<>" => sub {}, # Ignored
# Major operating modes
"help" => \&usage,
"debug:s" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
@@ -73,7 +66,7 @@ run(verilator_coverage_bin()
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
}
sub debug {
@@ -90,25 +83,25 @@ sub verilator_coverage_bin {
my $bin = "";
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|| "verilator_coverage_bin_dbg");
|| "verilator_coverage_bin_dbg");
if (defined($ENV{VERILATOR_ROOT})) {
my $dir = $ENV{VERILATOR_ROOT};
my $dir = $ENV{VERILATOR_ROOT};
if (-x "$dir/bin/$basename"
|| -x "$dir/bin/$basename.exe") { # From a "make install" into VERILATOR_ROOT
$bin = "$dir/bin/$basename";
} else {
$bin = "$dir/$basename"; # From pointing to kit directory
}
$bin = "$dir/bin/$basename";
} else {
$bin = "$dir/$basename"; # From pointing to kit directory
}
} else {
if (-x "$RealBin/$basename"
|| -x "$RealBin/$basename.exe") {
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
} else {
$bin = $basename; # Find in PATH
}
# Note we don't look under bin/$basename which would be right if running
# in the kit dir. Running that would likely break, since
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
} else {
$bin = $basename; # Find in PATH
}
# Note we don't look under bin/$basename which would be right if running
# in the kit dir. Running that would likely break, since
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
}
return $bin;
}
@@ -125,23 +118,23 @@ sub run {
system($command);
my $status = $?;
if ($status) {
if ($! =~ /no such file or directory/i) {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
} else {
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
if ($! =~ /no such file or directory/i) {
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
}
if ($Debug) { # For easy rerunning
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 127) {
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
} elsif (($status & 127) == 6) { # SIGABRT
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
} else {
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
}
}
+54 -54
View File
@@ -38,11 +38,11 @@ my $Opt_Lineno = 1;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"lineno!" => \$Opt_Lineno,
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"lineno!" => \$Opt_Lineno,
)) {
die "%Error: Bad usage, try 'verilator_difftree --help'\n";
}
@@ -68,22 +68,22 @@ sub diff_dir {
my %files;
foreach my $fn (glob("$a/*.tree")) {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{a} = $fn;
(my $base = $fn) =~ s!.*/!!;
$files{$base}{a} = $fn;
}
foreach my $fn (glob("$b/*.tree")) {
(my $base = $fn) =~ s!.*/!!;
$files{$base}{b} = $fn;
(my $base = $fn) =~ s!.*/!!;
$files{$base}{b} = $fn;
}
my $any;
foreach my $base (sort (keys %files)) {
my $a = $files{$base}{a};
my $b = $files{$base}{b};
next if !$a || !$b;
print "="x70,"\n";
print "= $a <-> $b\n";
diff_file($a,$b);
$any = 1;
my $a = $files{$base}{a};
my $b = $files{$base}{b};
next if !$a || !$b;
print "="x70,"\n";
print "= $a <-> $b\n";
diff_file($a,$b);
$any = 1;
}
$any or warn("%Warning: No .tree files found that have similar base names:\n "
.join("\n ", sort keys %files),"\n");
@@ -101,7 +101,7 @@ sub diff_file {
my $vera = version_from($a);
my $verb = version_from($b);
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|| ($vera >= 0x3900 && $verb < 0x3900));
|| ($vera >= 0x3900 && $verb < 0x3900));
filter($a, $tmp_a, $verCvt);
filter($b, $tmp_b, $verCvt);
@@ -115,8 +115,8 @@ sub version_from {
# Return dump format
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
while (defined (my $line=$f1->getline())) {
last if $. > 10;
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
last if $. > 10;
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
}
return 1.0;
}
@@ -130,36 +130,36 @@ sub filter {
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
while (defined (my $line=$f1->getline())) {
same_line:
next if $line =~ / This=/;
$line =~ s/0x[a-f0-9]+/0x/g;
$line =~ s/<e[0-9]+\#?>/<e>/g;
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
if ($verCvt) {
next if $line =~ /^ NETLIST/;
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
# # Below Ver1_Non_Dtyped may replace above further
if ($line =~ /: ([A-Z]+) /) {
my $type = $1;
next if $type =~ 'DTYPE';
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
$line =~ /^(\s+\S+:) /; my $prefix = $1;
while (defined ($line=$f1->getline())) {
next if $line =~ /^\s+[a-z]/; # Table body
next if $line =~ /^${prefix}[0-9]:/;
goto same_line;
}
next;
}
if ($Ver1_Non_Dtyped{$type}) {
$line =~ s! w[0-9]+!!g;
}
}
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
}
print $f2 $line;
next if $line =~ / This=/;
$line =~ s/0x[a-f0-9]+/0x/g;
$line =~ s/<e[0-9]+\#?>/<e>/g;
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
if ($verCvt) {
next if $line =~ /^ NETLIST/;
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
# # Below Ver1_Non_Dtyped may replace above further
if ($line =~ /: ([A-Z]+) /) {
my $type = $1;
next if $type =~ 'DTYPE';
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
$line =~ /^(\s+\S+:) /; my $prefix = $1;
while (defined ($line=$f1->getline())) {
next if $line =~ /^\s+[a-z]/; # Table body
next if $line =~ /^${prefix}[0-9]:/;
goto same_line;
}
next;
}
if ($Ver1_Non_Dtyped{$type}) {
$line =~ s! w[0-9]+!!g;
}
}
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
}
print $f2 $line;
}
$f1->close;
$f2->close;
@@ -168,8 +168,8 @@ sub filter {
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
@@ -179,11 +179,11 @@ sub debug {
sub parameter {
my $param = shift;
if (!defined $Opt_A) {
$Opt_A = $param;
$Opt_A = $param;
} elsif (!defined $Opt_B) {
$Opt_B = $param;
$Opt_B = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
+2 -2
View File
@@ -43,8 +43,8 @@ exit(0);
#######################################################################
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub parameter {
+87 -87
View File
@@ -24,11 +24,11 @@ my $Opt_File;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
}
@@ -39,8 +39,8 @@ profcfunc($Opt_File);
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
@@ -50,9 +50,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!defined $Opt_File) {
$Opt_File = $param;
$Opt_File = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -66,13 +66,13 @@ sub profcfunc {
my %funcs;
while (defined (my $line=$fh->getline())) {
# %time cumesec selfsec calls {stuff} name
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
$funcs{$func}{pct} += $pct;
$funcs{$func}{sec} += $sec;
$funcs{$func}{calls} += $calls;
}
# %time cumesec selfsec calls {stuff} name
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
$funcs{$func}{pct} += $pct;
$funcs{$func}{sec} += $sec;
$funcs{$func}{calls} += $calls;
}
# Older gprofs have no call column for single-call functions
# %time cumesec selfsec {stuff} name
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
@@ -88,10 +88,10 @@ sub profcfunc {
my %pointer_mods;
my %verilated_mods;
foreach my $func (keys %funcs) {
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
$verilated_mods{$1} = qr/^$1/;
$pointer_mods{$2} = $1;
}
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
$verilated_mods{$1} = qr/^$1/;
$pointer_mods{$2} = $1;
}
}
#print Dumper(\%pointer_mods, \%verilated_mods);
@@ -99,72 +99,72 @@ sub profcfunc {
my %vfuncs;
my %groups;
foreach my $func (keys %funcs) {
my $pct = $funcs{$func}{pct};
my $vfunc = $func;
my $design;
my $pct = $funcs{$func}{pct};
my $vfunc = $func;
my $design;
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
$design = $pointer_mods{$1};
}
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
$design = $pointer_mods{$1};
}
foreach my $vde (keys %verilated_mods) {
last if $design;
if ($func =~ /$verilated_mods{$vde}/) {
$design=$vde;
last;
}
}
foreach my $vde (keys %verilated_mods) {
last if $design;
if ($func =~ /$verilated_mods{$vde}/) {
$design=$vde;
last;
}
}
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
$vfunc = sprintf("VBlock %s:%d", $1, $2);
$groups{type}{"Verilog Blocks under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$1} += $pct;
} else {
if ($design) {
$vfunc = sprintf("VCommon %s", $func);
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
$groups{design}{'C++'} += $pct;
$groups{module}{'C++'} += $pct;
}
}
$vfuncs{$vfunc} = $funcs{$func};
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
$vfunc = sprintf("VBlock %s:%d", $1, $2);
$groups{type}{"Verilog Blocks under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$1} += $pct;
} else {
if ($design) {
$vfunc = sprintf("VCommon %s", $func);
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
$groups{design}{'C++'} += $pct;
$groups{module}{'C++'} += $pct;
}
}
$vfuncs{$vfunc} = $funcs{$func};
}
foreach my $type (qw(type design module)) {
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
}
if ($missing) {
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
}
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
}
if ($missing) {
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
}
print("Overall summary by $type:\n");
printf(" %-6s %s\n","% time",$type);
foreach my $what (sort (keys %{$groups{$type}})) {
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
}
print("\n");
print("Overall summary by $type:\n");
printf(" %-6s %s\n","% time",$type);
foreach my $what (sort (keys %{$groups{$type}})) {
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
}
print("\n");
}
print("Verilog code profile:\n");
@@ -181,14 +181,14 @@ sub profcfunc {
my $cume = 0;
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|| $a cmp $b}
(keys %vfuncs)) {
$cume += $vfuncs{$func}{sec};
printf +("%6.2f %9.2f %8.2f %8d %s\n",
$vfuncs{$func}{pct},
$cume, $vfuncs{$func}{sec},
$vfuncs{$func}{calls},
$func);
|| $a cmp $b}
(keys %vfuncs)) {
$cume += $vfuncs{$func}{sec};
printf +("%6.2f %9.2f %8.2f %8d %s\n",
$vfuncs{$func}{pct},
$cume, $vfuncs{$func}{sec},
$vfuncs{$func}{calls},
$func);
}
}
@@ -212,7 +212,7 @@ verilator_profcfunc - Read gprof report created with --prof-cfuncs
=head1 DESCRIPTION
Verilator_profcfunc reads a profile report created by gprof. The names of
the functions are then transformed, assuming the user used verilator's
the functions are then transformed, assuming the user used Verilator's
--prof-cfuncs, and a report printed showing the percentage of time, etc,
in each Verilog block.
+9 -7
View File
@@ -6,14 +6,14 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.010 2019-01-27],
AC_INIT([Verilator],[4.020 2019-10-06],
[https://www.veripool.org/verilator],
[verilator],[https://www.veripool.org/verilator])
# When releasing, also update header of Changes file
# and commit using "devel release" or "Version bump" message
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc)
AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc)
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
@@ -91,10 +91,10 @@ AC_SUBST(CFG_WITH_PREC11)
AC_MSG_RESULT($CFG_WITH_PREC11)
# Compiler flags
CFLAGS=-I${includedir}
CPPFLAGS=-I${includedir}
CXXFLAGS=-I${includedir}
LDFLAGS=-L${libdir}
CFLAGS+=" -I${includedir}"
CPPFLAGS+=" -I${includedir}"
CXXFLAGS+=" -I${includedir}"
LDFLAGS+=" -L${libdir}"
# Checks for programs.
AC_PROG_CC
@@ -273,7 +273,9 @@ AC_SUBST(CFG_CXXFLAGS_PARSER)
# without this flag, even though there's a conditional to prevent the divide.
# We still don't add no-div-by-zero as it throws message to stdout, though doesn't die.
#_MY_CXX_CHECK_OPT(-Wno-div-by-zero)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-faligned-new)
# For some reason -faligned-new does not work under Travis w/ clang but the
# configure test doesn't catch this either
AS_IF([test "x$TRAVIS_COMPILER" != xclang], [_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-faligned-new)])
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-fbracket-depth=4096)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Qunused-arguments)
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-bool-operation)
+1
View File
@@ -0,0 +1 @@
Makefile
+82
View File
@@ -0,0 +1,82 @@
= How to contribute to Verilator
Thanks for using Verilator! We welcome your contributions in whatever form.
This contributing document contains some suggestions that may make
contributions flow more efficiently.
==== Did you find a bug?
* Please **Ensure the bug was not already reported** by searching
https://www.veripool.org/projects/verilator/issues[Verilator Issues].
* If you're unable to find an open issue addressing the problem,
https://www.veripool.org/projects/verilator/issues/new[open a new issue].
** Be sure to include a **code sample** or an **executable test case**
demonstrating the bug and expected behavior that is not occurring.
** The ideal example works against other simulators, and is in the
test_regress/t test format, as described in
link:internals.adoc[docs/internals].
==== Did you write a patch that fixes a bug?
* Please https://www.veripool.org/projects/verilator/issues/new[Open a new
issue].
* You may attach a patch to the issue, or (preferred) may point to a github
repository branch within your github account.
** Verilator uses Travis CI to provide continuous integration. You may
want to setup Travis CI on your github branch to ensure your changes
keep the tests passing. See link:internals.adoc[docs/internals].
* Your source-code contributions must be certified as open source, under
the https://developercertificate.org/[Developer Certificate of
Origin]. On your first contribution, you must either:
** Have your patch include the addition of your name to
link:CONTRIBUTORS[docs/CONTRIBUTORS] (preferred).
** Use "git -s" as part of your commit. This adds a "signed-of-by"
attribute which will certify your contribution as described in the
https://github.com/wking/signed-off-by/blob/master/Documentation/SubmittingPatches[Signed-of-By
convention].
** Email, or post in an issue a statement that you certify your
contributions.
** In any of these cases your name will be added to
link:CONTRIBUTORS[docs/CONTRIBUTRORS] and you are agreeing all future
contributions are also certified.
** We occasionally accept contributions where people do not want their
name published. Please email us; you must still certify your
contribution using email.
* Your test contributions are generally considered released into the public
domain, unless you request otherwise or put a GNU/Artistic license on
your test file.
* Most important is we get your patch. If you'd like to clean up
indentation and related issues ahead of our feedback, that is
appreciated; please see the coding conventions in
link:internals.adoc[docs/internals].
==== Do you have questions?
* Please see the
https://www.veripool.org/projects/verilator/wiki/Faq[Verilator FAQ].
* Ask any question in the
https://www.veripool.org/projects/verilator/boards[Verilator forums].
==== Code of Conduct
* Our contributors and participants pledge to make participation in our
project and our community a positive experience for everyone. We follow
the https://www.contributor-covenant.org/version/1/4/code-of-conduct.html[Contributor
Covenant version 1.4].
Thanks!
+21
View File
@@ -0,0 +1,21 @@
The contributors listed below have certified their Verilator contributions
under the Developer Certificate of Origin
(https://developercertificate.org/).
Please see the Verilator manual for additional contributors.
Alex Chadwick
Gianfranco Costamagna
Howard Su
Jeremy Bennett
John Coiner
Kanad Kanhere
Lukasz Dalek
Maarten De Braekeleer
Philipp Wagner
Richard Myers
Sebastien Van Cauwenberghe
Stefan Wallentowitz
Todd Strader
Wilson Snyder
Yves Mathieu
+50
View File
@@ -0,0 +1,50 @@
#*****************************************************************************
# DESCRIPTION: Verilator documentation: Makefile pre-configure version
#
# This file is part of Verilator.
#
# Code available from: http://www.veripool.org/verilator
#
#*****************************************************************************
#
# Copyright 2003-2019 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.
#
# Verilator is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#****************************************************************************/
#
# This file is intended only to be called from the top-level Verilator Makefile.
#### Start of system configuration section. ####
DOXYGEN = doxygen
#### End of system configuration section. ####
######################################################################
.SUFFIXES:
default:
@echo "error: make not supported here, run 'make docs' from Verilator top-level"
clean mostlyclean distclean maintainer-clean::
rm -f $(SCRIPTS) *.tmp
rm -f *.aux *.cp *.cps *.dvi *.fn *.fns *.ky *.kys *.log
rm -f *.pg *.pgs *.toc *.tp *.tps *.vr *.vrs *.idx
rm -f *.ev *.evs *.ov *.ovs *.cv *.cvs *.ma *.mas
rm -f *.tex
distclean maintainer-clean::
rm -f *.info* *.1 $(INFOS)
rm -f Makefile
.PHONY: doxygen
doxygen:
$(DOXYGEN) doxygen.config
View File
+1 -1
View File
@@ -45,7 +45,7 @@ PROJECT_BRIEF = "Verilog to C translator"
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
PROJECT_LOGO = veripool-logo.png
PROJECT_LOGO = verilator_logo.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
+956
View File
@@ -0,0 +1,956 @@
= Verilator Internals Documentation
:toc: right
// Github doesn't render unless absolute URL
image::https://www.veripool.org/img/verilator_256_200_min.png[Logo,256,200,role="right"]
== Introduction
This file discusses internal and programming details for Verilator. It's a
reference for developers and debugging problems.
See also the Verilator internals presentation at http://www.veripool.org.
== Code Flows
=== Verilator Flow
The main flow of Verilator can be followed by reading the Verilator.cpp
`process()` function:
. First, the files specified on the command line are read. Reading
involves preprocessing, then lexical analysis with Flex and parsing with
Bison. This produces an abstract syntax tree (AST) representation of the
design, which is what is visible in the .tree files described below.
. Verilator then makes a series of passes over the AST, progressively
refining and optimizing it.
. Cells in the AST first linked, which will read and parse additional files
as above.
. Functions, variable and other references are linked to their definitions.
. Parameters are resolved and the design is elaborated.
. Verilator then performs many additional edits and optimizations on the
hierarchical design. This includes coverage, assertions, X elimination,
inlining, constant propagation, and dead code elimination.
. References in the design are then pseudo-flattened. Each module's
variables and functions get "Scope" references. A scope reference is an
occurrence of that un-flattened variable in the flattened hierarchy. A
module that occurs only once in the hierarchy will have a single scope and
single VarScope for each variable. A module that occurs twice will have a
scope for each occurrence, and two VarScopes for each variable. This
allows optimizations to proceed across the flattened design, while still
preserving the hierarchy.
. Additional edits and optimizations proceed on the pseudo-flat design.
These include module references, function inlining, loop unrolling,
variable lifetime analysis, lookup table creation, always splitting, and
logic gate simplifications (pushing inverters, etc).
. Verilator orders the code. Best case, this results in a single "eval"
function which has all always statements flowing from top to bottom with no
loops.
. Verilator mostly removes the flattening, so that code may be shared
between multiple invocations of the same module. It localizes variables,
combines identical functions, expands macros to C primitives, adds branch
prediction hints, and performs additional constant propagation.
. Verilator finally writes the C++ modules.
=== Key Classes Used in the Verilator Flow
==== `AstNode`
The AST is represented at the top level by the class `AstNode`. This
abstract class has derived classes for the individual components
(e.g. `AstGenerate` for a generate block) or groups of components
(e.g. `AstNodeFTask` for functions and tasks, which in turn has `AstFunc`
and `AstTask` as derived classes).
Each `AstNode` has pointers to up to four children, accessed by the `op1p`
through `op4p` methods. These methods are then abstracted in a specific
Ast* node class to a more specific name. For example with the `AstIf` node
(for `if` statements), `ifsp` calls `op2p` to give the pointer to the AST
for the "then" block, while `elsesp` calls `op3p` to give the pointer to
the AST for the "else" block, or NULL if there is not one.
`AstNode` has the concept of a next and previous AST - for example the next
and previous statements in a block. Pointers to the AST for these
statements (if they exist) can be obtained using the `back` and `next`
methods.
It is useful to remember that the derived class `AstNetlist` is at the top
of the tree, so checking for this class is the standard way to see if you
are at the top of the tree.
By convention, each function/method uses the variable `nodep` as a pointer
to the `AstNode` currently being processed.
==== `AstNVisitor`
The passes are implemented by AST visitor classes. These are implemented
by subclasses of the abstract class, `AstNVisitor`. Each pass creates an
instance of the visitor class, which in turn implements a method to perform
the pass.
==== `V3Graph`
A number of passes use graph algorithms, and the class `V3Graph` is
provided to represent those graphs. Graphs are directed, and algorithms are
provided to manipulate the graphs and to output them in
http://www.graphviz.org/[GraphViz] dot format. `V3Graph.h` provides
documentation of this class.
==== `V3GraphVertex`
`V3GraphVertex` is the base class for vertices in a graph. Vertices have
an associated `fanout`, `color` and `rank`, which may be used in algorithms
for ordering the graph. A generic `user`/`userp` member variable is also
provided.
Virtual methods are provided to specify the name, color, shape and style to
be used in dot output. Typically users provide derived classes from
`V3GraphVertex` which will reimplement these methods.
Iterators are provided to access in and out edges. Typically these are used
in the form:
for (V3GraphEdge *edgep = vertexp->inBeginp();
edgep;
edgep = edgep->inNextp()) {
==== `V3GraphEdge`
`V3GraphEdge` is the base class for directed edges between pairs of
vertices. Edges have an associated `weight` and may also be made
`cutable`. A generic `user`/`userp` member variable is also provided.
Accessors, `fromp` and `top` return the "from" and "to" vertices
respectively.
Virtual methods are provided to specify the label, color and style to be
used in dot output. Typically users provided derived classes from
`V3GraphEdge` which will reimplement these methods.
==== `V3GraphAlg`
This is the base class for graph algorithms. It implements a `bool` method,
`followEdge` which algorithms can use to decide whether an edge is
followed. This method returns true if the graph edge has weight greater
than one and a user function, `edgeFuncp` (supplied in the constructor)
returns `true`.
A number of predefined derived algorithm classes and access methods are
provided and documented in `V3GraphAlg.cpp`.
=== Multithreaded Mode
In `--threads` mode, the frontend of the Verilator pipeline is the same as
serial mode, up until V3Order.
`V3Order` builds a fine-grained, statement-level dependency graph that
governs the ordering of code within a single `eval()` call. In serial mode,
that dependency graph is used to order all statements into a total serial
order. In parallel mode, the same dependency graph is the starting point
for a partitioner (`V3Partition`).
The partitioner's goal is to coarsen the fine-grained graph into a coarser
graph, while maintaining as much available parallelism as possible. Often
the partitioner can transform an input graph with millions of nodes into a
coarsened execution graph with a few dozen nodes, while maintaining enough
parallelism to take advantage of a modern multicore CPU. Runtime
synchronization cost is not prohibitive with so few nodes.
==== Partitioning
Our partitioner is similar to the one Vivek Sarkar described in his 1989
paper _Partitioning and Scheduling Parallel Programs for Multiprocessors_.
Let's define some terms:
==== Par Factor
The available parallelism or "par-factor" of a DAG is the total cost to
execute all nodes, divided by the cost to execute the longest critical path
through the graph. This is the speedup you would get from running the graph
in parallel, if given infinite CPU cores available and communication and
synchronization are zero.
==== Macro Task
When the partitioner coarsens the graph, it combines nodes together. Each
fine-grained node represents an atomic "task"; combined nodes in the
coarsened graph are "macro-tasks". This term comes from Sarkar. Each
macro-task executes from start to end on one processor, without any
synchronization to any other macro-task during its
execution. (Synchronization only happens before the macro-task begins or
after it ends.)
==== Edge Contraction
Verilator's partitioner, like Sarkar's, primarily relies on "edge
contraction" to coarsen the graph. It starts with one macro-task per atomic
task and iteratively combines pairs of edge-connected macro-tasks.
==== Local Critical Path
Each node in the graph has a "local" critical path. That's the critical
path from the start of the graph to the start of the node, plus the node's
cost, plus the critical path from the end of the node to the end of the
graph.
Sarkar calls out an important trade-off: coarsening the graph reduces
runtime synchronization overhead among the macro-tasks, but it tends to
increase the critical path through the graph and thus reduces par-factor.
Sarkar's partitioner, and ours, chooses pairs of macro-tasks to merge such
that the growth in critical path is minimized. Each candidate merge would
result in a new node, which would have some local critical path. We choose
the candidate that would produce the shortest local critical path. Repeat
until par-factor falls to a target threshold. It's a greedy algorithm, and
it's not guaranteed to produce the best partition (which Sarkar proves is
NP-hard).
==== Estimating Logic Costs
To compute the cost of any given path through the graph, Verilator
estimates an execution cost for each task. Each macro-task has an execution
cost which is simply the sum of its tasks' costs. We assume that
communication overhead and synchronization overhead are zero, so the cost
of any given path through the graph is simply the sum of macro-task
execution costs. Sarkar does almost the same thing, except that he has
nonzero estimates for synchronization costs.
Verilator's cost estimates are assigned by `InstrCountCostVisitor`. This
class is perhaps the most fragile piece of the multithread implementation.
It's easy to have a bug where you count something cheap (eg. accessing one
element of a huge array) as if it were expensive (eg. by counting it as if
it were an access to the entire array.) Even without such gross bugs, the
estimates this produce are only loosely predictive of actual runtime cost.
Multithread performance would be better with better runtime costs
estimates. This is an area to improve.
==== Scheduling Macro-Tasks at Runtime
After coarsening the graph, we must schedule the macro-tasks for runtime.
Sarkar describes two options: you can dynamically schedule tasks at
runtime, with a runtime graph follower. Sarkar calls this the
"macro-dataflow model." Verilator does not support this; early experiments
with this approach had poor performance.
The other option is to statically assign macro-tasks to threads, with each
thread running its macro-tasks in a static order. Sarkar describes this in
Chapter 5. Verilator takes this static approach. The only dynamic aspect is
that each macro task may block before starting, to wait until its
prerequisites on other threads have finished.
The synchronization cost is cheap if the prereqs are done. If they're not,
fragmentation (idle CPU cores waiting) is possible. This is the major
source of overhead in this approach. The `--prof-threads` switch and the
`verilator_gantt` script can visualize the time lost to such fragmentation.
==== Locating Variables for Best Spatial Locality
After scheduling all code, we attempt to locate variables in memory such
that variables accessed by a single macro-task are close together in
memory. This provides "spatial locality" -- when we pull in a 64-byte
cache line to access a 2-byte variable, we want the other 62 bytes to be
ones we'll also likely access soon, for best cache performance.
This turns out to be critical for performance. It should allow Verilator to
scale to very large models. We don't rely on our working set fitting in any
CPU cache; instead we essentially "stream" data into caches from
memory. It's not literally streaming, where the address increases
monotonically, but it should have similar performance characteristics, so
long as each macro-task's dataset fits in one core's local caches.
To achieve spatial locality, we tag each variable with the set of
macro-tasks that access it. Let's call this set the "footprint" of that
variable. The variables in a given module have a set of footprints. We can
order those footprints to minimize the distance between them (distance is
the number of macro-tasks that are different across any two footprints) and
then emit all variables into the struct in ordered-footprint order.
The footprint ordering is literally the traveling salesman problem, and we
use a TSP-approximation algorithm to get close to an optimal sort.
This is an old idea. Simulators designed at DEC in the early 1990s used
similar techniques to optimize both single-thread and multi-thread modes.
(Verilator does not optimize variable placement for spatial locality in
serial mode; that is a possible area for improvement.)
==== Improving Multithreaded Performance Further (a TODO list)
===== Wave Scheduling
To allow the Verilated model to run in parallel with the testbench, it
might be nice to support "wave" scheduling, in which work on a cycle begins
before `eval()` is called or continues after `eval()` returns. For now all
work on a cycle happens during the `eval()` call, leaving Verilator's
threads idle while the testbench (everything outside `eval()`) is
working. This would involve fundamental changes within the partitioner,
however, it's probably the best bet for hiding testbench latency.
===== Efficient Dynamic Scheduling
To scale to more than a few threads, we may revisit a fully dynamic
scheduler. For large (>16 core) systems it might make sense to dedicate an
entire core to scheduling, so that scheduler data structures would fit in
its L1 cache and thus the cost of traversing priority-ordered ready lists
would not be prohibitive.
===== Static Scheduling with Runtime Repack
We could modify the static scheduling approach by gathering actual
macro-task execution times at run time, and dynamically re-packing the
macro-tasks into the threads also at run time. Say, re-pack once every
10,000 cycles or something. This has the potential to do better than our
static estimates about macro-task run times. It could potentially react to
CPU cores that aren't performing equally, due to NUMA or thermal throttling
or nonuniform competing memory traffic or whatever.
===== Clock Domain Balancing
Right now Verilator makes no attempt to balance clock domains across
macro-tasks. For a multi-domain model, that could lead to bad gantt chart
fragmentation. This could be improved if it's a real problem in practice.
===== Other Forms of MTask Balancing
The largest source of runtime overhead is idle CPUs, which happens due to
variance between our predicted runtime for each MTask and its actual
runtime. That variance is magnified if MTasks are homogeneous, containing
similar repeating logic which was generally close together in source code
and which is still packed together even after going through Verilator's
digestive tract.
If Verilator could avoid doing that, and instead would take source logic
that was close together and distribute it across MTasks, that would
increase the diversity of any given MTask, and this should reduce variance
in the cost estimates.
One way to do that might be to make various "tie breaker" comparison
routines in the sources to rely more heavily on randomness, and generally
try harder not to keep input nodes together when we have the option to
scramble things.
===== Performance Regression
It would be nice if we had a regression of large designs, with some
diversity of design styles, to test on both single- and multi-threaded
modes. This would help to avoid performance regressions, and also to
evaluate the optimizations while minimizing the impact of parasitic noise.
===== Per-Instance Classes
If we have multiple instances of the same module, and they partition
differently (likely; we make no attempt to partition them the same) then
the variable sort will be suboptimal for either instance. A possible
improvement would be to emit a unique class for each instance of a module,
and sort its variables optimally for that instance's code stream.
=== Verilated Flow
The evaluation loop outputted by Verilator is designed to allow a single
function to perform evaluation under most situations.
On the first evaluation, the Verilated code calls initial blocks, and then
"settles" the modules, by evaluating functions (from always statements)
until all signals are stable.
On other evaluations, the Verilated code detects what input signals have
changes. If any are clocks, it calls the appropriate sequential functions
(from `always @ posedge` statements). Interspersed with sequential functions
it calls combo functions (from `always @*`). After this is complete, it
detects any changes due to combo loops or internally generated clocks, and
if one is found must reevaluate the model again.
For SystemC code, the `eval()` function is wrapped in a SystemC
`SC_METHOD`, sensitive to all inputs. (Ideally it would only be sensitive
to clocks and combo inputs, but tracing requires all signals to cause
evaluation, and the performance difference is small.)
If tracing is enabled, a callback examines all variables in the design for
changes, and writes the trace for each change. To accelerate this process
the evaluation process records a bitmask of variables that might have
changed; if clear, checking those signals for changes may be skipped.
== Coding Conventions
=== Indentation style
We will work with contributors to fix up indentation style issues, but it
is appreciated if you could match our style:
* All files should contain the magic header to insure standard indentation:
+
// -*- mode: C++; c-file-style: "cc-mode" -*-
+
This sets indentation to the `cc-mode` defaults. (Verilator predates a
CC-mode change of several years ago which overrides the defaults with GNU
style indentation; the `c-set-style` undoes that.)
* Use 4 spaces per level, and no tabs.
* Use 2 spaces between the end of source and the beginning of a comment.
* Use "mixedCapsSymbols" instead of "underlined_symbls".
* Comment every member variable.
=== The `astgen` script
Some of the code implementing passes is extremely repetitive, and must be
implemented for each sub-class of `AstNode`. However, while repetitive,
there is more variability than can be handled in C++ macros.
In Verilator this is implemented by using a Perl script, `astgen` to
pre-process the C++ code. For example in `V3Const.cpp` this is used to
implement the `visit()` functions for each binary operation using the
`TREEOP` macro.
The original C++ source code is transformed into C++ code in the `obj_opt`
and `obj_dbg` sub-directories (the former for the optimized version of
Verilator, the latter for the debug version). So for example `V3Const.cpp`
into `V3Const__gen.cpp`.
=== Visitor Functions
Verilator uses the "Visitor" design pattern to implement its refinement and
optimization passes. This allows separation of the pass algorithm from the
AST on which it operates. Wikipedia provides an introduction to the concept
at http://en.wikipedia.org/wiki/Visitor_pattern.
As noted above, all visitors are derived classes of `AstNVisitor`. All
derived classes of `AstNode` implement the `accept` method, which takes as
argument a reference to an instance or a `AstNVisitor` derived class and
applies the visit method of the `AstNVisitor` to the invoking AstNode
instance (i.e. `this`).
One possible difficulty is that a call to `accept` may perform an edit
which destroys the node it receives as argument. The
`acceptSubtreeReturnEdits` method of `AstNode` is provided to apply
`accept` and return the resulting node, even if the original node is
destroyed (if it is not destroyed it will just return the original node).
The behavior of the visitor classes is achieved by overloading the `visit`
function for the different `AstNode` derived classes. If a specific
implementation is not found, the system will look in turn for overloaded
implementations up the inheritance hierarchy. For example calling `accept`
on `AstIf` will look in turn for:
void visit(AstIf* nodep)
void visit(AstNodeIf* nodep)
void visit(AstNodeStmt* nodep)
void visit(AstNode* nodep)
There are three ways data is passed between visitor functions.
1. A visitor-class member variable. This is generally for passing "parent"
information down to children. `m_modp` is a common example. It's set to
NULL in the constructor, where that node (`AstModule` visitor) sets it,
then the children are iterated, then it's cleared. Children under an
`AstModule` will see it set, while nodes elsewhere will see it clear. If
there can be nested items (for example an `AstFor` under an `AstFor`) the
variable needs to be save-set-restored in the `AstFor` visitor, otherwise
exiting the lower for will lose the upper for's setting.
2. User attributes. Each `AstNode` (*Note.* The AST node, not the visitor)
has five user attributes, which may be accessed as an integer using the
`user1()` through `user5()` methods, or as a pointer (of type `AstNUser`)
using the `user1p()` through `user5p()` methods (a common technique lifted
from graph traversal packages).
+
A visitor first clears the one it wants to use by calling
`AstNode::user#ClearTree()`, then it can mark any node's `user#()` with whatever
data it wants. Readers just call `nodep->user()`, but may need to cast
appropriately, so you'll often see `VN_CAST(nodep->userp(), SOMETYPE)`.
At the top of each visitor are comments describing how the `user()` stuff
applies to that visitor class. For example:
+
// NODE STATE
// Cleared entire netlist
// AstModule::user1p() // bool. True to inline this module
+
This says that at the `AstNetlist` `user1ClearTree()` is called. Each
`AstModule`'s `user1()` is used to indicate if we're going to inline it.
+
These comments are important to make sure a `user#()` on a given `AstNode`
type is never being used for two different purposes.
+
Note that calling `user#ClearTree` is fast, it doesn't walk the tree, so
it's ok to call fairly often. For example, it's commonly called on every
module.
3. Parameters can be passed between the visitors in close to the "normal"
function caller to callee way. This is the second `vup` parameter of type
`AstNUser` that is ignored on most of the visitor functions. V3Width does
this, but it proved more messy than the above and is deprecated. (V3Width
was nearly the first module written. Someday this scheme may be removed,
as it slows the program down to have to pass vup everywhere.)
=== Iterators
`AstNVisitor` provides a set of iterators to facilitate walking over the
tree. Each operates on the current `AstNVisitor` class (as this) and takes
an argument type `AstNode*`.
`iterate`::
Applies the `accept` method of the `AstNode` to the visitor function.
`iterateAndNextIgnoreEdit`::
Applies the `accept` method of each `AstNode` in a list (i.e. connected by
`nextp` and `backp` pointers).
`iterateAndNextNull`::
Applies the `accept` method of each `AstNode` in a list, only if the
provided node is non-NULL. If a node is edited by the call to `accept`,
apply `accept` again, until the node does not change.
`iterateListBackwards`::
Applies the `accept` method of each `AstNode` in a list, starting with the
last one.
`iterateChildren`::
Applies the `iterateAndNextNull` method on each child `op1p` through `op4p`
in turn.
`iterateChildrenBackwards`::
Applies the `iterateListBackwards` method on each child `op1p` through
`op4p` in turn.
==== Caution on Using Iterators When Child Changes
Visitors often replace one node with another node; V3Width and V3Const are
major examples. A visitor which is the parent of such a replacement needs
to be aware that calling iteration may cause the children to change. For
example:
// nodep->lhsp() is 0x1234000
iterateAndNextNull(nodep->lhsp()); // and under covers nodep->lhsp() changes
// nodep->lhsp() is 0x5678400
iterateAndNextNull(nodep->lhsp());
Will work fine, as even if the first iterate causes a new node to take the
place of the `lhsp()`, that edit will update `nodep->lhsp()` and the second
call will correctly see the change. Alternatively:
lp = nodep->lhsp();
// nodep->lhsp() is 0x1234000, lp is 0x1234000
iterateAndNextNull(lp); **lhsp=NULL;** // and under covers nodep->lhsp() changes
// nodep->lhsp() is 0x5678400, lp is 0x1234000
iterateAndNextNull(lp);
This will cause bugs or a core dump, as lp is a dangling pointer. Thus it
is advisable to set lhsp=NULL shown in the *'s above to make sure these
dangles are avoided. Another alternative used in special cases mostly in
V3Width is to use acceptSubtreeReturnEdits, which operates on a single node
and returns the new pointer if any. Note acceptSubtreeReturnEdits does not
follow `nextp()` links.
lp = acceptSubtreeReturnEdits(lp)
=== Identifying derived classes
A common requirement is to identify the specific `AstNode` class we are
dealing with. For example a visitor might not implement separate `visit`
methods for `AstIf` and `AstGenIf`, but just a single method for the base
class:
void visit (AstNodeIf* nodep)
However that method might want to specify additional code if it is called
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
possible node type, which returns true if the node is of that type (or
derived from that type). So our `visit` method could use:
if (VN_IS(nodep, AstGenIf) {
<code specific to AstGenIf>
}
Additionally the `VN_CAST` method converts pointers similar to C++
`dynamic_cast`. This either returns a pointer to the object cast to that
type (if it is of class `SOMETYPE`, or a derived class of `SOMETYPE`) or
else NULL. (However, for true/false tests use `VN_IS` as that is faster.)
== Testing
For an overview of how to write a test see the BUGS section of the
Verilator primary manual.
It is important to add tests for failures as well as success (for example
to check that an error message is correctly triggered).
Tests that fail should by convention have the suffix `_bad` in their name,
and include `fails = 1` in either their `compile` or `execute` step as
appropriate.
=== Preparing to Run Tests
For all tests to pass you must install the following packages:
* SystemC to compile the SystemC outputs, see http://systemc.org
* Parallel::Forker from CPAN to run tests in parallel, you can install this
with e.g. "sudo cpan install Parallel::Forker".
* vcddiff to find differences in VCD outputs. See the readme at
https://github.com/veripool/vcddiff
=== Controlling the Test Driver
Test drivers are written in PERL. All invoke the main test driver script,
which can provide detailed help on all the features available when writing
a test driver.
test_regress/t/driver.pl --help
For convenience, a summary of the most commonly used features is provided
here. All drivers require a call to `compile` subroutine to compile the
test. For run-time tests, this is followed by a call to the `execute`
subroutine. Both of these functions can optionally be provided with a hash
table as argument specifying additional options.
The test driver assumes by default that the source Verilog file name
matches the PERL driver name. So a test whose driver is `t/t_mytest.pl`
will expect a Verilog source file `t/t_mytest.v`. This can be changed
using the `top_filename` subroutine, for example
top_filename("t/t_myothertest.v");
By default all tests will run with major simulators (Icarus Verilog, NC,
VCS, ModelSim, etc) as well as Verilator, to allow results to be
compared. However if you wish a test only to be used with Verilator, you
can use the following:
scenarios(vlt => 1);
Of the many options that can be set through arguments to `compiler` and
`execute`, the following are particularly useful:
`verilator_flags2`::
A list of flags to be passed to verilator when compiling.
`fails`::
Set to 1 to indicate that the compilation or execution is intended to fail.
For example the following would specify that compilation requires two
defines and is expected to fail.
compile (
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
fails => 1,
);
=== Regression Testing for Developers
Developers will also want to call ./configure with two extra flags:
`--enable-ccwarn`::
Causes the build to stop on warnings as well as errors. A good way to
ensure no sloppy code gets added, however it can be painful when it comes
to testing, since third party code used in the tests (e.g. SystemC) may not
be warning free.
`--enable-longtests`::
In addition to the standard C, SystemC examples, also run the tests in the
`test_regress` directory when using _make test_'. This is disabled by
default as SystemC installation problems would otherwise falsely indicate a
Verilator problem.
When enabling the long tests, some additional PERL modules are needed,
which you can install using cpan.
cpan install Unix::Processors
There are some traps to avoid when running regression tests
* When checking the MANIFEST, the test will barf on unexpected code in the
Verilator tree. So make sure to keep any such code outside the tree.
* Not all Linux systems install Perldoc by default. This is needed for the
`--help_' option to Verilator, and also for regression testing. This can be
installed using cpan:
+
cpan install Pod::Perldoc
+
Many Linux systems also offer a standard package for this. Red
Hat/Fedora/Centos offer _perl-Pod-Perldoc_', while Debian/Ubuntu/Linux Mint
offer `perl-doc'.
* Running regression may exhaust resources on some Linux systems,
particularly file handles and user processes. Increase these to
respectively 16,384 and 4,096. The method of doing this is system
dependent, but on Fedora Linux it would require editing the
`/etc/security/limits.conf` file as root.
=== Continuous Integration
Verilator has a https://travis-ci.com/verilator/verilator[Travis CI environment]
which automatically tests the master branch for test failures on new commits. It
also runs a daily cron job to validate all of the tests against different OS and
compiler versions.
Developers can connect Travis CI to their GitHub account so that the CI
enviroment can check their branches too by doing the following:
* Go to https://github.com/marketplace/travis-ci and follow the prompts
* Only the Open Source (FREE) version of Travis CI is required
* Under a Travis CI project click More options > Settings in order to set up a
cron job on a particular branch
== Debugging
=== --debug
When you run with `--debug` there are two primary output file types placed
into the obj_dir, .tree and .dot files.
=== .dot output
Dot files are dumps of internal graphs in
http://www.graphviz.org/[Graphviz] dot format. When a dot file is dumped,
Verilator will also print a line on stdout that can be used to format the
output, for example:
dot -Tps -o ~/a.ps obj_dir/Vtop_foo.dot
You can then print a.ps. You may prefer gif format, which doesn't get
scaled so can be more useful with large graphs.
For dynamic graph viewing consider ZGRViewer
http://zvtm.sourceforge.net/zgrviewer.html. If you know of better
viewers let us know; ZGRViewer isn't great for large graphs.
=== .tree output
Tree files are dumps of the AST Tree and are produced between every major
algorithmic stage. An example:
NETLIST 0x90fb00 <e1> {a0}
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
The following summarizes the above example dump, with more detail on each
field in the section below.
[cols="20%,80%"]
|===
|`1:2:` | indicates the hierarchy of the `VAR` is the `op2p` pointer under
the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
|`VAR` | is the AstNodeType.
| `0x91a780` | is the address of this node.
| `<e74>` | means the 74th edit to the netlist was the last modification to
this node.
| `{a22}` | indicates this node is related to line 22 in the source filename
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
| `@dt=0x...` | indicates the address of the data type this node contains.
| `w32` | indicates the width is 32 bits.
| `out_wide` | is the name of the node, in this case the name of the variable.
| `[O]` | are flags which vary with the type of node, in this case it means the
variable is an output.
|===
In more detail the following fields are dumped common to all nodes. They
are produced by the `AstNode::dump()` method:
Tree Hierarchy::
The dump lines begin with numbers and colons to indicate the child node
hierarchy. As noted above, `AstNode` has lists of items at the same level
in the AST, connected by the `nextp()` and `prevp()` pointers. These appear
as nodes at the same level. For example after inlining:
NETLIST 0x929c1c8 <e1> {a0} w0
1: MODULE 0x92bac80 <e3144> {e14} w0 TOP_t L1 [P]
1:1: CELLINLINE 0x92bab18 <e3686#> {e14} w0 v -> t
1:1: CELLINLINE 0x92bc1d8 <e3688#> {e24} w0 v__DOT__i_test_gen -> test_gen
...
1: MODULE 0x92b9bb0 <e503> {e47} w0 test_gen L3
...
AstNode type::
The textual name of this node AST type (always in capitals). Many of these
correspond directly to Verilog entities (for example `MODULE` and
`TASK`), but others are internal to Verilator (for example `NETLIST` and
`BASICDTYPE`).
Address of the node::
A hexadecimal address of the node in memory. Useful for examining with the
debugger.
Last edit number::
Of the form `<ennnn>` or `<ennnn#>` , where `nnnn` is the number
of the last edit to modify this node. The trailing `#` indicates the node
has been edited since the last tree dump (which typically means in the last
refinement or optimization pass). GDB can watch for this, see << /Debugging >>.
Source file and line::
Of the form `{xxnnnn}`, where C{xx} is the filename letter (or
letters) and `nnnn` is the line number within that file. The first file is
`a`, the 26th is `z`, the 27th is `aa` and so on.
User pointers::
Shows the value of the node's user1p...user5p, if non-NULL.
Data type::
Many nodes have an explicit data type. "@dt=0x..." indicates the address
of the data type (AstNodeDType) this node uses.
+
If a data type is present and is numeric, it then prints the width of the
item. This field is a sequence of flag characters and width data as follows:
+
* `s` if the node is signed.
* `d` if the node is a double (i.e a floating point entity).
* `w` always present, indicating this is the width field.
* `u` if the node is unsized.
* `/nnnn` if the node is unsized, where `nnnn` is the minimum width.
Name of the entity represented by the node if it exists::
For example for a `VAR` it is the name of the variable.
Many nodes follow these fields with additional node specific
information. Thus the `VARREF` node will print either `[LV]` or `[RV]`
to indicate a left value or right value, followed by the node of the
variable being referred to. For example:
1:2:1:1: VARREF 0x92c2598 <e509> {e24} w0 clk [RV] <- VAR 0x92a2e90 <e79> {e18} w0 clk [I] INPUT
In general, examine the `dump()` method in `V3AstNodes.cpp` of the node
type in question to determine additional fields that may be printed.
The `MODULE` has a list of `CELLINLINE` nodes referred to by its
`op1p()` pointer, connected by `nextp()` and `prevp()` pointers.
Similarly the `NETLIST` has a list of modules referred to by its `op1p()`
pointer.
=== Debugging with GDB
The test_regress/driver.pl script accepts `--debug --gdb` to start
Verilator under gdb and break when an error is hit or the program is about
to exit. You can also use `--debug --gdbbt` to just backtrace and then
exit gdb. To debug the Verilated executable, use `--gdbsim`.
If you wish to start Verilator under GDB (or another debugger), then you
can use `--debug` and look at the underlying invocation of
`verilator_dbg`. For example
t/t_alw_dly.pl --debug
shows it invokes the command:
../verilator_bin_dbg --prefix Vt_alw_dly --x-assign unique --debug
-cc -Mdir obj_dir/t_alw_dly --debug-check -f input.vc t/t_alw_dly.v
Start GDB, then `start` with the remaining arguments.
gdb ../verilator_bin_dbg
...
(gdb) start --prefix Vt_alw_dly --x-assign unique --debug -cc -Mdir
obj_dir/t_alw_dly --debug-check -f input.vc t/t_alw_dly.v
> obj_dir/t_alw_dly/vlt_compile.log
...
Temporary breakpoint 1, main (argc=13, argv=0xbfffefa4, env=0xbfffefdc)
at ../Verilator.cpp:615
615 ios::sync_with_stdio();
(gdb)
You can then continue execution with breakpoints as required.
To break at a specific edit number which changed a node (presumably to find
what made a <e####> line in the tree dumps):
watch AstNode::s_editCntGbl==####
To print a node:
pn nodep
# or: call nodep->dumpGdb() # aliased to "pn" in src/.gdbinit
pnt nodep
# or: call nodep->dumpTreeGdb() # aliased to "pnt" in src/.gdbinit
When GDB halts, it is useful to understand that the backtrace will commonly
show the iterator functions between each invocation of `visit` in the
backtrace. You will typically see a frame sequence something like
...
visit()
iterateChildren()
iterateAndNext()
accept()
visit()
...
== Adding a New Feature
Generally what would you do to add a new feature?
. File an issue (if there isn't already) so others know what you're working on.
. Make a testcase in the test_regress/t/t_EXAMPLE format, see << /TESTING >>.
. If grammar changes are needed, look at the git version of VerilogPerl's
src/VParseGrammar.y, as this grammar supports the full SystemVerilog
language and has a lot of back-and-forth with Verilator's grammar. Copy
the appropriate rules to src/verilog.y and modify the productions.
. If a new Ast type is needed, add it to V3AstNodes.h.
. Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
file which you can examine to see if the parsing worked. See also the
sections above on debugging.
. Modify the later visitor functions to process the new feature as needed.
=== Adding a new pass
For more substantial changes you may need to add a new pass. The simplest
way to do this is to copy the `.cpp` and `.h` files from an existing
pass. You'll need to add a call into your pass from the `process()`
function in `src/verilator.cpp`.
To get your pass to build you'll need to add its binary filename to the
list in `src/Makefile_obj.in` and reconfigure.
== Distribution
Copyright 2008-2019 by Wilson Snyder. Verilator 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.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

+1 -1
View File
@@ -24,7 +24,7 @@ endif
# e.g. examples/tracing_c.
# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a
# package inatall, and verilator is in your path. Otherwise find the
# package install, and verilator is in your path. Otherwise find the
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
+1 -1
View File
@@ -24,7 +24,7 @@ endif
# e.g. examples/tracing_sc.
# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a
# package inatall, and verilator is in your path. Otherwise find the
# package install, and verilator is in your path. Otherwise find the
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
+1 -1
View File
@@ -21,7 +21,7 @@ endif
# Set up variables
# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a
# package inatall, and verilator is in your path. Otherwise find the
# package install, and verilator is in your path. Otherwise find the
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
+12 -8
View File
@@ -27,17 +27,21 @@ int main(int argc, char** argv, char** env) {
// Prevent unused variable warnings
if (0 && argc && argv && env) {}
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
Verilated::commandArgs(argc, argv);
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs
Verilated::debug(0);
// Randomization reset policy
// May be overridden by commandArgs
Verilated::randReset(2);
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
Vtop* top = new Vtop; // Or use a const unique_ptr, or the VL_UNIQUE_PTR wrapper
#if VM_TRACE
// If verilator was invoked with --trace argument,
@@ -90,14 +94,14 @@ int main(int argc, char** argv, char** env) {
#if VM_TRACE
// Dump trace data for this cycle
if (tfp) tfp->dump (main_time);
if (tfp) tfp->dump(main_time);
#endif
// Read outputs
VL_PRINTF ("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
main_time, top->clk, top->reset_l, top->in_quad,
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
main_time, top->clk, top->reset_l, top->in_quad,
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
}
// Final model cleanup
+6 -6
View File
@@ -14,18 +14,18 @@ module top
input fastclk,
input reset_l,
output [1:0] out_small,
output [39:0] out_quad,
output [69:0] out_wide,
output wire [1:0] out_small,
output wire [39:0] out_quad,
output wire [69:0] out_wide,
input [1:0] in_small,
input [39:0] in_quad,
input [69:0] in_wide
);
// Connect up the outputs, using some trivial logic
wire [1:0] out_small = ~reset_l ? '0 : (in_small + 2'b1);
wire [39:0] out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
wire [69:0] out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
assign out_small = ~reset_l ? '0 : (in_small + 2'b1);
assign out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
assign out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
// And an example sub module. The submodule will print stuff.
sub sub (/*AUTOINST*/
+1 -1
View File
@@ -21,7 +21,7 @@ endif
# Set up variables
# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a
# package inatall, and verilator is in your path. Otherwise find the
# package install, and verilator is in your path. Otherwise find the
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
ifeq ($(VERILATOR_ROOT),)
VERILATOR = verilator
+8 -4
View File
@@ -24,15 +24,19 @@ int sc_main(int argc, char* argv[]) {
// Prevent unused variable warnings
if (0 && argc && argv) {}
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
Verilated::commandArgs(argc, argv);
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs
Verilated::debug(0);
// Randomization reset policy
// May be overridden by commandArgs
Verilated::randReset(2);
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
// General logfile
ios::sync_with_stdio();
@@ -111,9 +115,9 @@ int sc_main(int argc, char* argv[]) {
// Apply inputs
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
reset_l = !1; // Assert reset
reset_l = !1; // Assert reset
} else if (VL_TIME_Q() > 1) {
reset_l = !0; // Deassert reset
reset_l = !0; // Deassert reset
}
// Simulate 1ns
+1 -1
View File
@@ -49,7 +49,7 @@ module sub
// An example assertion
always_ff @ (posedge clk) begin
AssertionExample: assert (!reset_l || count_c<100);
AssertionExample: assert(!reset_l || count_c<100);
end
// And example coverage analysis
+6 -6
View File
@@ -14,18 +14,18 @@ module top
input fastclk,
input reset_l,
output [1:0] out_small,
output [39:0] out_quad,
output [69:0] out_wide,
output wire [1:0] out_small,
output wire [39:0] out_quad,
output wire [69:0] out_wide,
input [1:0] in_small,
input [39:0] in_quad,
input [69:0] in_wide
);
// Connect up the outputs, using some trivial logic
wire [1:0] out_small = ~reset_l ? '0 : (in_small + 2'b1);
wire [39:0] out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
wire [69:0] out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
assign out_small = ~reset_l ? '0 : (in_small + 2'b1);
assign out_quad = ~reset_l ? '0 : (in_quad + 40'b1);
assign out_wide = ~reset_l ? '0 : (in_wide + 70'b1);
// And an example sub module. The submodule will print stuff.
sub sub (/*AUTOINST*/
+7 -1
View File
@@ -663,6 +663,7 @@ return(rc);
}
#ifndef FST_DYNAMIC_ALIAS2_DISABLE
static int fstWriterSVarint(FILE *handle, int64_t v)
{
unsigned char buf[15]; /* ceil(64/7) = 10 + sign byte padded way up */
@@ -688,6 +689,7 @@ len = pnt-buf;
fstFwrite(buf, len, 1, handle);
return(len);
}
#endif
/***********************/
@@ -4810,6 +4812,7 @@ uint32_t cur_blackout = 0;
int packtype;
unsigned char *mc_mem = NULL;
uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */
int dumpvars_state = 0;
if(!xc) return(0);
@@ -4819,7 +4822,6 @@ length_remaining = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
if(fv)
{
fprintf(fv, "$dumpvars\n");
#ifndef FST_WRITEX_DISABLE
fflush(fv);
setvbuf(fv, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */
@@ -4966,8 +4968,10 @@ for(;;)
if(beg_tim)
{
if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim);
fstWritex(xc, wx_buf, wx_len);
if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
}
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
{
@@ -5400,8 +5404,10 @@ for(;;)
}
}
if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]);
fstWritex(xc, wx_buf, wx_len);
if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
{
+1 -1
View File
@@ -248,7 +248,7 @@ static const int LZ4_minLength = (MFLIMIT+1);
/**************************************
* Common functions
**************************************/
static unsigned LZ4_NbCommonBytes (register size_t val)
static unsigned LZ4_NbCommonBytes (size_t val)
{
if (LZ4_isLittleEndian())
{
+650 -505
View File
File diff suppressed because it is too large Load Diff
+530 -475
View File
File diff suppressed because it is too large Load Diff
+15 -1
View File
@@ -116,8 +116,22 @@ endif
ifneq ($(VM_THREADS),0)
ifneq ($(VM_THREADS),)
CPPFLAGS += -DVL_THREADED
VK_LIBS_THREADED=1
endif
endif
ifneq ($(VM_TRACE_THREADED),0)
ifneq ($(VM_TRACE_THREADED),)
CPPFLAGS += -DVL_TRACE_THREADED
VK_LIBS_THREADED=1
endif
endif
ifneq ($(VK_LIBS_THREADED),0)
ifneq ($(VK_LIBS_THREADED),)
# Need C++11 at least, so always default to newest
CPPFLAGS += -DVL_THREADED $(CFG_CXXFLAGS_STD_NEWEST)
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
LDLIBS += $(CFG_LDLIBS_THREADS)
endif
endif
+1 -1
View File
@@ -17,7 +17,7 @@
//=========================================================================
//
// DESCRIPTION: Verilator: Include in verilog files to hide verilator defines
`ifdef _VERILATED_V_ `else
`define _VERILATED_V_ 1
+1 -1
View File
@@ -19,7 +19,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
///**** Product and Version name
+238 -236
View File
@@ -50,10 +50,10 @@ public: // But only local to this file
// CONSTRUCTORS
// Derived classes should call zero() in their constructor
VerilatedCovImpItem() {
for (int i=0; i<MAX_KEYS; ++i) {
m_keys[i]=KEY_UNDEF;
m_vals[i]=0;
}
for (int i=0; i<MAX_KEYS; ++i) {
m_keys[i] = KEY_UNDEF;
m_vals[i] = 0;
}
}
virtual ~VerilatedCovImpItem() {}
virtual vluint64_t count() const = 0;
@@ -96,7 +96,7 @@ private:
private:
// MEMBERS
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
@@ -107,294 +107,296 @@ private:
// CONSTRUCTORS
VerilatedCovImp() {
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
m_insertp = NULL;
m_insertFilenamep = NULL;
m_insertLineno = 0;
}
VL_UNCOPYABLE(VerilatedCovImp);
public:
~VerilatedCovImp() { clearGuts(); }
static VerilatedCovImp& imp() VL_MT_SAFE {
static VerilatedCovImp s_singleton;
return s_singleton;
static VerilatedCovImp s_singleton;
return s_singleton;
}
private:
// PRIVATE METHODS
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
static int nextIndex = KEY_UNDEF+1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++; assert(nextIndex>0);
m_valueIndexes.insert(std::make_pair(value, nextIndex));
m_indexValues.insert(std::make_pair(nextIndex, value));
return nextIndex;
static int nextIndex = KEY_UNDEF+1;
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
if (iter != m_valueIndexes.end()) return iter->second;
nextIndex++; assert(nextIndex>0);
m_valueIndexes.insert(std::make_pair(value, nextIndex));
m_indexValues.insert(std::make_pair(nextIndex, value));
return nextIndex;
}
static std::string dequote(const std::string& text) VL_PURE {
// Quote any special characters
std::string rtn;
for (const char* pos = text.c_str(); *pos; ++pos) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex,"%%%02X",pos[0]);
rtn += hex;
} else {
rtn += *pos;
}
}
return rtn;
// Quote any special characters
std::string rtn;
for (const char* pos = text.c_str(); *pos; ++pos) {
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
char hex[10]; sprintf(hex, "%%%02X", pos[0]);
rtn += hex;
} else {
rtn += *pos;
}
}
return rtn;
}
static bool legalKey(const std::string& key) VL_PURE {
// Because we compress long keys to a single letter, and
// don't want applications to either get confused if they use
// a letter differently, nor want them to rely on our compression...
// (Considered using numeric keys, but will remain back compatible.)
if (key.length()<2) return false;
if (key.length()==2 && isdigit(key[1])) return false;
return true;
// Because we compress long keys to a single letter, and
// don't want applications to either get confused if they use
// a letter differently, nor want them to rely on our compression...
// (Considered using numeric keys, but will remain back compatible.)
if (key.length()<2) return false;
if (key.length()==2 && isdigit(key[1])) return false;
return true;
}
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
std::string name;
if (key.length()==1 && isalpha(key[0])) {
name += std::string("\001")+key;
} else {
name += std::string("\001")+dequote(key);
}
name += std::string("\002")+dequote(value);
return name;
std::string name;
if (key.length()==1 && isalpha(key[0])) {
name += std::string("\001")+key;
} else {
name += std::string("\001")+dequote(key);
}
name += std::string("\002")+dequote(value);
return name;
}
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
// (foo.a.x, foo.b.x) => foo.*.x
// (foo.a.x, foo.b.y) => foo.*
// (foo.a.x, foo.b) => foo.*
if (old == add) return add;
// (foo.a.x, foo.b.x) => foo.*.x
// (foo.a.x, foo.b.y) => foo.*
// (foo.a.x, foo.b) => foo.*
if (old == add) return add;
if (old.empty()) return add;
if (add.empty()) return old;
const char* a = old.c_str();
const char* b = add.c_str();
const char* a = old.c_str();
const char* b = add.c_str();
// Scan forward to first mismatch
const char* apre = a;
const char* bpre = b;
while (*apre == *bpre) { apre++; bpre++; }
// Scan forward to first mismatch
const char* apre = a;
const char* bpre = b;
while (*apre == *bpre) { apre++; bpre++; }
// We used to backup and split on only .'s but it seems better to be verbose
// and not assume . is the separator
std::string prefix = std::string(a,apre-a);
// We used to backup and split on only .'s but it seems better to be verbose
// and not assume . is the separator
std::string prefix = std::string(a, apre-a);
// Scan backward to last mismatch
const char* apost = a+strlen(a)-1;
const char* bpost = b+strlen(b)-1;
while (*apost == *bpost
&& apost>apre && bpost>bpre) { apost--; bpost--; }
// Scan backward to last mismatch
const char* apost = a+strlen(a)-1;
const char* bpost = b+strlen(b)-1;
while (*apost == *bpost
&& apost>apre && bpost>bpre) { apost--; bpost--; }
// Forward to . so we have a whole word
std::string suffix = *bpost ? std::string(bpost+1) : "";
// Forward to . so we have a whole word
std::string suffix = *bpost ? std::string(bpost+1) : "";
std::string out = prefix+"*"+suffix;
std::string out = prefix+"*"+suffix;
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
return out;
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
return out;
}
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
std::string val = m_indexValues[itemp->m_vals[i]];
if (std::string::npos != val.find(match)) { // Found
return true;
}
}
}
return false;
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
// We don't compare keys, only values
std::string val = m_indexValues[itemp->m_vals[i]];
if (std::string::npos != val.find(match)) { // Found
return true;
}
}
}
return false;
}
static void selftest() VL_MT_SAFE {
// Little selftest
if (combineHier ("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
// Little selftest
if (combineHier("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
if (combineHier("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
}
void clearGuts() VL_REQUIRES(m_mutex) {
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
}
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
delete itemp;
}
m_items.clear();
m_indexValues.clear();
m_valueIndexes.clear();
}
public:
// PUBLIC METHODS
void clear() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
clearGuts();
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
clearGuts();
}
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
} else {
newlist.push_back(itemp);
}
}
m_items = newlist;
}
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
if (!itemMatchesString(itemp, matchp)) {
delete itemp;
} else {
newlist.push_back(itemp);
}
}
m_items = newlist;
}
}
void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
(*it)->zero();
}
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
(*it)->zero();
}
}
// We assume there's always call to i/f/p in that order
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
}
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp(const char* ckeyps[MAX_KEYS],
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
std::string linestr = vlCovCvtToStr(m_insertLineno);
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
// Default page if not specified
const char* fnstartp = m_insertFilenamep;
while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
const char* fnendp = fnstartp;
while (*fnendp && *fnendp!='.') fnendp++;
std::string page_default = "sp_user/"+std::string(fnstartp,fnendp-fnstartp);
ckeyps[2]="page"; valps[2]=page_default.c_str();
VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
std::string linestr = vlCovCvtToStr(m_insertLineno);
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
// Default page if not specified
const char* fnstartp = m_insertFilenamep;
while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1;
const char* fnendp = fnstartp;
while (*fnendp && *fnendp!='.') fnendp++;
std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp);
ckeyps[2]="page"; valps[2]=page_default.c_str();
// Keys -> strings
std::string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; ++i) {
// Keys -> strings
std::string keys[MAX_KEYS];
for (int i=0; i<MAX_KEYS; ++i) {
if (ckeyps[i] && ckeyps[i][0]) {
keys[i] = ckeyps[i];
}
}
// Ignore empty keys
for (int i=0; i<MAX_KEYS; ++i) {
if (!keys[i].empty()) {
for (int j=i+1; j<MAX_KEYS; ++j) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
}
}
}
}
// Insert the values
int addKeynum=0;
for (int i=0; i<MAX_KEYS; ++i) {
const std::string key = keys[i];
for (int j=i+1; j<MAX_KEYS; ++j) {
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
keys[i] = "";
break;
}
}
}
}
// Insert the values
int addKeynum = 0;
for (int i=0; i<MAX_KEYS; ++i) {
const std::string key = keys[i];
if (!keys[i].empty()) {
const std::string val = valps[i];
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
VL_FATAL_MT("",0,"",msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
const std::string val = valps[i];
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
m_insertp->m_keys[addKeynum] = valueIndex(key);
m_insertp->m_vals[addKeynum] = valueIndex(val);
addKeynum++;
if (!legalKey(key)) {
std::string msg
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
+key);
VL_FATAL_MT("", 0, "", msg.c_str());
}
}
}
m_items.push_back(m_insertp);
// Prepare for next
m_insertp = NULL;
}
void write(const char* filename) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
Verilated::quiesce();
VerilatedLockGuard lock(m_mutex);
#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
selftest();
selftest();
std::ofstream os(filename);
if (os.fail()) {
std::string msg = std::string("%Error: Can't write '")+filename+"'";
VL_FATAL_MT("",0,"",msg.c_str());
return;
}
os << "# SystemC::Coverage-3\n";
if (os.fail()) {
std::string msg = std::string("%Error: Can't write '")+filename+"'";
VL_FATAL_MT("", 0, "", msg.c_str());
return;
}
os << "# SystemC::Coverage-3\n";
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
EventMap eventCounts;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
std::string name;
std::string hier;
bool per_instance = false;
// Build list of events; totalize if collapsing hierarchy
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
EventMap eventCounts;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
VerilatedCovImpItem* itemp = *(it);
std::string name;
std::string hier;
bool per_instance = false;
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
std::string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
if (key == VL_CIK_HIER) {
hier = val;
} else {
// Print it
name += keyValueFormatter(key,val);
}
}
}
if (per_instance) { // Not collapsing hierarchies
name += keyValueFormatter(VL_CIK_HIER,hier);
hier = "";
}
for (int i=0; i<MAX_KEYS; ++i) {
if (itemp->m_keys[i] != KEY_UNDEF) {
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
std::string val = m_indexValues[itemp->m_vals[i]];
if (key == VL_CIK_PER_INSTANCE) {
if (val != "0") per_instance = true;
}
if (key == VL_CIK_HIER) {
hier = val;
} else {
// Print it
name += keyValueFormatter(key, val);
}
}
}
if (per_instance) { // Not collapsing hierarchies
name += keyValueFormatter(VL_CIK_HIER, hier);
hier = "";
}
// Group versus point labels don't matter here, downstream
// deals with it. Seems bad for sizing though and doesn't
// allow easy addition of new group codes (would be
// inefficient)
// Group versus point labels don't matter here, downstream
// deals with it. Seems bad for sizing though and doesn't
// allow easy addition of new group codes (would be
// inefficient)
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const std::string& oldhier = cit->second.first;
cit->second.second += itemp->count();
cit->second.first = combineHier(oldhier, hier);
} else {
eventCounts.insert(std::make_pair(name, make_pair(hier,itemp->count())));
}
}
// Find or insert the named event
EventMap::iterator cit = eventCounts.find(name);
if (cit != eventCounts.end()) {
const std::string& oldhier = cit->second.first;
cit->second.second += itemp->count();
cit->second.first = combineHier(oldhier, hier);
} else {
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
}
}
// Output body
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
os<<"C '"<<std::dec;
os<<it->first;
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
os<<"' "<<it->second.second;
os<<std::endl;
}
// Output body
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
os<<"C '"<<std::dec;
os<<it->first;
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER, it->second.first);
os<<"' "<<it->second.second;
os<<std::endl;
}
}
};
@@ -420,7 +422,7 @@ void VerilatedCov::_inserti(vluint64_t* itemp) VL_MT_SAFE {
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
}
void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
VerilatedCovImp::imp().insertf(filename,lineno);
VerilatedCovImp::imp().insertf(filename, lineno);
}
#define K(n) const char* key ## n
@@ -446,14 +448,14 @@ void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
// And versions with fewer arguments (oh for a language with named parameters!)
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(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(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));
}
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
}
// Backward compatibility for Verilator
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
@@ -461,10 +463,10 @@ void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
std::string val2str = vlCovCvtToStr(val2);
std::string val3str = vlCovCvtToStr(val3);
_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),N(19),
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
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),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 C
+19 -19
View File
@@ -44,31 +44,31 @@
/// The value may be a string, or another type which will be auto-converted to a string.
///
/// Some typical keys:
/// filename File the recording occurs in. Defaults to __FILE__
/// lineno Line number the recording occurs in. Defaults to __LINE__
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
/// hier Hierarchical name. Defaults to name()
/// type Type of coverage. Defaults to "user"
/// Other types are 'block', 'fsm', 'toggle'.
/// comment Description of the coverage event. Should be set by the user.
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
/// thresh Threshold to consider fully covered.
/// If unspecified, downstream tools will determine it.
/// filename File the recording occurs in. Defaults to __FILE__
/// lineno Line number the recording occurs in. Defaults to __LINE__
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
/// hier Hierarchical name. Defaults to name()
/// type Type of coverage. Defaults to "user"
/// Other types are 'block', 'fsm', 'toggle'.
/// comment Description of the coverage event. Should be set by the user.
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
/// thresh Threshold to consider fully covered.
/// If unspecified, downstream tools will determine it.
///
/// Examples:
///
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
/// vluint32_t m_cases[10];
/// constructor {
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
/// }
/// for (int i=0; i<10; ++i) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
/// for (int i=0; i<10; ++i) {
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
/// }
#define VL_COVER_INSERT(countp,args...) \
VL_IF_COVER(VerilatedCov::_inserti(countp); \
VerilatedCov::_insertf(__FILE__,__LINE__); \
VerilatedCov::_insertp("hier", name(), args))
VL_IF_COVER(VerilatedCov::_inserti(countp); \
VerilatedCov::_insertf(__FILE__,__LINE__); \
VerilatedCov::_insertp("hier", name(), args))
//=============================================================================
/// Convert VL_COVER_INSERT value arguments to strings
+11 -6
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#define _VERILATED_DPI_CPP_
#include "verilatedos.h"
@@ -320,7 +320,8 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
return;
}
default:
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
varp->vltype());
return;
}
}
@@ -348,7 +349,8 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
return;
}
default:
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
varp->vltype());
return;
}
}
@@ -370,7 +372,8 @@ static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecV
return;
}
default:
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
varp->vltype());
return;
}
}
@@ -707,11 +710,13 @@ void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
// Verilator doesn't support X/Z so can just call Bit version
svPutBitArrElem1(d, value, indx1);
}
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value,
int indx1, int indx2) {
// Verilator doesn't support X/Z so can just call Bit version
svPutBitArrElem2(d, value, indx1, indx2);
}
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3) {
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value,
int indx1, int indx2, int indx3) {
// Verilator doesn't support X/Z so can just call Bit version
svPutBitArrElem3(d, value, indx1, indx2, indx3);
}
+1 -1
View File
@@ -23,7 +23,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_DPI_H_
#define _VERILATED_DPI_H_ 1 ///< Header Guard
+13 -2
View File
@@ -24,6 +24,12 @@
#include "verilated.h"
#include "verilated_fst_c.h"
// GTKWave configuration
#ifdef VL_TRACE_THREADED
# define HAVE_LIBPTHREAD
# define FST_WRITER_PARALLEL
#endif
// Include the GTKWave implementation directly
#include "gtkwave/fastlz.c"
#include "gtkwave/fstapi.c"
@@ -57,7 +63,7 @@ protected:
VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb,
VerilatedFstCallback_t changecb,
void* ut, vluint32_t code)
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {};
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}
~VerilatedFstCallInfo() {}
};
@@ -72,6 +78,10 @@ VerilatedFst::VerilatedFst(void* fst)
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
m_assertOne.check();
m_fst = fstWriterCreate(filename, 1);
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
#ifdef VL_TRACE_THREADED
fstWriterSetParallelMode(m_fst, 1);
#endif
m_curScope.clear();
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
@@ -164,7 +174,8 @@ void VerilatedFst::addCallback(
VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(isOpen())) {
std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__+" called with already open file";
std::string msg = (std::string("Internal: ")+__FILE__+"::"+__FUNCTION__
+" called with already open file");
VL_FATAL_MT(__FILE__,__LINE__,"",msg.c_str());
}
VerilatedFstCallInfo* vci = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis, 1);
+18 -12
View File
@@ -77,11 +77,11 @@ public:
fstWriterClose(m_fst);
m_fst = NULL;
}
// void set_time_unit(const char* unitp); ///< Set time units (s/ms, defaults to ns)
// void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
void set_time_unit(const char* unitp) { fstWriterSetTimescaleFromString(m_fst, unitp); }
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
// void set_time_resolution(const char* unitp); ///< Set time resolution (s/ms, defaults to ns)
// void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
void set_time_resolution(const char* unitp) { if (unitp) {} }
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
// double timescaleToDouble(const char* unitp);
// std::string doubleToTimescale(double value);
@@ -157,12 +157,18 @@ public:
fstWriterEmitValueChange(m_fst, m_code2symbol[code], array2Str(newval, bits));
}
void fullBit(vluint32_t code, const vluint32_t newval) { chgBit(code, newval); }
void fullBus(vluint32_t code, const vluint32_t newval, int bits) { chgBus(code, newval, bits); }
void fullDouble(vluint32_t code, const double newval) { chgDouble(code, newval); }
void fullFloat(vluint32_t code, const float newval) { chgFloat(code, newval); }
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) { chgQuad(code, newval, bits); }
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) { chgArray(code, newval, bits); }
void fullBit(vluint32_t code, const vluint32_t newval) {
chgBit(code, newval); }
void fullBus(vluint32_t code, const vluint32_t newval, int bits) {
chgBus(code, newval, bits); }
void fullDouble(vluint32_t code, const double newval) {
chgDouble(code, newval); }
void fullFloat(vluint32_t code, const float newval) {
chgFloat(code, newval); }
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
chgQuad(code, newval, bits); }
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
chgArray(code, newval, bits); }
void declTriBit (vluint32_t code, const char* name, int arraynum);
void declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
@@ -216,11 +222,11 @@ public:
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
/// Set time units (s/ms, defaults to ns)
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
void set_time_unit(const char* unit) { /* TODO */ }
void set_time_unit(const char* unitp) { m_sptrace.set_time_unit(unitp); }
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
/// Set time resolution (s/ms, defaults to ns)
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
void set_time_resolution(const char* unit) { /* TODO */ }
void set_time_resolution(const char* unitp) { m_sptrace.set_time_resolution(unitp); }
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
/// Internal class access
+5 -3
View File
@@ -24,7 +24,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_HEAVY_H_
#define _VERILATED_HEAVY_H_ 1 ///< Header Guard
@@ -70,8 +70,10 @@ extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb,
extern void VL_WRITEMEM_N(bool hex, int width, int depth, int array_lsb,
const std::string& filename,
const void* memp, IData start, IData end) VL_MT_SAFE;
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_INX(int lbits, const std::string& ld,
const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits_ignored, std::string& output,
const char* formatp, ...) VL_MT_SAFE;
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) VL_MT_SAFE {
+167 -147
View File
@@ -19,12 +19,12 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#ifndef _VERILATED_IMP_H_
#define _VERILATED_IMP_H_ 1 ///< Header Guard
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_)
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_)
# error "verilated_imp.h only to be included by verilated*.cpp internals"
#endif
@@ -92,32 +92,32 @@ public:
// METHODS
//// Add message to queue (called by producer)
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
}
/// Service queue until completion (called by consumer)
void process() VL_EXCLUDES(m_mutex) {
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
// but on the reader side it's 4x faster to test an atomic then getting a mutex
while (m_depth) {
// Wait for a message to be added to the queue
// We don't use unique_lock as want to unlock with the message copy still in scope
// Tracking m_depth is redundant to e.g. getting the mutex and looking at queue size,
// but on the reader side it's 4x faster to test an atomic then getting a mutex
while (m_depth) {
// Wait for a message to be added to the queue
// We don't use unique_lock as want to unlock with the message copy still in scope
m_mutex.lock();
assert(!m_queue.empty()); // Otherwise m_depth is wrong
// Unfortunately to release the lock we need to copy the message
// (Or have the message be a pointer, but then new/delete cost on each message)
// We assume messages are small, so copy
auto it = m_queue.begin();
const VerilatedMsg msg = *(it);
m_queue.erase(it);
m_mutex.unlock();
m_depth--; // Ok if outside critical section as only this code checks the value
{
// (Or have the message be a pointer, but then new/delete cost on each message)
// We assume messages are small, so copy
auto it = m_queue.begin();
const VerilatedMsg msg = *(it);
m_queue.erase(it);
m_mutex.unlock();
m_depth--; // Ok if outside critical section as only this code checks the value
{
VL_DEBUG_IF(VL_DBG_MSGF("Executing callback from mtaskId=%d\n", msg.mtaskId()););
msg.run();
}
}
}
}
}
};
@@ -128,15 +128,15 @@ public:
// CONSTRUCTORS
VerilatedThreadMsgQueue() { }
~VerilatedThreadMsgQueue() {
// The only call of this with a non-empty queue is a fatal error.
// So this does not flush the queue, as the destination queue is not known to this class.
// The only call of this with a non-empty queue is a fatal error.
// So this does not flush the queue, as the destination queue is not known to this class.
}
private:
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
// METHODS
static VerilatedThreadMsgQueue& threadton() {
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
return t_s;
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
return t_s;
}
public:
/// Add message to queue, called by producer
@@ -153,11 +153,11 @@ public:
}
/// Push all messages to the eval's queue
static void flush(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
while (!threadton().m_queue.empty()) {
evalMsgQp->post(threadton().m_queue.front());
threadton().m_queue.pop();
Verilated::endOfEvalReqdDec();
}
while (!threadton().m_queue.empty()) {
evalMsgQp->post(threadton().m_queue.front());
threadton().m_queue.pop();
Verilated::endOfEvalReqdDec();
}
}
};
#endif // VL_THREADED
@@ -187,6 +187,10 @@ class VerilatedImp {
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); ///< Map the represents scope hierarchy
// Slow - somewhat static:
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
@@ -200,11 +204,11 @@ class VerilatedImp {
public: // But only for verilated*.cpp
// CONSTRUCTORS
VerilatedImp()
: m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
: m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
}
~VerilatedImp() {}
private:
@@ -219,21 +223,21 @@ public:
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 std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
s_s.m_argVecLoaded = true; // Complain only once
VL_FATAL_MT("unknown",0,"",
"%Error: Verilog called $test$plusargs or $value$plusargs without"
" testbench C first calling Verilated::commandArgs(argc,argv).");
}
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
if ((*it)[0]=='+') {
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
}
}
return "";
VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
s_s.m_argVecLoaded = true; // Complain only once
VL_FATAL_MT("unknown", 0, "",
"%Error: Verilog called $test$plusargs or $value$plusargs without"
" testbench C first calling Verilated::commandArgs(argc,argv).");
}
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
if ((*it)[0]=='+') {
if (0==strncmp(prefixp, it->c_str()+1, len)) return *it;
}
}
return "";
}
private:
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
@@ -247,78 +251,92 @@ public:
// 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.
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
if (it != s_s.m_userMap.end()) it->second = userData;
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (it != s_s.m_userMap.end()) it->second = userData;
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
}
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
else return NULL;
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
else return NULL;
}
private:
/// Symbol table destruction cleans up the entries for each scope.
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
} else {
++it;
}
}
// Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
} else {
++it;
}
}
}
static void userDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
it->first.first, it->first.second, it->second);
}
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
it->first.first, it->first.second, it->second);
}
}
public: // But only for verilated*.cpp
// METHODS - scope name
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at construction
VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
}
// Slow ok - called once/scope at construction
VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
}
}
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
else return NULL;
VerilatedLockGuard lock(s_s.m_nameMutex);
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
else return NULL;
}
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at destruction
VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
// Slow ok - called once/scope at destruction
VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
}
static void scopesDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
scopep->scopeDump();
}
VL_PRINTF_MT("\n");
VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin();
it!=s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
scopep->scopeDump();
}
VL_PRINTF_MT("\n");
}
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
// Thread save only assuming this is called only after model construction completed
// Thread save only assuming this is called only after model construction completed
return &s_s.m_nameMap;
}
public: // But only for verilated*.cpp
// METHODS - hierarchy
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
// Slow ok - called at construction for VPI accessible elements
VerilatedLockGuard lock(s_s.m_hierMapMutex);
s_s.m_hierMap[fromp].push_back(top);
}
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
// Thread save only assuming this is called only after model construction completed
return &s_s.m_hierMap;
}
public: // But only for verilated*.cpp
// METHODS - export names
@@ -329,40 +347,42 @@ public: // But only for verilated*.cpp
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
// miss at the cost of a multiply, and all lookups move to slowpath.
static int exportInsert(const char* namep) VL_MT_SAFE {
// Slow ok - called once/function at creation
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
return s_s.m_exportNext++;
} else {
return it->second;
}
// Slow ok - called once/function at creation
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
return s_s.m_exportNext++;
} else {
return it->second;
}
}
static int exportFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ")+namep
+" but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown",0,"", msg.c_str());
return -1;
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ")+namep
+" but no such DPI export function name exists in ANY model");
VL_FATAL_MT("unknown", 0, "", msg.c_str());
return -1;
}
static const char* exportName(int funcnum) VL_MT_SAFE {
// Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
}
return "*UNKNOWN*";
// Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
it!=s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
}
return "*UNKNOWN*";
}
static void exportsDump() VL_MT_SAFE {
VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
}
VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
it!=s_s.m_exportMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
}
}
// We don't free up m_exportMap until the end, because we can't be sure
// what other models are using the assigned funcnum's.
@@ -370,32 +390,32 @@ public: // But only for verilated*.cpp
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNew(FILE* fp) VL_MT_SAFE {
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
return (idx | (1UL<<31)); // bit 31 indicates not MCD
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
return (idx | (1UL<<31)); // bit 31 indicates not MCD
}
static void fdDelete(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
}
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
}
};
+62 -60
View File
@@ -56,17 +56,19 @@ bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
vluint8_t miss = 0;
while (size--) {
miss |= (*dp++ ^ *m_cp++);
miss |= (*dp++ ^ *m_cp++);
}
return (miss!=0);
}
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(readDiffers(datap,size))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize save-restore file as was made from different model");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap,
size_t size) VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(readDiffers(datap, size))) {
std::string fn = filename();
std::string msg = "Can't deserialize save-restore file as was made from different model:"
+filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
}
return *this; // For function chaining
}
@@ -84,10 +86,11 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong header signature");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong header signature: ")
+filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
}
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
}
@@ -101,10 +104,11 @@ void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature");
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
std::string fn = filename();
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
+filename();
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
close();
}
}
@@ -116,19 +120,19 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
m_assertOne.check();
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]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
, 0666);
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
}
m_isOpen = true;
m_filename = filenamep;
@@ -139,19 +143,19 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
m_assertOne.check();
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]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
, 0666);
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
if (m_fd<0) {
// User code can check isOpen()
m_isOpen = false;
return;
}
}
m_isOpen = true;
m_filename = filenamep;
@@ -184,21 +188,21 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
if (VL_UNLIKELY(!isOpen())) return;
vluint8_t* wp = m_bufp;
while (1) {
ssize_t remaining = (m_cp - wp);
if (remaining==0) break;
errno = 0;
ssize_t remaining = (m_cp - wp);
if (remaining==0) break;
errno = 0;
ssize_t got = ::write(m_fd, wp, remaining);
if (got>0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("",0,"",msg.c_str());
close();
break;
}
}
if (got>0) {
wp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
}
}
}
m_cp = m_bufp; // Reset buffer
}
@@ -213,30 +217,28 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
m_cp = m_bufp; // Reset buffer
// Read into buffer starting at m_endp
while (1) {
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
if (remaining==0) break;
errno = 0;
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
if (remaining==0) break;
errno = 0;
ssize_t got = ::read(m_fd, m_endp, remaining);
if (got>0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("",0,"",msg.c_str());
close();
break;
if (got>0) {
m_endp += got;
} else if (got < 0) {
if (errno != EAGAIN && errno != EINTR) {
// write failed, presume error (perhaps out of disk space)
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
VL_FATAL_MT("", 0, "", msg.c_str());
close();
break;
}
} else { // got==0, EOF
// Fill buffer from here to end with NULLs so reader's don't
// need to check eof each character.
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
break;
}
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
break;
}
}
}
//=============================================================================
// Serialization of types
+55 -55
View File
@@ -34,10 +34,10 @@ class VerilatedSerialize {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
@@ -50,13 +50,13 @@ protected:
VL_UNCOPYABLE(VerilatedSerialize);
public:
VerilatedSerialize() {
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
}
virtual ~VerilatedSerialize() {
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
}
// METHODS
bool isOpen() const { return m_isOpen; }
@@ -64,24 +64,24 @@ public:
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
virtual void flush() VL_MT_UNSAFE_ONE {}
inline VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *m_cp++ = *dp++;
size -= blk;
}
return *this; // For function chaining
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *m_cp++ = *dp++;
size -= blk;
}
return *this; // For function chaining
}
private:
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
flush();
}
return *this; // For function chaining
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
flush();
}
return *this; // For function chaining
}
};
@@ -93,12 +93,12 @@ class VerilatedDeserialize {
protected:
// MEMBERS
// For speed, keep m_cp as the first member of this structure
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
vluint8_t* m_bufp; ///< Output buffer
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
bool m_isOpen; ///< True indicates open file/stream
std::string m_filename; ///< Filename, for error messages
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16*1024; }
@@ -111,14 +111,14 @@ protected:
VL_UNCOPYABLE(VerilatedDeserialize);
public:
VerilatedDeserialize() {
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
m_endp = NULL;
m_isOpen = false;
m_bufp = new vluint8_t [bufferSize()];
m_cp = m_bufp;
m_endp = NULL;
}
virtual ~VerilatedDeserialize() {
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
close();
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
}
// METHODS
bool isOpen() const { return m_isOpen; }
@@ -126,15 +126,15 @@ public:
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
virtual void flush() VL_MT_UNSAFE_ONE {}
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *dp++ = *m_cp++;
size -= blk;
}
return *this; // For function chaining
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
while (size) {
bufferCheck();
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
const vluint8_t* __restrict maxp = dp + blk;
while (dp < maxp) *dp++ = *m_cp++;
size -= blk;
}
return *this; // For function chaining
}
// Read a datum and compare with expected value
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
@@ -143,12 +143,12 @@ public:
private:
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
fill();
}
return *this; // For function chaining
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
fill();
}
return *this; // For function chaining
}
};
@@ -158,7 +158,7 @@ private:
class VerilatedSave : public VerilatedSerialize {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
@@ -177,7 +177,7 @@ public:
class VerilatedRestore : public VerilatedDeserialize {
private:
int m_fd; ///< File descriptor we're writing to
int m_fd; ///< File descriptor we're writing to
public:
// CONSTRUCTORS
@@ -237,12 +237,12 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
return os.read(&rhs, sizeof(rhs));
}
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, std::string& rhs) {
vluint32_t len=rhs.length();
vluint32_t len = rhs.length();
os<<len;
return os.write(rhs.data(), len);
}
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
vluint32_t len=0;
vluint32_t len = 0;
os>>len;
rhs.resize(len);
return os.read((void*)rhs.data(), len);
+1 -1
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_SC_H_
#define _VERILATED_SC_H_ 1 ///< Header Guard
+13 -7
View File
@@ -27,7 +27,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_SYM_PROPS_H_
#define _VERILATED_SYM_PROPS_H_ 1 ///< Header Guard
@@ -142,22 +142,28 @@ public:
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
// DPI accessors
int left(int dim) const {
return dim==0 ? m_packed.left() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].left() : 0;
return dim==0 ? m_packed.left()
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].left() : 0;
}
int right(int dim) const {
return dim==0 ? m_packed.right() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].right() : 0;
return dim==0 ? m_packed.right()
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].right() : 0;
}
int low(int dim) const {
return dim==0 ? m_packed.low() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].low() : 0;
return dim==0 ? m_packed.low()
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].low() : 0;
}
int high(int dim) const {
return dim==0 ? m_packed.high() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].high() : 0;
return dim==0 ? m_packed.high()
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].high() : 0;
}
int increment(int dim) const {
return dim==0 ? m_packed.increment() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].increment() : 0;
return dim==0 ? m_packed.increment()
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].increment() : 0;
}
int elements(int dim) const {
return dim==0 ? m_packed.elements() : VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].elements() : 0;
return dim==0 ? m_packed.elements()
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].elements() : 0;
}
/// Total size in bytes (note DPI limited to 4GB)
size_t totalSize() const;
+11 -1
View File
@@ -26,7 +26,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATED_SYMS_H_
#define _VERILATED_SYMS_H_ 1 ///< Header Guard
@@ -36,6 +36,7 @@
#include "verilated_sym_props.h"
#include <map>
#include <vector>
//======================================================================
/// Types
@@ -63,4 +64,13 @@ public:
~VerilatedVarNameMap() {}
};
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
class VerilatedHierarchyMap
: public std::map<const VerilatedScope*, VerilatedScopeVector> {
public:
VerilatedHierarchyMap() {}
~VerilatedHierarchyMap() {}
};
#endif // Guard
+6 -4
View File
@@ -119,8 +119,11 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling)
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
unsigned cpus = std::thread::hardware_concurrency();
if (cpus < nThreads+1) {
VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with"
" --threads %d; may run slow.\n", cpus, nThreads+1);
static int warnedOnce = 0;
if (!warnedOnce++) {
VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with"
" --threads %d; may run slow.\n", cpus, nThreads+1);
}
}
// Create'em
for (int i=0; i<nThreads; ++i) {
@@ -218,8 +221,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
eit->m_cpu,
thread_id);
break;
default: assert(false);
break;
default: assert(false); break; // LCOV_EXCL_LINE
}
}
}
+13 -3
View File
@@ -52,6 +52,10 @@ public:
// METHODS
static vluint64_t yields() { return s_yields; }
static void yieldThread() {
++s_yields; // Statistics
std::this_thread::yield();
}
// Block until notify() has occurred, then return.
// If notify() has already occurred, return immediately.
@@ -63,11 +67,10 @@ public:
unsigned ct = 0;
while (VL_UNLIKELY(!notified())) {
VL_CPU_RELAX();
ct++;
++ct;
if (VL_UNLIKELY(ct > VL_LOCK_SPINS)) {
ct = 0;
++s_yields; // Statistics
std::this_thread::yield();
yieldThread();
}
}
}
@@ -149,8 +152,14 @@ public:
return m_upstreamDepsDone.load(std::memory_order_acquire) == target;
}
inline void waitUntilUpstreamDone(bool evenCycle) const {
unsigned ct = 0;
while (VL_UNLIKELY(!areUpstreamDepsDone(evenCycle))) {
VL_CPU_RELAX();
++ct;
if (VL_UNLIKELY(ct > VL_LOCK_SPINS)) {
ct = 0;
VlNotification::yieldThread();
}
}
}
};
@@ -177,6 +186,7 @@ public:
m_mtaskId = 0;
m_predictTime = 0;
m_startTime = 0;
m_endTime = 0;
m_cpu = getcpu();
}
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
+16 -10
View File
@@ -68,14 +68,17 @@ public:
}
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard lock(singleton().s_vcdMutex);
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(),
singleton().s_vcdVecp.end(), vcdp);
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
}
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
// Thread safety: Although this function is protected by a mutex so perhaps
// in the future we can allow tracing in separate threads, vcdp->flush() assumes call from single thread
// Thread safety: Although this function is protected by a mutex so
// perhaps in the future we can allow tracing in separate threads,
// vcdp->flush() assumes call from single thread
VerilatedLockGuard lock(singleton().s_vcdMutex);
for (VcdVec::const_iterator it=singleton().s_vcdVecp.begin(); it!=singleton().s_vcdVecp.end(); ++it) {
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
it != singleton().s_vcdVecp.end(); ++it) {
VerilatedVcd* vcdp = *it;
vcdp->flush();
}
@@ -102,7 +105,7 @@ protected:
VerilatedVcdCallInfo(VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb,
VerilatedVcdCallback_t changecb,
void* ut, vluint32_t code)
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {};
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {}
~VerilatedVcdCallInfo() {}
};
@@ -322,7 +325,7 @@ void VerilatedVcd::printQuad(vluint64_t n) {
void VerilatedVcd::printTime(vluint64_t timeui) {
// VCD file format specification does not allow non-integers for timestamps
// Dinotrace doesn't mind, but Cadence vvision seems to choke
// Dinotrace doesn't mind, but Cadence Vision seems to choke
if (VL_UNLIKELY(timeui < m_timeLastDump)) {
timeui = m_timeLastDump;
static VL_THREAD_LOCAL bool backTime = false;
@@ -523,7 +526,8 @@ void VerilatedVcd::module(const std::string& name) {
void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
int arraynum, bool tri, bool bussed, int msb, int lsb) {
if (!code) { VL_FATAL_MT(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
if (!code) { VL_FATAL_MT(__FILE__, __LINE__, "",
"Internal: internal trace problem, code 0 is illegal"); }
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
int codesNeeded = 1+int(bits/32);
@@ -644,10 +648,12 @@ void VerilatedVcd::addCallback(
{
m_assertOne.check();
if (VL_UNLIKELY(isOpen())) {
std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__+" called with already open file";
VL_FATAL_MT(__FILE__,__LINE__,"",msg.c_str());
std::string msg = std::string("Internal: ")+__FILE__+"::"+__FUNCTION__
+" called with already open file";
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
}
VerilatedVcdCallInfo* vci = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, m_nextCode);
VerilatedVcdCallInfo* vci
= new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, m_nextCode);
m_callbacks.push_back(vci);
}
+34 -19
View File
@@ -134,17 +134,24 @@ private:
// cppcheck-suppress functionConst
void dumpDone();
inline void printCode(vluint32_t code) {
if (code>=(94*94*94)) *m_writep++ = static_cast<char>((code/94/94/94)%94+33);
if (code>=(94*94)) *m_writep++ = static_cast<char>((code/94/94)%94+33);
if (code>=(94)) *m_writep++ = static_cast<char>((code/94)%94+33);
*m_writep++ = static_cast<char>((code)%94+33);
*m_writep++ = static_cast<char>('!' + code % 94);
code /= 94;
while (code) {
code--;
*m_writep++ = static_cast<char>('!' + code % 94);
code /= 94;
}
}
static std::string stringCode(vluint32_t code) VL_PURE {
std::string out;
if (code>=(94*94*94)) out += static_cast<char>((code/94/94/94)%94+33);
if (code>=(94*94)) out += static_cast<char>((code/94/94)%94+33);
if (code>=(94)) out += static_cast<char>((code/94)%94+33);
return out + static_cast<char>((code)%94+33);
out += static_cast<char>('!' + code % 94);
code /= 94;
while (code) {
code--;
out += static_cast<char>('!' + code % 94);
code /= 94;
}
return out;
}
// CONSTRUCTORS
@@ -155,7 +162,7 @@ public:
// ACCESSORS
/// Set size in megabytes after which new file should be created
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB=rolloverMB; };
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB=rolloverMB; }
/// Is file open?
bool isOpen() const { return m_isOpen; }
/// Change character that splits scopes. Note whitespace are ALWAYS escapes.
@@ -261,7 +268,8 @@ public:
*m_writep++=' '; printCode(code); *m_writep++='\n';
bufferCheck();
}
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 vluint32_t newtri, int bits) {
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) = newtri;
*m_writep++='b';
@@ -272,7 +280,8 @@ public:
*m_writep++=' '; printCode(code); *m_writep++='\n';
bufferCheck();
}
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
void fullTriArray(vluint32_t code, const vluint32_t* newvalp,
const vluint32_t* newtrip, int bits) {
for (int word=0; word<(((bits-1)/32)+1); ++word) {
m_sigs_oldvalp[code+word*2] = newvalp[word];
m_sigs_oldvalp[code+word*2+1] = newtrip[word];
@@ -312,7 +321,8 @@ public:
inline void chgBit(vluint32_t code, const vluint32_t newval) {
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
if (VL_UNLIKELY(diff)) {
// Verilator 3.510 and newer provide clean input, so the below is only for back compatibility
// Verilator 3.510 and newer provide clean input, so the below
// is only for back compatibility
if (VL_UNLIKELY(diff & 1)) { // Change after clean?
fullBit(code, newval);
}
@@ -342,17 +352,20 @@ public:
}
}
}
inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
inline void chgTriBit(vluint32_t code, const vluint32_t newval,
const vluint32_t newtri) {
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
| (m_sigs_oldvalp[code+1] ^ newtri));
if (VL_UNLIKELY(diff)) {
// Verilator 3.510 and newer provide clean input, so the below is only for back compatibility
// Verilator 3.510 and newer provide clean input, so the below
// is only for back compatibility
if (VL_UNLIKELY(diff & 1)) { // Change after clean?
fullTriBit(code, newval, newtri);
}
}
}
inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
inline void chgTriBus(vluint32_t code, const vluint32_t newval,
const vluint32_t newtri, int bits) {
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
| (m_sigs_oldvalp[code+1] ^ newtri));
if (VL_UNLIKELY(diff)) {
@@ -361,7 +374,8 @@ public:
}
}
}
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
inline void chgTriQuad(vluint32_t code, const vluint64_t newval,
const vluint32_t newtri, int bits) {
vluint64_t diff = ( ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) ^ newval)
| ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) ^ newtri));
if (VL_UNLIKELY(diff)) {
@@ -370,7 +384,8 @@ public:
}
}
}
inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp,
const vluint32_t* newtrip, int bits) {
for (int word=0; word<(((bits-1)/32)+1); ++word) {
if (VL_UNLIKELY((m_sigs_oldvalp[code+word*2] ^ newvalp[word])
| (m_sigs_oldvalp[code+word*2+1] ^ newtrip[word]))) {
@@ -425,7 +440,7 @@ public:
/// "cat" to be used to combine the header plus any number of data files.
void openNext(bool incFilename=true) VL_MT_UNSAFE_ONE { m_sptrace.openNext(incFilename); }
/// Set size in megabytes after which new file should be created
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); };
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); }
/// Close dump
void close() VL_MT_UNSAFE_ONE { m_sptrace.close(); }
/// Flush dump
@@ -447,7 +462,7 @@ public:
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
/// Internal class access
inline VerilatedVcd* spTrace() { return &m_sptrace; };
inline VerilatedVcd* spTrace() { return &m_sptrace; }
};
#endif // guard
+4 -2
View File
@@ -47,7 +47,8 @@ public:
sc_get_curr_simcontext()->add_trace_file(this);
# if (SYSTEMC_VERSION>=20060505)
// We want to avoid a depreciated warning, but still be back compatible.
// Turning off the message just for this still results in an annoying "to turn off" message.
// Turning off the message just for this still results in an
// annoying "to turn off" message.
sc_time t1sec(1,SC_SEC);
if (t1sec.to_default_time_units()!=0) {
sc_time tunits(1.0/t1sec.to_default_time_units(),SC_SEC);
@@ -69,7 +70,8 @@ public:
# if (SYSTEMC_VERSION>20011000)
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
# else
// VCD files must have integer timestamps, so we write all times in increments of time_resolution
// VCD files must have integer timestamps, so we write all times in
// increments of time_resolution
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
# endif
}
+656 -540
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -22,7 +22,7 @@
/// Code available from: http://www.veripool.org/verilator
///
//=========================================================================
#ifndef _VERILATED_VPI_H_
#define _VERILATED_VPI_H_ 1 ///< Header Guard
@@ -45,6 +45,9 @@ public:
/// Call value based callbacks
/// Users should call this from their main loops
static void callValueCbs() VL_MT_UNSAFE_ONE;
/// Call callbacks of arbitrary types
/// Users can call this from their application code
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE;
/// Self test, for internal use only
static void selfTest() VL_MT_UNSAFE_ONE;
};
+98 -88
View File
@@ -16,16 +16,16 @@
/// \file
/// \brief Verilator: Common include for OS portability (verilated & verilator)
///
/// This header is used by both the Verilator source code (run on the
/// build and host system), and the Verilated output (run on the target
/// system). Code needed by only the host system goes into
/// config_build.h.in, code needed by Verilated code only goes into
/// verilated.h, and code needed by both goes here (verilatedos.h).
/// This header is used by both the Verilator source code (run on the
/// build and host system), and the Verilated output (run on the target
/// system). Code needed by only the host system goes into
/// config_build.h.in, code needed by Verilated code only goes into
/// verilated.h, and code needed by both goes here (verilatedos.h).
///
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATEDOS_H_
#define _VERILATEDOS_H_ 1 ///< Header Guard
@@ -36,12 +36,10 @@
#ifdef __GNUC__
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
# define VL_ATTR_COLD __attribute__ ((cold))
# define VL_ATTR_HOT __attribute__ ((hot))
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
# ifdef _WIN32
# define VL_ATTR_PRINTF(fmtArgNum) // GCC with MS runtime will fool the print arg checker
# else
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
# endif
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
# define VL_ATTR_PURE __attribute__ ((pure))
# define VL_ATTR_UNUSED __attribute__ ((unused))
# define VL_FUNC __func__
@@ -58,8 +56,8 @@
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
# endif
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
# define VL_UNREACHABLE __builtin_unreachable();
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
@@ -69,51 +67,58 @@
// Defaults for unsupported compiler features
#ifndef VL_ATTR_ALIGNED
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
#endif
#ifndef VL_ATTR_ALWINLINE
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
#endif
#ifndef VL_ATTR_COLD
# define VL_ATTR_COLD ///< Function is rarely executed
#endif
#ifndef VL_ATTR_HOT
# define VL_ATTR_HOT ///< Function is highly executed
#endif
#ifndef VL_ATTR_NORETURN
# define VL_ATTR_NORETURN ///< Function does not ever return
# define VL_ATTR_NORETURN ///< Function does not ever return
#endif
#ifndef VL_ATTR_PRINTF
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
#endif
#ifndef VL_ATTR_PURE
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
#endif
#ifndef VL_ATTR_UNUSED
# define VL_ATTR_UNUSED ///< Function that may be never used
# define VL_ATTR_UNUSED ///< Function that may be never used
#endif
#ifndef VL_FUNC
# define VL_FUNC "__func__" ///< Name of current function for error macros
# define VL_FUNC "__func__" ///< Name of current function for error macros
#endif
#ifndef VL_CAPABILITY
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
#endif
#ifndef VL_LIKELY
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
#endif
#define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage)
#ifndef VL_UNREACHABLE
# define VL_UNREACHABLE ///< Point that may never be reached
# define VL_UNREACHABLE ///< Point that may never be reached
#endif
#ifndef VL_PREFETCH_RD
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
#endif
#ifndef VL_PREFETCH_RW
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
#endif
#ifdef VL_THREADED
@@ -124,12 +129,12 @@
# else
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
# endif
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
#else
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
#endif
#define VL_THREAD ///< Deprecated
#define VL_STATIC_OR_THREAD static ///< Deprecated
#define VL_THREAD ///< Deprecated
#define VL_STATIC_OR_THREAD static ///< Deprecated
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
@@ -138,18 +143,18 @@
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
#ifdef _MSC_VER
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
#else
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
# 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.
#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__)
# define VL_DANGLING(v)
#else
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
#endif
//=========================================================================
@@ -180,7 +185,7 @@
// Optimization
#ifndef VL_INLINE_OPT
# 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
//=========================================================================
@@ -202,42 +207,47 @@
//=========================================================================
// Basic integer types
#ifdef __MINGW32__
# define __USE_MINGW_ANSI_STDIO 1 // Force old MinGW (GCC 5 and older) to use C99 formats
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
#endif
#if defined(__CYGWIN__)
# include <stdint.h>
# include <sys/types.h> // __WORDSIZE
# include <unistd.h> // ssize_t
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
typedef int32_t vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
# else // Older Cygwin has long==uint32_t
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
# endif
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
# else
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
# endif
#elif defined(_WIN32) && defined(_MSC_VER)
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
# ifndef _SSIZE_T_DEFINED
# ifdef _WIN64
@@ -253,16 +263,16 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
# include <stdint.h> // Linux and most flavors
# include <sys/types.h> // __WORDSIZE
# include <unistd.h> // ssize_t
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit signed type
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
typedef uint32_t vluint32_t; ///< 32-bit signed type
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
typedef long vlsint64_t; ///< 64-bit signed type
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
# else
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
typedef long long vlsint64_t; ///< 64-bit signed type
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
# endif
#endif
@@ -270,10 +280,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
// Printing printf/scanf formats
// Alas cinttypes isn't that standard yet
#ifdef _WIN32
# define __STDC_FORMAT_MACROS 1 // Otherwise MinGW doesn't get PRId64 for fstapi.c
// Use Microsoft-specific format specifiers for Microsoft Visual C++ only
#ifdef _MSC_VER
# define VL_PRI64 "I64"
#else // Linux or compliant Unix flavors
#else // use standard C99 format specifiers
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
# define VL_PRI64 "l"
# else
@@ -305,11 +315,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//=========================================================================
// Integer size macros
#define VL_BYTESIZE 8 ///< Bits in a byte
#define VL_SHORTSIZE 16 ///< Bits in a short
#define VL_WORDSIZE 32 ///< Bits in a word
#define VL_QUADSIZE 64 ///< Bits in a quadword
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
#define VL_BYTESIZE 8 ///< Bits in a byte
#define VL_SHORTSIZE 16 ///< Bits in a short
#define VL_WORDSIZE 32 ///< Bits in a word
#define VL_QUADSIZE 64 ///< Bits in a quadword
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
/// Bytes this number of bits needs (1 bit=1 byte)
#define VL_BYTES_I(nbits) (((nbits)+(VL_BYTESIZE-1))/VL_BYTESIZE)
@@ -327,21 +337,21 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//=========================================================================
// Verilated function size macros
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
//=========================================================================
// Base macros
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
#define VL_SIZEBITS_I (VL_WORDSIZE-1) ///< Bit mask for bits in a word
#define VL_SIZEBITS_Q (VL_QUADSIZE-1) ///< Bit mask for bits in a quad
/// Mask for words with 1's where relevant bits are (0=all bits)
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
/// Mask for quads with 1's where relevant bits are (0=all bits)
#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
#define VL_BITWORD_I(bit) ((bit)/VL_WORDSIZE) ///< Word number for a wide quantity
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
@@ -397,4 +407,4 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//=========================================================================
#endif /*guard*/
#endif // Guard
-1006
View File
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -23,9 +23,9 @@ our $Debug;
our $Opt_Unsup;
if (! GetOptions (
#"help" => \&usage,
"debug" => sub { $Debug = 1; },
"unsup!" => \$Opt_Unsup, # Ignore unsupported
#"help" => \&usage,
"debug" => sub { $Debug = 1; },
"unsup!" => \$Opt_Unsup, # Ignore unsupported
)) {
die "usage();"
}
@@ -59,24 +59,24 @@ sub prep {
my $rule = "";
my $skip = 1;
while (defined(my $line = $fh->getline)) {
if ($skip == 1) {
next if $line !~ /%token/;
$skip = 2;
}
if ($skip == 1) {
next if $line !~ /%token/;
$skip = 2;
}
if ($Opt_Unsup) {
$line =~ s!//UNSUP!|!g;
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
}
if ($Opt_Unsup) {
$line =~ s!//UNSUP!|!g;
$line =~ s!(\s+)\|(\s+)!$1$2!g; # As "UNSUP" often replaces "|"
}
# %type<foo>
$line =~ s/^(%\S+)<(\S+)>/$1/;
# rule<foo>
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
# Productions
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
# %type<foo>
$line =~ s/^(%\S+)<(\S+)>/$1/;
# rule<foo>
$line =~ s/^([a-zA-Z0-9_]+)<\S+>:/$1:/;
# Productions
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
$fho->print($line);
$fho->print($line);
}
}
+20 -20
View File
@@ -32,27 +32,27 @@ foreach my $line (<STDIN>) {
$line =~ s!\s+! !g;
next if $line eq '';
if ($line =~ m!^\%\%!) {
$body++;
$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;
}
}
$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;
}
}
}
}
+263
View File
@@ -0,0 +1,263 @@
#!/usr/bin/perl -w
# See copyright, etc in below POD section.
######################################################################
use Cwd;
use File::Copy qw(cp);
use File::Path qw(mkpath);
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw($Debug);
our $Exclude_Line_Regexp;
our @Remove_Sources;
our @Source_Globs;
#======================================================================
# main
our $Opt_Stage = 0;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions(
"debug" => sub { $Debug = 1; },
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
)) {
die "%Error: Bad usage, try 'install_test --help'\n";
}
test();
exit(0);
#######################################################################
sub test {
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
require "./nodist/code_coverage.dat";
if ($Opt_Stage <= 0) {
print "Stage 0: configure (coverage on)\n";
run("make distclean");
run("./configure --enable-longtests CXX='g++ --coverage'");
run("make -k");
# The optimized versions will not collect good coverage, overwrite them
run("cp bin/verilator_bin_dbg bin/verilator_bin");
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
}
if ($Opt_Stage <= 1) {
print "Stage 1: make examples (with coverage on)\n";
run("make examples");
run("make test_regress");
}
my $cc_dir = "nodist/obj_dir/coverage";
if ($Opt_Stage <= 2) {
print "Stage 2: Create info files under $cc_dir\n";
mkpath($cc_dir);
mkpath("$cc_dir/info");
my $dats = `find . -print | grep .gcda`;
my %dirs;
foreach my $dat (split '\n', $dats) {
$dat =~ s!/[^/]+$!!;
$dirs{$dat} = 1;
}
foreach my $dir (sort keys %dirs) {
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info");
}
}
if ($Opt_Stage <= 3) {
# lcov doesn't have a control file to override single lines, so replicate the sources
print "Stage 3: Clone sources under $cc_dir\n";
clone_sources($cc_dir);
}
if ($Opt_Stage <= 4) {
print "Stage 4: Copy .gcno files\n";
my $dats = `find . -print | grep .gcno`;
foreach my $dat (split '\n', $dats) {
next if $dat =~ /$cc_dir/;
my $outdat = $cc_dir."/".$dat;
#print "cp $dat, $outdat);\n";
cp($dat, $outdat);
}
}
if ($Opt_Stage <= 5) {
print "Stage 5: Combine data files\n";
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
my $infos = `cd $cc_dir ; find info -print | grep .info`;
my $comb = "";
my @infos = (split /\n/, $infos);
foreach my $info (@infos) {
$comb .= " -a $info";
# Need to batch them to avoid overrunning shell command length limit
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
$comb = "";
}
}
}
if ($Opt_Stage <= 6) {
print "Stage 6: Filter processed source files\n";
my $cmd = '';
foreach my $glob (@Remove_Sources) {
$cmd .= " '$glob'";
}
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info");
}
if ($Opt_Stage <= 7) {
print "Stage 7: Create HTML\n";
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
}
if ($Opt_Stage <= 9) {
print "*-* All Finished *-*\n";
}
}
sub clone_sources {
my $cc_dir = shift;
my $excluded_lines = 0;
foreach my $glob (@Source_Globs) {
foreach my $infile (glob $glob) {
$infile !~ m!^/!
or die "%Error: source globs should be relative not absolute filenames,";
my $outfile = $cc_dir."/".$infile;
(my $outpath = $outfile) =~ s!/[^/]*$!!;
mkpath($outpath);
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
my $lineno = 0;
while (defined(my $line = $fh->getline)) {
$lineno++;
chomp $line;
if ($line !~ m!// LCOV_EXCL_LINE!
&& $line =~ /$Exclude_Line_Regexp/) {
$line .= " //code_coverage: // LCOV_EXCL_LINE";
$excluded_lines++;
#print "$infile:$lineno: $line";
} else {
}
$ofh->print("$line\n");
}
}
}
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
}
sub cleanup_abs_paths {
my $cc_dir = shift;
my $infile = shift;
my $outfile = shift;
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
my @lines;
while (defined(my $line = $fh->getline)) {
if ($line =~ m!^SF:!) {
$line =~ s!$ENV{VERILATOR_ROOT}/!!;
$line =~ s!$cc_dir/!!;
$line =~ s!obj_dbg/verilog.y$!verilog.y!;
#print "Remaining SF: ",$line;
}
push @lines, $line;
}
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
$ofh->print(@lines);
}
#######################################################################
# .dat file callbacks
sub exclude_line_regexp {
$Exclude_Line_Regexp = shift;
}
sub remove_source {
my @srcs = @_;
push @Remove_Sources, @srcs;
}
sub source_globs {
my @dirs = @_;
push @Source_Globs, @dirs;
}
#######################################################################
sub run {
# Run a system command, check errors
my $command = shift;
print "\t$command\n";
system "$command";
my $status = $?;
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
}
#######################################################################
__END__
=pod
=head1 NAME
code_coverage - Build and collect Verilator coverage
=head1 SYNOPSIS
cd $VERILATOR_ROOT
nodist/code_coverage
=head1 DESCRIPTION
code_coverage builds Verilator with C++ coverage support and runs tests
with coverage enabled.
This will rebuild the current object files.
=head1 ARGUMENTS
=over 4
=item --help
Displays this message and program version and exits.
=item -stage I<stage>
Runs a specific stage (see the script).
=back
=head1 DISTRIBUTION
Copyright 2019-2019 by Wilson Snyder. This package 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.
=head1 AUTHORS
Wilson Snyder <[email protected]>
=head1 SEE ALSO
C<lcov>
=cut
######################################################################
### Local Variables:
### compile-command: "cd .. ; nodist/code_coverage "
### End:
+42
View File
@@ -0,0 +1,42 @@
# -*- Perl -*-
# DESCRIPTION: Verilator: Internal C++ code lcov control file
#
# Copyright 2019-2019 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.
source_globs("src/*.cpp",
"src/*.h",
"src/*.l",
"src/*.y",
"src/obj_dbg/*.h",
"src/obj_dbg/*.cpp",
"include/*.c",
"include/*.cpp",
"include/*.h",
"include/*/*.h",
"include/*/*.cpp",
"include/*/*.c",
);
remove_source("/usr/include/*");
remove_source("*/include/sysc/*");
remove_source("*/V3ClkGater.cpp");
remove_source("*/V3ClkGater.h");
remove_source("*/V3GraphDfa.cpp");
remove_source("*/V3GraphDfa.h");
remove_source("*/V3Lexer_pregen.yy.cpp");
remove_source("*/V3PreLex_pregen.yy.cpp");
remove_source("*/verilog.c");
remove_source("*include/gtkwave/*");
# Something wrong in generation, unfortunately as would like this
#genhtml: ERROR: cannot read /svaha/wsnyder/SandBox/homecvs/v4/verilator/src/obj_dbg/verilog.y
#remove_source("*/src/obj_dbg/verilog.y");
remove_source("*test_regress/*");
remove_source("*examples/*");
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/);
1;
+38 -38
View File
@@ -24,11 +24,11 @@ $Debug = 0;
my $opt_filename;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
usage();
}
@@ -38,8 +38,8 @@ cwrite("graph_export.cpp");
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
@@ -49,9 +49,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!$opt_filename) {
$opt_filename = $param;
$opt_filename = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -64,30 +64,30 @@ sub dotread {
my $header = 1;
my $vnum = 0;
while (defined (my $line = $fh->getline)) {
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
next if $1 eq 'nTITLE';
$header = 0;
$Vertexes{$1} = {num => $vnum++,
line => $line,
name => $1,};
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
my $from=$1; my $to=$2;
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
my $edge = {num => $vnum++,
line => $line,
weight => $weight,
cutable => $cutable,
from => $from,
to => $to,};
push @Edges, $edge;
$Edges{$from}{$to} = $edge;
}
elsif ($header) {
push @Header, $line;
print "IGNORE: $line";
}
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
next if $1 eq 'nTITLE';
$header = 0;
$Vertexes{$1} = {num => $vnum++,
line => $line,
name => $1,};
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
my $from=$1; my $to=$2;
my $weight = 1; $weight = $1 if $line =~ /weight=(\d+)/;
my $cutable = undef; $cutable = $1 if $line =~ /style=(\S+)/;
my $edge = {num => $vnum++,
line => $line,
weight => $weight,
cutable => $cutable,
from => $from,
to => $to,};
push @Edges, $edge;
$Edges{$from}{$to} = $edge;
}
elsif ($header) {
push @Header, $line;
print "IGNORE: $line";
}
}
}
@@ -100,14 +100,14 @@ sub cwrite {
$fh->print("void V3GraphTestImport::dotImport() {\n");
$fh->print(" DfaGraph* gp = &m_graph;\n");
foreach my $ver (sort {$a->{num} <=> $b->{num}} (values %Vertexes)) {
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
$ver->{name}, $ver->{name}, $ver->{name});
$fh->printf(" V3GraphTestVertex* %s = new V3GraphTestVertex(gp, \"%s\"); if (%s) {}\n",
$ver->{name}, $ver->{name}, $ver->{name});
}
$fh->print("\n");
foreach my $edge (@Edges) {
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
$edge->{from}, $edge->{to},
$edge->{weight}, $edge->{cutable}?"true":"false");
$fh->printf(" new V3GraphEdge(gp, %s, %s, %s, %s);\n",
$edge->{from}, $edge->{to},
$edge->{weight}, $edge->{cutable}?"true":"false");
}
$fh->print("}\n");
}
+37 -37
View File
@@ -26,12 +26,12 @@ my $opt_filename;
my $opt_circle;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"circle=s" => \$opt_circle,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
"circle=s" => \$opt_circle,
)) {
usage();
}
@@ -43,8 +43,8 @@ dotwrite();
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
@@ -54,9 +54,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!$opt_filename) {
$opt_filename = $param;
$opt_filename = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -68,16 +68,16 @@ sub dotread {
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
my $header = 1;
while (defined (my $line = $fh->getline)) {
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
$header = 0;
$Vertexes{$1} = $2;
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
$Edges{$1}{$2} = $3;
}
elsif ($header) {
push @Header, $line;
}
if ($line =~ /^\t([a-zA-Z0-9_]+)\t(.*)$/) {
$header = 0;
$Vertexes{$1} = $2;
}
elsif ($line =~ /^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s+(.*)$/) {
$Edges{$1}{$2} = $3;
}
elsif ($header) {
push @Header, $line;
}
}
}
@@ -85,12 +85,12 @@ sub dotread {
sub simplify {
foreach my $ver (sort (keys %Vertexes)) {
$Vertexes{$ver} = _simplify($Vertexes{$ver});
$Vertexes{$ver} = _simplify($Vertexes{$ver});
}
foreach my $v1 (sort (keys %Edges)) {
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
}
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
$Edges{$v1}{$v2} = _simplify($Edges{$v1}{$v2});
}
}
}
@@ -103,15 +103,15 @@ sub _simplify {
sub dotwrite {
foreach my $line (@Header) {
print "$line";
print "$line";
}
foreach my $ver (sort (keys %Vertexes)) {
print "\t$ver\t$Vertexes{$ver}\n";
print "\t$ver\t$Vertexes{$ver}\n";
}
foreach my $v1 (sort (keys %Edges)) {
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
}
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
print "\t$v1 -> $v2\t$Edges{$v1}{$v2}\n";
}
}
print "}\n";
}
@@ -125,15 +125,15 @@ sub circle {
_circle_recurse($node, 1);
foreach my $ver (keys %Vertexes) {
if (!$User{$ver}) {
delete $Vertexes{$ver};
delete $Edges{$ver};
}
if (!$User{$ver}) {
delete $Vertexes{$ver};
delete $Edges{$ver};
}
}
foreach my $v1 (sort (keys %Edges)) {
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
}
foreach my $v2 (sort (keys %{$Edges{$v1}})) {
if (!$Vertexes{$v2}) { delete $Edges{$v1}{$v2}; }
}
}
}
@@ -148,7 +148,7 @@ sub _circle_recurse {
$User2{$node} = 1;
my $r = 0;
foreach my $v2 (keys %{$Edges{$node}}) {
$r |= _circle_recurse($v2,$level++)||0;
$r |= _circle_recurse($v2,$level++)||0;
}
$User{$node} = 1 if $r;
$User2{$node} = 2;
+25 -21
View File
@@ -22,7 +22,8 @@ Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"help" => sub { print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval => 2, output=>\*STDOUT, -noperldoc=>1); },
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
@@ -87,27 +88,30 @@ sub find_edits {
my $hunk = $editlines->{$lineno}{hunk};
$hunk_lastlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
}
# 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;
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};
# 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};
}
}
}
@@ -129,7 +133,7 @@ sub edit_file {
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";
+51 -51
View File
@@ -18,11 +18,11 @@ our $Opt_Jobs = calc_jobs();
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config("no_auto_abbrev");
if (! GetOptions (
"debug" => sub { $Debug = 1; },
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
"j=i" => \$Opt_Jobs,
if (! GetOptions(
"debug" => sub { $Debug = 1; },
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
"stage=i" => \$Opt_Stage,
"j=i" => \$Opt_Jobs,
)) {
die "%Error: Bad usage, try 'install_test --help'\n";
}
@@ -46,51 +46,51 @@ sub test {
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
if ($Opt_Stage <= 0) {
run("/bin/rm -rf $blddir");
run("/bin/mkdir -p $blddir");
run("cd $blddir && $srcdir/configure --prefix $prefix");
run("cd $blddir && make -j $Opt_Jobs");
run("/bin/rm -rf $blddir");
run("/bin/mkdir -p $blddir");
run("cd $blddir && $srcdir/configure --prefix $prefix");
run("cd $blddir && make -j $Opt_Jobs");
}
# Install it under the prefix
if ($Opt_Stage <= 1) {
run("/bin/rm -rf $prefix");
run("/bin/mkdir -p $prefix");
run("cd $blddir && make install");
run("test -e $prefix/share/man/man1/verilator.1");
run("/bin/rm -rf $prefix");
run("/bin/mkdir -p $prefix");
run("cd $blddir && make install");
run("test -e $prefix/share/man/man1/verilator.1");
run("test -e $prefix/share/verilator/examples/tracing_c/Makefile");
run("test -e $prefix/share/verilator/include/verilated.h");
run("test -e $prefix/bin/verilator");
run("test -e $prefix/bin/verilator_bin");
run("test -e $prefix/bin/verilator_bin_dbg");
run("test -e $prefix/share/verilator/include/verilated.h");
run("test -e $prefix/bin/verilator");
run("test -e $prefix/bin/verilator_bin");
run("test -e $prefix/bin/verilator_bin_dbg");
run("test -e $prefix/bin/verilator_gantt");
run("test -e $prefix/bin/verilator_profcfunc");
run("test -e $prefix/bin/verilator_profcfunc");
}
# Run a test using just the path
if ($Opt_Stage <= 2) {
my $dir = $testdirp;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
write_verilog($dir);
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
my $dir = $testdirp;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
write_verilog($dir);
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
}
# Run a test using exact path to binary
if ($Opt_Stage <= 3) {
my $dir = $testdirn;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
write_verilog($dir);
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && make -f Vfoo.mk");
run("cd $dir/obj_dir && ./Vfoo");
my $dir = $testdirn;
run("/bin/rm -rf $dir");
run("/bin/mkdir -p $dir");
write_verilog($dir);
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
run("cd $dir/obj_dir && make -f Vfoo.mk");
run("cd $dir/obj_dir && ./Vfoo");
}
if ($Opt_Stage <= 9) {
@@ -102,29 +102,29 @@ sub write_verilog {
my $dir = shift;
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
my $fh = IO::File->new(">$dir/foo.cpp");
$fh->print('#include "Vfoo.h"' ,"\n");
$fh->print('unsigned int main_time = 0;' ,"\n");
$fh->print('#include "Vfoo.h"' ,"\n");
$fh->print('unsigned int main_time = 0;' ,"\n");
$fh->print('double sc_time_stamp() {' ,"\n");
$fh->print(' return main_time;' ,"\n");
$fh->print('}' ,"\n");
$fh->print('int main() {' ,"\n");
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
$fh->print(' return main_time;' ,"\n");
$fh->print('}' ,"\n");
$fh->print('int main() {' ,"\n");
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
$fh->print(' top->eval();' ,"\n");
$fh->print(' main_time++;' ,"\n");
$fh->print(' }' ,"\n");
$fh->print(' top->final();' ,"\n");
$fh->print('}' ,"\n");
$fh->print(' }' ,"\n");
$fh->print(' top->final();' ,"\n");
$fh->print('}' ,"\n");
}
sub cleanenv {
foreach my $var (keys %ENV) {
if ($var eq "VERILATOR_ROOT"
if ($var eq "VERILATOR_ROOT"
|| $var eq "VERILATOR_INCLUDE"
|| $var eq "VERILATOR_NO_OPT_BUILD") {
print "unset $var # Was '$ENV{$var}'\n";
delete $ENV{$var}
}
print "unset $var # Was '$ENV{$var}'\n";
delete $ENV{$var}
}
}
}
@@ -132,8 +132,8 @@ sub cleanenv {
sub calc_jobs {
my $ok = eval "
use Unix::Processors;
return Unix::Processors->new->max_online;
use Unix::Processors;
return Unix::Processors->new->max_online;
";
$ok && !$@ or return 1;
print "driver.pl: Found $ok cores, using -j ",$ok+1,"\n" if $Debug;
+145 -145
View File
@@ -23,11 +23,11 @@ $Debug = 0;
my $opt_filename;
autoflush STDOUT 1;
autoflush STDERR 1;
if (! GetOptions (
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
if (! GetOptions(
"help" => \&usage,
"debug" => \&debug,
"<>" => \&parameter,
)) {
usage();
}
@@ -40,8 +40,8 @@ print '(query-replace-regexp "(\\([0-9a-z_]+\\))" "\\1" nil nil nil)',"\n";
#----------------------------------------------------------------------
sub usage {
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
exit(1);
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
exit(1); # Unreachable
}
sub debug {
@@ -51,9 +51,9 @@ sub debug {
sub parameter {
my $param = shift;
if (!$opt_filename) {
$opt_filename = $param;
$opt_filename = $param;
} else {
die "%Error: Unknown parameter: $param\n";
die "%Error: Unknown parameter: $param\n";
}
}
@@ -64,45 +64,45 @@ sub vread {
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
my $lasthier="";
$Tree = {
op => 'NETLIST',
t => [[],[],[],[],[],],
op => 'NETLIST',
t => [[],[],[],[],[],],
};
my @stack;
$stack[1] = $Tree;
while (defined (my $line = $fh->getline)) {
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
my $hier = $1;
my $op = $2;
my $lineno = $3;
my $width = $4;
my $etc = $5;
if ($line =~ /^\s+(\S+):\s+(\S+)\s+0x\S+\s+{(\d+)}\s+w(\d+)\s+(.*)$/) {
my $hier = $1;
my $op = $2;
my $lineno = $3;
my $width = $4;
my $etc = $5;
$etc =~ s/__DOT__/./g;
$etc =~ s/__PVT__//g;
$etc =~ s/__DOT__/./g;
$etc =~ s/__PVT__//g;
my $self = {
op => $op,
#width => $width,
#lineno => $lineno,
#line => $line,
etc => $etc,
args => [split(/[ \t]+/,$etc)],
t => [[],[],[],[],[],],
};
my $self = {
op => $op,
#width => $width,
#lineno => $lineno,
#line => $line,
etc => $etc,
args => [split(/[ \t]+/,$etc)],
t => [[],[],[],[],[],],
};
my @hiers = (1,split(/:/,$hier));
my $depth = $#hiers+1;
my $newchild = $hiers[$#hiers];
my @hiers = (1,split(/:/,$hier));
my $depth = $#hiers+1;
my $newchild = $hiers[$#hiers];
#print "DD $depth $newchild $op\n";
#print "DD $depth $newchild $op\n";
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
$stack[$depth] = $self;
push @{$stack[$depth-1]->{t}[$newchild]}, $self;
$stack[$depth] = $self;
$lasthier = $hier;
#print " $lasthier\n";
#print Dumper($Tree);
}
$lasthier = $hier;
#print " $lasthier\n";
#print Dumper($Tree);
}
}
}
@@ -168,125 +168,125 @@ sub nl { p "\n"," "x$Indent; }
sub gentree {
%OpMap = (
'NULLNODE' => sub { "" },
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
'ADD' => sub { p1;p " + ";p2; },
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'AND' => sub { p1;p " & ";p2; },
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
'CONST' => sub { p_const(); },
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
'DIV' => sub { p1;p " / ";p2; },
'EQ' => sub { p1;p " == ";p2; },
'EQCASE' => sub { p1;p " === ";p2; },
'EXTEND' => sub { t1; },
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
'FINISH' => sub { p '$finish;';nl },
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'GT' => sub { p1;p " > ";p2; },
'GTE' => sub { p1;p " >= ";p2; },
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
'LOGAND' => sub { p1;p " && ";p2; },
'LOGNOT' => sub { p1;p " || ";p2; },
'LOGOR' => sub { p "!";p1; },
'LT' => sub { p1;p " < ";p2; },
'LTE' => sub { p1;p " <= ";p2; },
'MODDIV' => sub { p1;p " % ";p2; },
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
'MUL' => sub { p1;p " * ";p2; },
'NEQ' => sub { p1;p " != ";p2; },
'NEQCASE' => sub { p1;p " !== ";p2; },
'NOT' => sub { p " ~";p1; },
'OR' => sub { p1;p " | ";p2; },
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
'PORT' => sub { p ""; },
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'RAND' => sub { p '$rand'; },
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
'REDAND' => sub { p "&(";p1;p ")"; },
'REDOR' => sub { p "|(";p1;p ")"; },
'REDXNOR' => sub { p "~|(";p1;p ")"; },
'REDXOR' => sub { p "~^(";p1;p ")"; },
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCOPE' => sub { t1;t2;t3;t4;t5; },
'SENITEM' => sub { a1;p " ";t1; },
'SENTREE' => sub { t1;t2;t3;t4;t5; },
'SHIFTL' => sub { p1;p " << ";p2; },
'SHIFTR' => sub { p1;p " >> ";p2; },
'STOP' => sub { p '$stop;';nl; },
'SUB' => sub { p1;p " - ";p2; },
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'TIME' => sub { p '$time'; },
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
'NEGATE' => sub { p " -";p1; },
'VAR' => sub { p_var(); },
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'VARREF' => sub { a1; },
'VARSCOPE' => sub { },
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
'XNOR' => sub { p1;p " ~^ ";p2; },
'XOR' => sub { p1;p " ^";p2; },
'NULLNODE' => sub { "" },
'NETLIST' => sub { nl;t1;t2;t3;t4;t5; },
'ACTIVE' => sub { p "always_act @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
'ADD' => sub { p1;p " + ";p2; },
'ALWAYS' => sub { p "always @(";t1;p ") begin";indentInc;nl;t2;t3;t4;t5;indentDec;p "end";nl; },
'ALWAYSPOST' => sub { p "ALWAYSPOST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'AND' => sub { p1;p " & ";p2; },
'ARRAYSEL' => sub { t1;p "[";t2;p "]"; },
'ASSIGN' => sub { t2;p " = ";t1;p ";";nl; },
'ASSIGNDLY' => sub { t2;p " <= ";t1;p ";";nl; },
'ASSIGNPOST' => sub { p "ASSIGNPOST what{";t1;p " = ";t2;p ";";nl; },
'ASSIGNPRE' => sub { p "ASSIGNPRE what{";t1;p " = ";t2;p ";";nl; },
'ASSIGNW' => sub { p "assign ";t2;p " = ";t1;p ";";nl; },
'ATTROF' => sub { p "ATTROF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'BEGIN' => sub { p "begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
'BITSEL' => sub { t1;local $Avoid_Hex=1; p "[";t2;p "]"; },
'CASE' => sub { p "CASE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CASEITEM' => sub { p "CASEITEM what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CAST' => sub { p "CAST what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CCALL' => sub { p "CCALL what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CELL' => sub { a1;p " ";a7;p " (/*CELL*/);"; nl; },
'CFUNC' => sub { p "CFUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CHANGEDET' => sub { p "CHANGEDET what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CINCLUDE' => sub { p "CINCLUDE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'COMMENT' => sub { p "//COMMENT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl;nl; },
'CONCAT' => sub { p "{";p1;p ",";p2;p "}"; },
'CONDITIONAL' => sub { p1;p " ? ";p2;p " : ";p3; },
'CONST' => sub { p_const(); },
'COVER' => sub { p "COVER what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CRETURN' => sub { p "CRETURN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'CSTMT' => sub { p "CSTMT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'DEFPARAM' => sub { p "defparam ";p1;p " = ";p2;p ";";nl; },
'DISPLAY' => sub { p '$write("';p1;p "\",";p2;p3;p4;p5;p ");";nl; },
'DIV' => sub { p1;p " / ";p2; },
'EQ' => sub { p1;p " == ";p2; },
'EQCASE' => sub { p1;p " === ";p2; },
'EXTEND' => sub { t1; },
'EXTRACT' => sub { t1;local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
'FINISH' => sub { p '$finish;';nl },
'FOR' => sub { p "for (";p1;p ",";p2;p ",";p3;p ") begin";indentInc;nl;p4;p5;indentDec;p "end";nl; },
'FUNC' => sub { p "FUNC what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'FUNCREF' => sub { p "FUNCREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'GT' => sub { p1;p " > ";p2; },
'GTE' => sub { p1;p " >= ";p2; },
'IF' => sub { p "if (";p1;p ") begin";indentInc;nl;t2;indentDec;if (exists3) {p "end else begin";indentInc;nl;t3;indentDec;} p "end"; nl; },
'INITARRAY' => sub { p "INITARRAY what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'INITIAL' => sub { p "initial begin";indentInc;nl;t1;t2;t3;t4;t5;indentDec;p "end";nl; },
'LOGAND' => sub { p1;p " && ";p2; },
'LOGNOT' => sub { p1;p " || ";p2; },
'LOGOR' => sub { p "!";p1; },
'LT' => sub { p1;p " < ";p2; },
'LTE' => sub { p1;p " <= ";p2; },
'MODDIV' => sub { p1;p " % ";p2; },
'MODULE' => sub { p "module ";a1;p " (/*AUTOARG*/);";indentInc;nl;t1;t2;t3;t4;t5;indentDec;nl;p "endmodule";nl; },
'MUL' => sub { p1;p " * ";p2; },
'NEQ' => sub { p1;p " != ";p2; },
'NEQCASE' => sub { p1;p " !== ";p2; },
'NOT' => sub { p " ~";p1; },
'OR' => sub { p1;p " | ";p2; },
'PIN' => sub { p ";p ";p1;p " (";p2;p "),";nl; },
'PORT' => sub { p ""; },
'PRAGMA' => sub { p "PRAGMA what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'RAND' => sub { p '$rand'; },
'RANGE' => sub { t1; local $Avoid_Hex=1; p "[";t2;p ":";t3;p "]"; },
'REDAND' => sub { p "&(";p1;p ")"; },
'REDOR' => sub { p "|(";p1;p ")"; },
'REDXNOR' => sub { p "~|(";p1;p ")"; },
'REDXOR' => sub { p "~^(";p1;p ")"; },
'REPLICATE' => sub { p "{";p1;p "{";p2;p "}}"; },
'SCCTOR' => sub { p "SCCTOR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCHDR' => sub { p "SCHDR what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCIMP' => sub { p "SCIMP what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCINT' => sub { p "SCINT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'SCOPE' => sub { t1;t2;t3;t4;t5; },
'SENITEM' => sub { a1;p " ";t1; },
'SENTREE' => sub { t1;t2;t3;t4;t5; },
'SHIFTL' => sub { p1;p " << ";p2; },
'SHIFTR' => sub { p1;p " >> ";p2; },
'STOP' => sub { p '$stop;';nl; },
'SUB' => sub { p1;p " - ";p2; },
'TASK' => sub { p "TASK what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'TASKREF' => sub { p "TASKREF what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'TEXT' => sub { p "TEXT what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'TIME' => sub { p '$time'; },
'TOPSCOPE' => sub { t1;t2;t3;t4;t5; },
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
'NEGATE' => sub { p " -";p1; },
'VAR' => sub { p_var(); },
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'VARREF' => sub { a1; },
'VARSCOPE' => sub { },
'WHILE' => sub { t1; p "while (";t2;p ") begin";indentInc;nl;t3;t4;indentDec;p "end";nl; },
'WORDSEL' => sub { p1;p "[";p2;p ":";p3;p "]"; },
'XNOR' => sub { p1;p " ~^ ";p2; },
'XOR' => sub { p1;p " ^";p2; },
);
}
sub p_var {
my $self = $Code_Self;
if ($self->{etc} =~ /\[I\]/) {
print "input";
print "input";
} elsif ($self->{etc} =~ /\[O\]/) {
print "output";
print "output";
} else {
print "reg";
print "reg";
}
p "\t";
{
local $Avoid_Hex=1;
t1;
local $Avoid_Hex=1;
t1;
}
p "\t";
a1;
if (exists2()) {
p " = ";
t2;
p " = ";
t2;
}
p ";";
nl;
@@ -295,10 +295,10 @@ sub p_var {
sub p_const {
my $v = $Code_Self->{args}[0];
if ($v =~ /\?32\?h(.*)$/
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
print hex $1;
|| ($Avoid_Hex && $v =~ /^[0-9?]*h(.*)$/)) {
print hex $1;
} else {
print $v;
print $v;
}
}
+9 -8
View File
@@ -60,6 +60,8 @@ pkgdatadir = @pkgdatadir@
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
CPPFLAGS += @CPPFLAGS@
CFLAGS += @CFLAGS@
CXXFLAGS += @CXXFLAGS@
LDFLAGS += @LDFLAGS@
EXEEXT = @EXEEXT@
CFG_CXXFLAGS_SRC = @CFG_CXXFLAGS_SRC@
@@ -135,7 +137,7 @@ VLCOVGEN = $(srcdir)/vlcovgen
all: make_info $(TGT)
make_info:
@echo " Compile flags: " $(CXX) ${CPPFLAGS}
@echo " Compile flags: " $(CXX) ${CFLAGS} ${CXXFLAGS} ${CPPFLAGS}
clean mostlyclean distclean maintainer-clean::
-rm -f *.o *.d perlxsi.c *_gen_*
@@ -167,7 +169,6 @@ RAW_OBJS = \
V3Cdc.o \
V3Changed.o \
V3Clean.o \
V3ClkGater.o \
V3Clock.o \
V3Combine.o \
V3Config.o \
@@ -280,21 +281,21 @@ V3Number_test: V3Number_test.o
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
%.o: %.cpp
$(OBJCACHE) ${CXX} ${CPPFLAGSWALL} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $<
%.o: %.c
$(OBJCACHE) ${CC} ${CPPFLAGSWALL} -c $<
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $<
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
#### Generated files
+239 -232
View File
@@ -21,15 +21,15 @@
//
// Note this can be called multiple times.
// Create a IACTIVE(initial), SACTIVE(combo)
// ALWAYS: Remove any-edges from sense list
// If no POS/NEG in senselist, Fold into SACTIVE(combo)
// Else fold into SACTIVE(sequent).
// OPTIMIZE: When support async clocks, fold into that active if possible
// INITIAL: Move into IACTIVE
// WIRE: Move into SACTIVE(combo)
// ALWAYS: Remove any-edges from sense list
// If no POS/NEG in senselist, Fold into SACTIVE(combo)
// Else fold into SACTIVE(sequent).
// OPTIMIZE: When support async clocks, fold into that active if possible
// INITIAL: Move into IACTIVE
// WIRE: Move into SACTIVE(combo)
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -56,66 +56,68 @@ class ActiveNamer : public ActiveBaseVisitor {
private:
typedef std::map<string,AstActive*> ActiveNameMap;
// STATE
AstScope* m_scopep; // Current scope to add statement to
AstActive* m_iActivep; // For current scope, the IActive we're building
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
AstScope* m_scopep; // Current scope to add statement to
AstActive* m_iActivep; // For current scope, the IActive we're building
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
SenTreeSet m_activeSens; // Sen lists for each active we've made
SenTreeSet m_activeSens; // Sen lists for each active we've made
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
ActiveMap m_activeMap; // Map sentree to active, for folding.
// METHODS
void addActive(AstActive* nodep) {
if (!m_scopep) nodep->v3fatalSrc("NULL scope");
m_scopep->addActivep(nodep);
UASSERT_OBJ(m_scopep, nodep, "NULL scope");
m_scopep->addActivep(nodep);
}
// VISITORS
virtual void visit(AstScope* nodep) {
m_scopep = nodep;
m_iActivep = NULL;
m_cActivep = NULL;
m_scopep = nodep;
m_iActivep = NULL;
m_cActivep = NULL;
m_activeSens.clear();
m_activeMap.clear();
iterateChildren(nodep);
// Don't clear scopep, the namer persists beyond this visit
// Don't clear scopep, the namer persists beyond this visit
}
virtual void visit(AstSenTree* nodep) {
// Simplify sensitivity list
V3Const::constifyExpensiveEdit(nodep); VL_DANGLING(nodep);
// Simplify sensitivity list
V3Const::constifyExpensiveEdit(nodep); VL_DANGLING(nodep);
}
// Empty visitors, speed things up
virtual void visit(AstNodeStmt* nodep) { }
//--------------------
// Default
virtual void visit(AstNode* nodep) {
// Default: Just iterate
// Default: Just iterate
iterateChildren(nodep);
}
// METHODS
public:
AstScope* scopep() { return m_scopep; }
AstActive* getCActive(FileLine* fl) {
if (!m_cActivep) {
m_cActivep = new AstActive(fl, "combo",
new AstSenTree(fl, new AstSenItem(fl,AstSenItem::Combo())));
m_cActivep->sensesStorep(m_cActivep->sensesp());
addActive(m_cActivep);
}
return m_cActivep;
if (!m_cActivep) {
m_cActivep = new AstActive(
fl, "combo",
new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo())));
m_cActivep->sensesStorep(m_cActivep->sensesp());
addActive(m_cActivep);
}
return m_cActivep;
}
AstActive* getIActive(FileLine* fl) {
if (!m_iActivep) {
m_iActivep = new AstActive(fl, "initial",
new AstSenTree(fl, new AstSenItem(fl,AstSenItem::Initial())));
m_iActivep->sensesStorep(m_iActivep->sensesp());
addActive(m_iActivep);
}
return m_iActivep;
if (!m_iActivep) {
m_iActivep = new AstActive(
fl, "initial",
new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial())));
m_iActivep->sensesStorep(m_iActivep->sensesp());
addActive(m_iActivep);
}
return m_iActivep;
}
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
// Return a sentree in this scope that matches given sense list.
// Return a sentree in this scope that matches given sense list.
AstActive* activep = NULL;
AstActive* activep = NULL;
AstSenTree* activeSenp = m_activeSens.find(sensesp);
if (activeSenp) {
ActiveMap::iterator it = m_activeMap.find(activeSenp);
@@ -123,26 +125,26 @@ public:
activep = it->second;
}
// Not found, form a new one
if (!activep) {
AstSenTree* newsenp = sensesp->cloneTree(false);
activep = new AstActive(fl, "sequent", newsenp);
activep->sensesStorep(activep->sensesp());
UINFO(8," New ACTIVE "<<activep<<endl);
// Form the sensitivity list
addActive(activep);
// Not found, form a new one
if (!activep) {
AstSenTree* newsenp = sensesp->cloneTree(false);
activep = new AstActive(fl, "sequent", newsenp);
activep->sensesStorep(activep->sensesp());
UINFO(8," New ACTIVE "<<activep<<endl);
// Form the sensitivity list
addActive(activep);
m_activeMap[newsenp] = activep;
m_activeSens.add(newsenp);
// Note actives may have also been added above in the Active visitor
}
return activep;
// Note actives may have also been added above in the Active visitor
}
return activep;
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ActiveNamer() {
m_scopep = NULL;
m_iActivep = NULL;
m_cActivep = NULL;
m_scopep = NULL;
m_iActivep = NULL;
m_cActivep = NULL;
}
virtual ~ActiveNamer() {}
void main(AstScope* nodep) {
@@ -157,66 +159,66 @@ class ActiveDlyVisitor : public ActiveBaseVisitor {
public:
enum CheckType { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
private:
CheckType m_check; // Combo logic or other
AstNode* m_alwaysp; // Always we're under
AstNode* m_assignp; // In assign
CheckType m_check; // Combo logic or other
AstNode* m_alwaysp; // Always we're under
AstNode* m_assignp; // In assign
// VISITORS
virtual void visit(AstAssignDly* nodep) {
if (m_check != CT_SEQ) {
// Convert to a non-delayed assignment
UINFO(5," ASSIGNDLY "<<nodep<<endl);
if (m_check == CT_INITIAL) {
nodep->v3warn(INITIALDLY, "Delayed assignments (<=) in initial"
" or final block; suggest blocking assignments (=).");
} else if (m_check == CT_LATCH) {
// Suppress. Shouldn't matter that the interior of the latch races
} else {
if (m_check != CT_SEQ) {
// Convert to a non-delayed assignment
UINFO(5," ASSIGNDLY "<<nodep<<endl);
if (m_check == CT_INITIAL) {
nodep->v3warn(INITIALDLY, "Delayed assignments (<=) in initial or final block\n"
<<nodep->warnMore()<<"... Suggest blocking assignments (=)");
} else if (m_check == CT_LATCH) {
// Suppress. Shouldn't matter that the interior of the latch races
} else {
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
" (non flop or latch) block; suggest blocking assignments (=).");
}
" (non flop or latch) block\n"
<<nodep->warnMore()<<"... Suggest blocking assignments (=)");
}
AstNode* newp = new AstAssign(nodep->fileline(),
nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack());
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
}
nodep->replaceWith(newp);
nodep->deleteTree(); VL_DANGLING(nodep);
}
}
virtual void visit(AstAssign* nodep) {
if (m_check == CT_SEQ) {
AstNode* las = m_assignp;
m_assignp = nodep;
if (m_check == CT_SEQ) {
AstNode* las = m_assignp;
m_assignp = nodep;
iterateAndNextNull(nodep->lhsp());
m_assignp = las;
}
m_assignp = las;
}
}
virtual void visit(AstVarRef* nodep) {
AstVar* varp=nodep->varp();
if (m_check == CT_SEQ
&& m_assignp
&& !varp->isUsedLoopIdx() // Ignore loop indicies
&& !varp->isTemp()
) {
// Allow turning off warnings on the always, or the variable also
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
&& !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
&& !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
) {
m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
nodep->v3warn(BLKSEQ,"Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).");
}
}
AstVar* varp = nodep->varp();
if (m_check == CT_SEQ
&& m_assignp
&& !varp->isUsedLoopIdx() // Ignore loop indices
&& !varp->isTemp()) {
// Allow turning off warnings on the always, or the variable also
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
&& !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
&& !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)) {
m_assignp->v3warn(BLKSEQ, "Blocking assignments (=) in sequential (flop or latch) block\n"
<<m_assignp->warnMore()<<"... Suggest delayed assignments (<=)");
m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
}
}
}
//--------------------
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ActiveDlyVisitor(AstNode* nodep, CheckType check) {
m_alwaysp = nodep;
m_check = check;
m_assignp = NULL;
m_alwaysp = nodep;
m_check = check;
m_assignp = NULL;
iterate(nodep);
}
virtual ~ActiveDlyVisitor() {}
@@ -229,183 +231,188 @@ class ActiveVisitor : public ActiveBaseVisitor {
private:
// NODE STATE
// Each call to V3Const::constify
// AstNode::user4() Used by V3Const::constify, called below
// AstNode::user4() Used by V3Const::constify, called below
// STATE
ActiveNamer m_namer; // Tracking of active names
AstCFunc* m_scopeFinalp; // Final function for this scope
bool m_itemCombo; // Found a SenItem combo
bool m_itemSequent; // Found a SenItem sequential
ActiveNamer m_namer; // Tracking of active names
AstCFunc* m_scopeFinalp; // Final function for this scope
bool m_itemCombo; // Found a SenItem combo
bool m_itemSequent; // Found a SenItem sequential
// VISITORS
virtual void visit(AstScope* nodep) {
// Create required actives and add to scope
UINFO(4," SCOPE "<<nodep<<endl);
// Clear last scope's names, and collect this scope's existing names
m_namer.main(nodep);
m_scopeFinalp = NULL;
// Create required actives and add to scope
UINFO(4," SCOPE "<<nodep<<endl);
// Clear last scope's names, and collect this scope's existing names
m_namer.main(nodep);
m_scopeFinalp = NULL;
iterateChildren(nodep);
}
virtual void visit(AstActive* nodep) {
// Actives are being formed, so we can ignore any already made
// Actives are being formed, so we can ignore any already made
}
virtual void visit(AstInitial* nodep) {
// Relink to IACTIVE, unless already under it
UINFO(4," INITIAL "<<nodep<<endl);
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
// Relink to IACTIVE, unless already under it
UINFO(4," INITIAL "<<nodep<<endl);
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignAlias* nodep) {
// Relink to CACTIVE, unless already under it
UINFO(4," ASSIGNW "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
// Relink to CACTIVE, unless already under it
UINFO(4," ASSIGNW "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstAssignW* nodep) {
// Relink to CACTIVE, unless already under it
UINFO(4," ASSIGNW "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
// Relink to CACTIVE, unless already under it
UINFO(4," ASSIGNW "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstCoverToggle* nodep) {
// Relink to CACTIVE, unless already under it
UINFO(4," COVERTOGGLE "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
// Relink to CACTIVE, unless already under it
UINFO(4," COVERTOGGLE "<<nodep<<endl);
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
}
virtual void visit(AstFinal* nodep) {
// Relink to CFUNC for the final
UINFO(4," FINAL "<<nodep<<endl);
if (!nodep->bodysp()) { // Empty, Kill it.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
if (!m_scopeFinalp) {
m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(), m_namer.scopep());
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
m_scopeFinalp->dontCombine(true);
m_scopeFinalp->formCallTree(true);
m_scopeFinalp->slow(true);
m_namer.scopep()->addActivep(m_scopeFinalp);
}
nodep->unlinkFrBack();
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName()));
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext());
nodep->deleteTree(); VL_DANGLING(nodep);
// Relink to CFUNC for the final
UINFO(4," FINAL "<<nodep<<endl);
if (!nodep->bodysp()) { // Empty, Kill it.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
if (!m_scopeFinalp) {
m_scopeFinalp = new AstCFunc(
nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(),
m_namer.scopep());
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
m_scopeFinalp->addInitsp(
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
m_scopeFinalp->dontCombine(true);
m_scopeFinalp->formCallTree(true);
m_scopeFinalp->slow(true);
m_namer.scopep()->addActivep(m_scopeFinalp);
}
nodep->unlinkFrBack();
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName(), true));
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext());
nodep->deleteTree(); VL_DANGLING(nodep);
}
// METHODS
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
// Move always to appropriate ACTIVE based on its sense list
if (oldsensesp
&& oldsensesp->sensesp()
// Move always to appropriate ACTIVE based on its sense list
if (oldsensesp
&& oldsensesp->sensesp()
&& VN_IS(oldsensesp->sensesp(), SenItem)
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
// Never executing. Kill it.
if (oldsensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
// Never executing. Kill it.
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
// Read sensitivitues
m_itemCombo = false;
m_itemSequent = false;
// Read sensitivities
m_itemCombo = false;
m_itemSequent = false;
iterateAndNextNull(oldsensesp);
bool combo = m_itemCombo;
bool sequent = m_itemSequent;
bool combo = m_itemCombo;
bool sequent = m_itemSequent;
if (!combo && !sequent) combo=true; // If no list, Verilog 2000: always @ (*)
if (combo && sequent) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
}
sequent = false;
}
if (!combo && !sequent) combo=true; // If no list, Verilog 2000: always @ (*)
if (combo && sequent) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
}
sequent = false;
}
AstActive* wantactivep = NULL;
if (combo && !sequent) {
// Combo: Relink to ACTIVE(combo)
wantactivep = m_namer.getCActive(nodep->fileline());
} else {
// Sequential: Build a ACTIVE(name)
// OPTIMIZE: We could substitute a constant for things in the sense list, for example
// always (posedge RESET) { if (RESET).... } we know RESET is true.
// Summarize a long list of combo inputs as just "combo"
#ifndef __COVERITY__ // Else dead code on next line.
if (combo) oldsensesp->addSensesp
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
AstActive* wantactivep = NULL;
if (combo && !sequent) {
// Combo: Relink to ACTIVE(combo)
wantactivep = m_namer.getCActive(nodep->fileline());
} else {
// Sequential: Build a ACTIVE(name)
// OPTIMIZE: We could substitute a constant for things in the sense list, for example
// always (posedge RESET) { if (RESET).... } we know RESET is true.
// Summarize a long list of combo inputs as just "combo"
#ifndef __COVERITY__ // Else dead code on next line.
if (combo) oldsensesp->addSensesp
(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
#endif
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
}
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
}
// Delete sensitivity list
if (oldsensesp) {
oldsensesp->unlinkFrBackWithNext()->deleteTree(); VL_DANGLING(oldsensesp);
}
// Delete sensitivity list
if (oldsensesp) {
oldsensesp->unlinkFrBackWithNext()->deleteTree(); VL_DANGLING(oldsensesp);
}
// Move node to new active
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
// Move node to new active
nodep->unlinkFrBack();
wantactivep->addStmtsp(nodep);
// Warn and/or convert any delayed assignments
if (combo && !sequent) {
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_LATCH);
} else {
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_COMBO);
}
}
else if (!combo && sequent) {
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
}
// Warn and/or convert any delayed assignments
if (combo && !sequent) {
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_LATCH);
} else {
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_COMBO);
}
}
else if (!combo && sequent) {
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
}
}
virtual void visit(AstAlways* nodep) {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALW "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALW "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
if (!nodep->bodysp()) {
// Empty always. Kill it.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
if (!nodep->bodysp()) {
// Empty always. Kill it.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
}
virtual void visit(AstAlwaysPublic* nodep) {
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALWPub "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
// Move always to appropriate ACTIVE based on its sense list
UINFO(4," ALWPub "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
}
virtual void visit(AstSenGate* nodep) {
AstSenItem* subitemp = nodep->sensesp();
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE
&& subitemp->edgeType() != AstEdgeType::ET_POSEDGE
&& subitemp->edgeType() != AstEdgeType::ET_NEGEDGE) {
nodep->v3fatalSrc("Strange activity type under SenGate");
}
AstSenItem* subitemp = nodep->sensesp();
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
nodep, "Strange activity type under SenGate");
iterateChildren(nodep);
}
virtual void visit(AstSenItem* nodep) {
if (nodep->edgeType() == AstEdgeType::ET_ANYEDGE) {
m_itemCombo = true;
// Delete the sensitivity
// We'll add it as a generic COMBO SenItem in a moment.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->varrefp()) {
// V3LinkResolve should have cleaned most of these up
if (!nodep->varrefp()->width1()) nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
<<nodep->varrefp()->prettyName());
m_itemSequent = true;
nodep->varrefp()->varp()->usedClock(true);
}
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
m_itemCombo = true;
// Delete the sensitivity
// We'll add it as a generic COMBO SenItem in a moment.
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
} else if (nodep->varrefp()) {
// V3LinkResolve should have cleaned most of these up
if (!nodep->varrefp()->width1()) {
nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
<<nodep->varrefp()->prettyNameQ());
}
m_itemSequent = true;
nodep->varrefp()->varp()->usedClock(true);
}
}
// Empty visitors, speed things up
@@ -416,11 +423,11 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ActiveVisitor(AstNetlist* nodep) {
m_scopeFinalp = NULL;
m_itemCombo = false;
m_itemSequent = false;
m_scopeFinalp = NULL;
m_itemCombo = false;
m_itemSequent = false;
iterate(nodep);
}
virtual ~ActiveVisitor() {}
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ACTIVE_H_
#define _V3ACTIVE_H_ 1
@@ -34,4 +34,4 @@ public:
static void activeAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+68 -66
View File
@@ -21,12 +21,12 @@
//
// Note this can be called multiple times.
// Across all ACTIVES
// SenTrees are now under each ACTIVE statement, we want them global:
// Find SenTree in under global TopScope, or create it there
// Move SenTree the global SenTree
// SenTrees are now under each ACTIVE statement, we want them global:
// Find SenTree in under global TopScope, or create it there
// Move SenTree the global SenTree
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -43,91 +43,93 @@ class ActiveTopVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist
// AstNode::user() bool. True if processed
// AstNode::user() bool. True if processed
// Each call to V3Const::constify
// AstNode::user4() Used by V3Const::constify, called below
AstUser1InUse m_inuser1;
// AstNode::user4() Used by V3Const::constify, called below
AstUser1InUse m_inuser1;
// STATE
AstTopScope* m_topscopep; // Top scope for adding sentrees under
SenTreeFinder m_finder; // Find global sentree's and add them
AstTopScope* m_topscopep; // Top scope for adding sentrees under
SenTreeFinder m_finder; // Find global sentree's and add them
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstTopScope* nodep) {
m_topscopep = nodep;
m_finder.main(m_topscopep);
m_topscopep = nodep;
m_finder.main(m_topscopep);
iterateChildren(nodep);
m_topscopep = NULL;
m_topscopep = NULL;
}
virtual void visit(AstNodeModule* nodep) {
// Create required actives and add to module
// We can start ordering at a module, or a scope
UINFO(4," MOD "<<nodep<<endl);
// Create required actives and add to module
// We can start ordering at a module, or a scope
UINFO(4," MOD "<<nodep<<endl);
iterateChildren(nodep);
}
virtual void visit(AstActive* nodep) {
UINFO(4," ACTIVE "<<nodep<<endl);
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
AstSenTree* sensesp = nodep->sensesp();
if (!sensesp) nodep->v3fatalSrc("NULL");
if (sensesp->sensesp()
UINFO(4," ACTIVE "<<nodep<<endl);
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
AstSenTree* sensesp = nodep->sensesp();
UASSERT_OBJ(sensesp, nodep, "NULL");
if (sensesp->sensesp()
&& VN_IS(sensesp->sensesp(), SenItem)
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
// Never executing. Kill it.
if (sensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
// Copy combo tree to settlement tree with duplicated statements
if (sensesp->hasCombo()) {
AstSenTree* newsentreep
// Never executing. Kill it.
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
"Never senitem should be alone, else the never should be eliminated.");
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
return;
}
// Copy combo tree to settlement tree with duplicated statements
if (sensesp->hasCombo()) {
AstSenTree* newsentreep
= new AstSenTree(nodep->fileline(),
new AstSenItem (nodep->fileline(), AstSenItem::Settle()));
AstActive* newp = new AstActive(nodep->fileline(),"settle", newsentreep);
newp->sensesStorep(newsentreep);
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
nodep->addNextHere(newp);
}
// Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp);
UINFO(4," lookdone\n");
if (wantp != sensesp) {
// Move the active's contents to the other active
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
if (nodep->sensesStorep()) {
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different");
sensesp->unlinkFrBack();
// There may be other references to same sense tree,
// we'll be removing all references when we get to them,
// but don't dangle our pointer yet!
pushDeletep(sensesp);
}
nodep->sensesp(wantp);
}
// No need to do statements under it, they're already moved.
new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
AstActive* newp = new AstActive(nodep->fileline(),"settle", newsentreep);
newp->sensesStorep(newsentreep);
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
nodep->addNextHere(newp);
}
// Move the SENTREE for each active up to the global level.
// This way we'll easily see what clock domains are identical
AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp);
UINFO(4," lookdone\n");
if (wantp != sensesp) {
// Move the active's contents to the other active
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
if (nodep->sensesStorep()) {
UASSERT_OBJ(sensesp == nodep->sensesStorep(), nodep,
"sensesStore should have been deleted earlier if different");
sensesp->unlinkFrBack();
// There may be other references to same sense tree,
// we'll be removing all references when we get to them,
// but don't dangle our pointer yet!
pushDeletep(sensesp);
}
nodep->sensesp(wantp);
}
// No need to do statements under it, they're already moved.
//iterateChildren(nodep);
}
virtual void visit(AstInitial* nodep) {
nodep->v3fatalSrc("Node should have been under ACTIVE");
virtual void visit(AstInitial* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignAlias* nodep) {
nodep->v3fatalSrc("Node should have been under ACTIVE");
virtual void visit(AstAssignAlias* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAssignW* nodep) {
nodep->v3fatalSrc("Node should have been under ACTIVE");
virtual void visit(AstAssignW* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlways* nodep) {
nodep->v3fatalSrc("Node should have been under ACTIVE");
virtual void visit(AstAlways* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstAlwaysPublic* nodep) {
nodep->v3fatalSrc("Node should have been under ACTIVE");
virtual void visit(AstAlwaysPublic* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
virtual void visit(AstFinal* nodep) {
nodep->v3fatalSrc("Node should have been deleted");
virtual void visit(AstFinal* nodep) { // LCOV_EXCL_LINE
nodep->v3fatalSrc("Node should have been deleted");
}
// Empty visitors, speed things up
virtual void visit(AstNodeMath* nodep) {}
@@ -137,9 +139,9 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit ActiveTopVisitor(AstNetlist* nodep) {
m_topscopep = NULL;
m_topscopep = NULL;
iterate(nodep);
}
virtual ~ActiveTopVisitor() {}
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ACTIVETOP_H_
#define _V3ACTIVETOP_H_ 1
@@ -34,4 +34,4 @@ public:
static void activeTopAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+211 -205
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -37,46 +37,46 @@ class AssertVisitor : public AstNVisitor {
private:
// NODE STATE/TYPES
// Cleared on netlist
// AstNode::user() -> bool. True if processed
AstUser1InUse m_inuser1;
// AstNode::user() -> bool. True if processed
AstUser1InUse m_inuser1;
// STATE
AstNodeModule* m_modp; // Last module
AstBegin* m_beginp; // Last begin
AstNodeModule* m_modp; // Last module
AstBegin* m_beginp; // Last begin
unsigned m_modPastNum; // Module past numbering
V3Double0 m_statAsCover; // Statistic tracking
V3Double0 m_statAsPsl; // Statistic tracking
V3Double0 m_statAsFull; // Statistic tracking
V3Double0 m_statAsSV; // Statistic tracking
VDouble0 m_statAsCover; // Statistic tracking
VDouble0 m_statAsPsl; // Statistic tracking
VDouble0 m_statAsFull; // Statistic tracking
VDouble0 m_statAsSV; // Statistic tracking
// METHODS
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename()
+":"+cvtToStr(nodep->fileline()->lineno())
+": Assertion failed in %m"
+((message != "")?": ":"")+message
+"\n");
return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename()
+":"+cvtToStr(nodep->fileline()->lineno())
+": Assertion failed in %m"
+((message != "")?": ":"")+message
+"\n");
}
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
// cppcheck-suppress nullPointer
AstNode* timenewp = new AstTime(nodep->fileline());
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
nodep->fmtp()->addExprsp(timenewp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
}
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
// cppcheck-suppress nullPointer
AstNode* timenewp = new AstTime(nodep->fileline());
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
nodep->fmtp()->addExprsp(timenewp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
}
}
AstNode* newIfAssertOn(AstNode* nodep) {
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
FileLine* fl = nodep->fileline();
AstNode* newp
AstNode* newp
= new AstIf(fl,
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
@@ -84,46 +84,47 @@ private:
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
nodep, NULL);
newp->user1(true); // Don't assert/cover this if
return newp;
newp->user1(true); // Don't assert/cover this if
return newp;
}
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
// Like newFireAssert() but omits the asserts-on check
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
AstNode* bodysp = dispp;
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
AstDisplay* dispp = new AstDisplay(nodep->fileline(),
AstDisplayType::DT_ERROR, message, NULL, NULL);
AstNode* bodysp = dispp;
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
bodysp->addNext(new AstStop(nodep->fileline()));
return bodysp;
}
AstNode* newFireAssert(AstNode* nodep, const string& message) {
AstNode* bodysp = newFireAssertUnchecked(nodep, message);
bodysp = newIfAssertOn(bodysp);
return bodysp;
bodysp = newIfAssertOn(bodysp);
return bodysp;
}
void newPslAssertion(AstNode* nodep, AstNode* propp, AstSenTree* sentreep,
AstNode* stmtsp, const string& message) {
propp->unlinkFrBack();
sentreep->unlinkFrBack();
if (stmtsp) stmtsp->unlinkFrBack();
//
AstNode* bodysp = NULL;
bool selfDestruct = false;
AstNode* stmtsp, const string& message) {
propp->unlinkFrBack();
sentreep->unlinkFrBack();
if (stmtsp) stmtsp->unlinkFrBack();
//
AstNode* bodysp = NULL;
bool selfDestruct = false;
AstIf* ifp = NULL;
if (AstPslCover* snodep = VN_CAST(nodep, PslCover)) {
++m_statAsCover;
if (!v3Global.opt.coverageUser()) {
selfDestruct = true;
} else {
// V3Coverage assigned us a bucket to increment.
if (!v3Global.opt.coverageUser()) {
selfDestruct = true;
} else {
// V3Coverage assigned us a bucket to increment.
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
if (!covincp) snodep->v3fatalSrc("Missing AstCoverInc under assertion");
covincp->unlinkFrBack();
if (message!="") covincp->declp()->comment(message);
bodysp = covincp;
}
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
covincp->unlinkFrBack();
if (message!="") covincp->declp()->comment(message);
bodysp = covincp;
}
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL);
@@ -142,169 +143,173 @@ private:
ifp = new AstIf(nodep->fileline(), propp, NULL, stmtsp);
// It's more LIKELY that we'll take the NULL if clause
// than the sim-killing else clause:
ifp->branchPred(AstBranchPred::BP_LIKELY);
ifp->branchPred(VBranchPred::BP_LIKELY);
bodysp = newIfAssertOn(ifp);
} else if (VN_IS(nodep, PslRestrict)) {
// IEEE says simulator ignores these
pushDeletep(nodep->unlinkFrBack()); VL_DANGLING(nodep);
return;
} else {
nodep->v3fatalSrc("Unknown node type");
}
} else {
nodep->v3fatalSrc("Unknown node type");
}
AstNode* newp = new AstAlways(nodep->fileline(),
VAlwaysKwd::ALWAYS, sentreep, bodysp);
// Install it
if (selfDestruct) {
// Delete it after making the tree. This way we can tell the user
// if it wasn't constructed nicely or has other errors without needing --coverage.
newp->deleteTree();
nodep->unlinkFrBack();
} else {
nodep->replaceWith(newp);
}
// Bye
pushDeletep(nodep); VL_DANGLING(nodep);
// Install it
if (selfDestruct) {
// Delete it after making the tree. This way we can tell the user
// if it wasn't constructed nicely or has other errors without needing --coverage.
newp->deleteTree();
nodep->unlinkFrBack();
} else {
nodep->replaceWith(newp);
}
// Bye
pushDeletep(nodep); VL_DANGLING(nodep);
}
void newVAssertion(AstVAssert* nodep, AstNode* propp) {
propp->unlinkFrBackWithNext();
AstNode* passsp = nodep->passsp(); if (passsp) passsp->unlinkFrBackWithNext();
AstNode* failsp = nodep->failsp(); if (failsp) failsp->unlinkFrBackWithNext();
//
propp->unlinkFrBackWithNext();
AstNode* passsp = nodep->passsp(); if (passsp) passsp->unlinkFrBackWithNext();
AstNode* failsp = nodep->failsp(); if (failsp) failsp->unlinkFrBackWithNext();
//
if (VN_IS(nodep, VAssert)) {
if (passsp) passsp = newIfAssertOn(passsp);
if (failsp) failsp = newIfAssertOn(failsp);
} else {
nodep->v3fatalSrc("Unknown node type");
}
if (passsp) passsp = newIfAssertOn(passsp);
if (failsp) failsp = newIfAssertOn(failsp);
} else {
nodep->v3fatalSrc("Unknown node type");
}
AstIf* ifp = new AstIf(nodep->fileline(), propp, passsp, failsp);
AstNode* newp = ifp;
if (VN_IS(nodep, VAssert)) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
//
// Install it
nodep->replaceWith(newp);
// Bye
pushDeletep(nodep); VL_DANGLING(nodep);
AstNode* newp = ifp;
if (VN_IS(nodep, VAssert)) ifp->branchPred(VBranchPred::BP_UNLIKELY);
//
// Install it
nodep->replaceWith(newp);
// Bye
pushDeletep(nodep); VL_DANGLING(nodep);
}
// VISITORS
virtual void visit(AstIf* nodep) {
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
AstNode* propp = NULL;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
// nextIf statement. Otherwise it will be null.
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
AstNode* propp = NULL;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
// nextIf statement. Otherwise it will be null.
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
iterateAndNextNull(ifp->condp());
// Recurse into the true case.
// Recurse into the true case.
iterateAndNextNull(ifp->ifsp());
// If the last else is not an else if, recurse into that too.
if (ifp->elsesp() && !nextifp) {
// If the last else is not an else if, recurse into that too.
if (ifp->elsesp() && !nextifp) {
iterateAndNextNull(ifp->elsesp());
}
}
// Build a bitmask of the true predicates
AstNode* predp = ifp->condp()->cloneTree(false);
if (propp) {
propp = new AstConcat(nodep->fileline(), predp, propp);
} else {
propp = predp;
}
// Build a bitmask of the true predicates
AstNode* predp = ifp->condp()->cloneTree(false);
if (propp) {
propp = new AstConcat(nodep->fileline(), predp, propp);
} else {
propp = predp;
}
// Record if this ends with an 'else' that does not have an if
if (ifp->elsesp() && !nextifp) {
hasDefaultElse = true;
}
// Record if this ends with an 'else' that does not have an if
if (ifp->elsesp() && !nextifp) {
hasDefaultElse = true;
}
ifp = nextifp;
} while (ifp);
ifp = nextifp;
} while (ifp);
AstNode *newifp = nodep->cloneTree(false);
bool allow_none = nodep->unique0Pragma();
AstNode *newifp = nodep->cloneTree(false);
bool allow_none = nodep->unique0Pragma();
// Empty case means no property
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
// Empty case means no property
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
AstNode* ohot = ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot (nodep->fileline(), propp)));
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
AstNode* ohot = ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* checkifp = new AstIf(nodep->fileline(),
new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep, "'unique if' statement violated"),
newifp);
checkifp->branchPred(AstBranchPred::BP_UNLIKELY);
nodep->replaceWith(checkifp);
pushDeletep(nodep);
} else {
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->replaceWith(checkifp);
pushDeletep(nodep);
} else {
iterateChildren(nodep);
}
}
}
//========== Case assertions
virtual void visit(AstCase* nodep) {
iterateChildren(nodep);
if (!nodep->user1SetOnce()) {
bool has_default=false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) has_default=true;
}
if (nodep->fullPragma() || nodep->priorityPragma()) {
// Simply need to add a default if there isn't one already
++m_statAsFull;
if (!has_default) {
nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
newFireAssert(nodep, "synthesis full_case, but non-match found")));
}
}
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
// Need to check that one, and only one of the case items match at any moment
// If there's a default, we allow none to match, else exactly one must match
++m_statAsFull;
if (!has_default && !nodep->itemsp()) {
// Not parallel, but harmlessly so.
} else {
AstNode* propp = NULL;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
AstNode* onep;
if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
onep = AstEqWild::newTyped(itemp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
} else {
onep = AstEq::newTyped(icondp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
}
if (propp) propp = new AstConcat(icondp->fileline(), onep, propp);
else propp = onep;
}
}
// Empty case means no property
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
if (!nodep->user1SetOnce()) {
bool has_default = false;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) has_default = true;
}
if (nodep->fullPragma() || nodep->priorityPragma()) {
// Simply need to add a default if there isn't one already
++m_statAsFull;
if (!has_default) {
nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
newFireAssert(nodep, "synthesis full_case, but non-match found")));
}
}
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
// Need to check that one, and only one of the case items match at any moment
// If there's a default, we allow none to match, else exactly one must match
++m_statAsFull;
if (!has_default && !nodep->itemsp()) {
// Not parallel, but harmlessly so.
} else {
AstNode* propp = NULL;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp();
icondp!=NULL; icondp=icondp->nextp()) {
AstNode* onep;
if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
onep = AstEqWild::newTyped(itemp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
} else {
onep = AstEq::newTyped(icondp->fileline(),
nodep->exprp()->cloneTree(false),
icondp->cloneTree(false));
}
if (propp) propp = new AstConcat(icondp->fileline(), onep, propp);
else propp = onep;
}
}
// Empty case means no property
if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
bool allow_none = has_default || nodep->unique0Pragma();
AstNode* ohot = (allow_none
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot (nodep->fileline(), propp)));
bool allow_none = has_default || nodep->unique0Pragma();
AstNode* ohot
= (allow_none
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
AstIf* ifp = new AstIf(nodep->fileline(),
new AstLogNot(nodep->fileline(), ohot),
newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"),
NULL);
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
nodep->addNotParallelp(ifp);
}
}
}
ifp->branchPred(VBranchPred::BP_UNLIKELY);
nodep->addNotParallelp(ifp);
}
}
}
}
//========== Past
@@ -312,10 +317,11 @@ private:
iterateChildren(nodep);
uint32_t ticks = 1;
if (nodep->ticksp()) {
if (!VN_IS(nodep->ticksp(), Const)) nodep->v3fatalSrc("Expected constant ticks, checked in V3Width");
UASSERT_OBJ(VN_IS(nodep->ticksp(), Const), nodep,
"Expected constant ticks, checked in V3Width");
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
}
if (ticks<1) nodep->v3fatalSrc("0 tick should have been checked in V3Width");
UASSERT_OBJ(ticks>=1, nodep, "0 tick should have been checked in V3Width");
AstNode* inp = nodep->exprp()->unlinkFrBack();
AstVar* invarp = NULL;
AstSenTree* sentreep = nodep->sentreep(); sentreep->unlinkFrBack();
@@ -341,46 +347,46 @@ private:
//========== Statements
virtual void visit(AstDisplay* nodep) {
iterateChildren(nodep);
// Replace the special types with standard text
if (nodep->displayType()==AstDisplayType::DT_INFO) {
replaceDisplay(nodep, "-Info");
} else if (nodep->displayType()==AstDisplayType::DT_WARNING) {
replaceDisplay(nodep, "%%Warning");
} else if (nodep->displayType()==AstDisplayType::DT_ERROR
|| nodep->displayType()==AstDisplayType::DT_FATAL) {
replaceDisplay(nodep, "%%Error");
}
// Replace the special types with standard text
if (nodep->displayType()==AstDisplayType::DT_INFO) {
replaceDisplay(nodep, "-Info");
} else if (nodep->displayType()==AstDisplayType::DT_WARNING) {
replaceDisplay(nodep, "%%Warning");
} else if (nodep->displayType()==AstDisplayType::DT_ERROR
|| nodep->displayType()==AstDisplayType::DT_FATAL) {
replaceDisplay(nodep, "%%Error");
}
}
virtual void visit(AstNodePslCoverOrAssert* nodep) {
iterateChildren(nodep);
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
nodep->stmtsp(), nodep->name()); VL_DANGLING(nodep);
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
nodep->stmtsp(), nodep->name()); VL_DANGLING(nodep);
}
virtual void visit(AstVAssert* nodep) {
iterateChildren(nodep);
newVAssertion(nodep, nodep->propp()); VL_DANGLING(nodep);
++m_statAsSV;
newVAssertion(nodep, nodep->propp()); VL_DANGLING(nodep);
++m_statAsSV;
}
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_modp = nodep;
m_modPastNum = 0;
//
//
iterateChildren(nodep);
// Reset defaults
m_modp = NULL;
// Reset defaults
m_modp = NULL;
}
virtual void visit(AstBegin* nodep) {
// This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin
AstBegin* lastp = m_beginp;
{
m_beginp = nodep;
// This code is needed rather than a visitor in V3Begin,
// because V3Assert is called before V3Begin
AstBegin* lastp = m_beginp;
{
m_beginp = nodep;
iterateChildren(nodep);
}
m_beginp = lastp;
}
m_beginp = lastp;
}
virtual void visit(AstNode* nodep) {
@@ -389,17 +395,17 @@ private:
public:
// CONSTRUCTORS
explicit AssertVisitor(AstNetlist* nodep) {
m_beginp = NULL;
m_modp = NULL;
m_beginp = NULL;
m_modp = NULL;
m_modPastNum = 0;
// Process
// Process
iterate(nodep);
}
virtual ~AssertVisitor() {
V3Stats::addStat("Assertions, PSL asserts", m_statAsPsl);
V3Stats::addStat("Assertions, SystemVerilog asserts", m_statAsSV);
V3Stats::addStat("Assertions, cover statements", m_statAsCover);
V3Stats::addStat("Assertions, full/parallel case", m_statAsFull);
V3Stats::addStat("Assertions, PSL asserts", m_statAsPsl);
V3Stats::addStat("Assertions, SystemVerilog asserts", m_statAsSV);
V3Stats::addStat("Assertions, cover statements", m_statAsCover);
V3Stats::addStat("Assertions, full/parallel case", m_statAsFull);
}
};
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASSERT_H_
#define _V3ASSERT_H_ 1
@@ -34,4 +34,4 @@ public:
static void assertAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+48 -48
View File
@@ -18,9 +18,9 @@
//
//*************************************************************************
// Pre steps:
// Attach clocks to each assertion
// Attach clocks to each assertion
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -51,37 +51,37 @@ private:
VL_DEBUG_FUNC; // Declare debug()
AstSenTree* newSenTree(AstNode* nodep) {
// Create sentree based on clocked or default clock
// Return NULL for always
AstSenTree* newp = NULL;
// Create sentree based on clocked or default clock
// Return NULL for always
AstSenTree* newp = NULL;
AstNodeSenItem* senip = m_senip;
if (!senip) senip = m_seniDefaultp;
if (!senip) senip = m_seniAlwaysp;
if (!senip) {
nodep->v3error("Unsupported: Unclocked assertion");
newp = new AstSenTree(nodep->fileline(), NULL);
} else {
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
}
return newp;
if (!senip) {
nodep->v3error("Unsupported: Unclocked assertion");
newp = new AstSenTree(nodep->fileline(), NULL);
} else {
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
}
return newp;
}
void clearAssertInfo() {
m_senip = NULL;
m_senip = NULL;
}
// VISITORS
//========== Statements
virtual void visit(AstClocking* nodep) {
UINFO(8," CLOCKING"<<nodep<<endl);
// Store the new default clock, reset on new module
m_seniDefaultp = nodep->sensesp();
// Trash it, keeping children
if (nodep->bodysp()) {
nodep->replaceWith(nodep->bodysp()->unlinkFrBack());
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep); VL_DANGLING(nodep);
UINFO(8," CLOCKING"<<nodep<<endl);
// Store the new default clock, reset on new module
m_seniDefaultp = nodep->sensesp();
// Trash it, keeping children
if (nodep->bodysp()) {
nodep->replaceWith(nodep->bodysp()->unlinkFrBack());
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep); VL_DANGLING(nodep);
}
virtual void visit(AstAlways* nodep) {
iterateAndNextNull(nodep->sensesp());
@@ -93,12 +93,12 @@ private:
}
virtual void visit(AstNodePslCoverOrAssert* nodep) {
if (nodep->sentreep()) return; // Already processed
clearAssertInfo();
// Find PslClocking's burried under nodep->exprsp
if (nodep->sentreep()) return; // Already processed
clearAssertInfo();
// Find PslClocking's buried under nodep->exprsp
iterateChildren(nodep);
nodep->sentreep(newSenTree(nodep));
clearAssertInfo();
nodep->sentreep(newSenTree(nodep));
clearAssertInfo();
}
virtual void visit(AstPast* nodep) {
if (nodep->sentreep()) return; // Already processed
@@ -108,26 +108,26 @@ private:
virtual void visit(AstPslClocked* nodep) {
// No need to iterate the body, once replace will get iterated
iterateAndNextNull(nodep->sensesp());
if (m_senip) {
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
}
// Block is the new expression to evaluate
AstNode* blockp = nodep->propp()->unlinkFrBack();
if (nodep->disablep()) {
blockp = new AstAnd(nodep->disablep()->fileline(),
new AstNot(nodep->disablep()->fileline(),
nodep->disablep()->unlinkFrBack()),
blockp);
}
// Unlink and just keep a pointer to it, convert to sentree as needed
m_senip = nodep->sensesp();
nodep->replaceWith(blockp);
pushDeletep(nodep); VL_DANGLING(nodep);
if (m_senip) {
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
}
// Block is the new expression to evaluate
AstNode* blockp = nodep->propp()->unlinkFrBack();
if (nodep->disablep()) {
blockp = new AstAnd(nodep->disablep()->fileline(),
new AstNot(nodep->disablep()->fileline(),
nodep->disablep()->unlinkFrBack()),
blockp);
}
// Unlink and just keep a pointer to it, convert to sentree as needed
m_senip = nodep->sensesp();
nodep->replaceWith(blockp);
pushDeletep(nodep); VL_DANGLING(nodep);
}
virtual void visit(AstNodeModule* nodep) {
iterateChildren(nodep);
// Reset defaults
m_seniDefaultp = NULL;
// Reset defaults
m_seniDefaultp = NULL;
}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
@@ -136,10 +136,10 @@ private:
public:
// CONSTRUCTORS
explicit AssertPreVisitor(AstNetlist* nodep) {
m_seniDefaultp = NULL;
m_seniDefaultp = NULL;
m_seniAlwaysp = NULL;
clearAssertInfo();
// Process
clearAssertInfo();
// Process
iterate(nodep);
}
virtual ~AssertPreVisitor() {}
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASSERTPRE_H_
#define _V3ASSERTPRE_H_ 1
@@ -34,4 +34,4 @@ public:
static void assertPreAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+461 -409
View File
File diff suppressed because it is too large Load Diff
+1010 -964
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3ASTCONSTONLY_H_
#define _V3ASTCONSTONLY_H_ 1
@@ -30,4 +30,4 @@
#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
#endif // Guard
#endif // Guard
+237 -251
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -57,7 +57,7 @@ void AstNodeVarRef::cloneRelink() {
}
int AstNodeSel::bitConst() const {
AstConst* constp=VN_CAST(bitp(), Const);
AstConst* constp = VN_CAST(bitp(), Const);
return (constp ? constp->toSInt() : 0);
}
@@ -65,25 +65,30 @@ void AstNodeClassDType::repairMemberCache() {
clearCache();
for (AstMemberDType* itemp = membersp(); itemp; itemp=VN_CAST(itemp->nextp(), MemberDType)) {
if (m_members.find(itemp->name())!=m_members.end()) {
itemp->v3error("Duplicate declaration of member name: "<<itemp->prettyName()); }
else m_members.insert(make_pair(itemp->name(), itemp));
itemp->v3error("Duplicate declaration of member name: "<<itemp->prettyNameQ()); }
else m_members.insert(make_pair(itemp->name(), itemp));
}
}
const char* AstNodeClassDType::broken() const {
vl_unordered_set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp=VN_CAST(itemp->nextp(), MemberDType)) {
exists.insert(itemp);
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) {
if (VL_UNLIKELY(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: "<<it->first);
return "member broken";
}
if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: "<<it->first);
return "member broken";
}
}
return NULL;
}
void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs,
const V3Number& rhs, const V3Number& ths) {
if (lhs.isNeqZero()) out.opAssign(rhs); else out.opAssign(ths);
}
int AstBasicDType::widthAlignBytes() const {
if (width()<=8) return 1;
else if (width()<=16) return 2;
@@ -115,38 +120,46 @@ int AstNodeClassDType::widthAlignBytes() const {
}
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
} else {
return new AstEq(fl, lhsp, rhsp);
return new AstEq(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstGte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstGteD(fl, lhsp, rhsp);
if (lhsp->isString() && rhsp->isString()) {
return new AstGteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstGteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstGteS(fl, lhsp, rhsp);
return new AstGteS(fl, lhsp, rhsp);
} else {
return new AstGte(fl, lhsp, rhsp);
return new AstGte(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstLteD(fl, lhsp, rhsp);
if (lhsp->isString() && rhsp->isString()) {
return new AstLteN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstLteD(fl, lhsp, rhsp);
} else if (lhsp->isSigned() && rhsp->isSigned()) {
return new AstLteS(fl, lhsp, rhsp);
return new AstLteS(fl, lhsp, rhsp);
} else {
return new AstLte(fl, lhsp, rhsp);
return new AstLte(fl, lhsp, rhsp);
}
}
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
} else {
return new AstEqWild(fl, lhsp, rhsp);
return new AstEqWild(fl, lhsp, rhsp);
}
}
@@ -168,10 +181,12 @@ bool AstVar::isScBv() const {
return ((isSc() && width() >= v3Global.opt.pinsBv()) || m_attrScBv);
}
bool AstVar::isScUint() const {
return ((isSc() && v3Global.opt.pinsScUint() && width() >= 2 && width() <= 64) && !isScBv());
return ((isSc() && v3Global.opt.pinsScUint()
&& width() >= 2 && width() <= 64) && !isScBv());
}
bool AstVar::isScBigUint() const {
return ((isSc() && v3Global.opt.pinsScBigUint() && width() >= 65 && width() <= 512) && !isScBv());
return ((isSc() && v3Global.opt.pinsScBigUint()
&& width() >= 65 && width() <= 512) && !isScBv());
}
void AstVar::combineType(AstVarType type) {
@@ -208,8 +223,8 @@ string AstVar::verilogKwd() const {
}
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
if (forReturn) named=false;
if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
UASSERT_OBJ(!forReturn, this,
"Internal data is never passed as return, but as first argument");
string otype;
AstBasicDType* bdtypep = basicp();
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
@@ -279,21 +294,21 @@ string AstVar::vlEnumType() const {
AstBasicDType* bdtypep = basicp();
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
return "VLVT_PTR";
return "VLVT_PTR";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
return "VLVT_PTR";
return "VLVT_PTR";
} else if (strtype) {
arg += "VLVT_STRING";
arg += "VLVT_STRING";
} else if (widthMin() <= 8) {
arg += "VLVT_UINT8";
arg += "VLVT_UINT8";
} else if (widthMin() <= 16) {
arg += "VLVT_UINT16";
arg += "VLVT_UINT16";
} else if (widthMin() <= VL_WORDSIZE) {
arg += "VLVT_UINT32";
arg += "VLVT_UINT32";
} else if (isQuad()) {
arg += "VLVT_UINT64";
arg += "VLVT_UINT64";
} else if (isWide()) {
arg += "VLVT_WDATA";
arg += "VLVT_WDATA";
}
// else return "VLVT_UNKNOWN"
return arg;
@@ -339,28 +354,28 @@ string AstVar::vlPropInit() const {
out += ", "+cvtToStr(adtypep->declRange().left())+", "+cvtToStr(adtypep->declRange().right());
dtp = adtypep->subDTypep();
}
else break; // AstBasicDType - nothing below
else break; // AstBasicDType - nothing below
}
return out;
}
string AstVar::cPubArgType(bool named, bool forReturn) const {
if (forReturn) named=false;
if (forReturn) named = false;
string arg;
if (isWide() && isReadOnly()) arg += "const ";
if (widthMin() == 1) {
arg += "bool";
arg += "bool";
} else if (widthMin() <= VL_WORDSIZE) {
arg += "uint32_t";
arg += "uint32_t";
} else if (isWide()) {
arg += "uint32_t"; // []'s added later
arg += "uint32_t"; // []'s added later
} else {
arg += "vluint64_t";
arg += "vluint64_t";
}
if (isWide()) {
if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
arg += " (& "+name();
arg += ")["+cvtToStr(widthWords())+"]";
if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
arg += " (& "+name();
arg += ")["+cvtToStr(widthWords())+"]";
} else {
if (!forReturn && (isWritable()
|| direction().isRefOrConstRef())) arg += "&";
@@ -370,25 +385,25 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
}
string AstVar::dpiArgType(bool named, bool forReturn) const {
if (forReturn) named=false;
if (forReturn) named = false;
string arg;
if (isDpiOpenArray()) {
arg = "const svOpenArrayHandle";
} else if (!basicp()) {
arg = "UNKNOWN";
} else if (basicp()->keyword().isDpiBitVal()) {
if (widthMin() == 1) {
arg = "unsigned char";
if (widthMin() == 1) {
arg = "unsigned char";
if (!forReturn && isWritable()) arg += "*";
} else {
if (forReturn) {
arg = "svBitVecVal";
} else if (isReadOnly()) {
arg = "const svBitVecVal*";
} else {
arg = "svBitVecVal*";
}
}
arg = "const svBitVecVal*";
} else {
arg = "svBitVecVal*";
}
}
} else if (basicp()->keyword().isDpiLogicVal()) {
if (widthMin() == 1) {
arg = "unsigned char";
@@ -403,9 +418,9 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
}
}
} else {
arg = basicp()->keyword().dpiType();
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
arg = "unsigned "+arg;
arg = basicp()->keyword().dpiType();
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
arg = "unsigned "+arg;
}
if (!forReturn && isWritable()) arg += "*";
}
@@ -415,23 +430,23 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
string AstVar::scType() const {
if (isScBigUint()) {
return (string("sc_biguint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
return (string("sc_biguint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
} else if (isScUint()) {
return (string("sc_uint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
return (string("sc_uint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
} else if (isScBv()) {
return (string("sc_bv<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
return (string("sc_bv<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
} else if (widthMin() == 1) {
return "bool";
return "bool";
} else if (widthMin() <= VL_WORDSIZE) {
if (widthMin() <= 8 && v3Global.opt.pinsUint8()) {
return "uint8_t";
} else if (widthMin() <= 16 && v3Global.opt.pinsUint8()) {
return "uint16_t";
} else {
return "uint32_t";
}
if (widthMin() <= 8 && v3Global.opt.pinsUint8()) {
return "uint8_t";
} else if (widthMin() <= 16 && v3Global.opt.pinsUint8()) {
return "uint16_t";
} else {
return "uint32_t";
}
} else {
return "vluint64_t";
return "vluint64_t";
}
}
@@ -440,25 +455,25 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) {
// Historically sc variables are identified by a variable
// attribute. TODO it would better be a data type attribute.
if (AstVar* anodep = VN_CAST(nodep, Var)) {
if (anodep->isSc()) return anodep;
else return NULL;
if (anodep->isSc()) return anodep;
else return NULL;
}
else if (VN_IS(nodep, VarRef)) {
if (VN_CAST(nodep, VarRef)->varp()->isSc()) return VN_CAST(nodep, VarRef)->varp();
else return NULL;
else return NULL;
}
else if (VN_IS(nodep, ArraySel)) {
if (nodep->op1p()) if (AstVar* p = scVarRecurse(nodep->op1p())) return p;
if (nodep->op2p()) if (AstVar* p = scVarRecurse(nodep->op2p())) return p;
if (nodep->op3p()) if (AstVar* p = scVarRecurse(nodep->op3p())) return p;
if (nodep->op4p()) if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
if (nodep->op1p()) if (AstVar* p = scVarRecurse(nodep->op1p())) return p;
if (nodep->op2p()) if (AstVar* p = scVarRecurse(nodep->op2p())) return p;
if (nodep->op3p()) if (AstVar* p = scVarRecurse(nodep->op3p())) return p;
if (nodep->op4p()) if (AstVar* p = scVarRecurse(nodep->op4p())) return p;
}
return NULL;
}
string AstVar::mtasksString() const {
std::ostringstream os;
os<<" all: ";
os<<"all: ";
for (MTaskIdSet::const_iterator it = m_mtaskIds.begin();
it != m_mtaskIds.end(); ++it) {
os<<*it<<" ";
@@ -473,58 +488,58 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
// ref order: a[1][2][3][4]
// Created as: reg [4] a [1][2][3];
// *or* reg a [1][2][3][4];
// // The bit select is optional; used only if "leftover" []'s
// SEL: SEL4(SEL3(SEL2(SEL1(VARREF0 a))))
// DECL: VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (DT RANGE3))))
// *or* VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (ARRAYSEL3 (DT))))
// SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0
// // The bit select is optional; used only if "leftover" []'s
// SEL: SEL4(SEL3(SEL2(SEL1(VARREF0 a))))
// DECL: VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (DT RANGE3))))
// *or* VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (ARRAYSEL3 (DT))))
// SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0
// TODO this function should be removed in favor of recursing the dtype(),
// as that allows for more complicated data types.
int dim = 0;
for (AstNodeDType* dtypep=this; dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if ((dim++)==dimension) {
return dtypep;
}
dtypep = adtypep->subDTypep();
continue;
}
if ((dim++)==dimension) {
return dtypep;
}
dtypep = adtypep->subDTypep();
continue;
}
else if (AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
// AstBasicDType - nothing below, return null
if (adtypep->isRanged()) {
if ((dim++) == dimension) {
return adtypep;
}
}
return NULL;
}
// AstBasicDType - nothing below, return null
if (adtypep->isRanged()) {
if ((dim++) == dimension) {
return adtypep;
}
}
return NULL;
}
else if (AstNodeClassDType* adtypep = VN_CAST(dtypep, NodeClassDType)) {
if (adtypep->packed()) {
if ((dim++) == dimension) {
return adtypep;
}
}
return NULL;
}
// Node no ->next in loop; use continue where necessary
break;
if (adtypep->packed()) {
if ((dim++) == dimension) {
return adtypep;
}
}
return NULL;
}
// Node no ->next in loop; use continue where necessary
break;
}
return NULL;
}
uint32_t AstNodeDType::arrayUnpackedElements() {
uint32_t entries=1;
uint32_t entries = 1;
for (AstNodeDType* dtypep=this; dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) {
entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep();
}
else {
// AstBasicDType - nothing below, 1
break;
}
entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep();
}
else {
// AstBasicDType - nothing below, 1
break;
}
}
return entries;
}
@@ -534,17 +549,17 @@ std::pair<uint32_t,uint32_t> AstNodeDType::dimensions(bool includeBasic) {
uint32_t packed = 0;
uint32_t unpacked = 0;
for (AstNodeDType* dtypep=this; dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
if (VN_IS(adtypep, PackArrayDType)) packed++;
else unpacked++;
dtypep = adtypep->subDTypep();
continue;
}
else unpacked++;
dtypep = adtypep->subDTypep();
continue;
}
else if (const AstBasicDType* adtypep = VN_CAST(dtypep, BasicDType)) {
if (includeBasic && adtypep->isRanged()) packed++;
}
break;
if (includeBasic && adtypep->isRanged()) packed++;
}
break;
}
return make_pair(packed, unpacked);
}
@@ -553,27 +568,28 @@ int AstNodeDType::widthPow2() const {
// I.e. width 30 returns 32, width 32 returns 32.
uint32_t width = this->width();
for (int p2=30; p2>=0; p2--) {
if (width > (1UL<<p2)) return (1UL<<(p2+1));
if (width > (1UL<<p2)) return (1UL<<(p2+1));
}
return 1;
}
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
// Else AstArraySel etc; search for the base
while (nodep) {
if (VN_IS(nodep, ArraySel)) { nodep=VN_CAST(nodep, ArraySel)->fromp(); continue; }
else if (VN_IS(nodep, Sel)) { nodep=VN_CAST(nodep, Sel)->fromp(); continue; }
// AstNodeSelPre stashes the associated variable under an ATTROF of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
else if (VN_IS(nodep, AttrOf)) { nodep=VN_CAST(nodep, AttrOf)->fromp(); continue; }
if (VN_IS(nodep, ArraySel)) { nodep = VN_CAST(nodep, ArraySel)->fromp(); continue; }
else if (VN_IS(nodep, Sel)) { nodep = VN_CAST(nodep, Sel)->fromp(); continue; }
// AstNodeSelPre stashes the associated variable under an ATTROF
// of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
else if (VN_IS(nodep, AttrOf)) { nodep = VN_CAST(nodep, AttrOf)->fromp(); continue; }
else if (VN_IS(nodep, NodePreSel)) {
if (VN_CAST(nodep, NodePreSel)->attrp()) {
nodep=VN_CAST(nodep, NodePreSel)->attrp();
} else {
nodep=VN_CAST(nodep, NodePreSel)->lhsp();
}
continue;
}
else break;
nodep = VN_CAST(nodep, NodePreSel)->attrp();
} else {
nodep = VN_CAST(nodep, NodePreSel)->lhsp();
}
continue;
}
else break;
}
return nodep;
}
@@ -598,7 +614,7 @@ string AstScope::nameDotless() const {
string out = shortName();
string::size_type pos;
while ((pos = out.find('.')) != string::npos) {
out.replace(pos, 1, "__");
out.replace(pos, 1, "__");
}
return out;
}
@@ -606,58 +622,58 @@ string AstScope::nameDotless() const {
string AstScopeName::scopePrettyNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp=scopeTextp; textp; textp=VN_CAST(textp->nextp(), Text)) {
out += textp->text();
out += textp->text();
}
// TOP will be replaced by top->name()
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
if (out.substr(0,1) == ".") out.replace(0,1,"");
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, "");
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
return AstNode::prettyName(out);
}
string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
string out;
for (AstText* textp=scopeTextp; textp; textp=VN_CAST(textp->nextp(), Text)) {
out += textp->text();
out += textp->text();
}
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
if (out.substr(0,1) == ".") out.replace(0,1,"");
if (out.substr(0, 10) == "__DOT__TOP") out.replace(0, 10, "");
if (out.substr(0, 7) == "__DOT__") out.replace(0, 7, "");
if (out.substr(0, 1) == ".") out.replace(0, 1, "");
string::size_type pos;
while ((pos = out.find('.')) != string::npos) {
out.replace(pos, 1, "__");
out.replace(pos, 1, "__");
}
while ((pos=out.find("__DOT__")) != string::npos) {
out.replace(pos, 7, "__");
while ((pos = out.find("__DOT__")) != string::npos) {
out.replace(pos, 7, "__");
}
return out;
}
bool AstSenTree::hasClocked() const {
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) {
if (senp->isClocked()) return true;
if (senp->isClocked()) return true;
}
return false;
}
bool AstSenTree::hasSettle() const {
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) {
if (senp->isSettle()) return true;
if (senp->isSettle()) return true;
}
return false;
}
bool AstSenTree::hasInitial() const {
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) {
if (senp->isInitial()) return true;
if (senp->isInitial()) return true;
}
return false;
}
bool AstSenTree::hasCombo() const {
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp=VN_CAST(senp->nextp(), NodeSenItem)) {
if (senp->isCombo()) return true;
if (senp->isCombo()) return true;
}
return false;
}
@@ -666,20 +682,14 @@ void AstTypeTable::clearCache() {
// When we mass-change widthMin in V3WidthCommit, we need to correct the table.
// Just clear out the maps; the search functions will be used to rebuild the map
for (int i=0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
m_basicps[i] = NULL;
}
for (int isbit=0; isbit<_IDX0_MAX; ++isbit) {
for (int numer=0; numer<AstNumeric::_ENUM_MAX; ++numer) {
LogicMap& mapr = m_logicMap[isbit][numer];
mapr.clear();
}
m_basicps[i] = NULL;
}
m_detailedMap.clear();
// Clear generic()'s so dead detection will work
for (AstNode* nodep = typesp(); nodep; nodep=nodep->nextp()) {
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
bdtypep->generic(false);
}
bdtypep->generic(false);
}
}
}
@@ -688,8 +698,8 @@ void AstTypeTable::repairCache() {
clearCache();
for (AstNode* nodep = typesp(); nodep; nodep=nodep->nextp()) {
if (AstBasicDType* bdtypep = VN_CAST(nodep, BasicDType)) {
(void)findInsertSameDType(bdtypep);
}
(void)findInsertSameDType(bdtypep);
}
}
}
@@ -709,30 +719,16 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd)
}
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
int width, int widthMin, AstNumeric numeric) {
int idx = IDX0_LOGIC;
if (kwd == AstBasicDTypeKwd::LOGIC) idx = IDX0_LOGIC;
else if (kwd == AstBasicDTypeKwd::BIT) idx = IDX0_BIT;
else fl->v3fatalSrc("Bad kwd for findLogicBitDType");
std::pair<int,int> widths = make_pair(width,widthMin);
LogicMap& mapr = m_logicMap[idx][static_cast<int>(numeric)];
LogicMap::const_iterator it = mapr.find(widths);
if (it != mapr.end()) return it->second;
//
int width, int widthMin, AstNumeric numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
// Because the detailed map doesn't update this map,
// check the detailed map for this same node, and if found update this map
// Also adds this new node to the detailed map
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) new1p->deleteTree();
else addTypesp(newp);
//
mapr.insert(make_pair(widths,newp));
return newp;
}
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
VNumRange range, int widthMin, AstNumeric numeric) {
VNumRange range, int widthMin, AstNumeric numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) new1p->deleteTree();
@@ -742,11 +738,11 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
VBasicTypeKey key (nodep->width(), nodep->widthMin(), nodep->numeric(),
nodep->keyword(), nodep->nrange());
nodep->keyword(), nodep->nrange());
DetailedMap& mapr = m_detailedMap;
DetailedMap::const_iterator it = mapr.find(key);
if (it != mapr.end()) return it->second;
mapr.insert(make_pair(key,nodep));
mapr.insert(make_pair(key, nodep));
nodep->generic(true);
// No addTypesp; the upper function that called new() is responsible for adding
return nodep;
@@ -756,12 +752,12 @@ AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
// Special walking tree inserters
void AstNode::addBeforeStmt(AstNode* newp, AstNode*) {
if (!backp()) newp->v3fatalSrc("Can't find current statement to addBeforeStmt");
UASSERT_OBJ(backp(), newp, "Can't find current statement to addBeforeStmt");
// Look up; virtual call will find where to put it
this->backp()->addBeforeStmt(newp, this);
}
void AstNode::addNextStmt(AstNode* newp, AstNode*) {
if (!backp()) newp->v3fatalSrc("Can't find current statement to addNextStmt");
UASSERT_OBJ(backp(), newp, "Can't find current statement to addNextStmt");
// Look up; virtual call will find where to put it
this->backp()->addNextStmt(newp, this);
}
@@ -778,39 +774,41 @@ void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
// Preconditions insert first just before themselves (the normal rule for other statement types)
// Preconditions insert first just before themselves (the normal rule
// for other statement types)
if (belowp == precondsp()) {
// Must have been first statement in precondsp list, so newp is new first statement
belowp->addHereThisAsNext(newp);
// Must have been first statement in precondsp list, so newp is new first statement
belowp->addHereThisAsNext(newp);
} else if (belowp == condp()) {
// Goes before condition, IE in preconditions
addPrecondsp(newp);
// Goes before condition, IE in preconditions
addPrecondsp(newp);
} else if (belowp == bodysp()) {
// Was first statement in body, so new front
belowp->addHereThisAsNext(newp);
// Was first statement in body, so new front
belowp->addHereThisAsNext(newp);
} else {
belowp->v3fatalSrc("Doesn't look like this was really under the while");
belowp->v3fatalSrc("Doesn't look like this was really under the while");
}
}
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
// Preconditions insert first just before themselves (the normal rule for other statement types)
// Preconditions insert first just before themselves (the normal rule
// for other statement types)
if (belowp == precondsp()) {
// Next in precond list
belowp->addNextHere(newp);
// Next in precond list
belowp->addNextHere(newp);
} else if (belowp == condp()) {
// Becomes first statement in body, body may have been empty
if (bodysp()) {
bodysp()->addHereThisAsNext(newp);
} else {
addBodysp(newp);
}
// Becomes first statement in body, body may have been empty
if (bodysp()) {
bodysp()->addHereThisAsNext(newp);
} else {
addBodysp(newp);
}
} else if (belowp == bodysp()) {
// Next statement in body
belowp->addNextHere(newp);
// Next statement in body
belowp->addNextHere(newp);
} else {
belowp->v3fatalSrc("Doesn't look like this was really under the while");
belowp->v3fatalSrc("Doesn't look like this was really under the while");
}
}
@@ -822,7 +820,7 @@ void AstNode::dump(std::ostream& str) {
//<<" "<<cvtToHex(this)->m_backp
<<" <e"<<std::dec<<editCount()
<<((editCount()>=editCountLast())?"#>":">")
<<" {"<<fileline()->filenameLetters()<<std::dec<<fileline()->lineno()<<"}";
<<" {"<<fileline()->filenameLetters()<<std::dec<<fileline()->lastLineno()<<"}";
if (user1p()) str<<" u1="<<cvtToHex(user1p());
if (user2p()) str<<" u2="<<cvtToHex(user2p());
if (user3p()) str<<" u3="<<cvtToHex(user3p());
@@ -830,17 +828,17 @@ void AstNode::dump(std::ostream& str) {
if (user5p()) str<<" u5="<<cvtToHex(user5p());
if (hasDType()) {
// Final @ so less likely to by accident read it as a nodep
if (dtypep()==this) str<<" @dt="<<"this@";
if (dtypep()==this) str<<" @dt="<<"this@";
else str<<" @dt="<<cvtToHex(dtypep())<<"@";
if (AstNodeDType* dtp = dtypep()) {
dtp->dumpSmall(str);
}
} else { // V3Broken will throw an error
if (AstNodeDType* dtp = dtypep()) {
dtp->dumpSmall(str);
}
} else { // V3Broken will throw an error
if (dtypep()) str<<" %Error-dtype-exp=null,got="<<cvtToHex(dtypep());
}
if (name()!="") {
if (VN_IS(this, Const)) str<<" "<<name(); // Already quoted
else str<<" "<<V3Number::quoteNameControls(name());
else str<<" "<<V3OutFormatter::quoteNameControls(name());
}
}
@@ -929,9 +927,9 @@ void AstRange::dump(std::ostream& str) {
if (littleEndian()) str<<" [LITTLE]";
}
void AstRefDType::dump(std::ostream& str) {
static bool s_recursing = false;
this->AstNodeDType::dump(str);
if (defp()) {
static bool s_recursing = false;
if (!s_recursing) { // Prevent infinite dump if circular typedefs
s_recursing = true;
str<<" -> "; defp()->dump(str);
@@ -950,7 +948,7 @@ void AstNodeDType::dump(std::ostream& str) {
if (generic()) str<<" [GENERIC]";
if (AstNodeDType* dtp = virtRefDTypep()) {
str<<" refdt="<<cvtToHex(dtp);
dtp->dumpSmall(str);
dtp->dumpSmall(str);
}
}
void AstNodeDType::dumpSmall(std::ostream& str) {
@@ -961,7 +959,7 @@ void AstNodeDType::dumpSmall(std::ostream& str) {
<<(isDouble()?"d":"")
<<(isString()?"str":"");
if (!isDouble() && !isString()) {
str<<"w"<<(widthSized()?"":"u")<<width();
str<<"w"<<(widthSized()?"":"u")<<width();
}
if (!widthSized()) str<<"/"<<widthMin();
str<<")";
@@ -995,8 +993,8 @@ void AstPackageImport::dump(std::ostream& str) {
void AstSel::dump(std::ostream& str) {
this->AstNode::dump(str);
if (declRange().ranged()) {
str<<" decl"<<declRange()<<"]";
if (declElWidth()!=1) str<<"/"<<declElWidth();
str<<" decl"<<declRange()<<"]";
if (declElWidth()!=1) str<<"/"<<declElWidth();
}
}
void AstSliceSel::dump(std::ostream& str) {
@@ -1013,37 +1011,21 @@ void AstMTaskBody::dump(std::ostream& str) {
void AstTypeTable::dump(std::ostream& str) {
this->AstNode::dump(str);
for (int i=0; i < static_cast<int>(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
if (AstBasicDType* subnodep=m_basicps[i]) {
str<<endl; // Newline from caller, so newline first
if (AstBasicDType* subnodep = m_basicps[i]) {
str<<endl; // Newline from caller, so newline first
str<<"\t\t"<<std::setw(8)<<AstBasicDTypeKwd(i).ascii();
str<<" -> ";
subnodep->dump(str);
}
}
for (int isbit=0; isbit<2; ++isbit) {
for (int issigned=0; issigned<AstNumeric::_ENUM_MAX; ++issigned) {
LogicMap& mapr = m_logicMap[isbit][issigned];
for (LogicMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
AstBasicDType* dtypep = it->second;
str<<endl; // Newline from caller, so newline first
std::stringstream nsstr;
nsstr<<(isbit?"bw":"lw")
<<it->first.first<<"/"<<it->first.second;
str<<"\t\t"<<std::setw(8)<<nsstr.str();
if (issigned) str<<" s"; else str<<" u";
str<<" -> ";
dtypep->dump(str);
}
}
str<<" -> ";
subnodep->dump(str);
}
}
{
DetailedMap& mapr = m_detailedMap;
for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
AstBasicDType* dtypep = it->second;
str<<endl; // Newline from caller, so newline first
str<<"\t\tdetailed -> ";
dtypep->dump(str);
}
DetailedMap& mapr = m_detailedMap;
for (DetailedMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
AstBasicDType* dtypep = it->second;
str<<endl; // Newline from caller, so newline first
str<<"\t\tdetailed -> ";
dtypep->dump(str);
}
}
// Note get newline from caller too.
}
@@ -1152,8 +1134,8 @@ void AstBegin::dump(std::ostream& str) {
void AstCoverDecl::dump(std::ostream& str) {
this->AstNode::dump(str);
if (this->dataDeclNullp()) {
str<<" -> ";
this->dataDeclNullp()->dump(str);
str<<" -> ";
this->dataDeclNullp()->dump(str);
} else {
if (binNum()) { str<<" bin"<<std::dec<<binNum(); }
}
@@ -1175,12 +1157,16 @@ void AstNodeText::dump(std::ostream& str) {
string out = text();
string::size_type pos;
if ((pos = out.find('\n')) != string::npos) {
out.erase(pos,out.length()-pos);
out += "...";
out.erase(pos, out.length()-pos);
out += "...";
}
str<<" \""<<out<<"\"";
}
void AstVFile::dump(std::ostream& str) {
this->AstNode::dump(str);
}
void AstCFile::dump(std::ostream& str) {
this->AstNode::dump(str);
if (source()) str<<" [SRC]";
@@ -1189,8 +1175,8 @@ void AstCFile::dump(std::ostream& str) {
void AstCCall::dump(std::ostream& str) {
this->AstNode::dump(str);
if (funcp()) {
str<<" "<<funcp()->name()<<" => ";
funcp()->dump(str);
str<<" "<<funcp()->name()<<" => ";
funcp()->dump(str);
}
}
void AstCFunc::dump(std::ostream& str) {
+2381 -1973
View File
File diff suppressed because it is too large Load Diff
+154 -152
View File
@@ -20,15 +20,15 @@
// V3Begin's Transformations:
//
// Each module:
// Look for BEGINs
// BEGIN(VAR...) -> VAR ... {renamed}
// FOR -> WHILEs
// Look for BEGINs
// BEGIN(VAR...) -> VAR ... {renamed}
// FOR -> WHILEs
//
// There are two scopes; named BEGINs change %m and variable scopes.
// Unnamed BEGINs change only variable, not $display("%m") scope.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -47,17 +47,17 @@ class BeginState {
private:
// NODE STATE
//Entire netlist:
// AstNodeFTask::user1 -> bool, 1=processed
AstUser1InUse m_inuser1;
bool m_anyFuncInBegin;
// AstNodeFTask::user1 -> bool, 1=processed
AstUser1InUse m_inuser1;
bool m_anyFuncInBegin;
public:
BeginState() {
m_anyFuncInBegin = false;
m_anyFuncInBegin = false;
}
~BeginState() {}
void userMarkChanged(AstNode* nodep) {
nodep->user1(true);
m_anyFuncInBegin = true;
nodep->user1(true);
m_anyFuncInBegin = true;
}
bool anyFuncInBegin() const { return m_anyFuncInBegin; }
};
@@ -67,171 +67,173 @@ public:
class BeginVisitor : public AstNVisitor {
private:
// STATE
BeginState* m_statep; // Current global state
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_repeatNum; // Repeat counter
int m_ifDepth; // Current if depth
BeginState* m_statep; // Current global state
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_repeatNum; // Repeat counter
int m_ifDepth; // Current if depth
// METHODS
VL_DEBUG_FUNC; // Declare debug()
// VISITORS
virtual void visit(AstNodeModule* nodep) {
m_modp = nodep;
m_repeatNum = 0;
m_modp = nodep;
m_repeatNum = 0;
iterateChildren(nodep);
m_modp = NULL;
m_modp = NULL;
}
virtual void visit(AstNodeFTask* nodep) {
UINFO(8," "<<nodep<<endl);
// Rename it
if (m_unnamedScope != "") {
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
m_statep->userMarkChanged(nodep);
}
// BEGIN wrapping a function rename that function, but don't affect the inside function's variables
// We then restart with empty naming; so that any begin's inside the function will rename inside the function
// Process children
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
m_namedScope = "";
m_unnamedScope = "";
m_ftaskp = nodep;
UINFO(8," "<<nodep<<endl);
// Rename it
if (m_unnamedScope != "") {
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
m_statep->userMarkChanged(nodep);
}
// BEGIN wrapping a function rename that function, but don't affect
// the inside function's variables. We then restart with empty
// naming; so that any begin's inside the function will rename
// inside the function.
// Process children
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
m_namedScope = "";
m_unnamedScope = "";
m_ftaskp = nodep;
iterateChildren(nodep);
m_ftaskp = NULL;
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
m_ftaskp = NULL;
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
}
virtual void visit(AstBegin* nodep) {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8," "<<nodep<<endl);
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
UINFO(8,"nname "<<m_namedScope<<endl);
if (nodep->name() != "") { // Else unneeded unnamed block
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0,pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (!nodep->unnamed()) {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
}
if (m_unnamedScope=="") m_unnamedScope = ident;
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
}
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8," "<<nodep<<endl);
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
UINFO(8,"nname "<<m_namedScope<<endl);
if (nodep->name() != "") { // Else unneeded unnamed block
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0, pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (!nodep->unnamed()) {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
}
if (m_unnamedScope=="") m_unnamedScope = ident;
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
}
// Remap var names and replace lower Begins
// Remap var names and replace lower Begins
iterateAndNextNull(nodep->stmtsp());
if (nodep->genforp()) nodep->v3fatalSrc("GENFORs should have been expanded earlier");
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier");
}
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
// Cleanup
AstNode* addsp = NULL;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep); VL_DANGLING(nodep);
// Cleanup
AstNode* addsp = NULL;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
}
if (addsp) {
nodep->replaceWith(addsp);
} else {
nodep->unlinkFrBack();
}
pushDeletep(nodep); VL_DANGLING(nodep);
}
virtual void visit(AstVar* nodep) {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
else m_modp->addStmtp(nodep);
}
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
m_statep->userMarkChanged(nodep);
// Move to module
nodep->unlinkFrBack();
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
else m_modp->addStmtp(nodep);
}
}
virtual void visit(AstCell* nodep) {
UINFO(8," CELL "<<nodep<<endl);
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
// Rename it
nodep->name(m_namedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
// Move to module
nodep->unlinkFrBack();
m_modp->addStmtp(nodep);
}
UINFO(8," CELL "<<nodep<<endl);
if (m_namedScope != "") {
m_statep->userMarkChanged(nodep);
// Rename it
nodep->name(m_namedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
// Move to module
nodep->unlinkFrBack();
m_modp->addStmtp(nodep);
}
iterateChildren(nodep);
}
virtual void visit(AstVarXRef* nodep) {
UINFO(9, " VARXREF "<<nodep<<endl);
if (m_namedScope != "" && nodep->inlinedDots() == "") {
nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to "<<nodep<<endl);
}
UINFO(9, " VARXREF "<<nodep<<endl);
if (m_namedScope != "" && nodep->inlinedDots() == "") {
nodep->inlinedDots(m_namedScope);
UINFO(9, " rescope to "<<nodep<<endl);
}
}
virtual void visit(AstScopeName* nodep) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's
if (m_namedScope != "") {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (nodep->user1SetOnce()) return; // Don't double-add text's
if (m_namedScope != "") {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__")+m_namedScope));
if (afterp) nodep->scopeAttrp(afterp);
}
if (afterp) nodep->scopeAttrp(afterp);
}
iterateChildren(nodep);
}
virtual void visit(AstCoverDecl* nodep) {
// Don't need to fix path in coverage statements, they're not under
// any BEGINs, but V3Coverage adds them all under the module itself.
// Don't need to fix path in coverage statements, they're not under
// any BEGINs, but V3Coverage adds them all under the module itself.
iterateChildren(nodep);
}
// VISITORS - LINT CHECK
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
// Check IFDEPTH warning - could be in other transform files if desire
int prevIfDepth = m_ifDepth;
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
m_ifDepth = -1;
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once
m_ifDepth = -1;
}
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
// Check IFDEPTH warning - could be in other transform files if desire
int prevIfDepth = m_ifDepth;
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
m_ifDepth = -1;
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once
m_ifDepth = -1;
}
iterateChildren(nodep);
m_ifDepth = prevIfDepth;
m_ifDepth = prevIfDepth;
}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
BeginVisitor(AstNetlist* nodep, BeginState* statep) {
m_statep = statep;
m_modp = NULL;
m_ftaskp = NULL;
m_repeatNum = 0;
m_ifDepth = 0;
m_statep = statep;
m_modp = NULL;
m_ftaskp = NULL;
m_repeatNum = 0;
m_ifDepth = 0;
iterate(nodep);
}
virtual ~BeginVisitor() {}
@@ -244,29 +246,29 @@ class BeginRelinkVisitor : public AstNVisitor {
private:
// NODE STATE
// Input:
// AstNodeFTask::user1p // Node replaced, rename it
// AstNodeFTask::user1p // Node replaced, rename it
// VISITORS
virtual void visit(AstNodeFTaskRef* nodep) {
if (nodep->taskp()->user1()) { // It was converted
UINFO(9, " relinkFTask "<<nodep<<endl);
nodep->name(nodep->taskp()->name());
}
if (nodep->taskp()->user1()) { // It was converted
UINFO(9, " relinkFTask "<<nodep<<endl);
nodep->name(nodep->taskp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstVarRef* nodep) {
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef "<<nodep<<endl);
nodep->name(nodep->varp()->name());
}
if (nodep->varp()->user1()) { // It was converted
UINFO(9, " relinVarRef "<<nodep<<endl);
nodep->name(nodep->varp()->name());
}
iterateChildren(nodep);
}
virtual void visit(AstIfaceRefDType* nodep) {
// May have changed cell names
// TypeTable is always after all modules, so names are stable
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
if (nodep->cellp()) nodep->cellName(nodep->cellp()->name());
UINFO(8," rename to "<<nodep<<endl);
// May have changed cell names
// TypeTable is always after all modules, so names are stable
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
if (nodep->cellp()) nodep->cellName(nodep->cellp()->name());
UINFO(8," rename to "<<nodep<<endl);
iterateChildren(nodep);
}
//--------------------
@@ -274,7 +276,7 @@ private:
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) {
iterate(nodep);
}
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3BEGIN_H_
#define _V3BEGIN_H_ 1
@@ -34,4 +34,4 @@ public:
static void debeginAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+54 -54
View File
@@ -18,15 +18,15 @@
//
//*************************************************************************
// BRANCH TRANSFORMATIONS:
// At each IF/(IF else).
// Count underneath $display/$stop statements.
// If more on if than else, this branch is unlikely, or vice-versa.
// At each FTASKREF,
// Count calls into the function
// Then, if FTASK is called only once, add inline attribute
// At each IF/(IF else).
// Count underneath $display/$stop statements.
// If more on if than else, this branch is unlikely, or vice-versa.
// At each FTASKREF,
// Count calls into the function
// Then, if FTASK is called only once, add inline attribute
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -44,89 +44,89 @@ class BranchVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstFTask::user1() -> int. Number of references
AstUser1InUse m_inuser1;
// AstFTask::user1() -> int. Number of references
AstUser1InUse m_inuser1;
// TYPES
typedef std::vector<AstCFunc*> CFuncVec;
// STATE
int m_likely; // Excuses for branch likely taken
int m_unlikely; // Excuses for branch likely not taken
CFuncVec m_cfuncsp; // List of all tasks
int m_likely; // Excuses for branch likely taken
int m_unlikely; // Excuses for branch likely not taken
CFuncVec m_cfuncsp; // List of all tasks
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void reset() {
m_likely = false;
m_unlikely = false;
m_likely = false;
m_unlikely = false;
}
void checkUnlikely(AstNode* nodep) {
if (nodep->isUnlikely()) {
UINFO(4," UNLIKELY: "<<nodep<<endl);
m_unlikely++;
}
if (nodep->isUnlikely()) {
UINFO(4," UNLIKELY: "<<nodep<<endl);
m_unlikely++;
}
}
// VISITORS
virtual void visit(AstNodeIf* nodep) {
UINFO(4," IF: "<<nodep<<endl);
int lastLikely = m_likely;
int lastUnlikely = m_unlikely;
{
// Do if
reset();
UINFO(4," IF: "<<nodep<<endl);
int lastLikely = m_likely;
int lastUnlikely = m_unlikely;
{
// Do if
reset();
iterateAndNextNull(nodep->ifsp());
int ifLikely = m_likely;
int ifUnlikely = m_unlikely;
// Do else
reset();
int ifLikely = m_likely;
int ifUnlikely = m_unlikely;
// Do else
reset();
iterateAndNextNull(nodep->elsesp());
int elseLikely = m_likely;
int elseUnlikely = m_unlikely;
// Compute
int likeness = ifLikely - ifUnlikely - (elseLikely - elseUnlikely);
if (likeness>0) {
nodep->branchPred(AstBranchPred::BP_LIKELY);
} else if (likeness<0) {
nodep->branchPred(AstBranchPred::BP_UNLIKELY);
} // else leave unknown
}
m_likely = lastLikely;
m_unlikely = lastUnlikely;
int elseLikely = m_likely;
int elseUnlikely = m_unlikely;
// Compute
int likeness = ifLikely - ifUnlikely - (elseLikely - elseUnlikely);
if (likeness > 0) {
nodep->branchPred(VBranchPred::BP_LIKELY);
} else if (likeness < 0) {
nodep->branchPred(VBranchPred::BP_UNLIKELY);
} // else leave unknown
}
m_likely = lastLikely;
m_unlikely = lastUnlikely;
}
virtual void visit(AstCCall* nodep) {
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
checkUnlikely(nodep);
nodep->funcp()->user1Inc();
iterateChildren(nodep);
}
virtual void visit(AstCFunc* nodep) {
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
checkUnlikely(nodep);
m_cfuncsp.push_back(nodep);
iterateChildren(nodep);
}
virtual void visit(AstNode* nodep) {
checkUnlikely(nodep);
checkUnlikely(nodep);
iterateChildren(nodep);
}
// METHODS
void calc_tasks() {
for (CFuncVec::iterator it=m_cfuncsp.begin(); it!=m_cfuncsp.end(); ++it) {
AstCFunc* nodep = *it;
if (!nodep->dontInline()) {
nodep->isInline(true);
}
}
for (CFuncVec::iterator it=m_cfuncsp.begin(); it!=m_cfuncsp.end(); ++it) {
AstCFunc* nodep = *it;
if (!nodep->dontInline()) {
nodep->isInline(true);
}
}
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit BranchVisitor(AstNetlist* nodep) {
reset();
reset();
iterateChildren(nodep);
calc_tasks();
calc_tasks();
}
virtual ~BranchVisitor() {}
};
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3BRANCH_H_
#define _V3BRANCH_H_ 1
@@ -35,4 +35,4 @@ public:
static void branchAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+145 -133
View File
@@ -20,11 +20,11 @@
// V3Broken's Transformations:
//
// Entire netlist
// Mark all nodes
// Check all links point to marked nodes
// Mark all nodes
// Check all links point to marked nodes
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -47,128 +47,139 @@ private:
// MEMBERS
// For each node, we keep if it exists or not.
typedef vl_unordered_map<const AstNode*,int> NodeMap; // Performance matters (when --debug)
static NodeMap s_nodes; // Set of all nodes that exist
static NodeMap s_nodes; // Set of all nodes that exist
// BITMASK
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
public:
// METHODS
static void deleted(const AstNode* nodep) {
// Called by operator delete on any node - only if VL_LEAK_CHECKS
// Called by operator delete on any node - only if VL_LEAK_CHECKS
if (debug()>=9) cout<<"-nodeDel: "<<cvtToHex(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) {
reinterpret_cast<const AstNode*>(nodep)
->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted");
}
if (iter!=s_nodes.end()) s_nodes.erase(iter);
NodeMap::iterator iter = s_nodes.find(nodep);
UASSERT_OBJ(!(iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
reinterpret_cast<const AstNode*>(nodep),
"Deleting AstNode object that was never tracked or already deleted");
if (iter!=s_nodes.end()) s_nodes.erase(iter);
}
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
// GCC 4.4.* compiler warning bug, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
static void addNewed(const AstNode* nodep) {
// Called by operator new on any node - only if VL_LEAK_CHECKS
// Called by operator new on any node - only if VL_LEAK_CHECKS
if (debug()>=9) cout<<"-nodeNew: "<<cvtToHex(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter!=s_nodes.end() || (iter->second & FLAG_ALLOCATED)) {
nodep->v3fatalSrc("Newing AstNode object that is already allocated");
}
if (iter == s_nodes.end()) {
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
s_nodes.insert(make_pair(nodep,flags));
}
NodeMap::iterator iter = s_nodes.find(nodep);
UASSERT_OBJ(!(iter !=s_nodes.end() && (iter->second & FLAG_ALLOCATED)),
nodep, "Newing AstNode object that is already allocated");
if (iter == s_nodes.end()) {
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
s_nodes.insert(make_pair(nodep, flags));
}
}
static void setUnder(const AstNode* nodep, bool flag) {
// Called by BrokenCheckVisitor when each node entered/exited
if (!okIfLinkedTo(nodep)) return;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter!=s_nodes.end()) {
iter->second &= ~FLAG_UNDER_NOW;
if (flag) iter->second |= FLAG_UNDER_NOW;
}
// Called by BrokenCheckVisitor when each node entered/exited
if (!okIfLinkedTo(nodep)) return;
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter!=s_nodes.end()) {
iter->second &= ~FLAG_UNDER_NOW;
if (flag) iter->second |= FLAG_UNDER_NOW;
}
}
static void addInTree(AstNode* nodep, bool linkable) {
#ifndef VL_LEAK_CHECKS
if (!linkable) return; // save some time, else the map will get huge!
if (!linkable) return; // save some time, else the map will get huge!
#endif
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) {
NodeMap::iterator iter = s_nodes.find(nodep);
if (VL_UNCOVERABLE(iter == s_nodes.end())) {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif
} else {
if (!(iter->second & FLAG_ALLOCATED)) {
} else {
#ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
UASSERT_OBJ(iter->second & FLAG_ALLOCATED, nodep,
"AstNode is in tree, but not allocated");
#endif
}
if (iter->second & FLAG_IN_TREE) {
nodep->v3fatalSrc("AstNode is already in tree at another location");
}
}
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
if (iter == s_nodes.end()) {
s_nodes.insert(make_pair(nodep,or_flags));
} else {
iter->second |= or_flags;
}
UASSERT_OBJ(!(iter->second & FLAG_IN_TREE), nodep,
"AstNode is already in tree at another location");
}
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
if (iter == s_nodes.end()) {
s_nodes.insert(make_pair(nodep, or_flags));
} else {
iter->second |= or_flags;
}
}
static bool isAllocated(const AstNode* nodep) {
// Some generic node has a pointer to this node. Is it allocated?
// Use this when might not be in tree; otherwise use okIfLinkedTo().
#ifdef VL_LEAK_CHECKS
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
if (!(iter->second & FLAG_ALLOCATED)) return false;
#endif
return true;
}
static bool okIfLinkedTo(const AstNode* nodep) {
// Someone has a pointer to this node. Is it kosher?
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
// Some node in tree has a pointer to this node. Is it kosher?
NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) return false;
#ifdef VL_LEAK_CHECKS
if (!(iter->second & FLAG_ALLOCATED)) return false;
if (!(iter->second & FLAG_ALLOCATED)) return false;
#endif
if (!(iter->second & FLAG_IN_TREE)) return false;
if (!(iter->second & FLAG_LINKABLE)) return false;
return true;
if (!(iter->second & FLAG_IN_TREE)) return false;
if (!(iter->second & FLAG_LINKABLE)) return false;
return true;
}
static bool okIfBelow(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;
// 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 void prepForTree() {
#ifndef VL_LEAK_CHECKS
s_nodes.clear();
s_nodes.clear();
#endif
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
it->second &= ~FLAG_IN_TREE;
it->second &= ~FLAG_LINKABLE;
}
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
it->second &= ~FLAG_IN_TREE;
it->second &= ~FLAG_LINKABLE;
}
}
static void doneWithTree() {
for (int backs=0; backs<2; backs++) { // Those with backp() are probably under one leaking without
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
if ((it->second & FLAG_ALLOCATED)
&& !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs==1 : backs==0)) {
// Use only AstNode::dump instead of the virtual one, as there
// may be varp() and other cross links that are bad.
if (v3Global.opt.debugCheck()) {
for (int backs=0; backs<2; backs++) { // Those with backp() are probably under one leaking without
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
if ((it->second & FLAG_ALLOCATED)
&& !(it->second & FLAG_IN_TREE)
&& !(it->second & FLAG_LEAKED)
&& (it->first->backp() ? backs==1 : backs==0)) {
// Use only AstNode::dump instead of the virtual one, as there
// may be varp() and other cross links that are bad.
if (v3Global.opt.debugCheck()) {
// When get this message, find what forgot to delete the
// node by running GDB, where for node "<e###>" use:
// watch AstNode::s_editCntGbl==####
// run
// bt
std::cerr<<"%Error: LeakedNode"<<(it->first->backp()?"Back: ":": ");
AstNode* rawp = const_cast<AstNode*>
(static_cast<const AstNode*>(it->first));
rawp->AstNode::dump(std::cerr);
std::cerr<<endl;
V3Error::incErrors();
}
it->second |= FLAG_LEAKED;
}
}
}
V3Error::incErrors();
}
it->second |= FLAG_LEAKED;
}
}
}
}
public:
// CONSTUCTORS
// CONSTRUCTORS
BrokenTable() {}
virtual ~BrokenTable() {}
};
@@ -190,19 +201,19 @@ class BrokenMarkVisitor : public AstNVisitor {
// Mark every node in the tree
private:
// NODE STATE
// Nothing! // This may be called deep inside other routines
// // so userp and friends may not be used
// Nothing! // This may be called deep inside other routines
// // so userp and friends may not be used
// METHODS
void processAndIterate(AstNode* nodep) {
BrokenTable::addInTree(nodep, nodep->maybePointedTo());
BrokenTable::addInTree(nodep, nodep->maybePointedTo());
iterateChildrenConst(nodep);
}
// VISITORS
virtual void visit(AstNode* nodep) {
processAndIterate(nodep);
processAndIterate(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit BrokenMarkVisitor(AstNetlist* nodep) {
iterate(nodep);
}
@@ -215,52 +226,50 @@ public:
class BrokenCheckVisitor : public AstNVisitor {
private:
void checkWidthMin(const AstNode* nodep) {
if (nodep->width() != nodep->widthMin()
&& v3Global.widthMinUsage()==VWidthMinUsage::MATCHES_WIDTH) {
nodep->v3fatalSrc("Width != WidthMin");
}
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
nodep, "Width != WidthMin");
}
void processAndIterate(AstNode* nodep) {
BrokenTable::setUnder(nodep,true);
if (const char* whyp=nodep->broken()) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
}
if (nodep->dtypep()) {
if (!nodep->dtypep()->brokeExists()) {
nodep->v3fatalSrc("Broken link in node->dtypep() to "
<<cvtToHex(nodep->dtypep()));
} else if (!VN_IS(nodep->dtypep(), NodeDType)) {
nodep->v3fatalSrc("Non-dtype link in node->dtypep() to "
<<cvtToHex(nodep->dtypep()));
BrokenTable::setUnder(nodep, true);
const char* whyp = nodep->broken();
UASSERT_OBJ(!whyp, nodep,
"Broken link in node (or something without maybePointedTo): "<<whyp);
if (nodep->dtypep()) {
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
"Broken link in node->dtypep() to "<<cvtToHex(nodep->dtypep()));
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
"Non-dtype link in node->dtypep() to "<<cvtToHex(nodep->dtypep()));
}
if (v3Global.assertDTypesResolved()) {
if (nodep->hasDType()) {
UASSERT_OBJ(nodep->dtypep(), nodep,
"No dtype on node with hasDType(): "<<nodep->prettyTypeName());
} else {
UASSERT_OBJ(!nodep->dtypep(), nodep,
"DType on node without hasDType(): "<<nodep->prettyTypeName());
}
}
if (v3Global.assertDTypesResolved()) {
if (nodep->hasDType()) {
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype on node with hasDType(): "<<nodep->prettyTypeName());
} else {
if (nodep->dtypep()) nodep->v3fatalSrc("DType on node without hasDType(): "<<nodep->prettyTypeName());
}
if (nodep->getChildDTypep()) nodep->v3fatalSrc("childDTypep() non-null on node after should have removed");
UASSERT_OBJ(!nodep->getChildDTypep(), nodep,
"childDTypep() non-null on node after should have removed");
if (const AstNodeDType* dnodep = VN_CAST(nodep, NodeDType)) checkWidthMin(dnodep);
}
checkWidthMin(nodep);
}
checkWidthMin(nodep);
iterateChildrenConst(nodep);
BrokenTable::setUnder(nodep,false);
BrokenTable::setUnder(nodep, false);
}
virtual void visit(AstNodeAssign* nodep) {
processAndIterate(nodep);
if (v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()) {
nodep->v3fatalSrc("Assignment LHS is not an lvalue");
}
processAndIterate(nodep);
UASSERT_OBJ(!(v3Global.assertDTypesResolved()
&& nodep->brokeLhsMustBeLvalue()
&& VN_IS(nodep->lhsp(), NodeVarRef)
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
nodep, "Assignment LHS is not an lvalue");
}
virtual void visit(AstNode* nodep) {
processAndIterate(nodep);
processAndIterate(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit BrokenCheckVisitor(AstNetlist* nodep) {
iterate(nodep);
}
@@ -273,16 +282,16 @@ public:
void V3Broken::brokenAll(AstNetlist* nodep) {
//UINFO(9,__FUNCTION__<<": "<<endl);
static bool inBroken = false;
if (inBroken) {
// A error called by broken can recurse back into broken; avoid this
UINFO(1,"Broken called under broken, skipping recursion.\n");
if (VL_UNCOVERABLE(inBroken)) {
// A error called by broken can recurse back into broken; avoid this
UINFO(1,"Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
} else {
inBroken = true;
BrokenTable::prepForTree();
BrokenMarkVisitor mvisitor (nodep);
BrokenCheckVisitor cvisitor (nodep);
BrokenTable::doneWithTree();
inBroken = false;
inBroken = true;
BrokenTable::prepForTree();
BrokenMarkVisitor mvisitor (nodep);
BrokenCheckVisitor cvisitor (nodep);
BrokenTable::doneWithTree();
inBroken = false;
}
}
@@ -292,3 +301,6 @@ void V3Broken::addNewed(AstNode* nodep) {
void V3Broken::deleted(AstNode* nodep) {
BrokenTable::deleted(nodep);
}
bool V3Broken::isAllocated(AstNode* nodep) {
return BrokenTable::isAllocated(nodep);
}
+3 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3BROKEN_H_
#define _V3BROKEN_H_ 1
@@ -34,6 +34,7 @@ public:
static void brokenAll(AstNetlist* nodep);
static void addNewed(AstNode* nodep);
static void deleted(AstNode* nodep);
static bool isAllocated(AstNode* nodep);
};
#endif // Guard
#endif // Guard
+80 -75
View File
@@ -18,14 +18,14 @@
//
//*************************************************************************
// V3CCtors's Transformations:
// Iterates over all modules and
// for all AstVar, create a creates a AstCReset node in an _ctor_var_reset AstCFunc.
// for all AstCoverDecl, move the declaration into a _configure_coverage AstCFunc.
// For each variable that needs reset, add a AstCReset node.
// Iterates over all modules and
// for all AstVar, create a creates a AstCReset node in an _ctor_var_reset AstCFunc.
// for all AstCoverDecl, move the declaration into a _configure_coverage AstCFunc.
// For each variable that needs reset, add a AstCReset node.
//
// For primary inputs, add _eval_debug_assertions.
// For primary inputs, add _eval_debug_assertions.
//
// This transformation honors outputSplitCFuncs.
// This transformation honors outputSplitCFuncs.
//*************************************************************************
#include "config_build.h"
@@ -43,59 +43,60 @@
class V3CCtorsVisitor {
private:
string m_basename;
string m_argsp;
string m_callargsp;
AstNodeModule* m_modp; // Current module
AstCFunc* m_tlFuncp; // Top level function being built
AstCFunc* m_funcp; // Current function
int m_numStmts; // Number of statements output
int m_funcNum; // Function number being built
string m_basename;
string m_argsp;
string m_callargsp;
AstNodeModule* m_modp; // Current module
AstCFunc* m_tlFuncp; // Top level function being built
AstCFunc* m_funcp; // Current function
int m_numStmts; // Number of statements output
int m_funcNum; // Function number being built
public:
void add(AstNode* nodep) {
if (v3Global.opt.outputSplitCFuncs()
&& v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_funcp = NULL;
}
if (!m_funcp) {
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum), NULL, "void");
m_funcp->isStatic(false);
m_funcp->declPrivate(true);
m_funcp->slow(true);
m_funcp->argTypes(m_argsp);
m_modp->addStmtp(m_funcp);
if (v3Global.opt.outputSplitCFuncs()
&& v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_funcp = NULL;
}
if (!m_funcp) {
m_funcp = new AstCFunc(m_modp->fileline(),
m_basename+"_"+cvtToStr(++m_funcNum), NULL, "void");
m_funcp->isStatic(false);
m_funcp->declPrivate(true);
m_funcp->slow(true);
m_funcp->argTypes(m_argsp);
m_modp->addStmtp(m_funcp);
// Add a top call to it
AstCCall* callp = new AstCCall(m_modp->fileline(), m_funcp);
callp->argTypes(m_callargsp);
// Add a top call to it
AstCCall* callp = new AstCCall(m_modp->fileline(), m_funcp);
callp->argTypes(m_callargsp);
m_tlFuncp->addStmtsp(callp);
m_numStmts = 0;
}
m_funcp->addStmtsp(nodep);
m_numStmts += 1;
m_tlFuncp->addStmtsp(callp);
m_numStmts = 0;
}
m_funcp->addStmtsp(nodep);
m_numStmts += 1;
}
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename,
const string& argsp="", const string& callargsp="",
const string& stmt="") {
m_basename = basename;
m_argsp = argsp;
m_callargsp = callargsp;
m_modp = nodep;
m_numStmts = 0;
m_funcNum = 0;
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void");
m_tlFuncp->declPrivate(true);
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(true);
m_tlFuncp->argTypes(m_argsp);
if (stmt != "") {
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp);
const string& stmt="") {
m_basename = basename;
m_argsp = argsp;
m_callargsp = callargsp;
m_modp = nodep;
m_numStmts = 0;
m_funcNum = 0;
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void");
m_tlFuncp->declPrivate(true);
m_tlFuncp->isStatic(false);
m_tlFuncp->slow(true);
m_tlFuncp->argTypes(m_argsp);
if (stmt != "") {
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp);
}
~V3CCtorsVisitor() {}
private:
@@ -105,7 +106,7 @@ private:
//######################################################################
void V3CCtors::evalAsserts() {
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module
AstNodeModule* modp = v3Global.rootp()->modulesp(); // Top module wrapper
AstCFunc* funcp = new AstCFunc(modp->fileline(), "_eval_debug_assertions", NULL, "void");
funcp->declPrivate(true);
funcp->isStatic(false);
@@ -116,36 +117,38 @@ void V3CCtors::evalAsserts() {
if (AstVar* varp = VN_CAST(np, Var)) {
if (varp->isPrimaryInish() && !varp->isSc()) {
if (AstBasicDType* basicp = VN_CAST(varp->dtypeSkipRefp(), BasicDType)) {
int storedWidth = basicp->widthAlignBytes() * 8;
int lastWordWidth = varp->width() % storedWidth;
if (lastWordWidth != 0) {
// if (signal & CONST(upper_non_clean_mask)) { fail; }
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
if (varp->isWide()) {
newp = new AstWordSel(varp->fileline(), newp,
new AstConst(varp->fileline(), varp->widthWords()-1));
}
uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
V3Number num (varp->fileline(), storedWidth, value);
newp = new AstAnd(varp->fileline(), newp,
new AstConst(varp->fileline(), num));
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
int storedWidth = basicp->widthAlignBytes() * 8;
int lastWordWidth = varp->width() % storedWidth;
if (lastWordWidth != 0) {
// if (signal & CONST(upper_non_clean_mask)) { fail; }
AstNode* newp = new AstVarRef(varp->fileline(), varp, false);
if (varp->isWide()) {
newp = new AstWordSel(
varp->fileline(), newp,
new AstConst(varp->fileline(), varp->widthWords()-1));
}
uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
newp = new AstAnd(varp->fileline(), newp,
new AstConst(varp->fileline(), AstConst::WidthedValue(),
storedWidth, value));
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
new AstCStmt(varp->fileline(),
"Verilated::overWidthError(\""+varp->prettyName()+"\");"));
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
newp = ifp;
funcp->addStmtsp(newp);
}
}
}
}
ifp->branchPred(VBranchPred::BP_UNLIKELY);
newp = ifp;
funcp->addStmtsp(newp);
}
}
}
}
}
}
void V3CCtors::cctorsAll() {
UINFO(2,__FUNCTION__<<": "<<endl);
evalAsserts();
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
for (AstNodeModule* modp = v3Global.rootp()->modulesp();
modp; modp = VN_CAST(modp->nextp(), NodeModule)) {
// Process each module in turn
{
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
@@ -153,14 +156,16 @@ void V3CCtors::cctorsAll() {
if (AstVar* varp = VN_CAST(np, Var)) {
if (!varp->isIfaceParent() && !varp->isIfaceRef()
&& !varp->noReset()) {
var_reset.add(new AstCReset(varp->fileline(), new AstVarRef(varp->fileline(), varp, true)));
var_reset.add(new AstCReset(varp->fileline(),
new AstVarRef(varp->fileline(), varp, true)));
}
}
}
}
if (v3Global.opt.coverage()) {
V3CCtorsVisitor configure_coverage
(modp, "_configure_coverage", EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
(modp, "_configure_coverage",
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
"if (0 && vlSymsp && first) {} // Prevent unused\n");
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) {
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CCTORS_H_
#define _V3CCTORS_H_ 1
@@ -37,4 +37,4 @@ private:
};
#endif // Guard
#endif // Guard
+345 -335
View File
@@ -20,23 +20,24 @@
// V3Case's Transformations:
//
// Each module:
// TBD: Eliminate tristates by adding __in, __inen, __en wires in parallel
// Need __en in changed list if a signal is on the LHS of a assign
// Cases:
// CASE(v) CASEITEM(items,body) -> IF (OR (EQ (AND v mask)
// (AND item1 mask))
// (other items))
// body
// Or, converts to a if/else tree.
// FUTURES:
// Large 16+ bit tables with constants and no masking (address muxes)
// TBD: Eliminate tristates by adding __in, __inen, __en wires in parallel
// Need __en in changed list if a signal is on the LHS of a assign
// Cases:
// CASE(v) CASEITEM(items,body) -> IF (OR (EQ (AND v mask)
// (AND item1 mask))
// (other items))
// body
// Or, converts to a if/else tree.
// FUTURES:
// Large 16+ bit tables with constants and no masking (address muxes)
// Enter all into std::multimap, sort by value and use a tree of < and == compares.
// "Diagonal" find of {rightmost,leftmost} bit {set,clear}
// "Diagonal" find of {rightmost,leftmost} bit {set,clear}
// Ignoring mask, check each value is unique (using std::multimap as above?)
// Each branch is then mask-and-compare operation (IE <000000001_000000000 at midpoint.)
// Each branch is then mask-and-compare operation (IE
// <000000001_000000000 at midpoint.)
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -48,68 +49,70 @@
#include <algorithm>
#include <cstdarg>
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
//######################################################################
class CaseLintVisitor : public AstNVisitor {
private:
AstNodeCase* m_caseExprp; // Under a CASE value node, if so the relevant case statement
AstNodeCase* m_caseExprp; // Under a CASE value node, if so the relevant case statement
// METHODS
VL_DEBUG_FUNC; // Declare debug()
virtual void visit(AstNodeCase* nodep) {
if (VN_IS(nodep, Case) && VN_CAST(nodep, Case)->casex()) {
nodep->v3warn(CASEX,"Suggest casez (with ?'s) in place of casex (with X's)");
}
// Detect multiple defaults
bool hitDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) {
if (hitDefault) {
nodep->v3error("Multiple default statements in case statement.");
}
hitDefault = true;
}
}
nodep->v3warn(CASEX, "Suggest casez (with ?'s) in place of casex (with X's)");
}
// Detect multiple defaults
bool hitDefault = false;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
if (itemp->isDefault()) {
if (hitDefault) {
itemp->v3error("Multiple default statements in case statement.");
}
hitDefault = true;
}
}
// Check for X/Z in non-casex statements
{
m_caseExprp = nodep;
// Check for X/Z in non-casex statements
{
m_caseExprp = nodep;
iterate(nodep->exprp());
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
iterateAndNextNull(itemp->condsp());
}
m_caseExprp = NULL;
}
}
m_caseExprp = NULL;
}
}
virtual void visit(AstConst* nodep) {
// See also neverItem
if (m_caseExprp && nodep->num().isFourState()) {
// See also neverItem
if (m_caseExprp && nodep->num().isFourState()) {
if (VN_IS(m_caseExprp, GenCase)) {
nodep->v3error("Use of x/? constant in generate case statement, (no such thing as 'generate casez')");
nodep->v3error("Use of x/? constant in generate case statement, (no such thing as 'generate casez')");
} else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) {
// Don't sweat it, we already complained about casex in general
// Don't sweat it, we already complained about casex in general
} else if (VN_IS(m_caseExprp, Case) && (VN_CAST(m_caseExprp, Case)->casez()
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
if (nodep->num().isUnknown()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, (perhaps intended ?/z in constant)");
}
} else {
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, (perhaps intended casex/casez)");
}
}
if (nodep->num().isUnknown()) {
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, (perhaps intended ?/z in constant)");
}
} else {
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, (perhaps intended casex/casez)");
}
}
}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CaseLintVisitor(AstNodeCase* nodep) {
m_caseExprp = NULL;
m_caseExprp = NULL;
iterate(nodep);
}
virtual ~CaseLintVisitor() {}
@@ -122,340 +125,347 @@ class CaseVisitor : public AstNVisitor {
private:
// NODE STATE
// Cleared each Case
// AstIf::user3() -> bool. Set true to indicate clone not needed
AstUser3InUse m_inuser3;
// AstIf::user3() -> bool. Set true to indicate clone not needed
AstUser3InUse m_inuser3;
// STATE
V3Double0 m_statCaseFast; // Statistic tracking
V3Double0 m_statCaseSlow; // Statistic tracking
VDouble0 m_statCaseFast; // Statistic tracking
VDouble0 m_statCaseSlow; // Statistic tracking
// Per-CASE
int m_caseWidth; // Width of valueItems
int m_caseItems; // Number of caseItem unique values
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
AstNode* m_valueItem[1<<CASE_OVERLAP_WIDTH]; // For each possible value, the case branch we need
int m_caseWidth; // Width of valueItems
int m_caseItems; // Number of caseItem unique values
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
AstNode* m_valueItem[1<<CASE_OVERLAP_WIDTH]; // For each possible value, the case branch we need
// METHODS
VL_DEBUG_FUNC; // Declare debug()
bool isCaseTreeFast(AstCase* nodep) {
int width = 0;
bool opaque = false;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (icondp->isDouble()) opaque = true;
int width = 0;
bool opaque = false;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (icondp->isDouble()) opaque = true;
if (!VN_IS(icondp, Const)) width = CASE_BARF; // Can't parse; not a constant
m_caseItems++;
}
}
m_caseWidth = width;
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
m_caseNoOverlapsAllCovered = false;
return false; // Too wide for analysis
}
UINFO(8,"Simple case statement: "<<nodep<<endl);
// Zero list of items for each value
m_caseItems++;
}
}
m_caseWidth = width;
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
m_caseNoOverlapsAllCovered = false;
return false; // Too wide for analysis
}
UINFO(8,"Simple case statement: "<<nodep<<endl);
// Zero list of items for each value
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) m_valueItem[i] = NULL;
// Now pick up the values for each assignment
// We can cheat and use uint32_t's because we only support narrow case's
bool bitched = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
//if (debug()>=9) icondp->dumpTree(cout," caseitem: ");
// Now pick up the values for each assignment
// We can cheat and use uint32_t's because we only support narrow case's
bool bitched = false;
for (AstCaseItem* itemp = nodep->itemsp();
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
//if (debug()>=9) icondp->dumpTree(cout, " caseitem: ");
AstConst* iconstp = VN_CAST(icondp, Const);
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this");
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
V3Number nummask (itemp->fileline(), iconstp->width());
nummask.opBitsNonX(iconstp->num());
uint32_t mask = nummask.toUInt();
V3Number numval (itemp->fileline(), iconstp->width());
numval.opBitsOne(iconstp->num());
uint32_t val = numval.toUInt();
UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this");
if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
} else {
V3Number nummask (itemp, iconstp->width());
nummask.opBitsNonX(iconstp->num());
uint32_t mask = nummask.toUInt();
V3Number numval (itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
uint32_t val = numval.toUInt();
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
if ((i & mask) == val) {
if (!m_valueItem[i]) {
m_valueItem[i] = itemp;
} else if (!itemp->ignoreOverlap() && !bitched) {
itemp->v3warn(CASEOVERLAP,"Case values overlap (example pattern 0x"<<std::hex<<i<<")");
bitched = true;
m_caseNoOverlapsAllCovered = false;
}
}
}
}
}
// Defaults were moved to last in the caseitem list by V3LinkDot
if (itemp->isDefault()) { // Case statement's default... Fill the table
if ((i & mask) == val) {
if (!m_valueItem[i]) {
m_valueItem[i] = itemp;
} else if (!itemp->ignoreOverlap() && !bitched) {
icondp->v3warn(CASEOVERLAP, "Case values overlap (example pattern 0x"
<<std::hex<<i<<")");
bitched = true;
m_caseNoOverlapsAllCovered = false;
}
}
}
}
}
// Defaults were moved to last in the caseitem list by V3LinkDot
if (itemp->isDefault()) { // Case statement's default... Fill the table
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
if (!m_valueItem[i]) m_valueItem[i] = itemp;
}
}
}
if (!m_valueItem[i]) m_valueItem[i] = itemp;
}
}
}
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
if (!m_valueItem[i]) {
nodep->v3warn(CASEINCOMPLETE,"Case values incompletely covered (example pattern 0x"<<std::hex<<i<<")");
m_caseNoOverlapsAllCovered = false;
return false;
}
}
if (m_caseItems <= 3) return false; // Not worth simplifing
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
if (!m_valueItem[i]) {
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered (example pattern 0x"
<<std::hex<<i<<")");
m_caseNoOverlapsAllCovered = false;
return false;
}
}
if (m_caseItems <= 3) return false; // Not worth simplifying
// Convert valueItem from AstCaseItem* to the expression
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
}
return true; // All is fine
}
return true; // All is fine
}
AstNode* replaceCaseFastRecurse(AstNode* cexprp, int msb, uint32_t upperValue) {
if (msb<0) {
// There's no space for a IF. We know upperValue is thus down to a specific
// exact value, so just return the tree value
// Note can't clone here, as we're going to check for equivelence above
return m_valueItem[upperValue];
}
else {
// Make left and right subtrees
// cexpr[msb:lsb] == 1
AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | 0);
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));
if (msb<0) {
// There's no space for a IF. We know upperValue is thus down to a specific
// exact value, so just return the tree value
// Note can't clone here, as we're going to check for equivalence above
return m_valueItem[upperValue];
}
else {
// Make left and right subtrees
// cexpr[msb:lsb] == 1
AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | 0);
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));
if (tree0p == tree1p) {
// Same logic on both sides, so we can just return one of 'em
return tree0p;
}
// We could have a "checkerboard" with A B A B, we can use the same IF on both edges
bool same = true;
for (uint32_t a=upperValue,
b=(upperValue|(1UL<<msb));
a < (upperValue|(1UL<<msb));
a++, b++) {
if (m_valueItem[a] != m_valueItem[b]) { same=false; break; }
}
if (same) {
tree1p->deleteTree(); VL_DANGLING(tree1p);
return tree0p;
}
if (tree0p == tree1p) {
// Same logic on both sides, so we can just return one of 'em
return tree0p;
}
// We could have a "checkerboard" with A B A B, we can use the same IF on both edges
bool same = true;
for (uint32_t a=upperValue,
b=(upperValue|(1UL<<msb));
a < (upperValue|(1UL<<msb));
a++, b++) {
if (m_valueItem[a] != m_valueItem[b]) { same = false; break; }
}
if (same) {
tree1p->deleteTree(); VL_DANGLING(tree1p);
return tree0p;
}
// Must have differing logic, so make a selection
// Must have differing logic, so make a selection
// Case expressions can't be linked twice, so clone them
if (tree0p && !tree0p->user3()) tree0p = tree0p->cloneTree(true);
if (tree1p && !tree1p->user3()) tree1p = tree1p->cloneTree(true);
// Case expressions can't be linked twice, so clone them
if (tree0p && !tree0p->user3()) tree0p = tree0p->cloneTree(true);
if (tree1p && !tree1p->user3()) tree1p = tree1p->cloneTree(true);
// Alternate scheme if we ever do multiple bits at a time:
//V3Number nummask (cexprp->fileline(), cexprp->width(), (1UL<<msb));
//AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// new AstConst(cexprp->fileline(), nummask));
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false),
msb, 1);
AstNode* eqp = new AstNeq(cexprp->fileline(),
new AstConst(cexprp->fileline(), 0),
and1p);
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
ifp->user3(1); // So we don't bother to clone it
return ifp;
}
// Alternate scheme if we ever do multiple bits at a time:
//V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
//AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
// new AstConst(cexprp->fileline(), nummask));
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false),
msb, 1);
AstNode* eqp = new AstNeq(cexprp->fileline(),
new AstConst(cexprp->fileline(), 0),
and1p);
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
ifp->user3(1); // So we don't bother to clone it
return ifp;
}
}
void replaceCaseFast(AstCase* nodep) {
// CASEx(cexpr,....
// -> tree of IF(msb, IF(msb-1, 11, 10)
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
// CASEx(cexpr,....
// -> tree of IF(msb, IF(msb-1, 11, 10)
// IF(msb-1, 01, 00))
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
if (debug()>=9) {
if (debug()>=9) {
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);
}
}
}
}
}
}
// Handle any assertions
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
// Handle any assertions
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
AstNode::user3ClearTree();
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth-1, 0UL);
// Case expressions can't be linked twice, so clone them
if (ifrootp && !ifrootp->user3()) ifrootp = ifrootp->cloneTree(true);
AstNode::user3ClearTree();
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth-1, 0UL);
// Case expressions can't be linked twice, so clone them
if (ifrootp && !ifrootp->user3()) ifrootp = ifrootp->cloneTree(true);
if (ifrootp) nodep->replaceWith(ifrootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
cexprp->deleteTree(); VL_DANGLING(cexprp);
if (debug()>=9) ifrootp->dumpTree(cout," _simp: ");
if (ifrootp) nodep->replaceWith(ifrootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
cexprp->deleteTree(); VL_DANGLING(cexprp);
if (debug()>=9) ifrootp->dumpTree(cout, " _simp: ");
}
void replaceCaseComplicated(AstCase* nodep) {
// CASEx(cexpr,ITEM(icond1,istmts1),ITEM(icond2,istmts2),ITEM(default,istmts3))
// -> IF((cexpr==icond1),istmts1,
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
// ,istmts2, istmts3
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
// We'll do this in two stages. First stage, convert the conditions to
// the appropriate IF AND terms.
if (debug()>=9) nodep->dumpTree(cout," _comp_IN: ");
bool hadDefault = false;
// CASEx(cexpr,ITEM(icond1,istmts1),ITEM(icond2,istmts2),ITEM(default,istmts3))
// -> IF((cexpr==icond1),istmts1,
// IF((EQ (AND MASK cexpr) (AND MASK icond1)
// ,istmts2, istmts3
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
// We'll do this in two stages. First stage, convert the conditions to
// the appropriate IF AND terms.
if (debug()>=9) nodep->dumpTree(cout, " _comp_IN: ");
bool hadDefault = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
if (!itemp->condsp()) {
// Default clause. Just make true, we'll optimize it away later
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
hadDefault = true;
} else {
// Expressioned clause
AstNode* icondNextp = NULL;
AstNode* ifexprp = NULL; // If expression to test
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) {
icondNextp = icondp->nextp();
icondp->unlinkFrBack();
if (!itemp->condsp()) {
// Default clause. Just make true, we'll optimize it away later
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
hadDefault = true;
} else {
// Expressioned clause
AstNode* icondNextp = NULL;
AstNode* ifexprp = NULL; // If expression to test
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) {
icondNextp = icondp->nextp();
icondp->unlinkFrBack();
AstNode* condp = NULL; // Default is to use and1p/and2p
AstNode* condp = NULL; // Default is to use and1p/and2p
AstConst* iconstp = VN_CAST(icondp, Const);
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
if (iconstp && neverItem(nodep, iconstp)) {
// X in casez can't ever be executed
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
// For simplicity, make expression that is not equal, and let later
// optimizations remove it
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
} else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) {
// Similar logic in V3Width::visit(AstInside)
AstNode* ap = AstGte::newTyped(itemp->fileline(),
cexprp->cloneTree(false),
irangep->lhsp()->unlinkFrBack());
AstNode* bp = AstLte::newTyped(itemp->fileline(),
cexprp->cloneTree(false),
irangep->rhsp()->unlinkFrBack());
condp = new AstAnd(itemp->fileline(), ap, bp);
} else if (iconstp && iconstp->num().isFourState()
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
V3Number nummask (itemp->fileline(), iconstp->width());
nummask.opBitsNonX(iconstp->num());
V3Number numval (itemp->fileline(), iconstp->width());
numval.opBitsOne(iconstp->num());
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
AstNode* and1p = cexprp->cloneTree(false);
AstNode* and2p = icondp;
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
}
if (!ifexprp) {
ifexprp = condp;
} else {
ifexprp = new AstLogOr(itemp->fileline(), ifexprp, condp);
}
}
// Replace expression in tree
itemp->condsp(ifexprp);
}
}
cexprp->deleteTree(); VL_DANGLING(cexprp);
if (!hadDefault) {
// If there was no default, add a empty one, this greatly simplifies below code
// and constant propagation will just eliminate it for us later.
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::LogicTrue()),
NULL));
}
if (debug()>=9) nodep->dumpTree(cout," _comp_COND: ");
// Now build the IF statement tree
// The tree can be quite huge. Pull ever group of 8 out, and make a OR tree.
// This reduces the depth for the bottom elements, at the cost of some of the top elements.
// If we ever have profiling data, we should pull out the most common item from here and
// instead make it the first IF branch.
int depth = 0;
AstNode* grouprootp = NULL;
AstIf* groupnextp = NULL;
AstIf* itemnextp = NULL;
// Similar logic in V3Width::visit(AstInside)
AstNode* ap = AstGte::newTyped(itemp->fileline(),
cexprp->cloneTree(false),
irangep->lhsp()->unlinkFrBack());
AstNode* bp = AstLte::newTyped(itemp->fileline(),
cexprp->cloneTree(false),
irangep->rhsp()->unlinkFrBack());
condp = new AstAnd(itemp->fileline(), ap, bp);
} else if (iconstp && iconstp->num().isFourState()
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
V3Number nummask (itemp, iconstp->width());
nummask.opBitsNonX(iconstp->num());
V3Number numval (itemp, iconstp->width());
numval.opBitsOne(iconstp->num());
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
new AstConst(itemp->fileline(), nummask));
AstNode* and2p = new AstAnd(itemp->fileline(),
new AstConst(itemp->fileline(), numval),
new AstConst(itemp->fileline(), nummask));
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
} else {
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
AstNode* and1p = cexprp->cloneTree(false);
AstNode* and2p = icondp;
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
}
if (!ifexprp) {
ifexprp = condp;
} else {
ifexprp = new AstLogOr(itemp->fileline(), ifexprp, condp);
}
}
// Replace expression in tree
itemp->condsp(ifexprp);
}
}
cexprp->deleteTree(); VL_DANGLING(cexprp);
if (!hadDefault) {
// If there was no default, add a empty one, this greatly simplifies below code
// and constant propagation will just eliminate it for us later.
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
new AstConst(nodep->fileline(), AstConst::LogicTrue()),
NULL));
}
if (debug()>=9) nodep->dumpTree(cout, " _comp_COND: ");
// Now build the IF statement tree
// The tree can be quite huge. Pull ever group of 8 out, and make a OR tree.
// This reduces the depth for the bottom elements, at the cost of
// some of the top elements. If we ever have profiling data, we
// should pull out the most common item from here and instead make
// it the first IF branch.
int depth = 0;
AstNode* grouprootp = NULL;
AstIf* groupnextp = NULL;
AstIf* itemnextp = NULL;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
if (istmtsp) istmtsp->unlinkFrBackWithNext();
// Expressioned clause
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
{ // Prepare for next group
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = NULL;
AstIf* newp = new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL);
if (groupnextp) groupnextp->addElsesp(newp);
else grouprootp = newp;
groupnextp = newp;
} else { // Continue group, modify if condition to OR in this new condition
AstNode* condp = groupnextp->condp()->unlinkFrBack();
groupnextp->condp(new AstOr(ifexprp->fileline(),
condp,
ifexprp->cloneTree(true)));
}
}
{ // Make the new lower IF and attach in the tree
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
itemexprp->deleteTree(); VL_DANGLING(itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
if (itemnextp) itemnextp->addElsesp(newp);
else groupnextp->addIfsp(newp); // First in a new group
itemnextp = newp;
}
}
if (debug()>=9) nodep->dumpTree(cout," _comp_TREE: ");
// Handle any assertions
replaceCaseParallel(nodep, false);
// Replace the CASE... with IF...
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout," _new: ");
if (grouprootp) nodep->replaceWith(grouprootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
if (istmtsp) istmtsp->unlinkFrBackWithNext();
// Expressioned clause
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
{ // Prepare for next group
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
if (depth == 1) { // First group or starting new group
itemnextp = NULL;
AstIf* newp = new AstIf(itemp->fileline(),
ifexprp->cloneTree(true), NULL, NULL);
if (groupnextp) groupnextp->addElsesp(newp);
else grouprootp = newp;
groupnextp = newp;
} else { // Continue group, modify if condition to OR in this new condition
AstNode* condp = groupnextp->condp()->unlinkFrBack();
groupnextp->condp(new AstOr(ifexprp->fileline(),
condp,
ifexprp->cloneTree(true)));
}
}
{ // Make the new lower IF and attach in the tree
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
itemexprp->deleteTree(); VL_DANGLING(itemexprp);
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
}
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
if (itemnextp) itemnextp->addElsesp(newp);
else groupnextp->addIfsp(newp); // First in a new group
itemnextp = newp;
}
}
if (debug()>=9) nodep->dumpTree(cout, " _comp_TREE: ");
// Handle any assertions
replaceCaseParallel(nodep, false);
// Replace the CASE... with IF...
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
if (grouprootp) nodep->replaceWith(grouprootp);
else nodep->unlinkFrBack();
nodep->deleteTree(); VL_DANGLING(nodep);
}
void replaceCaseParallel(AstCase* nodep, bool noOverlapsAllCovered) {
// Take the notParallelp tree under the case statement created by V3Assert
// If the statement was proven to have no overlaps and all cases covered, we're done with it.
// Else, convert to a normal statement parallel with the case statement.
if (nodep->notParallelp() && !noOverlapsAllCovered) {
AstNode* parp = nodep->notParallelp()->unlinkFrBackWithNext();
nodep->addNextHere(parp);
}
// Take the notParallelp tree under the case statement created by V3Assert
// If the statement was proven to have no overlaps and all cases
// covered, we're done with it.
// Else, convert to a normal statement parallel with the case statement.
if (nodep->notParallelp() && !noOverlapsAllCovered) {
AstNode* parp = nodep->notParallelp()->unlinkFrBackWithNext();
nodep->addNextHere(parp);
}
}
bool neverItem(AstCase* casep, AstConst* itemp) {
// Xs in case or casez are impossible due to two state simulations
if (casep->casex()) {
} else if (casep->casez() || casep->caseInside()) {
if (itemp->num().isUnknown()) return true;
} else {
if (itemp->num().isFourState()) return true;
}
return false;
// Xs in case or casez are impossible due to two state simulations
if (casep->casex()) {
} else if (casep->casez() || casep->caseInside()) {
if (itemp->num().isUnknown()) return true;
} else {
if (itemp->num().isFourState()) return true;
}
return false;
}
// VISITORS
virtual void visit(AstCase* nodep) {
V3Case::caseLint(nodep);
V3Case::caseLint(nodep);
iterateChildren(nodep);
if (debug()>=9) nodep->dumpTree(cout," case_old: ");
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
// It's a simple priority encoder or complete statement
// we can make a tree of statements to avoid extra comparisons
++m_statCaseFast;
replaceCaseFast(nodep); VL_DANGLING(nodep);
} else {
++m_statCaseSlow;
replaceCaseComplicated(nodep); VL_DANGLING(nodep);
}
if (debug()>=9) nodep->dumpTree(cout, " case_old: ");
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
// It's a simple priority encoder or complete statement
// we can make a tree of statements to avoid extra comparisons
++m_statCaseFast;
replaceCaseFast(nodep); VL_DANGLING(nodep);
} else {
++m_statCaseSlow;
replaceCaseComplicated(nodep); VL_DANGLING(nodep);
}
}
//--------------------
// Default: Just iterate
@@ -464,19 +474,19 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CaseVisitor(AstNetlist* nodep) {
m_caseWidth = 0;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = false;
m_caseNoOverlapsAllCovered = false;
for (uint32_t i=0; i<(1UL<<CASE_OVERLAP_WIDTH); ++i) {
m_valueItem[i] = NULL;
}
iterate(nodep);
}
virtual ~CaseVisitor() {
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
}
};
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CASE_H_
#define _V3CASE_H_ 1
@@ -35,4 +35,4 @@ public:
static void caseLint(AstNodeCase* nodep);
};
#endif // Guard
#endif // Guard
+74 -74
View File
@@ -20,27 +20,27 @@
// V3Cast's Transformations:
//
// Each module:
// For each math operator, if above operator requires 32 bits,
// and this isn't, cast to 32 bits.
// Likewise for 64 bit operators.
// For each math operator, if above operator requires 32 bits,
// and this isn't, cast to 32 bits.
// Likewise for 64 bit operators.
//
// C++ rules:
// Integral promotions allow conversion to larger int. Unsigned is only
// used if a int would not fit the value.
// Integral promotions allow conversion to larger int. Unsigned is only
// used if a int would not fit the value.
//
// Bools converts to int, not unsigned.
// Bools converts to int, not unsigned.
//
// Most operations return unsigned if either operand is unsigned.
// Most operations return unsigned if either operand is unsigned.
//
// Unsignedness can be lost on results of the below operations, as they
// may need the sign bit for proper operation:
// /, %, /=, %=, <, <=, >, or >=
// Unsignedness can be lost on results of the below operations, as they
// may need the sign bit for proper operation:
// /, %, /=, %=, <, <=, >, or >=
//
// Signed values are always sign extended on promotion or right shift,
// even if assigning to a unsigned.
// Signed values are always sign extended on promotion or right shift,
// even if assigning to a unsigned.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -58,8 +58,8 @@ class CastVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstNode::user() // bool. Indicates node is of known size
AstUser1InUse m_inuser1;
// AstNode::user() // bool. Indicates node is of known size
AstUser1InUse m_inuser1;
// STATE
@@ -67,97 +67,97 @@ private:
VL_DEBUG_FUNC; // Declare debug()
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
UINFO(4," NeedCast "<<nodep<<endl);
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
//
UINFO(4," NeedCast "<<nodep<<endl);
AstNRelinker relinkHandle;
nodep->unlinkFrBack(&relinkHandle);
//
AstCCast* castp = new AstCCast(nodep->fileline(), nodep, needsize, nodep->widthMin());
relinkHandle.relink(castp);
//if (debug()>8) castp->dumpTree(cout,"-castins: ");
//
insureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
relinkHandle.relink(castp);
//if (debug()>8) castp->dumpTree(cout, "-castins: ");
//
insureLower32Cast(castp);
nodep->user1(1); // Now must be of known size
}
int castSize(AstNode* nodep) {
if (nodep->isQuad()) return VL_QUADSIZE;
else if (nodep->width()<=8) return 8;
else if (nodep->width()<=16) return 16;
else return VL_WORDSIZE;
if (nodep->isQuad()) return VL_QUADSIZE;
else if (nodep->width()<=8) return 8;
else if (nodep->width()<=16) return 16;
else return VL_WORDSIZE;
}
void insureCast(AstNode* nodep) {
if (castSize(nodep->backp()) != castSize(nodep)
|| !nodep->user1()) {
insertCast(nodep, castSize(nodep->backp()));
}
if (castSize(nodep->backp()) != castSize(nodep)
|| !nodep->user1()) {
insertCast(nodep, castSize(nodep->backp()));
}
}
void insureLower32Cast(AstCCast* nodep) {
// If we have uint64 = CAST(uint64(x)) then the upcasting
// really needs to be CAST(uint64(CAST(uint32(x))).
// Otherwise a (uint64)(a>b) would return wrong value, as
// less than has undeterministic signedness.
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
// If we have uint64 = CAST(uint64(x)) then the upcasting
// really needs to be CAST(uint64(CAST(uint32(x))).
// Otherwise a (uint64)(a>b) would return wrong value, as
// less than has nondeterministic signedness.
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
&& !VN_IS(nodep->lhsp(), CCast)) {
insertCast(nodep->lhsp(), VL_WORDSIZE);
}
insertCast(nodep->lhsp(), VL_WORDSIZE);
}
}
// VISITORS
virtual void visit(AstNodeUniop* nodep) {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
nodep->user1(nodep->lhsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
}
virtual void visit(AstNodeBiop* nodep) {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
}
virtual void visit(AstNodeTriop* nodep) {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1()
| nodep->thsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) insureCast(nodep->thsp());
nodep->user1(nodep->lhsp()->user1()
| nodep->rhsp()->user1()
| nodep->thsp()->user1());
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
if (nodep->sizeMattersThs()) insureCast(nodep->thsp());
}
virtual void visit(AstCCast* nodep) {
iterateChildren(nodep);
insureLower32Cast(nodep);
nodep->user1(1);
insureLower32Cast(nodep);
nodep->user1(1);
}
virtual void visit(AstNegate* nodep) {
iterateChildren(nodep);
nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin()==1) {
// We want to avoid a GCC "converting of negative value" warning
// from our expansion of
// out = {32{a<b}} => out = - (a<b)
insertCast(nodep->lhsp(), castSize(nodep));
} else {
insureCast(nodep->lhsp());
}
nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin()==1) {
// We want to avoid a GCC "converting of negative value" warning
// from our expansion of
// out = {32{a<b}} => out = - (a<b)
insertCast(nodep->lhsp(), castSize(nodep));
} else {
insureCast(nodep->lhsp());
}
}
virtual void visit(AstVarRef* nodep) {
if (!nodep->lvalue()
if (!nodep->lvalue()
&& !VN_IS(nodep->backp(), CCast)
&& VN_IS(nodep->backp(), NodeMath)
&& !VN_IS(nodep->backp(), ArraySel)
&& nodep->backp()->width()
&& castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
&& nodep->backp()->width()
&& castSize(nodep) != castSize(nodep->varp())) {
// Cast vars to IData first, else below has upper bits wrongly set
// CData x=3; out = (QData)(x<<30);
insertCast(nodep, castSize(nodep));
}
nodep->user1(1);
}
nodep->user1(1);
}
virtual void visit(AstConst* nodep) {
// Constants are of unknown size if smaller than 33 bits, becase
// we're too lazy to wrap every constant in the universe in
// ((IData)#).
nodep->user1(nodep->isQuad() || nodep->isWide());
// Constants are of unknown size if smaller than 33 bits, because
// we're too lazy to wrap every constant in the universe in
// ((IData)#).
nodep->user1(nodep->isQuad() || nodep->isWide());
}
// NOPs
@@ -170,7 +170,7 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
explicit CastVisitor(AstNetlist* nodep) {
iterate(nodep);
}
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CAST_H_
#define _V3CAST_H_ 1
@@ -34,4 +34,4 @@ public:
static void castAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+431 -422
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -17,7 +17,7 @@
// GNU General Public License for more details.
//
//*************************************************************************
#ifndef _V3CDC_H_
#define _V3CDC_H_ 1
@@ -34,4 +34,4 @@ public:
static void cdcAll(AstNetlist* nodep);
};
#endif // Guard
#endif // Guard
+161 -151
View File
@@ -20,16 +20,16 @@
// V3Changed's Transformations:
//
// Each module:
// Each combo block
// For each variable that comes from combo block and is generated AFTER a usage
// Add __Vlast_{var} to local section, init to current value (just use array?)
// Change = if any var != last.
// If a signal is used as a clock in this module or any
// module *below*, and it isn't a input to this module,
// we need to indicate a new clock has been created.
// Each combo block
// For each variable that comes from combo block and is generated AFTER a usage
// Add __Vlast_{var} to local section, init to current value (just use array?)
// Change = if any var != last.
// If a signal is used as a clock in this module or any
// module *below*, and it isn't a input to this module,
// we need to indicate a new clock has been created.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
@@ -47,56 +47,60 @@
class ChangedState {
public:
// STATE
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstCFunc* m_chgFuncp; // Change function we're building
AstCFunc* m_tlChgFuncp; // Top level change function we're building
int m_numStmts; // Number of statements added to m_chgFuncp
int m_funcNum; // Number of change functions emitted
AstNodeModule* m_topModp; // Top module
AstScope* m_scopetopp; // Scope under TOPSCOPE
AstCFunc* m_chgFuncp; // Change function we're building
AstCFunc* m_tlChgFuncp; // Top level change function we're building
int m_numStmts; // Number of statements added to m_chgFuncp
int m_funcNum; // Number of change functions emitted
ChangedState() {
m_topModp = NULL;
m_chgFuncp = NULL;
m_scopetopp = NULL;
m_tlChgFuncp = NULL;
m_numStmts = 0;
m_funcNum = 0;
m_topModp = NULL;
m_chgFuncp = NULL;
m_scopetopp = NULL;
m_tlChgFuncp = NULL;
m_numStmts = 0;
m_funcNum = 0;
}
~ChangedState() {}
void maybeCreateChgFuncp() {
// Don't create an extra function call if splitting is disabled
if (!v3Global.opt.outputSplitCFuncs()) {
m_chgFuncp = m_tlChgFuncp;
return;
}
if (!m_chgFuncp || v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_chgFuncp = new AstCFunc(m_scopetopp->fileline(), "_change_request_" + cvtToStr(++m_funcNum), m_scopetopp, "QData");
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_chgFuncp->symProlog(true);
m_chgFuncp->declPrivate(true);
m_scopetopp->addActivep(m_chgFuncp);
// Don't create an extra function call if splitting is disabled
if (!v3Global.opt.outputSplitCFuncs()) {
m_chgFuncp = m_tlChgFuncp;
return;
}
if (!m_chgFuncp || v3Global.opt.outputSplitCFuncs() < m_numStmts) {
m_chgFuncp = new AstCFunc(m_scopetopp->fileline(),
"_change_request_" + cvtToStr(++m_funcNum),
m_scopetopp, "QData");
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_chgFuncp->symProlog(true);
m_chgFuncp->declPrivate(true);
m_scopetopp->addActivep(m_chgFuncp);
// Add a top call to it
AstCCall* callp = new AstCCall(m_scopetopp->fileline(), m_chgFuncp);
callp->argTypes("vlSymsp");
// Add a top call to it
AstCCall* callp = new AstCCall(m_scopetopp->fileline(), m_chgFuncp);
callp->argTypes("vlSymsp");
if (!m_tlChgFuncp->stmtsp()) {
m_tlChgFuncp->addStmtsp(new AstCReturn(m_scopetopp->fileline(), callp));
} else {
if (!m_tlChgFuncp->stmtsp()) {
m_tlChgFuncp->addStmtsp(new AstCReturn(m_scopetopp->fileline(), callp));
} else {
AstCReturn* returnp = VN_CAST(m_tlChgFuncp->stmtsp(), CReturn);
if (!returnp) m_scopetopp->v3fatalSrc("Lost CReturn in top change function");
// This is currently using AstLogOr which will shortcut the evaluation if
// any function returns true. This is likely what we want and is similar to the logic already in use
// inside V3EmitC, however, it also means that verbose logging may miss to print change detect variables.
AstNode* newp = new AstCReturn(m_scopetopp->fileline(),
new AstLogOr(m_scopetopp->fileline(), callp,
returnp->lhsp()->unlinkFrBack()));
returnp->replaceWith(newp);
returnp->deleteTree(); VL_DANGLING(returnp);
}
m_numStmts = 0;
}
UASSERT_OBJ(returnp, m_scopetopp, "Lost CReturn in top change function");
// This is currently using AstLogOr which will shortcut the
// evaluation if any function returns true. This is likely what
// we want and is similar to the logic already in use inside
// V3EmitC, however, it also means that verbose logging may
// miss to print change detect variables.
AstNode* newp = new AstCReturn(m_scopetopp->fileline(),
new AstLogOr(m_scopetopp->fileline(), callp,
returnp->lhsp()->unlinkFrBack()));
returnp->replaceWith(newp);
returnp->deleteTree(); VL_DANGLING(returnp);
}
m_numStmts = 0;
}
}
};
@@ -106,112 +110,116 @@ public:
class ChangedInsertVisitor : public AstNVisitor {
private:
// STATE
ChangedState* m_statep; // Shared state across visitors
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
AstNode* m_varEqnp; // Original var's equation to get var value
AstNode* m_newLvEqnp; // New var's equation to read value
AstNode* m_newRvEqnp; // New var's equation to set value
uint32_t m_detects; // # detects created
ChangedState* m_statep; // Shared state across visitors
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
AstNode* m_varEqnp; // Original var's equation to get var value
AstNode* m_newLvEqnp; // New var's equation to read value
AstNode* m_newRvEqnp; // New var's equation to set value
uint32_t m_detects; // # detects created
// CONSTANTS
enum MiscConsts {
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
// Ok to increase this, but may result in much slower model
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
// Ok to increase this, but may result in much slower model
};
void newChangeDet() {
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "<<m_vscp->prettyName()<<endl
<<m_vscp->warnMore()
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased"<<endl);
return;
}
m_statep->maybeCreateChgFuncp();
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "
<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "
<<m_vscp->prettyName()<<endl
<<m_vscp->warnMore()
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased"<<endl);
return;
}
m_statep->maybeCreateChgFuncp();
AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(),
m_varEqnp->cloneTree(true),
m_newRvEqnp->cloneTree(true), false);
m_statep->m_chgFuncp->addStmtsp(changep);
m_statep->m_chgFuncp->addStmtsp(changep);
AstAssign* initp = new AstAssign(m_vscp->fileline(),
m_newLvEqnp->cloneTree(true),
m_varEqnp->cloneTree(true));
m_statep->m_chgFuncp->addFinalsp(initp);
EmitCBaseCounterVisitor visitor(initp);
m_statep->m_numStmts += visitor.count();
m_statep->m_chgFuncp->addFinalsp(initp);
EmitCBaseCounterVisitor visitor(initp);
m_statep->m_numStmts += visitor.count();
}
virtual void visit(AstBasicDType* nodep) {
newChangeDet();
newChangeDet();
}
virtual void visit(AstPackArrayDType* nodep) {
newChangeDet();
newChangeDet();
}
virtual void visit(AstUnpackArrayDType* nodep) {
for (int index=0; index < nodep->elementsConst(); ++index) {
AstNode* origVEp = m_varEqnp;
AstNode* origNLEp = m_newLvEqnp;
AstNode* origNREp = m_newRvEqnp;
for (int index=0; index < nodep->elementsConst(); ++index) {
AstNode* origVEp = m_varEqnp;
AstNode* origNLEp = m_newLvEqnp;
AstNode* origNREp = m_newRvEqnp;
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
iterate(nodep->subDTypep()->skipRefp());
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
m_varEqnp = origVEp;
m_newLvEqnp = origNLEp;
m_newRvEqnp = origNREp;
}
m_varEqnp = origVEp;
m_newLvEqnp = origNLEp;
m_newRvEqnp = origNREp;
}
}
virtual void visit(AstNodeClassDType* nodep) {
if (nodep->packedUnsup()) {
newChangeDet();
} else {
if (debug()) nodep->dumpTree(cout,"-DETECTARRAY-class-");
if (nodep->packedUnsup()) {
newChangeDet();
} else {
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-class-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
" (probably with UNOPTFLAT warning suppressed): "
<<m_vscp->varp()->prettyName());
}
<<m_vscp->varp()->prettyNameQ());
}
}
virtual void visit(AstNode* nodep) {
iterateChildren(nodep);
if (debug()) nodep->dumpTree(cout,"-DETECTARRAY-general-");
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
" (probably with UNOPTFLAT warning suppressed): "
<<m_vscp->varp()->prettyName());
<<m_vscp->varp()->prettyNameQ());
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
m_statep = statep;
m_vscp = vscp;
m_detects = 0;
{
AstVar* varp = m_vscp->varp();
string newvarname = "__Vchglast__"+m_vscp->scopep()->nameDotless()+"__"+varp->shortName();
// Create: VARREF(_last)
// ASSIGN(VARREF(_last), VARREF(var))
// ...
// CHANGEDET(VARREF(_last), VARREF(var))
AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
m_statep->m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
m_statep->m_scopetopp->addVarp(m_newvscp);
m_statep = statep;
m_vscp = vscp;
m_detects = 0;
{
AstVar* varp = m_vscp->varp();
string newvarname = ("__Vchglast__"+m_vscp->scopep()->nameDotless()
+"__"+varp->shortName());
// Create: VARREF(_last)
// ASSIGN(VARREF(_last), VARREF(var))
// ...
// CHANGEDET(VARREF(_last), VARREF(var))
AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP,
newvarname, varp);
m_statep->m_topModp->addStmtp(newvarp);
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
m_statep->m_scopetopp->addVarp(m_newvscp);
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
}
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
}
iterate(vscp->dtypep()->skipRefp());
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
m_varEqnp->deleteTree();
m_newLvEqnp->deleteTree();
m_newRvEqnp->deleteTree();
}
virtual ~ChangedInsertVisitor() {}
};
@@ -223,61 +231,63 @@ class ChangedVisitor : public AstNVisitor {
private:
// NODE STATE
// Entire netlist:
// AstVarScope::user1() -> bool. True indicates processed
AstUser1InUse m_inuser1;
// AstVarScope::user1() -> bool. True indicates processed
AstUser1InUse m_inuser1;
// STATE
ChangedState* m_statep; // Shared state across visitors
ChangedState* m_statep; // Shared state across visitors
// METHODS
VL_DEBUG_FUNC; // Declare debug()
void genChangeDet(AstVarScope* vscp) {
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
ChangedInsertVisitor visitor (vscp, m_statep);
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: "<<vscp->prettyNameQ());
ChangedInsertVisitor visitor (vscp, m_statep);
}
// VISITORS
virtual void visit(AstNodeModule* nodep) {
UINFO(4," MOD "<<nodep<<endl);
if (nodep->isTop()) {
m_statep->m_topModp = nodep;
}
UINFO(4," MOD "<<nodep<<endl);
if (nodep->isTop()) {
m_statep->m_topModp = nodep;
}
iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) {
UINFO(4," TS "<<nodep<<endl);
// Clearing
AstNode::user1ClearTree();
// Create the change detection function
AstScope* scopep = nodep->scopep();
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
UINFO(4," TS "<<nodep<<endl);
// Clearing
AstNode::user1ClearTree();
// Create the change detection function
AstScope* scopep = nodep->scopep();
UASSERT_OBJ(scopep, nodep,
"No scope found on top level, perhaps you have no statements?");
m_statep->m_scopetopp = scopep;
// Create a wrapper change detection function that calls each change detection function
m_statep->m_tlChgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "QData");
m_statep->m_tlChgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_statep->m_tlChgFuncp->symProlog(true);
m_statep->m_tlChgFuncp->declPrivate(true);
m_statep->m_scopetopp->addActivep(m_statep->m_tlChgFuncp);
// Each change detection function needs at least one AstChangeDet
// to ensure that V3EmitC outputs the necessary code.
m_statep->maybeCreateChgFuncp();
m_statep->m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false));
// Create a wrapper change detection function that calls each change detection function
m_statep->m_tlChgFuncp = new AstCFunc(nodep->fileline(),
"_change_request", scopep, "QData");
m_statep->m_tlChgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_statep->m_tlChgFuncp->symProlog(true);
m_statep->m_tlChgFuncp->declPrivate(true);
m_statep->m_scopetopp->addActivep(m_statep->m_tlChgFuncp);
// Each change detection function needs at least one AstChangeDet
// to ensure that V3EmitC outputs the necessary code.
m_statep->maybeCreateChgFuncp();
m_statep->m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false));
iterateChildren(nodep);
}
virtual void visit(AstVarScope* nodep) {
if (nodep->isCircular()) {
UINFO(8," CIRC "<<nodep<<endl);
if (!nodep->user1SetOnce()) {
genChangeDet(nodep);
}
}
if (nodep->isCircular()) {
UINFO(8," CIRC "<<nodep<<endl);
if (!nodep->user1SetOnce()) {
genChangeDet(nodep);
}
}
}
virtual void visit(AstNodeMath* nodep) {
// Short-circuit
// Short-circuit
}
//--------------------
// Default: Just iterate
@@ -286,9 +296,9 @@ private:
}
public:
// CONSTUCTORS
// CONSTRUCTORS
ChangedVisitor(AstNetlist* nodep, ChangedState* statep) {
m_statep = statep;
m_statep = statep;
iterate(nodep);
}
virtual ~ChangedVisitor() {}

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