summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2016-09-23 07:09:40 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2016-09-23 07:09:40 +0200
commit4f096fe65b77435daba019248273e547fa18d167 (patch)
tree52a8438cfecf42cc43e8ec6b9625d26bbd12159a
parentc89f61c730da973adc7cce93f0839db49683c761 (diff)
Squashed commit of the following:
commit 0c697b9eacacfebd69c9603c2cb79ec70311197d Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 20 09:29:56 2016 +0200 Added autotest.sh -I commit e788ad48855cf02ba426abef83077b7f4ec80fa3 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Sep 19 20:43:43 2016 +0200 Cosmetic fix in test_autotb.cc commit 2e244c2d8e8e57f185b4165267682536843c8616 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Sep 19 20:43:28 2016 +0200 Added yosys-smtbmc --noinfo and --dummy commit 5e155aa1214a586e0db50c27e9b487915032f08e Author: Clifford Wolf <clifford@clifford.at> Date: Mon Sep 19 10:20:20 2016 +0200 Avoid creating very long strings in test_autotb commit aaa99c35bdcde8bec9d44ca23814f323a4e09c75 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Sep 19 01:30:07 2016 +0200 Added $past, $stable, $rose, $fell SVA functions commit d009cdd6eef5a24a11584a543bab8543f3940f6c Author: Clifford Wolf <clifford@clifford.at> Date: Sun Sep 18 20:48:09 2016 +0200 Improved handling of SMT2 logics in yosys-smtbmc commit 13a03b84d402d4a9891e6513a44551572d3e92db Author: Clifford Wolf <clifford@clifford.at> Date: Sun Sep 18 18:48:59 2016 +0200 Added support for bus interfaces to "read_liberty -lib" commit 0ead5a9e44fecf0712658efd168ebd7868039867 Merge: 7bc88e8 d8ad889 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Sep 18 00:50:02 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 7bc88e81010d5e641a55da9fb99724a90a2a4efa Author: Clifford Wolf <clifford@clifford.at> Date: Sun Sep 18 00:48:36 2016 +0200 yosys-smtbmc: added -i support smtc files commit d8ad889594cb5746d3d0b1f7590eeaf63d13c64a Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 14 20:46:54 2016 +0200 Bugfix in techmap parameter handling commit d39db41df87113792c383fc2f127a3d42ae6dd0e Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 13 13:23:06 2016 +0200 Work-around for boolector bug commit d01e34136ecfecc3f155d3fe7c74e07346ecae4e Merge: 6f416c1 2c031cd Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 13 12:34:19 2016 +0200 Merge pull request #228 from Kmanfi/test Fix for modules with big interfaces. commit 2c031cd24f536a35a32ce3c78d548fa627265557 Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Tue Sep 13 13:13:27 2016 +0300 Fix for modules with big interfaces. commit 6f416c19537fcaab27b26d66c3144b468cec136a Author: Clifford Wolf <clifford@clifford.at> Date: Sun Sep 11 18:08:56 2016 +0200 Added missing :produce-models setting to smtio.py commit 5199aafca0579aceb3b4a2ad1af610bcb4ccfcd1 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Sep 10 16:24:08 2016 +0200 Minor improvements to smtio.py vcd writer commit b582f11074c1877888341cf6d3fdceb490e88a3e Author: Clifford Wolf <clifford@clifford.at> Date: Sat Sep 10 15:14:41 2016 +0200 fixed write_smt2 for (non-combinatorial) loops through hierarchical cells commit 3ceba145d54f725c90436c7322a67320d4308ce8 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Sep 8 18:08:15 2016 +0200 smt2 mem init bugfix commit 2c0d818296eda10f763287784b749a712bfeda98 Merge: 14bfd3c 9e72046 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Sep 8 11:17:05 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 14bfd3c5c159626a2b3b8dec3a446e0f7c4c7e0c Author: Clifford Wolf <clifford@clifford.at> Date: Thu Sep 8 11:16:12 2016 +0200 yosys-smtbmc meminit support commit 9e72046906bdb9a15054c6c54b0003bfdc3baf6e Merge: 209a3d9 df4ab16 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Sep 8 10:06:40 2016 +0200 Merge pull request #225 from Kmanfi/test Typo fix. commit df4ab169a7ae84f9380e658e3ac5958a3d3e57d3 Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Thu Sep 8 10:57:16 2016 +0300 Typo fix. commit 209a3d9ffcb5f7efbe60b0e0d45755329532535e Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 7 21:01:51 2016 +0200 Bugfix in "yosys-smtbmc --unroll" commit 6770d6e0f878b4e172bb04f1d0df5fa72f05e167 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 7 20:57:56 2016 +0200 Added "yosys-smtbmc --unroll" commit ceff7ecd91e152dfac1d80188e592667cbec0392 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 7 13:43:57 2016 +0200 Install celledges.h commit cb7dbf4070a7ca3658b7e473cb54f2eafb6c9ae3 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 7 12:42:16 2016 +0200 Improvements in assertpmux commit e2570ffb872382f190b98d89b2eb7995a5d46758 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 7 11:08:54 2016 +0200 Updated ABC to hg 8e08604f8ad3 commit ab18e9df7c55581a9713a332af425011793106a7 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Sep 7 00:28:01 2016 +0200 Added assertpmux commit f3f5a0204542da3b49e88bcf0b461b6476d45d63 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 6 17:43:24 2016 +0200 Added "tee +INT -INT" commit fc5281b3f7656dd5e245f4ab7d81f39a14693f6b Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 6 17:35:25 2016 +0200 Run log_flush() before solving in sat command commit d55a93b39ff331aea16d627de92b1cbee2be68db Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 6 17:35:06 2016 +0200 Bugfix in parsing of BLIF latch init values commit 97583ab7295499b1b78ac7035e6e0b37d7b87734 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 6 17:34:42 2016 +0200 Avoid creation of bogus initial blocks for assert/assume in always @* commit dcb5a6ea8aaf857ea02f2a6c789e2a13ce501299 Author: Larry Doolittle <ldoolitt@recycle.lbl.gov> Date: Mon Sep 5 19:58:18 2016 -0700 Fix spelling and grammar in README commit 97b449fe55384d6637db8a0850ed33a4c864bbc3 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Sep 6 01:40:31 2016 +0200 yosys-smtbmc: flush stdout after each log msg commit 372d672c2a73314aa4a796357ae09f1570527500 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Sep 4 16:32:47 2016 +0200 Minor bugfix in write_smt2 commit 19a3b3732cc0ab25858b99ce29a172abcfe1fd43 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Sep 3 18:49:53 2016 +0200 Minor README updates commit fa5565b606bf58de1e1150c937afe014fcd928b6 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Sep 3 14:26:00 2016 +0200 Added boolector support to yosys-smtbmc commit d2eba7631ff8bfb897db72f787ca365003176ca1 Merge: 2ee9bf1 068d5bc Author: Clifford Wolf <clifford@clifford.at> Date: Fri Sep 2 13:55:51 2016 +0200 Merge branch 'smtbmc-kmanfi' commit 068d5bc02ffea9ba627bbf7151fdb36500eae0f2 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Sep 2 13:54:24 2016 +0200 Made examples/smtbmc/demo1.v more interesting commit 948aac9e1eaed04aa8de08e62cfb078d6337e9c9 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Sep 2 13:46:56 2016 +0200 Don't re-create hex_dict for each value commit d88cd0ae7f8761637722d5d2c6cc1c8bac762ce3 Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Fri Sep 2 13:09:09 2016 +0300 More PEP 8 fixes. commit c4ba1965fd4300cb7de48cde996bb068d951967d Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Fri Sep 2 13:01:31 2016 +0300 Indentation and PEP 8 fixes. CamelCase and white space after semicolon. commit 2343dda946e5ff335573c6b047d299bb90c98b1e Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Fri Sep 2 12:50:23 2016 +0300 Use dict lookup instead of many ifs. commit 279298c0b85250fd0c4e3637d10f9cf24e832259 Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Fri Sep 2 11:12:30 2016 +0300 Fix: Unresolved reference. commit 74dd36ad5555ceae0ce153e67bf26d594e9f09da Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Fri Sep 2 11:02:19 2016 +0300 Some syntax fixes. Generator and comma separated list modifications. commit 2ee9bf10d029396ba03b1d3023f15ff585e26bcb Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 23:57:24 2016 +0200 Added "prep -nomem" commit aa25a4cec66bfde84f9142b21679e82ba90ee910 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 19:27:42 2016 +0200 Added $anyconst support to yosys-smtbmc commit 6f41e5277d1d41db7a620c73cf1b65558b55f236 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 19:09:56 2016 +0200 Removed $aconst cell type commit a8124c137e2bfa3605dacadfe469ea22934b4cb3 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 14:49:47 2016 +0200 Fixed memory bug in write_smt2 commit b04a40d9fe6725dbe1b97a63931b0c0710e3149d Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 12:40:09 2016 +0200 Made "write_smt2 -bv -mem" default, added "write_smt2 -nobv -nomem" commit 39e4faa2e4c51c9588df233c795b4e85523879cf Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 11:26:10 2016 +0200 Added $anyconst support to smt2 back-end commit 4ea7054b56c568e15ffe9ee3560fd458fabcdf00 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 30 01:34:04 2016 +0200 Improved init spec handling in opt_rmdff, modernized the code a bit commit c417421495c3510add13859b2e33983880b4a224 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 29 22:41:45 2016 +0200 Added "yosys-smtbmc --dump-all" commit b226893461af46f2183be8ca9dfab62b49133c71 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 29 14:53:32 2016 +0200 More yosys-smtbmc bugfixes commit a2e2fc5980e3465011d7373be34e2d018240ede4 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 29 13:53:12 2016 +0200 Various fixes and improvements in yosys-smtbmc commit eae390ae17839bf0273b32149f46a2560a23d934 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 28 21:35:33 2016 +0200 Removed $predict again commit 66582964bc11aadf3d0783a346706d801451a13f Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 28 12:34:36 2016 +0200 Improved "show" help message commit f56dba8e2053d12fbd8e1e9b7dc83f3e4e340f3d Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 27 22:04:15 2016 +0200 Some changes to yosys-smtbmc cmd line options, add --final-only commit 23afeadb5e01a7b816c6ae203746caa8ae2aaed7 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 27 17:06:22 2016 +0200 Fixed handling of transparent bram rd ports on ROMs commit adcda6817e0df097bf70f8c200edcf15341f3188 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 27 14:30:36 2016 +0200 Added smtc "final" statement commit 7500b403de9eeafcc3de2a8eba051a03d5f5f10e Merge: 1276c87 3356d39 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Aug 26 23:36:15 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 3356d3947bc8cd343019587f5fc33b8ca27afdb3 Merge: 17233b1 ee620c6 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Aug 26 23:36:05 2016 +0200 Merge pull request #215 from frznchckn/to_upstream Add some useful flexibility to build process commit 1276c87a56f6f6d1a134877f024d2af785354570 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Aug 26 23:35:27 2016 +0200 Added read_verilog -norestrict -assume-asserts commit ee620c6a24a62725f6f41b43728fe7ce4112e130 Author: Russell L Friesenhahn <russellf@arlut.utexas.edu> Date: Fri Aug 26 11:15:36 2016 -0500 Relax test to see if yosys dir is a git repository in Makefile This prevents the test from failing in the case that yosys is a submodule of a repository since for a submodule the .git is actually a file containing the location of the submodule's .git directory commit 23f217b1668415009a7a842b66012686c2f2d5b0 Author: Russell L Friesenhahn <russellf@arlut.utexas.edu> Date: Tue Aug 16 22:07:36 2016 -0500 Allow redefining of the ABC repository URL For persons or organizations that prefer to keep their own mirrors of repositories, users may now specify the URL of the ABC Mercurial repository that yosys clones during build. The URL may be set in the Makefile directly, on the command-line, or in the environment commit 17233b11e185d2c863ccd06830e8cd0d2be38e83 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Aug 26 17:33:02 2016 +0200 Various fixes and improvements in smt2 back-end commit 4be4969bae5d99af572ca99859dc4a550c24d4cf Author: Clifford Wolf <clifford@clifford.at> Date: Thu Aug 25 11:44:25 2016 +0200 Improved verilog parser errors commit ad56ad44c3bdd3d075a32879785a04e3e30491eb Author: Clifford Wolf <clifford@clifford.at> Date: Wed Aug 24 23:18:29 2016 +0200 More yosys-smtbmc smtc features commit ee3e7a0e45e764c2655391b0e444e4379c97fe3c Author: Clifford Wolf <clifford@clifford.at> Date: Wed Aug 24 22:09:50 2016 +0200 yosys-smtbmc --smtc -g commit cd18235f30221ea2a5d51ab8b1d2639f51f1e99d Author: Clifford Wolf <clifford@clifford.at> Date: Wed Aug 24 15:30:08 2016 +0200 Added SV "restrict" keyword commit 6523023645bd2227cac68f46364dff3867d9641a Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 22 17:45:01 2016 +0200 Minor yosys-smtbmc bugfix commit 583ceee6eb69fb8093f7d184d737ea93e2744c5b Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 22 17:27:43 2016 +0200 Added "yosys-smtbmc --constr" commit 2bd30e20261240057752f124506c8b38af95afc4 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 22 16:48:46 2016 +0200 Added "yosys-smtbmc --dump-constr" commit f8a77abfac6da12e2e11c43b4e6aa6e613ac0d4b Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 22 15:05:57 2016 +0200 Added glob support to all front-ends commit 450f6f59b494af14014f0cbe93df4ceca0eecd76 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 22 14:27:46 2016 +0200 Fixed bug with memories that do not have a down-to-zero data width commit cad40fc87449e69a086a627bfb25aa49ae400753 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 22 14:26:33 2016 +0200 Fixed bug in memory_share for memory ports with different ABITS commit 7a33b9892a7a542ca1ac0b503c4368a1721a9afb Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 21 15:56:22 2016 +0200 yosys-smtbmc: improved --dump-vlogtb handling of memories commit cdd0b85e47d6c1718ec5c0d2d80c87af3e3bbc83 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 21 13:45:46 2016 +0200 Added another mem2reg test case commit 82a4a0230feedd994546ad57a1f4ae79b8f80136 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 21 13:23:58 2016 +0200 Another bugfix in mem2reg code commit dbdd8927e78622885bc85c429e783b89b2d3022d Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 21 13:18:09 2016 +0200 Minor improvements to AstNode::dumpAst() and AstNode::dumpVlog() commit a93fcec93fdd5da581ece4a593369978db9dd42c Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 18:44:27 2016 +0200 Added examples/smtbmc/demo2.v commit f7578b0239720562571d88d5a0406488075a2a31 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 18:43:39 2016 +0200 Added "yosys-smtbmc --dump-vlogtb" commit ed785194def450e68f217a3ae1764b5c5a679298 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 18:42:32 2016 +0200 Added support for memories to smtio.py commit c325bae792a953037c115ad6763081c7ad15f01c Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 18:41:57 2016 +0200 Deprecated "write_smt2 -regs" (by default on now), and some other smt2 back-end improvements commit 28271e43c9876daad3deddd0668188406e56b8ae Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 16:32:50 2016 +0200 Added "yosys-smtbmc -g" commit a889acb897b742f8d17ebccb0fb0d0a8e622fb70 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 16:07:59 2016 +0200 Added smtbmc longopt support commit fe9315b7a19bcb6dcde1a1ce49dd23f999bda7eb Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 13:47:46 2016 +0200 Fixed finish_addr handling in $readmemh/$readmemb commit 75bf7416f0dcf7b5bf3e095779f78039c75c316c Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 13:06:06 2016 +0200 Bugfix in partial mem write handling in verilog back-end commit d77a914683207ab9e4be20d8a10573acd8af777a Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 20 12:52:50 2016 +0200 Added "wreduce -memx" commit 15ef6084533809894dd0b5200a65497047c2ccf8 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Aug 19 19:48:26 2016 +0200 Added memory_memx pass, "memory -memx", and "prep -memx" commit f6629b9c29838879cec6a94d6cb47afc6fbd2db4 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Aug 19 18:38:25 2016 +0200 Optimize memory address port width in wreduce and memory_collect, not verilog front-end commit 9b8e06bee177f53c34a9dd6dd907a822f21659be Author: Clifford Wolf <clifford@clifford.at> Date: Thu Aug 18 21:47:02 2016 +0200 Added missing support for mem read enable ports to verilog back-end commit b3a01451a54506addf7493d4e3abaa621aa5689c Author: Clifford Wolf <clifford@clifford.at> Date: Thu Aug 18 13:43:12 2016 +0200 Bugfix in test_autotb commit de8ee412c30e92efe3a3e1434c0f4b495f8cdbbe Author: Clifford Wolf <clifford@clifford.at> Date: Thu Aug 18 11:17:45 2016 +0200 Improved smtbmc vcd generation performance commit dfcd30ea869f43af520aef033aa1311457112904 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Aug 17 20:10:02 2016 +0200 Added printing of code loc of failed asserts to yosys-smtbmc commit 42a971226bd1972c3c21d386c02c1bc2ac850129 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 22:44:38 2016 +0200 Fixed default build config commit 1419f3983ef28cf8c9ec8837010bef498f085b63 Merge: 5767e4b 5299b17 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 22:41:53 2016 +0200 Merge pull request #203 from cr1901/master Add MSYS2-compatible build. commit 5299b170568bd1de71c906eeb8929a053febc039 Author: William D. Jones <thor0505@comcast.net> Date: Tue Aug 16 14:41:37 2016 -0400 Add MSYS2-compatible build. commit 5767e4bc4db8d70bd02945769b6784618f7d003a Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 09:36:49 2016 +0200 Use _Exit(0) on win32, always use _Exit(1) in log_error() commit 5531bd757808499c23d082c4aa3566cfd5e5ec70 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 09:08:26 2016 +0200 Updated ABC to hg rev a86455b00da5 commit 00f29d5e5cdd08a14aa02119f46f8ee10cd1368d Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 09:07:13 2016 +0200 Fixed use-after-free dict<> usage pattern in hierarchy.cc commit b4d544f0d90d50059d95520d863924bffa3122ac Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 00:56:42 2016 +0200 Updated ABC to hg rev 760ba358e790 commit 4561586eedb32fc5525cae87fded69860f609686 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 00:52:10 2016 +0200 ABC mxe cross-build fix commit 321e15b0bfe84bf3b34b3a24d90ff55fe90de7cd Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 16 00:36:24 2016 +0200 Minor fixes in show command commit 5d90a5b9058d0e47643026b3439644cf974566a4 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 15 09:33:06 2016 +0200 Added greenpak4_dffinv commit f0a8713fea9fea016e5a83fefd9e00a32f4a88d2 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 15 08:26:20 2016 +0200 Fixed upto handling in verilog back-end commit 1058660ac882d97bd41737627c6246948edcab90 Merge: 6ac67ea 0b0ba96 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Aug 14 15:49:08 2016 +0200 Merge pull request #200 from azonenberg/master Updates to GP_RCOSC, new GP_DFF*I cells commit 0b0ba964881ce2996ee2feb1a5ca91c21669f0f7 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sun Aug 14 00:30:45 2016 -0700 greenpak4: Changed name of inverted output ports for consistency commit 3b9756c6a3ae1d1f5b6e530d4b50e07710b44987 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sun Aug 14 00:11:44 2016 -0700 greenpak4: Added GP_DFFxI cells commit 2b062c48cb4405f4a1bb6bd49edaf687bbc2cc4e Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Aug 13 22:27:58 2016 -0700 greenpak4: Renamed ports for better consistency (see azonenberg/openfpga:#6) commit 6ac67eac10cfd3e9508ef02f6301455fc3c13451 Merge: e9fe57c 0515809 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Aug 11 11:17:44 2016 +0200 Merge pull request #198 from whitequark/master synth_greenpak4: use attrmvcp to move LOC from wires to cells commit 0515809448d11beae27a6199ea02c59b36b58299 Author: whitequark <whitequark@whitequark.org> Date: Wed Aug 10 20:09:35 2016 +0000 synth_greenpak4: use attrmvcp to move LOC from wires to cells. commit e9fe57c75e225f80156ceabbc10741c3cfee1c87 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Aug 10 19:32:11 2016 +0200 Only allow posedge/negedge with 1 bit wide signals commit 73b7232ec89d9e3611ee5dbbc0cf663a33b09c8f Author: Clifford Wolf <clifford@clifford.at> Date: Wed Aug 10 13:44:08 2016 +0200 Fixed some compiler warnings in attrmap command commit b0aab4e3046f1a598314e2563fa84b3a8ddc7fa5 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 9 19:56:55 2016 +0200 Added "attrmap" command commit 39da8eddaefc078c6f7aba9958c40daec69f33d4 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 9 19:56:10 2016 +0200 Added log_const() API commit 3c6d31fd061fb591a95b08ecfd1d2e50690dfc48 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 9 11:18:48 2016 +0200 Added "attrmvcp" pass commit f7730d43bb4d5b44ec76e1080f4baf2f6b26807f Author: Yury Gribov <tetra2005@gmail.com> Date: Sun Aug 7 21:34:33 2016 +0100 Use /proc/self/exe on Cygwin as well. commit 9d15529214f164701ac4f53d0f3a5d4943b8f8dd Author: Clifford Wolf <clifford@clifford.at> Date: Mon Aug 8 11:47:35 2016 +0200 Undo "preserve wire attributes in iopadmap" change (it was OK before) commit 88a67afa7d044bd1abb952d7c709876e4159db1a Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 6 13:32:29 2016 +0200 Added "test_autotb -seed" (and "autotest.sh -S") commit 90c17aad56b0bf4b3ace5dea8c2d8555b52d4bfb Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 6 13:24:59 2016 +0200 preserve wire attributes in iopadmap commit 7f755dec75824e27dd79173a76d5819bf7fdbd27 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Aug 6 13:16:23 2016 +0200 Fixed bug in parsing real constants commit 5d6765a9d20ab2a88c02d06cb58fca2bfaf39c8d Author: Clifford Wolf <clifford@clifford.at> Date: Tue Aug 2 10:37:19 2016 +0200 Added "insbuf" command commit 21e1bac0846e01fb58ae1fd42215b92f245ae18d Merge: 5fe13a1 da56a5b Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 30 12:50:39 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 5fe13a16eaaee4ac53523b5325cb9d92b5a1150d Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 30 12:46:06 2016 +0200 Added "write_verilog -defparam" commit 7fa61cba1bd9c29a6a9516a75003db576f673b4c Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 30 12:38:40 2016 +0200 Added "write_verilog -nodec -nostr" commit da56a5bbc60e58c305227105b68654264738c241 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 27 16:11:37 2016 +0200 Added $initstate support to smtbmc flow commit 8d88fcb27011a6f8f47a8615c30ab658fafab0f2 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 27 15:52:20 2016 +0200 Added SatGen support for $anyconst commit 9540be1d45cce45d0008a4160bc4aa70ff0dfe1d Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 27 15:44:11 2016 +0200 Removed $predict support from SatGen commit 40563129872f5a2287f54cb0dbd79534b493a5d6 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 27 15:41:22 2016 +0200 Added $anyconst and $aconst commit a7b07696238dbfd8e4fb5fd41d597200abef4909 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 27 15:40:17 2016 +0200 Added "read_verilog -dump_rtlil" commit 8537c4d2061db1ee11defc357781c6c534be5b3d Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jul 25 16:39:25 2016 +0200 Renamed AbstractCellEdgesDatabase::add_cell() to add_edges_from_cell() commit 5b944ef11b8964a00d833ad29c96ad46da06f7a3 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jul 25 16:37:58 2016 +0200 Fixed a verilog parser memory leak commit 7a67add95d3d2f3293f84e38b891024d6444d2a4 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jul 25 12:48:03 2016 +0200 Fixed parsing of empty positional cell ports commit b1c432af5613b0e5817ccc35bb081737dfcb6867 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jul 24 17:21:53 2016 +0200 Improvements in CellEdgesDatabase commit f162b858f22e66dd553973c1275fc7994fc615f1 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jul 24 13:59:57 2016 +0200 Added CellEdgesDatabase API commit 54966679df103781f0c8d72079aedd84a9dc0ec6 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jul 24 12:18:39 2016 +0200 Moved SatHelper::setup_init() code to SatHelper::setup() commit 34e833103b77b06972ead21a9373c5541cb5ee7d Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 23 17:01:03 2016 +0200 Added $initstate support to "sat" command commit 9aae1d1e8ff1afa15459e5463397d1557ba8a361 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 23 11:56:53 2016 +0200 No tristate warning message for "read_verilog -lib" commit 89deb412c68505a0c66e92a93a334e08370f0e6b Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 22 10:28:45 2016 +0200 Added satgen initstate support commit 7fef5ff10436a51a91f57157f687345795f60e40 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Jul 21 14:37:28 2016 +0200 Using $initstate in "initial assume" and "initial assert" commit 5c166e76e52cdaf6ea97952c17d3d79185a59f96 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Jul 21 14:23:22 2016 +0200 Added $initstate cell type and vlog function commit d7763634b68a735443c61aa32918ee0cdd6e9250 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Jul 21 13:34:33 2016 +0200 After reading the SV spec, using non-standard predict() instead of expect() commit 721f1f5ecfb6334904f6058d6d376d21b5efc438 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 13 16:56:17 2016 +0200 Added basic support for $expect cells commit b3155af5f65333d272da339222e1e1962fb088b7 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 13 09:49:05 2016 +0200 Added examples/smtbmc commit 2afc72cae31720d7eacb0423a0dc87d4eccb1aa1 Merge: 9e5c947 546233f Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 13 09:39:27 2016 +0200 Merge pull request #191 from whitequark/json-module-attributes write_json: also write module attributes commit 9e5c9471e366e1abaad62525e783eb549274d951 Merge: e92998a 32bea97 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jul 13 09:24:31 2016 +0200 Merge pull request #193 from azonenberg/master Removed splitnets in synth_greenpak4, added GP_DAC, refactored GP_BANDGAP commit 32bea97b757e11002133d8e69b23eac3df7fb800 Merge: 52a738a e92998a Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Tue Jul 12 16:12:37 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit e92998a79cec635270a350117eddb52c6232f388 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Jul 12 09:46:15 2016 +0200 Minor bugfix in FSM reset state detection commit 546233f0e154cca0bacb4960faf54ba8d206c1fd Author: whitequark <whitequark@whitequark.org> Date: Tue Jul 12 06:32:04 2016 +0000 write_json: also write module attributes. commit 52a738a54435d9e54ac7cb523551ae866cc76770 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Jul 11 22:45:55 2016 -0700 Added GP_DAC cell commit baae472b83b3dac1293bb95ff0a87d9180a67479 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Jul 11 22:45:42 2016 -0700 Removed VOUT port of GP_BANDGAP commit 8619d33114edc58d89247ac3471d4115e1689a82 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Jul 11 22:42:25 2016 -0700 Removed splitnets in prep for new gp4par parser commit c71785d65e9775093b24ce684ed4fbe93bedb04d Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jul 11 12:49:33 2016 +0200 Yosys-smtbmc: Support for hierarchical VCD dumping commit 0153ad85d906105f5b4b520f6d62dbf646b2c285 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jul 11 11:49:05 2016 +0200 Moved smt2 yosys info parsing from smtbmc.py to smtio.py commit cdb58f68ab180deea6d13caa131aa0ea62cb2a8a Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jul 11 11:40:55 2016 +0200 Added "prep -auto-top" and "synth -auto-top" commit a72fb85dc2195a4519a8f360bd5f0846ef8d26a4 Merge: 771c5fe 307e31a Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jul 10 18:17:09 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 307e31a95e96165650798e68fd5bb22809f4127f Merge: b5a9fba c064583 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jul 10 18:12:00 2016 +0200 Merge pull request #189 from whitequark/master greenpak4: add GP_COUNT{8,14}_ADV cells commit 771c5fe0009cf2195e12be40b242662380681624 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jul 10 18:11:25 2016 +0200 Support for hierarchical designs in smt2 back-end commit c0645839fe499fbc37199744cab5c624e5840dba Author: whitequark <whitequark@whitequark.org> Date: Sun Jul 10 14:41:34 2016 +0000 greenpak4: add GP_COUNT{8,14}_ADV cells. commit b5a9fba0db5a8f29cffa22aa61f9d9cb7f69009a Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 9 14:02:49 2016 +0200 Further improved fsm_detect output, attempt to detect self-resetting circuits commit d63ffabacbe26aa5ade942940a44671427e2db7c Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 9 13:23:06 2016 +0200 Added printing of some warning messages to fsm_detect commit d3f0d7242732d8fb8885600c00c80c1aff8b5253 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 18:31:31 2016 +0200 Added warning about adding fsm_encoding attributes to wires to manual commit 21659847a7a31f80140e03a5b6351da54c062836 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 14:41:36 2016 +0200 Minor fixes in ice40_ff* passes for sloppy SB_DFF instantiations commit 9a101dc1f78acb404cc98e0acc4530c238070fd8 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 14:31:06 2016 +0200 Fixed mem assignment in left-hand-side concatenation commit b782076698b76445b6b1087671687483c6d6c545 Merge: e420412 27b5347 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 11:56:53 2016 +0200 Merge branch 'eddiehung-vtr' commit 27b5347a871d209ec4cba094e1203cc896c9c4b3 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 11:49:55 2016 +0200 Restored blif "-true - .." behavior, use "-true + .." for eddiehung-vtr behavior commit 72149aba2e8fece72450a81142a44d123154fd12 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 11:41:26 2016 +0200 In BLIF, a .names without entries already always outputs 0 commit 6bda61292513cbe7ffd69b4e3462b849757d2337 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 11:35:15 2016 +0200 Undo eddiehung-vtr Makefile changes commit f6b7cf23d65c8e86cbfb742f30167dcc89825cbd Merge: e420412 7c62318 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 8 11:32:36 2016 +0200 Merge branch 'yosys-0.5-vtr' of https://github.com/eddiehung/yosys into eddiehung-vtr commit e420412043228cec6a15b356cc9eea82bbafe9c0 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jul 2 13:32:20 2016 +0200 Fixed autotest.sh handling of `timescale commit 080f95f9332d9caae95095ab9935f78d3b60f204 Merge: df5ebfa 6ed6b3c Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 1 12:24:31 2016 +0200 Merge branch 'assert-limit' commit 6ed6b3cb6d1f1735201861d30cd70736b76e5221 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jul 1 12:24:13 2016 +0200 Replaced "select -assert-limit" with -assert-max and -assert-min commit 9a742f4069d6413bcf46b84c3b3f0e5cfc47f647 Author: eshellko <kornukhin@mail.ru> Date: Fri Jul 1 10:24:22 2016 +0400 Added 'assert-limit' option for 'select' command For resource limited designs such as FPGA it can be useful to specify limit of specific resources available on board. So user can check if he should change RTL as early as mapping done. commit df5ebfa0a0fc6d060caaa21b74a2f1a7b4ba0f86 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Jun 30 09:58:13 2016 +0200 Improved ice40_ffinit error reporting commit 7cddab0788cadc220ffa098c4ac037362ad6948e Merge: 541083c 545bcb3 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Jun 21 08:44:20 2016 +0200 Merge pull request #181 from rubund/input_logic_allowed Allow defining input ports as "input logic" in SystemVerilog commit 545bcb37e8fa569d88374f92aafdcc1004e9b587 Author: Ruben Undheim <ruben.undheim@gmail.com> Date: Mon Jun 20 20:16:37 2016 +0200 Allow defining input ports as "input logic" in SystemVerilog commit 541083cf329addb57117618de41697dd010d07cf Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jun 19 22:19:19 2016 +0200 Bugfix in "abc -script" handling commit 9bca8ccd40d70b6f6ad218cb9b1ae7dd4d3e8e68 Merge: ca91bcc a8200a7 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jun 19 15:48:40 2016 +0200 Merge branch 'sv_packages' of https://github.com/rubund/yosys commit ca91bccb6b03a0b098f80bf14b55a1444eef73c0 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Jun 19 13:08:16 2016 +0200 Added "deminout" commit a8200a773fb8cf2ce2d8793716b62e01c97dd731 Author: Ruben Undheim <ruben.undheim@gmail.com> Date: Sat Jun 18 14:13:36 2016 +0200 A few modifications after pull request comments - Renamed Design::packages to Design::verilog_packages - No need to include ast.h in rtlil.h commit 9e28290b0f4f6006897b46fd3ab8817a1c82b0b1 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jun 18 12:33:13 2016 +0200 Added "read_blif -sop" commit 5ffad4e0737bfb7e86129f3c74e7ee917ef782cc Author: Clifford Wolf <clifford@clifford.at> Date: Sat Jun 18 12:28:49 2016 +0200 Added $sop support to BLIF back-end commit 178ff3e7f6f9766f0b1a3e8dcc96e030aea59b15 Author: Ruben Undheim <ruben.undheim@gmail.com> Date: Sat Jun 18 10:24:21 2016 +0200 Added support for SystemVerilog packages with localparam definitions commit 3380281e15ca61cec8beda70938fb7b6f4c121d6 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 20:15:35 2016 +0200 Added "dc2" to default ABC scripts commit 7a4ee5da747382df323d41f60e974ef92bdc1e82 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 20:15:11 2016 +0200 Fixed init issue in mem2reg_test2 test case commit f498204ae462e2307f93c3ba8e6ba3b793b94d1f Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 19:39:35 2016 +0200 Added "abc -I <num> -P <num>" commit ebece2b8d5123aeb372df3ce226927bf3e6d09d6 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 17:47:30 2016 +0200 Added $sop SAT model commit 95757efb25dc51a73b384b475b0fc87d0e11d10e Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 16:31:16 2016 +0200 Improved support for $sop cells commit 52bb1b968d4bfbbbd84eca88f0e80c486cc1a16e Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 13:46:01 2016 +0200 Added $sop cell type and "abc -sop" commit c3365034e9db8b6450db578daefd860276d5071f Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 17 11:16:31 2016 +0200 Updated ABC to hg rev b5df6e2b76f0 commit 99edf249669158b8c8bef0c7c3b926a2bbb7a621 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Jun 9 11:47:41 2016 +0200 Added "nlutmap -assert" commit 52b0b4e31e98816bc15b957c89bca76619231143 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jun 8 12:14:32 2016 +0200 Do not run "wreduce" in "prep -ifx" commit 2032e6d8e46c0b715e73423cb34f4a624617df6e Author: Clifford Wolf <clifford@clifford.at> Date: Mon Jun 6 17:15:50 2016 +0200 Added "proc_mux -ifx" commit dcf576641b4a9b476d51fbe1b0cdfb57d02a76e6 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Jun 3 11:38:31 2016 +0200 Added "setundef -init" commit d2695e2bfa0c1bc8cbcb5cd8396b12a7f83959af Author: Clifford Wolf <clifford@clifford.at> Date: Thu Jun 2 14:37:07 2016 +0200 Fix all undef-muxes in dlatch input cone commit adfc80727c19021f911833305f5d322af6b8a0aa Author: Clifford Wolf <clifford@clifford.at> Date: Wed Jun 1 13:25:06 2016 +0200 Avoid creating undef-muxes when inferring latches in proc_dlatch commit 11f7b8a2a1dd6e5c47e8081e4485127331fd80be Author: Clifford Wolf <clifford@clifford.at> Date: Sun May 29 12:17:36 2016 +0200 Added opt_expr support for div/mod by power-of-two commit 766032c5f85e33c8aabb69d1868c3493f254695f Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 27 17:55:03 2016 +0200 Fixed procedural assignments to non-unique lvalues, e.g. {y,y} = {a,b} commit ee071586c55915c6535bad0a47bf80c8f2029272 Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 27 17:25:33 2016 +0200 Fixed access-after-delete bug in mem2reg code commit e9ceec26ffe773d36b5316c79149913777d6581f Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 27 16:37:36 2016 +0200 fixed typos in error messages commit 611f121cb9fb8a451e891356a6260f4b299afc7d Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 27 16:33:13 2016 +0200 Fixed "scc" for cells that have feedback singals _and_ are part of a larger loop commit 33742f4e8f5b39940a1dc6aa9582e94516cd0a5f Merge: 8e9e793 e22e4d5 Author: Clifford Wolf <clifford@clifford.at> Date: Sun May 22 18:15:08 2016 +0200 Merge pull request #172 from zeldin/deterministic_hierarchy Made the expansion order of hierarchy deterministic commit e22e4d59b8abe9ba60d32402d0ff9b84d266743d Author: Marcus Comstedt <marcus@mc.pp.se> Date: Sun May 22 16:37:47 2016 +0200 Made the expansion order of hierarchy deterministic commit 8e9e793126a2772eed4b041bc60415943c71d5ee Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 20 17:13:11 2016 +0200 Some fixes in tests/asicworld/*_tb.v commit 1e227caf720bc5870ea9244e6b5657cf9c9717ab Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 20 16:58:02 2016 +0200 Improvements and fixes in autotest.sh script and test_autotb commit 884ec967871dede8d5ad6fb730a405e421a18dbe Merge: f3983a0 8c3bc2a Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 20 16:48:50 2016 +0200 Merge branch 'master' of https://github.com/Kmanfi/yosys commit f3983a094052e875e05823a6063c1775d1f84b39 Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 20 16:43:13 2016 +0200 Also escape "=" in spice output commit 060bf4819a3742ba2ad8142c9a7e665555c22ac7 Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 20 16:21:35 2016 +0200 Small improvements in Verilog front-end docs commit 8c3bc2ac0da4457f90775608e9701e0a7ba1e4cf Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Thu May 19 11:53:29 2016 +0300 Close opened dump file. commit f6221ade950411ed10e6f260971cff78b30b8666 Author: Kaj Tuomi <kaj.tuomi@siru.fi> Date: Thu May 19 11:34:38 2016 +0300 Fix for Modelsim transcript line warp issue #164 commit ffcdc53a18197e40571b9c604fff07408cc12346 Author: Clifford Wolf <clifford@clifford.at> Date: Sun May 15 00:05:30 2016 +0200 Don't sign-extend memory bram initialization data commit 864eeadcd9244505c7c026e2044799ff5bcf4782 Author: Clifford Wolf <clifford@clifford.at> Date: Sat May 14 11:43:20 2016 +0200 Added missing "#define HASHLIB_H" commit d05115ceda2969badb83b3b2f0cefcd447c29451 Author: Clifford Wolf <clifford@clifford.at> Date: Sat May 14 11:35:39 2016 +0200 Minor presentation fixes commit 407cdea0bc3a3d2a258b30a3e19d0861c3c4ba6f Author: Clifford Wolf <clifford@clifford.at> Date: Wed May 11 09:31:53 2016 +0200 Updated min GCC requirement to GCC 4.8 commit b8b39472bb1b991ab96dede1b188868d9d98246b Author: Clifford Wolf <clifford@clifford.at> Date: Mon May 9 12:43:49 2016 +0200 Added manual download link to README commit 570014800aa34d71868d04f9ef83e4a13b847773 Author: Clifford Wolf <clifford@clifford.at> Date: Sun May 8 10:50:39 2016 +0200 Include <cmath> in yosys.h commit fa76d51941ce5e4076317195bd1b603bccb74f02 Merge: f103bfb 47eace0 Author: Clifford Wolf <clifford@clifford.at> Date: Sun May 8 10:22:01 2016 +0200 Merge pull request #162 from azonenberg/master Added GP_DELAY cell. Fixed several errors in simulation models. commit 47eace0b9f2b9ddd7ae76e06e2ade85ceea88e17 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat May 7 21:29:26 2016 -0700 Added GP_DELAY cell commit 41bbad4e4c25bc1b0227348ec0329187c8688c4b Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat May 7 21:14:42 2016 -0700 Fixed typo in port name commit b5171541cd9da6a4e2b5aaaaf3bca76e059c7e3f Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat May 7 21:14:18 2016 -0700 Fixed extra semicolon commit 85ee88b0ee13eb49bb255d7e66a62fce823c028a Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat May 7 21:14:00 2016 -0700 Fixed typo in parameter name commit a0c19aae55d878576c7481a6a4a5d10ba98c5224 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat May 7 21:13:47 2016 -0700 Added simulation timescale declaration commit f103bfb9baddcd5ff16e610bc314c3de9eb3d526 Author: Clifford Wolf <clifford@clifford.at> Date: Sat May 7 10:53:18 2016 +0200 Fixes for MXE build commit c3f6e0ea851b90b11671015f2bb472c857f0e2d9 Author: Clifford Wolf <clifford@clifford.at> Date: Sat May 7 09:33:16 2016 +0200 Added support for "keep" attribute to shregmap commit 6fe3d5a1cf938081110db0470def2b2687dd665f Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 6 23:02:37 2016 +0200 Added synth_ice40 support for latches via logic loops commit d10dfccabb6bf4b1ba3f334b899f57093b8a0ddc Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 6 15:05:53 2016 +0200 Added "write_blif -noalias" commit 126da0ad3dfb7b75aaaadc97c7d40b495da9d164 Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 6 14:32:32 2016 +0200 Fixed ice40_opt lut unmapping, added "ice40_opt -unlut" commit aadca148da35963888e362d6eb5a3982b1903c10 Author: Clifford Wolf <clifford@clifford.at> Date: Fri May 6 13:59:30 2016 +0200 Fixed preservation of important attributes in techmap commit ec1938737bcfb625d4e62afaefd30d67acb588bf Merge: 9647dc3 2096a05 Author: Clifford Wolf <clifford@clifford.at> Date: Thu May 5 18:18:48 2016 +0200 Merge pull request #159 from azonenberg/master Fixes to use new I/O pad techmapping, renamed ports for GP_SHREG commit 2096a05ec2aaecb89316c5a229b497c21c2327f9 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed May 4 17:13:54 2016 -0700 Changed order of passes for better handling of INIT attributes on "output reg" FFs commit 3486637b19030bc65af77c99c282ff5a7e610ee8 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed May 4 17:04:50 2016 -0700 Changed port names in greenpak shregmap commit dee1c27a19f91fb44df67b2ab9834ee8140772c4 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed May 4 17:03:45 2016 -0700 Renamed module parameter commit a613f171aeb8703b6849a87b73899389fb9912d8 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed May 4 15:55:16 2016 -0700 Refactored synth_greenpak4 to use iopadmap for mapping GP_IOBUF/GP_OBUFT cells instead of extract commit 9647dc3c07039c49b9bcf5932050467ca451ceef Author: Clifford Wolf <clifford@clifford.at> Date: Wed May 4 22:48:02 2016 +0200 Added tristate buffer support to iopadmap commit 86add2907276ab7c9ec2c2861901a7a7adedf0fa Merge: 7a74ae4 deb1ecc Author: Clifford Wolf <clifford@clifford.at> Date: Wed May 4 19:12:59 2016 +0200 Merge pull request #157 from azonenberg/master Added GP_ABUF cell, support for tri-state I/O buffers in GreenPak commit deb1eccab5bad3e5a090254e0d3a069a3c474d8b Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed May 4 08:06:18 2016 -0700 Fixed incorrect signal naming in GP_IOBUF commit 2db8dd6d354b8d29382054668ae34e7852b413a2 Merge: dcee325 7a74ae4 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed May 4 07:23:27 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 7a74ae4c5403ce68a8245c45359d49f80d6e863a Merge: 658f936 12000b9 Author: Clifford Wolf <clifford@clifford.at> Date: Wed May 4 10:48:42 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 658f93663b12d3199f636cad8bf75aa1ee58108b Author: Clifford Wolf <clifford@clifford.at> Date: Wed May 4 10:48:23 2016 +0200 Fixed iopadmap attribute handling commit dcee3256d59907c474542e0dfd24df7c047e6f50 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Tue May 3 22:53:29 2016 -0700 Added tri-state I/O extraction for GreenPak commit 66095153fd6110dbe84552175d4919f4f5fd75fc Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Tue May 3 22:03:04 2016 -0700 Added GreenPak I/O buffer cells commit 9fc9d5f1fb1eea47118c00ecad1352ec84fd3047 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon May 2 20:29:39 2016 -0700 Added comment to clarify GP_ABUF cell commit 79460208c928e62c608d71c0d6d484293835e8dc Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon May 2 20:27:41 2016 -0700 Added GP_ABUF cell commit 12000b90de0bade5fca641c49f3375316220ed39 Merge: 06d35ea 3a85e40 Author: Clifford Wolf <clifford@clifford.at> Date: Mon May 2 09:49:07 2016 +0200 Merge pull request #154 from azonenberg/master Add GP_PGA cell commit 3a85e40f42f4fa52934562135571cfcba35af80e Merge: fb87022 06d35ea Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sun May 1 10:07:21 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 06d35ea9425dbfeff8bcd0d842a31d22843b937b Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 29 10:26:22 2016 +0200 Improved TCL_VERSION detection so it does not read .tclshrc commit fb87022dca2bd8366cb006951e3f59c9f0540476 Merge: 134e093 e01464e Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 29 00:57:37 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit e01464e2ac2bf3bd2752e10b48d2fc3ffc4fdf9e Author: Clifford Wolf <clifford@clifford.at> Date: Thu Apr 28 23:17:30 2016 +0200 Added "qwp -v" commit 134e093e4e86080e1e4066f32128d268a36aeee5 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 27 23:07:21 2016 -0700 Added GP_PGA cell commit 0d2923cccd00ed14537f3239b0059a76673798a4 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 26 19:49:05 2016 +0200 Connections between inputs and inouts are driven by the input commit 958fb29c76a13838a922ff8553178d2c31c1ddef Author: Clifford Wolf <clifford@clifford.at> Date: Mon Apr 25 16:37:11 2016 +0200 Fixed test_autotb for modules with many cell ports commit 93e107e455b506731d9114e0dc2644f78797cf0f Author: Clifford Wolf <clifford@clifford.at> Date: Mon Apr 25 10:43:04 2016 +0200 Fixed proc_mux performance bug commit d086224a39fcd488062d7f75cc936cce5435069c Merge: b1d6f05 d57c851 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Apr 25 10:33:18 2016 +0200 Merge pull request #150 from azonenberg/master GreenPak analog comparator support commit d57c85111f4136e5ae098aa42cd337f82dd4b57e Merge: 349d717 b1d6f05 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sun Apr 24 22:11:56 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 349d7172023e9ee38b8e25e3bd04e2dfd0af1e62 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sun Apr 24 17:01:21 2016 -0700 Removed VIN_BUF_EN commit b1d6f05fa2156017f50383d01d49342c8ec5e209 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Apr 24 19:29:56 2016 +0200 Fixed performance bug in proc_dlatch commit 9aa4b3309c35d842e2b1a04172745a5e34a3c445 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Apr 24 17:12:34 2016 +0200 Added "yosys -D ALL" commit 6e215f374dcd92e2c1bff8ad6114f3d3dc9b06f5 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 23 22:53:49 2016 -0700 Renamed VOUT to OUT on GP_ACMP cell commit 512486dcf37f779e6271e299eb186ab2559eb344 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 23 22:33:36 2016 -0700 Added GP_ACMP cell commit 09ffebb9959510cacdc04c926800223235f50313 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Apr 24 00:48:33 2016 +0200 Added "prep -flatten" and "synth -flatten" commit 77aa2031e7e93b3d91b7594ad21d84e946b7cb04 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Apr 24 00:48:06 2016 +0200 Converted "prep" to ScriptPass commit 096c25d29d7e66003123dc4700ae72b0a4c10ca2 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 23 23:10:13 2016 +0200 Improvements in greenpak4 shreg mapping commit c9c5192cd63dc4c08441e94c8d53428503ccc4af Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 23 23:09:45 2016 +0200 Run clean after splitnets in synth_greenpak4 commit 7f16784f3c0151c9b7f2861965d73ce7c960ebb5 Merge: 421b0d7 e13c661 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 23 12:22:08 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit e13c66122ef4bc9cc8da77cda1d6bf594104acdb Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 23 20:20:21 2016 +0200 Added "shregmap -zinit" for greenpak4 tech commit 421b0d715c43fbcbfc1465518d444c9ca97cbabb Merge: 2849fd4 34195f2 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 23 10:18:15 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 34195f281fc4829f58c3dfc9c7944691044186e0 Merge: f85cfa5 0cbe70e Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 23 10:33:32 2016 +0200 Merge https://github.com/azonenberg/yosys commit f85cfa56667e32ff9e165f9d957d05bde25342c0 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 23 10:31:19 2016 +0200 Added "shregmap" to synth_greenpak4 commit a24021ea20bb70d0368c6b3e549a87fa5c4ab8ae Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 23 10:27:33 2016 +0200 Converted synth_greenpak4 to ScriptPass commit 2849fd486eaa1a77316cc6ffc86ec885b8a0d9fb Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 22 23:01:39 2016 -0700 Fixed typo in help text commit 0cbe70eaa40056a9d41070652282694cd7285b1a Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 22 19:08:19 2016 -0700 Fixed typo commit ab11f2aa701f4ff7a8df98d2a4158ea1f661a205 Merge: d90c1e9 7311be4 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 22 19:07:55 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 7311be4028a9caad5a0fac1a3433220b4233ef84 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 22 19:42:08 2016 +0200 Added "shregmap -tech greenpak4" commit 779e2cc819463fa5bc4ebfee397eb06368eb10b0 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 22 18:02:55 2016 +0200 Added support for "active high" and "active low" latches in BLIF front-end commit 60ac1bd178eef96b5cc34091dca7552cc3cad70f Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 22 18:00:46 2016 +0200 Added support for "active high" and "active low" latches in BLIF back-end commit 965b0d59b5da01dc34f01e01d723b75140df7c60 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 22 12:13:06 2016 +0200 More flexible handling of initialization values commit 0bc95f1e049afc35bb5ea30663b0a5725dfbf584 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Apr 21 23:28:37 2016 +0200 Added "yosys -D" feature commit 1565d1af69f552b790aa43fd6be194ee59ab76f3 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Apr 21 19:47:25 2016 +0200 Fixed performance bug in "share" pass commit 5a09fa45535ffceae90359be727d2ff6e0ac2c58 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Apr 21 15:31:54 2016 +0200 Fixed handling of parameters and const functions in casex/casez pattern commit f38ca3e18fb27472595d59be8c0cea7ef50b7c4c Author: Clifford Wolf <clifford@clifford.at> Date: Thu Apr 21 13:02:56 2016 +0200 Improvements in opt_expr commit 1761d08dd239bcf1765ebf807fc22514edac387f Author: Clifford Wolf <clifford@clifford.at> Date: Thu Apr 21 12:06:07 2016 +0200 Bugfix and improvements in memory_share commit d90c1e952256dc00d070863835e061d73e4bc6b3 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 20 20:48:19 2016 -0700 Added GP_VREF cell commit bf64974d43600b2e8ad63a1762489a152c002a41 Merge: f1fa757 8c9ac5d Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 19 10:37:04 2016 +0200 Merge pull request #149 from azonenberg/master GP_RCOSC and GP_SHREG cells plus some cleanup commit 8c9ac5db7bd97fce3bfe5040a238d4f08d726473 Merge: b2c36f6 f1fa757 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Apr 18 19:22:52 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit f1fa757d0e7de4fce01dd4c2b2ec8f1aed0fb1a6 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Apr 18 11:58:21 2016 +0200 Added "shregmap -params" commit 525651c8f6fc5a4f00f3c7b5208d6882f75ac736 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Apr 18 11:44:10 2016 +0200 Added "shregmap -zinit" and "shregmap -init" commit b2c36f6136d0fa3a6203197d78092bc1bb31e998 Merge: be57071 ce7c980 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sun Apr 17 08:15:34 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit ce7c980ec755c481182de9bd078e190bd8d9ff51 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Apr 17 15:37:22 2016 +0200 Improvements in "shregmap" commit be570712d82eafb28850d4400f2220991c3864a4 Merge: d0aaf8d de647a3 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 16 15:14:32 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit de647a390c654bcdb04255c89d5d970cb0c1ed24 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 16 23:20:49 2016 +0200 Added "shregmap" pass commit fbdb8e7b3ed94993228181f949506355989ef54b Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 16 23:20:34 2016 +0200 Fixed copy&paste error in log message in lut2mux commit a07f893a5fd018e426e1aa6de7ad986ea8acd468 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 16 23:20:11 2016 +0200 Minor hashlib bugfix commit d0aaf8d2621fd75b968700ec4cb8dd6acf568737 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 13 23:13:51 2016 -0700 Added GP_SHREG cell commit cdefa60367cf15b2e0a7fb35e4a42fe8358755b5 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 13 23:13:39 2016 -0700 Refactoring: alphabetized cells_sim commit f1679936fe3f40d7fab3438a00dad2fed5a5f00e Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 9 01:18:02 2016 -0700 Fixed missing semicolon commit c1b8d3b580601ad9ba61b247fa967efdfe19fcda Merge: 58d8715 3d9ff91 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 9 01:17:24 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 58d87156815871c47c0ea356ba50b738537adfab Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Apr 9 01:17:13 2016 -0700 Added GP_RCOSC cell commit 3d9ff912c208d330fea12c0149fbe352e9ea7c0a Merge: ace4622 01a5f71 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 8 11:58:40 2016 +0200 Merge pull request #147 from azonenberg/master Added GP_BANDGAP, GP_POR, GP_RINGOSC primitives commit 01a5f711871658c9997f7352414cd4ac50ed772c Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 6 23:42:22 2016 -0700 Fixed assertion failure for non-inferrable counters in some cases commit 48c10d90f4b8c813782d4c5a304b2e1e24d140d8 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 6 23:10:34 2016 -0700 Added second divider to GP_RINGOSC commit 1df559c7062b62a8b72b70d40d65da99667a2183 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 6 22:40:25 2016 -0700 Added GP_RINGOSC primitive commit f6a0f2cf73e8dde315493f113235bbfa27920391 Merge: c2b909c ace4622 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Apr 6 22:31:22 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit ace462237f1223a41f6d29d1fe29652fcf435882 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 5 13:25:23 2016 +0200 Hashlib indenting fix commit 38245b6733d9ec28ae1d37fb5ffba62b0aec791c Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 5 13:25:05 2016 +0200 Added msan origins tracking commit 6041f780c31525c1fc4d34b95317d7946466957b Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 5 12:51:04 2016 +0200 Prefer noninverting FFs in dfflibmap commit eaac5bfbc7faa7144a85590a94d14094899d197f Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 5 08:26:10 2016 +0200 Improved formatting of "sat" output tables commit 3920bf58d01ad9b34a7afba5bfa2f19ffff53240 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Apr 5 08:18:21 2016 +0200 Fixed some typos commit c2b909c051edf189d6e1f807bb367c3c543dc058 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Apr 4 21:46:07 2016 -0700 Added GP_POR commit c01ff05fabe948acfbbb259e92b3bd0009bd068e Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Apr 4 16:56:43 2016 -0700 Added GP_BANDGAP cell commit e4e6becba9259a125bfd2788d453f5ac33272d2f Merge: 27e0d29 71f9f40 Author: Clifford Wolf <clifford@clifford.at> Date: Sun Apr 3 17:16:26 2016 +0200 Merge pull request #145 from laanwj/master Add instructions for building manual on Ubuntu commit 71f9f40fa9e44351f7a9ebabff622c2569689745 Author: Wladimir J. van der Laan <laanwj@gmail.com> Date: Sun Apr 3 14:26:56 2016 +0200 Fix a few typos in the manual commit f9d7091c3b04fd9aa067ed1c087a29faac55d640 Author: Wladimir J. van der Laan <laanwj@gmail.com> Date: Sun Apr 3 14:26:46 2016 +0200 Add instructions for building manual on Ubuntu commit 27e0d29863bcf80520993574415f79b32312c5fb Merge: 7a4dd27 34667de Author: Clifford Wolf <clifford@clifford.at> Date: Sat Apr 2 10:19:36 2016 +0200 Merge pull request #144 from azonenberg/master Added COUNT_EXTRACT constraint to greenpak4_counters pass. Added support for inferring level-resettable counters. Fixed use-after-free. commit 34667ded53ca50d612dc71302544fdde744d853d Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 1 23:41:03 2016 -0700 Removed more debug prints commit 87e7cd9fbd6e603da262e68f7ec68eb0d7233c2c Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 1 23:39:32 2016 -0700 Removed forgotten debug code commit 2386885f228ebecccf4987ac81bde11df56dae38 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 1 21:18:29 2016 -0700 Added GreenPak inverter support commit b0a28c793cebcd1a7317b63b215151ce9ace3a42 Merge: 6dbcf50 7a4dd27 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 1 18:09:08 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 6dbcf50fa1ea8591d8d944234627e6918612060b Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 1 18:07:59 2016 -0700 Added support for inferring counters with asynchronous resets. Fixed use-after-free in inference pass. commit 7a4dd27b1b36e4e4667f31ee7b3c6e6bc3896f60 Merge: 2553319 f277267 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Apr 1 09:13:52 2016 +0200 Merge pull request #143 from azonenberg/master Fixed several techmapping issues irelated to greenpak flipflops commit f277267916b7b1c97fe90576abecde003cc231ab Merge: 736a998 2553319 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Fri Apr 1 00:03:00 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 736a998a75e12ca83b45b74a79e78fae8ab12d16 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Thu Mar 31 23:16:45 2016 -0700 DFFINIT is now correctly called for all kinds of flipflop, not just DFF commit 7498ff8041cdd464521a6802055a9893a0c6cf61 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Thu Mar 31 22:51:22 2016 -0700 Fixed incorrect port name in cells_map.v commit 25533190818b0fe207be9a4626a9a273a08ae219 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 11:16:34 2016 +0200 Added ScriptPass helper class for script-like passes commit 6cafd08ac1090f405168187632fab4308129c599 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 09:58:55 2016 +0200 Improved opt_merge support for $pmux cells commit 6f1b6dc322bf6cceeadef7c666b8ff333ec6f2bf Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 09:57:44 2016 +0200 Added log_dump() support for dict<> and pool<> containers commit e5dd5c0bcccd4e79921e6a28b550a5960a93ee07 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 09:57:23 2016 +0200 Preserve empty $pmux default cases commit e2f6d61c004776f2f573f3c5b70ad352ce6b4e1a Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 09:56:56 2016 +0200 Typo fixes in opt_expr and opt_merge commit c04a3d276320aa9aca4e3a678df3135b35473055 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 23:58:45 2016 -0700 Fixed typo (wasn't written in 2012) commit ec93680bd583b670e03ed98b4b1081eab8d0f3f6 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 08:52:49 2016 +0200 Renamed opt_share to opt_merge commit 1d0f0d668ade740c928c66c400476924abf62384 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 08:43:28 2016 +0200 Renamed opt_const to opt_expr commit d31c968d76e99d5c7288d0eb844e041bb36aa77d Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 08:00:59 2016 +0200 Fixed typo in greenpak4_counters.cc commit cecd0cf788a7fcefe6e88c32557fd844482a1c9c Merge: 0db5328 984561c Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 31 07:59:55 2016 +0200 Merge pull request #142 from azonenberg/master Add initial GreenPak4 counter inference, misc related fixes commit 984561c034bac0b996d8b2201105a795c6c0e00d Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 22:52:01 2016 -0700 Renamed counters pass to greenpak4_counters commit 1ae33344f4f18f4fbb899e4635659bf1cd8f0448 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 22:40:14 2016 -0700 Added initial implementation of "counters" pass to synth_greenpak4. Can only infer non-resettable down counters for now. commit 1b42e0c471ba81843e3fbd1869e84b36f8a24c2f Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 22:03:50 2016 -0700 Reduced log verbosity commit ad19e0c64ab69ab059efc258ae616f4fb5b8847d Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 21:54:23 2016 -0700 Continued work on counter extraction. Can recognize compatible RTL counters but not replace with hard macros. commit d16d05e41587a282a53eda59af837b7d264498fc Merge: 94a6923 0db5328 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 20:38:18 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 94a6923e7dd363c5b11116e9bd85aa012fed512a Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 20:30:25 2016 -0700 Updated tech lib for greenpak4 counter with some clarifications commit dd7204c0bdb65956fdf27925da3ccfe6f592d012 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 20:30:03 2016 -0700 Fixed typo in log message commit 0db53284fd610cac1e956a87c7eec7df3d8564c5 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 30 13:52:26 2016 +0200 We have 2016 for a while now commit 48dbc75beddd6db92f09125b49761859be33693d Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 30 13:24:49 2016 +0200 Added .vhd file extension support commit 489caf32c54ee250338eca72c5f0098106d17788 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Wed Mar 30 01:07:20 2016 -0700 Initial work on greenpak4 counter extraction. Doesn't work but a decent start commit 2c15a3a9d0aad62f92c37bd76b763d6c2cf079b1 Merge: a47f695 19c2023 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 30 10:02:18 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit a47f69536a1ac93657d334f57dac2a800ab34f3f Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 30 10:02:03 2016 +0200 Added support for installed plugins commit 3ea60266488fe7e0b040c379a11d523c11ec9460 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Tue Mar 29 20:02:59 2016 -0700 Added splitnets to synth_greenpak4 commit 19c20235b55648c150df294320b9f2515d2f3c5b Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 29 15:12:14 2016 +0200 Added more cell help messages commit 8c8b2e72b1b34f6219c87e7bd5b39620947cd787 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 29 13:44:14 2016 +0200 Fixed indenting in techlibs/greenpak4/gp_dff.lib commit d4472ae9453c3eb713e2260b198d0236632a60b7 Merge: 9578443 75f0030 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 29 09:53:35 2016 +0200 Merge pull request #141 from azonenberg/master Add Greenpak4 SYSRESET block support commit 75f0030458a6c5e37238e2437ea469ba9dfd389b Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Mar 28 23:16:43 2016 -0700 Added keep constraint to GP_SYSRESET cell commit ea9cc0309245c8d1af5d34b836238f197d34e332 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Mon Mar 28 22:49:46 2016 -0700 Added GP_SYSRESET block commit 95784437ac237be981d0cf573386ba22f28f9624 Merge: 2ec832d 963c0d2 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 28 16:54:23 2016 +0200 Merge pull request #137 from ravenexp/master Embed DATDIR make variable value into yosys binary. commit 2ec832ddced03aff3fb5cef53ae935f39d32547c Merge: aade2c2 73870c1 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 28 16:53:47 2016 +0200 Merge pull request #138 from SebKuzminsky/help-typo fix a cut-n-paste error in the -h help commit aade2c21fa4bdbeb129122d4b1832459e30aec82 Merge: a922d70 3197b6c Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 28 16:53:24 2016 +0200 Merge pull request #139 from azonenberg/master Add GreenPak4 LF oscillator support, renamed internal cell for consistency commit 3197b6c3721b4985b5a5e4223ce7092e27f750c7 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Mar 26 23:29:02 2016 -0700 Added GP_COUNT8/GP_COUNT14 cells commit 31a7567affb7425af1aa27d6dcda4666859ce62f Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Mar 26 14:13:52 2016 -0700 Changed GP_LFOSC parameter configuration commit 44fd3cd149786bc3aaf180af8ec83f790d9cebbe Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Mar 26 13:42:53 2016 -0700 Added GP_LFOSC cell commit af15b92c861f11d1f4b5016fed0cb8cb45af9175 Author: Andrew Zonenberg <azonenberg@drawersteak.com> Date: Sat Mar 26 13:42:41 2016 -0700 Renamed GP4_V* cells to GP_V* for consistency commit 73870c1edfb72a402d69394b5dc6b0a7dd5bb596 Author: Sebastian Kuzminsky <seb@highlab.com> Date: Sat Mar 26 11:15:35 2016 -0600 fix a cut-n-paste error in the -h help commit 963c0d2525c9d7af9a2c7640b554923f3a4f647e Author: Sergey Kvachonok <ravenexp@gmail.com> Date: Sat Mar 26 11:01:53 2016 +0300 Embed DATDIR make variable value into yosys binary. Use it as the last resort in the share/ directory location search. commit a922d705d4c5e5c2f0cfc59f31fa11901ef307e1 Merge: 5328a85 e14055e Author: Clifford Wolf <clifford@clifford.at> Date: Fri Mar 25 09:16:45 2016 +0100 Merge pull request #136 from ravenexp/master Minor Makefile adjustments commit e14055edf06f4551f220b3875a95d8c25b8b7aae Author: Sergey Kvachonok <ravenexp@gmail.com> Date: Fri Mar 25 08:47:45 2016 +0300 Optionally use ${CC} when compiling test utils. Default to gcc when not set. commit d53a16e43a6db35b15584e582c64cfac0f7e5e3d Author: Sergey Kvachonok <ravenexp@gmail.com> Date: Thu Mar 24 16:07:05 2016 +0300 Allow redefining pkg-config Makefile command. Example usage: $ make CXX=i686-w64-mingw32-g++ PKG_CONFIG=i686-w64-mingw32-pkg-config commit 972f4a9616006f6030d1627c65f5ced68aabfff4 Author: Sergey Kvachonok <ravenexp@gmail.com> Date: Thu Mar 24 12:18:21 2016 +0300 Allow redefining binary and data install locations. Add three more Makefile variables in addition to PREFIX: $ make BINDIR=/.../bin LIBDIR=/.../lib DATDIR=/.../share/yosys The defaults are: BINDIR = $(PREFIX)/bin LIBDIR = $(PREFIX)/lib DATDIR = $(PREFIX)/share/yosys commit 5328a851490588d6162ca0edaad5ed713bc75401 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 24 12:16:32 2016 +0100 Do not set "nosync" on task outputs, fixes #134 commit 9717495401e58a3d0a41113b541442227daa7cc3 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 23 08:56:08 2016 +0100 Fixed handling of inverters (aka 1-input luts) in nlutmap commit b4bf787f1091c79d6fed6ac1ec91ebadbceb8023 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 23 08:46:10 2016 +0100 Added GP_DFFS, GP_DFFR, and GP_DFFSR commit 456c10f16e5b535fc5aa95eacfabbe018fef2348 Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 23 08:12:54 2016 +0100 Added GP_DFF INIT parameter commit 4f2ea221dcdc632cdbb22f91403d076b61ec69ca Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 22 14:46:10 2016 +0100 Added ast.h to exported headers commit 043fa0fad039287ee1b6a6fec3d925b9c7304af8 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 21 16:33:34 2016 +0100 Cleanup abstract modules at end of "hierarchy -top" commit 2c7e107d7a55a47fe6f6943e4541014649b57567 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 21 16:30:55 2016 +0100 Support for abstract modules in chparam commit 4f0d4899ce2c93f1f4eef685b03d9f06d4433429 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 21 16:19:51 2016 +0100 Added support for $stop system task commit ca8f8e30f20fd48127003486f1701ac17fd35aa6 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 21 09:44:52 2016 +0100 Improvements in synth_greenpak4, added -part option commit bb9374b67c583761f4bdc72dbd19a79940d51082 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Mar 19 20:02:40 2016 +0100 Improvements in ABCEXTERNAL handling commit b471a32ec3c563bcb02b84a15217beca18b409ab Merge: e5d42eb 2656b2c Author: Clifford Wolf <clifford@clifford.at> Date: Sat Mar 19 19:46:27 2016 +0100 Merge pull request #130 from ravenexp/master Support calling out to an external ABC. commit 2656b2c55a139bc158cb67b18dd201bd0f4cf0c6 Author: Sergey Kvachonok <ravenexp@gmail.com> Date: Sat Mar 19 18:36:18 2016 +0300 Support calling out to an external ABC. $ make ABCEXTERNAL=my-abc && make ABCEXTERNAL=my-abc install configures yosys to use an external ABC executable instead of building and installing the in-tree ABC copy (yosys-abc). commit e5d42ebb4d921aa9b9ad952b063f6ca2e3ffd9db Author: Clifford Wolf <clifford@clifford.at> Date: Sat Mar 19 11:51:13 2016 +0100 Added $display %m support, fixed mem leak in $display, fixes #128 commit ff5c61b1207304e97714d40d37c1627510cc08a8 Author: Clifford Wolf <clifford@clifford.at> Date: Sat Mar 19 11:09:10 2016 +0100 Added black box modules for all the 7-series design elements (as listed in ug953) commit ef4207d5ade8254c9b0f63cac2ad5fee310362d4 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Mar 18 12:15:00 2016 +0100 Fixed localparam signdness, fixes #127 commit b6d08f39baf508951ef36bedbd583f2b9fb48d1b Author: Clifford Wolf <clifford@clifford.at> Date: Fri Mar 18 10:53:29 2016 +0100 Set "nosync" attribute on internal task/function wires commit 33c10350b22a8cc943cf3c294ee86969c5ce97f4 Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 15 12:22:31 2016 +0100 Fixed Verilog parser fix and more similar improvements commit 81d4e9e7c1c311f837dadb1634c83b4e70929669 Author: Andrew Becker <andrew.becker@epfl.ch> Date: Mon Mar 14 19:28:34 2016 +0100 Use left-recursive rule for cell_port_list in Verilog parser. commit 2a8d5e64f5a994fa8f4f51c00d647ad977e42e4b Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 14 13:03:28 2016 +0100 Bugfix in write_verilog for RTLIL processes commit dac807fb33a3619dea955ce4b16342e6e0008111 Author: Clifford Wolf <clifford@clifford.at> Date: Fri Mar 11 11:30:01 2016 +0100 Cleanups and improvements in examples/cmos/ commit 3265795154200786adbb399c6615915a6641f958 Merge: 35a6ad4 b34385e Author: Clifford Wolf <clifford@clifford.at> Date: Fri Mar 11 11:10:44 2016 +0100 Merge commit 'b34385ec924b6067c1f82bdbae923f8062518956' commit 35a6ad4cc162d0f6aeec5bab1fd52d6ca041d868 Author: Clifford Wolf <clifford@clifford.at> Date: Thu Mar 10 11:14:51 2016 +0100 Fixed typos in verilog_defaults help message commit d117893007baa506b702967ac6ee9f70af3c236a Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 8 21:30:45 2016 +0100 Added "write_edif -nogndvcc" commit dcd4fb998435b13193a9816e54d4c6b9284d119b Author: Clifford Wolf <clifford@clifford.at> Date: Tue Mar 8 16:54:15 2016 +0100 Added examples/cxx-api/evaldemo.cc commit e7ed653771ab3483f988f4adfca5c635c10c3480 Merge: c4aaed0 b0ac32b Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 7 11:17:44 2016 +0100 Merge branch 'master' of github.com:cliffordwolf/yosys commit c4aaed099f948f8212898faecfc0f09027347928 Author: Clifford Wolf <clifford@clifford.at> Date: Mon Mar 7 11:14:11 2016 +0100 Using "mfs" and "lutpack" in ABC lut mapping commit b34385ec924b6067c1f82bdbae923f8062518956 Author: Uros Platise <uros@isotel.eu> Date: Sat Mar 5 08:34:05 2016 +0100 Completed ngspice digital example with verilog tb commit b0ac32bc03b340b26e0d3bb778af1c915722abdf Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 2 12:07:57 2016 +0100 Added digital (xspice) example code to examples/cmos/ commit 5547fae4cf2e254d2f35f76f5c0b07abec2376dd Author: Clifford Wolf <clifford@clifford.at> Date: Wed Mar 2 12:02:59 2016 +0100 Be more conservative with net names in spice output commit b36cad75f6d785559391ca7875d893f40736c305 Merge: c89f61c 7e6426a Author: Clifford Wolf <clifford@clifford.at> Date: Mon Feb 29 10:18:50 2016 +0100 Merge pull request #119 from SebKuzminsky/spelling-fixes user-facing spelling fixes commit 7e6426a67da352e0ea41f80b9303087545cb12ac Author: Sebastian Kuzminsky <seb@highlab.com> Date: Sun Feb 28 15:14:01 2016 -0700 user-facing spelling fixes "speciefied" -> "specified" "unkown" -> "unknown" commit 7c623182393aa2e8445336a99f0cfd4bc7c7e88f Author: eddiehung <e.hung@imperial.ac.uk> Date: Sun May 3 12:53:09 2015 +0100 Fix for all zero mask commit 079c1205fec6d194114b3d031d78a23cb8e0e7f9 Author: eddiehung <e.hung@imperial.ac.uk> Date: Sun May 3 10:37:20 2015 +0100 Escape '<' and '>' some more commit 872e13321c4c39997d3b14408224ef1c2fcc0821 Author: eddiehung <e.hung@imperial.ac.uk> Date: Tue Apr 28 08:56:00 2015 +0100 For vtr, escape angle brackets as well commit 058deb777e72458fa018e21eaf0322ca75b86fd7 Author: eddiehung <e.hung@imperial.ac.uk> Date: Tue Apr 28 08:55:26 2015 +0100 blifwriter: write out .names for true/false/undef type == '-'
-rw-r--r--CodingReadme4
-rw-r--r--Makefile108
-rw-r--r--README61
-rw-r--r--backends/blif/blif.cc105
-rw-r--r--backends/btor/btor.cc2
-rwxr-xr-xbackends/btor/verilog2btor.sh2
-rw-r--r--backends/edif/edif.cc55
-rw-r--r--backends/ilang/ilang_backend.cc2
-rw-r--r--backends/intersynth/intersynth.cc4
-rw-r--r--backends/json/json.cc16
-rw-r--r--backends/smt2/smt2.cc483
-rw-r--r--backends/smt2/smtbmc.py622
-rw-r--r--backends/smt2/smtio.py545
-rw-r--r--backends/smv/smv.cc2
-rw-r--r--backends/spice/spice.cc67
-rw-r--r--backends/verilog/verilog_backend.cc170
-rw-r--r--examples/cmos/.gitignore4
-rw-r--r--examples/cmos/README13
-rw-r--r--examples/cmos/cmos_cells_digital.sp31
-rw-r--r--examples/cmos/counter_digital.ys16
-rw-r--r--examples/cmos/counter_tb.gtkw5
-rw-r--r--examples/cmos/counter_tb.v33
-rw-r--r--examples/cmos/testbench.sp2
-rw-r--r--examples/cmos/testbench_digital.sh15
-rw-r--r--examples/cmos/testbench_digital.sp26
-rw-r--r--examples/cxx-api/evaldemo.cc55
-rw-r--r--examples/smtbmc/.gitignore22
-rw-r--r--examples/smtbmc/Makefile59
-rw-r--r--examples/smtbmc/demo1.v19
-rw-r--r--examples/smtbmc/demo2.v29
-rw-r--r--examples/smtbmc/demo3.smtc5
-rw-r--r--examples/smtbmc/demo3.v18
-rw-r--r--examples/smtbmc/demo4.smtc11
-rw-r--r--examples/smtbmc/demo4.v13
-rw-r--r--examples/smtbmc/demo5.v18
-rw-r--r--examples/smtbmc/demo6.v14
-rw-r--r--examples/smtbmc/demo7.v18
-rw-r--r--frontends/ast/ast.cc71
-rw-r--r--frontends/ast/ast.h18
-rw-r--r--frontends/ast/genrtlil.cc105
-rw-r--r--frontends/ast/simplify.cc412
-rw-r--r--frontends/blif/blifparse.cc125
-rw-r--r--frontends/blif/blifparse.h2
-rw-r--r--frontends/ilang/ilang_frontend.cc2
-rw-r--r--frontends/liberty/liberty.cc80
-rw-r--r--frontends/verific/verific.cc2
-rw-r--r--frontends/verilog/verilog_frontend.cc43
-rw-r--r--frontends/verilog/verilog_frontend.h9
-rw-r--r--frontends/verilog/verilog_lexer.l9
-rw-r--r--frontends/verilog/verilog_parser.y131
-rw-r--r--frontends/vhdl2verilog/vhdl2verilog.cc4
-rw-r--r--kernel/celledges.cc209
-rw-r--r--kernel/celledges.h63
-rw-r--r--kernel/celltypes.h42
-rw-r--r--kernel/driver.cc38
-rw-r--r--kernel/hashlib.h7
-rw-r--r--kernel/log.cc51
-rw-r--r--kernel/log.h48
-rw-r--r--kernel/register.cc77
-rw-r--r--kernel/register.h17
-rw-r--r--kernel/rtlil.cc51
-rw-r--r--kernel/rtlil.h5
-rw-r--r--kernel/satgen.h131
-rw-r--r--kernel/yosys.cc45
-rw-r--r--kernel/yosys.h4
-rw-r--r--manual/APPNOTE_012_Verilog_to_BTOR.tex4
-rw-r--r--manual/CHAPTER_CellLib.tex6
-rw-r--r--manual/CHAPTER_Optimize.tex26
-rw-r--r--manual/CHAPTER_Overview.tex6
-rw-r--r--manual/CHAPTER_Prog/stubnets.cc2
-rw-r--r--manual/PRESENTATION_ExSyn.tex10
-rw-r--r--manual/PRESENTATION_Prog.tex4
-rw-r--r--manual/PRESENTATION_Prog/my_cmd.cc2
-rw-r--r--manual/command-reference-manual.tex6
-rw-r--r--manual/manual.tex6
-rw-r--r--passes/cmds/check.cc2
-rw-r--r--passes/cmds/connwrappers.cc2
-rw-r--r--passes/cmds/cover.cc2
-rw-r--r--passes/cmds/plugin.cc8
-rw-r--r--passes/cmds/qwp.cc32
-rw-r--r--passes/cmds/scc.cc8
-rw-r--r--passes/cmds/select.cc42
-rw-r--r--passes/cmds/setattr.cc6
-rw-r--r--passes/cmds/setundef.cc94
-rw-r--r--passes/cmds/show.cc18
-rw-r--r--passes/cmds/splice.cc2
-rw-r--r--passes/cmds/splitnets.cc2
-rw-r--r--passes/cmds/stat.cc2
-rw-r--r--passes/cmds/tee.cc10
-rw-r--r--passes/cmds/torder.cc2
-rw-r--r--passes/equiv/equiv_induct.cc2
-rw-r--r--passes/equiv/equiv_make.cc2
-rw-r--r--passes/equiv/equiv_mark.cc2
-rw-r--r--passes/equiv/equiv_miter.cc2
-rw-r--r--passes/equiv/equiv_purge.cc2
-rw-r--r--passes/equiv/equiv_remove.cc2
-rw-r--r--passes/equiv/equiv_simple.cc2
-rw-r--r--passes/equiv/equiv_status.cc2
-rw-r--r--passes/equiv/equiv_struct.cc2
-rw-r--r--passes/fsm/fsm.cc2
-rw-r--r--passes/fsm/fsm_detect.cc139
-rw-r--r--passes/fsm/fsm_expand.cc2
-rw-r--r--passes/fsm/fsm_export.cc2
-rw-r--r--passes/fsm/fsm_extract.cc9
-rw-r--r--passes/fsm/fsm_info.cc2
-rw-r--r--passes/fsm/fsm_map.cc2
-rw-r--r--passes/fsm/fsm_opt.cc2
-rw-r--r--passes/fsm/fsm_recode.cc2
-rw-r--r--passes/hierarchy/hierarchy.cc20
-rw-r--r--passes/hierarchy/singleton.cc2
-rw-r--r--passes/hierarchy/submod.cc6
-rw-r--r--passes/memory/Makefile.inc1
-rw-r--r--passes/memory/memory.cc15
-rw-r--r--passes/memory/memory_bram.cc7
-rw-r--r--passes/memory/memory_collect.cc18
-rw-r--r--passes/memory/memory_dff.cc2
-rw-r--r--passes/memory/memory_map.cc2
-rw-r--r--passes/memory/memory_memx.cc92
-rw-r--r--passes/memory/memory_share.cc51
-rw-r--r--passes/memory/memory_unpack.cc2
-rw-r--r--passes/opt/Makefile.inc4
-rw-r--r--passes/opt/opt.cc52
-rw-r--r--passes/opt/opt_clean.cc5
-rw-r--r--passes/opt/opt_expr.cc (renamed from passes/opt/opt_const.cc)216
-rw-r--r--passes/opt/opt_merge.cc (renamed from passes/opt/opt_share.cc)70
-rw-r--r--passes/opt/opt_muxtree.cc4
-rw-r--r--passes/opt/opt_reduce.cc2
-rw-r--r--passes/opt/opt_rmdff.cc123
-rw-r--r--passes/opt/share.cc55
-rw-r--r--passes/opt/wreduce.cc31
-rw-r--r--passes/proc/proc.cc16
-rw-r--r--passes/proc/proc_arst.cc2
-rw-r--r--passes/proc/proc_clean.cc2
-rw-r--r--passes/proc/proc_dff.cc2
-rw-r--r--passes/proc/proc_dlatch.cc147
-rw-r--r--passes/proc/proc_init.cc31
-rw-r--r--passes/proc/proc_mux.cc53
-rw-r--r--passes/proc/proc_rmdead.cc6
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/assertpmux.cc240
-rw-r--r--passes/sat/eval.cc2
-rw-r--r--passes/sat/expose.cc2
-rw-r--r--passes/sat/freduce.cc2
-rw-r--r--passes/sat/miter.cc12
-rw-r--r--passes/sat/sat.cc217
-rw-r--r--passes/techmap/Makefile.inc8
-rw-r--r--passes/techmap/abc.cc216
-rw-r--r--passes/techmap/aigmap.cc2
-rw-r--r--passes/techmap/alumacc.cc2
-rw-r--r--passes/techmap/attrmap.cc250
-rw-r--r--passes/techmap/attrmvcp.cc139
-rw-r--r--passes/techmap/deminout.cc116
-rw-r--r--passes/techmap/dff2dffe.cc2
-rw-r--r--passes/techmap/dffinit.cc2
-rw-r--r--passes/techmap/dfflibmap.cc26
-rw-r--r--passes/techmap/dffsr2dff.cc2
-rw-r--r--passes/techmap/extract.cc10
-rw-r--r--passes/techmap/hilomap.cc2
-rw-r--r--passes/techmap/insbuf.cc94
-rw-r--r--passes/techmap/iopadmap.cc168
-rw-r--r--passes/techmap/lut2mux.cc2
-rw-r--r--passes/techmap/maccmap.cc2
-rw-r--r--passes/techmap/muxcover.cc2
-rw-r--r--passes/techmap/nlutmap.cc20
-rw-r--r--passes/techmap/pmuxtree.cc2
-rw-r--r--passes/techmap/shregmap.cc584
-rw-r--r--passes/techmap/simplemap.cc33
-rw-r--r--passes/techmap/techmap.cc48
-rw-r--r--passes/techmap/tribuf.cc2
-rw-r--r--passes/tests/test_autotb.cc63
-rw-r--r--passes/tests/test_cell.cc171
-rw-r--r--techlibs/common/prep.cc170
-rw-r--r--techlibs/common/simlib.v136
-rw-r--r--techlibs/common/synth.cc177
-rw-r--r--techlibs/common/techmap.v6
-rw-r--r--techlibs/greenpak4/Makefile.inc2
-rw-r--r--techlibs/greenpak4/cells_map.v74
-rw-r--r--techlibs/greenpak4/cells_sim.v425
-rw-r--r--techlibs/greenpak4/gp_dff.lib26
-rw-r--r--techlibs/greenpak4/greenpak4_counters.cc442
-rw-r--r--techlibs/greenpak4/greenpak4_dffinv.cc197
-rw-r--r--techlibs/greenpak4/synth_greenpak4.cc192
-rw-r--r--techlibs/ice40/Makefile.inc1
-rw-r--r--techlibs/ice40/ice40_ffinit.cc38
-rw-r--r--techlibs/ice40/ice40_ffssr.cc9
-rw-r--r--techlibs/ice40/ice40_opt.cc38
-rw-r--r--techlibs/ice40/latches_map.v11
-rw-r--r--techlibs/ice40/synth_ice40.cc210
-rw-r--r--techlibs/xilinx/Makefile.inc1
-rw-r--r--techlibs/xilinx/cells_xtra.sh145
-rw-r--r--techlibs/xilinx/cells_xtra.v3293
-rw-r--r--techlibs/xilinx/synth_xilinx.cc4
-rw-r--r--tests/asicworld/code_hdl_models_arbiter_tb.v28
-rw-r--r--tests/asicworld/code_verilog_tutorial_counter_tb.v36
-rw-r--r--tests/asicworld/code_verilog_tutorial_first_counter_tb.v15
-rw-r--r--tests/asicworld/code_verilog_tutorial_fsm_full_tb.v12
-rw-r--r--tests/simple/constmuldivmod.v27
-rw-r--r--tests/simple/mem2reg.v41
-rw-r--r--tests/simple/memory.v64
-rwxr-xr-xtests/tools/autotest.sh59
-rw-r--r--tests/tools/cmp_tbdata.c4
201 files changed, 12525 insertions, 1800 deletions
diff --git a/CodingReadme b/CodingReadme
index ba184be5..cbe1fb8b 100644
--- a/CodingReadme
+++ b/CodingReadme
@@ -239,7 +239,7 @@ C++ Language
-------------
Yosys is written in C++11. At the moment only constructs supported by
-gcc 4.6 are allowed in Yosys code. This will change in future releases.
+gcc 4.8 are allowed in Yosys code. This will change in future releases.
In general Yosys uses "int" instead of "size_t". To avoid compiler
warnings for implicit type casts, always use "GetSize(foobar)" instead
@@ -368,7 +368,7 @@ And if a version of the verific library is currently available:
../../yosys test_navre.ys
-Finally run all tests with "make config-{clang,gcc,gcc-4.6}":
+Finally run all tests with "make config-{clang,gcc,gcc-4.8}":
cd ~yosys
make clean
diff --git a/Makefile b/Makefile
index f2171c8a..fd31776a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,10 @@
CONFIG := clang
# CONFIG := gcc
-# CONFIG := gcc-4.6
+# CONFIG := gcc-4.8
# CONFIG := emcc
# CONFIG := mxe
+# CONFIG := msys2
# features (the more the better)
ENABLE_TCL := 1
@@ -29,8 +30,9 @@ SANITIZER =
PREFIX ?= /usr/local
INSTALL_SUDO :=
-TARGET_BINDIR := $(DESTDIR)$(PREFIX)/bin
-TARGET_DATDIR := $(DESTDIR)$(PREFIX)/share/yosys
+BINDIR := $(PREFIX)/bin
+LIBDIR := $(PREFIX)/lib
+DATDIR := $(PREFIX)/share/yosys
EXE =
OBJS =
@@ -47,9 +49,11 @@ all: top-all
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
VPATH := $(YOSYS_SRC)
-CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(DESTDIR)$(PREFIX)/include
-LDFLAGS += -L$(DESTDIR)$(PREFIX)/lib
+CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include
+LDFLAGS += -L$(LIBDIR)
LDLIBS = -lstdc++ -lm
+
+PKG_CONFIG = pkg-config
SED = sed
BISON = bison
@@ -68,7 +72,7 @@ else
LDLIBS += -lrt
endif
-YOSYS_VER := 0.6+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline 5869d26da021.. | wc -l; })
+YOSYS_VER := 0.6+$(shell test -e .git && { git log --author=clifford@clifford.at --oneline 5869d26da021.. | wc -l; })
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@@ -78,10 +82,15 @@ OBJS = kernel/version_$(GIT_REV).o
# is just a symlink to your actual ABC working directory, as 'make mrproper'
# will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC..
-ABCREV = ae7d65e71adc
+ABCREV = 8e08604f8ad3
ABCPULL = 1
+ABCURL ?= https://bitbucket.org/alanmi/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)"
+# set ABCEXTERNAL = <abc-command> to use an external ABC instance
+# Note: The in-tree ABC (yosys-abc) will not be installed when ABCEXTERNAL is set.
+ABCEXTERNAL =
+
define newline
@@ -105,8 +114,8 @@ ifeq ($(SANITIZER),address)
ENABLE_COVER := 0
endif
ifeq ($(SANITIZER),memory)
-CXXFLAGS += -fPIE
-LDFLAGS += -fPIE
+CXXFLAGS += -fPIE -fsanitize-memory-track-origins
+LDFLAGS += -fPIE -fsanitize-memory-track-origins
endif
ifeq ($(SANITIZER),cfi)
CXXFLAGS += -flto
@@ -117,12 +126,12 @@ endif
else ifeq ($(CONFIG),gcc)
CXX = gcc
LD = gcc
-CXXFLAGS += -std=gnu++0x -Os
+CXXFLAGS += -std=c++11 -Os
-else ifeq ($(CONFIG),gcc-4.6)
-CXX = gcc-4.6
-LD = gcc-4.6
-CXXFLAGS += -std=gnu++0x -Os
+else ifeq ($(CONFIG),gcc-4.8)
+CXX = gcc-4.8
+LD = gcc-4.8
+CXXFLAGS += -std=c++11 -Os
else ifeq ($(CONFIG),emcc)
CXX = emcc
@@ -155,18 +164,29 @@ yosys.html: misc/yosys.html
$(P) cp misc/yosys.html yosys.html
else ifeq ($(CONFIG),mxe)
-CXX = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
-LD = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
-CXXFLAGS += -std=gnu++0x -Os -D_POSIX_SOURCE
+CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
+LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc
+CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
-ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -x c++ -fpermissive -w"
+ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
EXE = .exe
+else ifeq ($(CONFIG),msys2)
+CXX = i686-w64-mingw32-gcc
+LD = i686-w64-mingw32-gcc
+CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
+CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
+LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
+LDLIBS := $(filter-out -lrt,$(LDLIBS))
+ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -x c++ -fpermissive -w"
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="$(CXX)" CXX="$(CXX)"
+EXE = .exe
+
else ifneq ($(CONFIG),none)
-$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none)
+$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2)
endif
ifeq ($(ENABLE_LIBYOSYS),1)
@@ -182,12 +202,12 @@ endif
endif
ifeq ($(ENABLE_PLUGINS),1)
-CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell pkg-config --silence-errors --cflags libffi)
-LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl
+CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell $(PKG_CONFIG) --silence-errors --cflags libffi)
+LDLIBS += $(shell $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
endif
ifeq ($(ENABLE_TCL),1)
-TCL_VERSION ?= tcl$(shell echo 'puts [info tclversion]' | tclsh)
+TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
LDLIBS += -l$(TCL_VERSION)
@@ -204,8 +224,10 @@ endif
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
+ifeq ($(ABCEXTERNAL),)
TARGETS += yosys-abc$(EXE)
endif
+endif
ifeq ($(ENABLE_VERIFIC),1)
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
@@ -257,6 +279,7 @@ $(eval $(call add_include_file,kernel/log.h))
$(eval $(call add_include_file,kernel/rtlil.h))
$(eval $(call add_include_file,kernel/register.h))
$(eval $(call add_include_file,kernel/celltypes.h))
+$(eval $(call add_include_file,kernel/celledges.h))
$(eval $(call add_include_file,kernel/consteval.h))
$(eval $(call add_include_file,kernel/sigtools.h))
$(eval $(call add_include_file,kernel/modtools.h))
@@ -267,10 +290,14 @@ $(eval $(call add_include_file,libs/ezsat/ezsat.h))
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
$(eval $(call add_include_file,libs/sha1/sha1.h))
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
+$(eval $(call add_include_file,frontends/ast/ast.h))
$(eval $(call add_include_file,backends/ilang/ilang_backend.h))
-OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o kernel/cellaigs.o
+OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
+OBJS += kernel/cellaigs.o kernel/celledges.o
+
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
+kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"'
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
@@ -349,9 +376,9 @@ kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\"; }" > kernel/version_$(GIT_REV).cc
yosys-config: misc/yosys-config.in
- $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(TARGET_DATDIR)/include",$(CXXFLAGS))#;' \
+ $(P) $(SED) -e 's#@CXXFLAGS@#$(subst -I. -I"$(YOSYS_SRC)",-I"$(DATDIR)/include",$(CXXFLAGS))#;' \
-e 's#@CXX@#$(CXX)#;' -e 's#@LDFLAGS@#$(LDFLAGS)#;' -e 's#@LDLIBS@#$(LDLIBS)#;' \
- -e 's#@BINDIR@#$(TARGET_BINDIR)#;' -e 's#@DATDIR@#$(TARGET_DATDIR)#;' < $< > yosys-config
+ -e 's#@BINDIR@#$(BINDIR)#;' -e 's#@DATDIR@#$(DATDIR)#;' < $< > yosys-config
$(Q) chmod +x yosys-config
abc/abc-$(ABCREV)$(EXE):
@@ -362,8 +389,8 @@ ifneq ($(ABCREV),default)
fi
$(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
- echo "Pulling ABC from bitbucket.org:"; set -x; \
- test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \
+ echo "Pulling ABC from $(ABCURL):"; set -x; \
+ test -d abc || hg clone $(ABCURL) abc; \
cd abc && $(MAKE) DEP= clean && hg pull && hg update -r $(ABCREV); \
fi
endif
@@ -408,20 +435,20 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS)
@echo ""
install: $(TARGETS) $(EXTRA_TARGETS)
- $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PREFIX)/bin
- $(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(PREFIX)/bin/
- $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PREFIX)/share/yosys
- $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(PREFIX)/share/yosys/.
+ $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
+ $(INSTALL_SUDO) install $(TARGETS) $(DESTDIR)$(BINDIR)
+ $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
+ $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1)
- $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PREFIX)/lib/
+ $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) ldconfig
endif
uninstall:
- $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(PREFIX)/bin/,$(notdir $(TARGETS)))
- $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(PREFIX)/share/yosys/
+ $(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)$(BINDIR),$(notdir $(TARGETS)))
+ $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1)
- $(INSTALL_SUDO) rm -vf $(DESTDIR)$(PREFIX)/lib/libyosys.so
+ $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
endif
update-manual: $(TARGETS) $(EXTRA_TARGETS)
@@ -456,7 +483,7 @@ qtcreator:
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
- echo "Analyse: $$f" >&2; cpp -std=gnu++0x -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
+ echo "Analyse: $$f" >&2; cpp -std=c++11 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
@@ -485,8 +512,8 @@ config-clang: clean
config-gcc: clean
echo 'CONFIG := gcc' > Makefile.conf
-config-gcc-4.6: clean
- echo 'CONFIG := gcc-4.6' > Makefile.conf
+config-gcc-4.8: clean
+ echo 'CONFIG := gcc-4.8' > Makefile.conf
config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf
@@ -501,6 +528,9 @@ config-mxe: clean
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
+config-msys2: clean
+ echo 'CONFIG := msys2' > Makefile.conf
+
config-gprof: clean
echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
@@ -522,5 +552,5 @@ echo-git-rev:
-include techlibs/*/*.d
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator
-.PHONY: config-clean config-clang config-gcc config-gcc-4.6 config-gprof config-sudo
+.PHONY: config-clean config-clang config-gcc config-gcc-4.8 config-gprof config-sudo
diff --git a/README b/README
index 5c649a4e..32e9ba24 100644
--- a/README
+++ b/README
@@ -3,7 +3,7 @@
| |
| yosys -- Yosys Open SYnthesis Suite |
| |
- | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |
+ | Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |
| |
| Permission to use, copy, modify, and/or distribute this software for any |
| purpose with or without fee is hereby granted, provided that the above |
@@ -52,12 +52,12 @@ You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
TCL, readline and libffi are optional (see ENABLE_* settings in Makefile).
Xdot (graphviz) is used by the "show" command in yosys to display schematics.
-For example on Ubuntu Linux 14.04 LTS the following commands will install all
+For example on Ubuntu Linux 16.04 LTS the following commands will install all
prerequisites for building yosys:
- $ yosys_deps="build-essential clang bison flex libreadline-dev gawk
- tcl-dev libffi-dev git mercurial graphviz xdot pkg-config python3"
- $ sudo apt-get install $yosys_deps
+ $ sudo apt-get install build-essential clang bison flex \
+ libreadline-dev gawk tcl-dev libffi-dev git mercurial \
+ graphviz xdot pkg-config python3
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
as a source distribution for Visual Studio. Visit the Yosys download page for
@@ -308,6 +308,10 @@ Verilog Attributes and non-standard features
for everything that comes after the {* ... *} statement. (Reset
by adding an empty {* *} statement.)
+- In module parameter and port declarations, and cell port and parameter
+ lists, a trailing comma is ignored. This simplifies writing verilog code
+ generators a bit in some cases.
+
- Modules can be declared with "module mod_name(...);" (with three dots
instead of a list of module ports). With this syntax it is sufficient
to simply declare a module port as 'input' or 'output' in the module
@@ -350,8 +354,8 @@ Verilog Attributes and non-standard features
endmodule
- A limited subset of DPI-C functions is supported. The plugin mechanism
- (see "help plugin") can be used load .so files with implementations of
- DPI-C routines. As a non-standard extension it is possible to specify
+ (see "help plugin") can be used to load .so files with implementations
+ of DPI-C routines. As a non-standard extension it is possible to specify
a plugin alias using the "<alias>:" syntax. for example:
module dpitest;
@@ -366,7 +370,7 @@ Verilog Attributes and non-standard features
must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
- The system tasks $finish and $display are supported in initial blocks
- in and unconditional context (only if/case statements on parameters
+ in an unconditional context (only if/case statements on parameters
and constant values). The intended use for this is synthesis-time DRC.
@@ -380,6 +384,47 @@ from SystemVerilog:
form. In module context: "assert property (<expression>);" and within an
always block: "assert(<expression>);". It is transformed to a $assert cell.
+- The "assume" statements from SystemVerilog are also supported. The same
+ limitations as with the "assert" statement apply.
+
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
"bit" are supported.
+- SystemVerilog packages are supported. Once a SystemVerilog file is read
+ into a design with "read_verilog", all its packages are available to
+ SystemVerilog files being read into the same design afterwards.
+
+
+Building the documentation
+==========================
+
+Note that there is no need to build the manual if you just want to read it.
+Simply download the PDF from http://www.clifford.at/yosys/documentation.html
+instead.
+
+On Ubuntu, texlive needs these packages to be able to build the manual:
+
+ sudo apt-get install texlive-binaries
+ sudo apt-get install texlive-science # install algorithm2e.sty
+ sudo apt-get install texlive-bibtex-extra # gets multibib.sty
+ sudo apt-get install texlive-fonts-extra # gets skull.sty and dsfont.sty
+ sudo apt-get install texlive-publishers # IEEEtran.cls
+
+Also the non-free font luximono should be installed, there is unfortunately
+no Ubuntu package for this so it should be installed separately using
+`getnonfreefonts`:
+
+ wget https://tug.org/fonts/getnonfreefonts/install-getnonfreefonts
+ sudo texlua install-getnonfreefonts # will install to /usr/local by default, can be changed by editing BINDIR at MANDIR at the top of the script
+ getnonfreefonts luximono # installs to /home/user/texmf
+
+Then execute, from the root of the repository:
+
+ make manual
+
+Notes:
+
+- To run `make manual` you need to have installed yosys with `make install`,
+ otherwise it will fail on finding `kernel/yosys.h` while building
+ `PRESENTATION_Prog`.
+
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index f3b57765..6a379e67 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -41,13 +41,14 @@ struct BlifDumperConfig
bool param_mode;
bool attr_mode;
bool blackbox_mode;
+ bool noalias_mode;
std::string buf_type, buf_in, buf_out;
std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
std::string true_type, true_out, false_type, false_out, undef_type, undef_out;
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false),
- cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { }
+ cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false), noalias_mode(false) { }
};
struct BlifDumper
@@ -86,12 +87,13 @@ struct BlifDumper
}
vector<shared_str> cstr_buf;
+ pool<SigBit> cstr_bits_seen;
const char *cstr(RTLIL::IdString id)
{
std::string str = RTLIL::unescape_id(id);
for (size_t i = 0; i < str.size(); i++)
- if (str[i] == '#' || str[i] == '=')
+ if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>')
str[i] = '?';
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
@@ -99,15 +101,17 @@ struct BlifDumper
const char *cstr(RTLIL::SigBit sig)
{
+ cstr_bits_seen.insert(sig);
+
if (sig.wire == NULL) {
- if (sig == RTLIL::State::S0) return config->false_type == "-" ? config->false_out.c_str() : "$false";
- if (sig == RTLIL::State::S1) return config->true_type == "-" ? config->true_out.c_str() : "$true";
- return config->undef_type == "-" ? config->undef_out.c_str() : "$undef";
+ if (sig == RTLIL::State::S0) return config->false_type == "-" || config->false_type == "+" ? config->false_out.c_str() : "$false";
+ if (sig == RTLIL::State::S1) return config->true_type == "-" || config->true_type == "+" ? config->true_out.c_str() : "$true";
+ return config->undef_type == "-" || config->undef_type == "+" ? config->undef_out.c_str() : "$undef";
}
std::string str = RTLIL::unescape_id(sig.wire->name);
for (size_t i = 0; i < str.size(); i++)
- if (str[i] == '#' || str[i] == '=')
+ if (str[i] == '#' || str[i] == '=' || str[i] == '<' || str[i] == '>')
str[i] = '?';
if (sig.wire->width != 1)
@@ -200,19 +204,25 @@ struct BlifDumper
if (!config->impltf_mode) {
if (!config->false_type.empty()) {
- if (config->false_type != "-")
+ if (config->false_type == "+")
+ f << stringf(".names %s\n", config->false_out.c_str());
+ else if (config->false_type != "-")
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
config->false_type.c_str(), config->false_out.c_str());
} else
f << stringf(".names $false\n");
if (!config->true_type.empty()) {
- if (config->true_type != "-")
+ if (config->true_type == "+")
+ f << stringf(".names %s\n1\n", config->true_out.c_str());
+ else if (config->true_type != "-")
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
config->true_type.c_str(), config->true_out.c_str());
} else
f << stringf(".names $true\n1\n");
if (!config->undef_type.empty()) {
- if (config->undef_type != "-")
+ if (config->undef_type == "+")
+ f << stringf(".names %s\n", config->undef_out.c_str());
+ else if (config->undef_type != "-")
f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type),
config->undef_type.c_str(), config->undef_out.c_str());
} else
@@ -317,14 +327,25 @@ struct BlifDumper
continue;
}
+ if (!config->icells_mode && cell->type == "$_DLATCH_N_") {
+ f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
+ cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
+ continue;
+ }
+
+ if (!config->icells_mode && cell->type == "$_DLATCH_P_") {
+ f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
+ cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
+ continue;
+ }
+
if (!config->icells_mode && cell->type == "$lut") {
f << stringf(".names");
auto &inputs = cell->getPort("\\A");
auto width = cell->parameters.at("\\WIDTH").as_int();
log_assert(inputs.size() == width);
- for (int i = width-1; i >= 0; i--) {
+ for (int i = width-1; i >= 0; i--)
f << stringf(" %s", cstr(inputs.extract(i, 1)));
- }
auto &output = cell->getPort("\\Y");
log_assert(output.size() == 1);
f << stringf(" %s", cstr(output));
@@ -340,6 +361,34 @@ struct BlifDumper
continue;
}
+ if (!config->icells_mode && cell->type == "$sop") {
+ f << stringf(".names");
+ auto &inputs = cell->getPort("\\A");
+ auto width = cell->parameters.at("\\WIDTH").as_int();
+ auto depth = cell->parameters.at("\\DEPTH").as_int();
+ vector<State> table = cell->parameters.at("\\TABLE").bits;
+ while (GetSize(table) < 2*width*depth)
+ table.push_back(State::S0);
+ log_assert(inputs.size() == width);
+ for (int i = 0; i < width; i++)
+ f << stringf(" %s", cstr(inputs.extract(i, 1)));
+ auto &output = cell->getPort("\\Y");
+ log_assert(output.size() == 1);
+ f << stringf(" %s", cstr(output));
+ f << stringf("\n");
+ for (int i = 0; i < depth; i++) {
+ for (int j = 0; j < width; j++) {
+ bool pat0 = table.at(2*width*i + 2*j + 0) == State::S1;
+ bool pat1 = table.at(2*width*i + 2*j + 1) == State::S1;
+ if (pat0 && !pat1) f << "0";
+ else if (!pat0 && pat1) f << "1";
+ else f << "-";
+ }
+ f << " 1\n";
+ }
+ continue;
+ }
+
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
for (auto &conn : cell->connections())
for (int i = 0; i < conn.second.size(); i++) {
@@ -361,14 +410,21 @@ struct BlifDumper
for (auto &conn : module->connections())
for (int i = 0; i < conn.first.size(); i++)
+ {
+ SigBit lhs_bit = conn.first[i];
+ SigBit rhs_bit = conn.second[i];
+
+ if (config->noalias_mode && cstr_bits_seen.count(lhs_bit) == 0)
+ continue;
+
if (config->conn_mode)
- f << stringf(".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
+ f << stringf(".conn %s %s\n", cstr(rhs_bit), cstr(lhs_bit));
else if (!config->buf_type.empty())
- f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)),
- config->buf_out.c_str(), cstr(conn.first.extract(i, 1)));
+ f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(),
+ config->buf_in.c_str(), cstr(rhs_bit), config->buf_out.c_str(), cstr(lhs_bit));
else
- f << stringf(".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
-
+ f << stringf(".names %s %s\n1 1\n", cstr(rhs_bit), cstr(lhs_bit));
+ }
f << stringf(".end\n");
}
@@ -406,7 +462,14 @@ struct BlifBackend : public Backend {
log(" use the specified cell types to drive nets that are constant 1, 0, or\n");
log(" undefined. when '-' is used as <cell-type>, then <out-port> specifies\n");
log(" the wire name to be used for the constant signal and no cell driving\n");
- log(" that wire is generated.\n");
+ log(" that wire is generated. when '+' is used as <cell-type>, then <out-port>\n");
+ log(" specifies the wire name to be used for the constant signal and a .names\n");
+ log(" statement is generated to drive the wire.\n");
+ log("\n");
+ log(" -noalias\n");
+ log(" if a net name is aliasing another net name, then by default a net\n");
+ log(" without fanout is created that is driven by the other net. This option\n");
+ log(" suppresses the generation of this nets without fanout.\n");
log("\n");
log("The following options can be useful when the generated file is not going to be\n");
log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n");
@@ -448,7 +511,7 @@ struct BlifBackend : public Backend {
std::string false_type, false_out;
BlifDumperConfig config;
- log_header("Executing BLIF backend.\n");
+ log_header(design, "Executing BLIF backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -517,6 +580,10 @@ struct BlifBackend : public Backend {
config.impltf_mode = true;
continue;
}
+ if (args[argidx] == "-noalias") {
+ config.noalias_mode = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
@@ -540,7 +607,7 @@ struct BlifBackend : public Backend {
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0)
- log_error("Found munmapped emories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
+ log_error("Found unmapped memories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
if (module->name == RTLIL::escape_id(top_module_name)) {
BlifDumper::dump(*f, module, design, config);
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index 465723f1..bbe90e85 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -1065,7 +1065,7 @@ struct BtorBackend : public Backend {
std::string false_type, false_out;
BtorDumperConfig config;
- log_header("Executing BTOR backend.\n");
+ log_header(design, "Executing BTOR backend.\n");
size_t argidx=1;
extra_args(f, filename, args, argidx);
diff --git a/backends/btor/verilog2btor.sh b/backends/btor/verilog2btor.sh
index 1c537d5b..dfd7f1a8 100755
--- a/backends/btor/verilog2btor.sh
+++ b/backends/btor/verilog2btor.sh
@@ -22,7 +22,7 @@ hierarchy -top $3;
hierarchy -libdir $DIR;
hierarchy -check;
proc;
-opt; opt_const -mux_undef; opt;
+opt; opt_expr -mux_undef; opt;
rename -hide;;;
#techmap -map +/pmux2mux.v;;
splice; opt;
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc
index 475e43da..d16f1831 100644
--- a/backends/edif/edif.cc
+++ b/backends/edif/edif.cc
@@ -100,6 +100,11 @@ struct EdifBackend : public Backend {
log(" -top top_module\n");
log(" set the specified module as design top module\n");
log("\n");
+ log(" -nogndvcc\n");
+ log(" do not create \"GND\" and \"VCC\" cells. (this will produce an error\n");
+ log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
+ log(" constant drivers first)\n");
+ log("\n");
log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n");
log("command generates EDIF files for the Xilinx place&route tools. It might be\n");
log("necessary to make small modifications to this command when a different tool\n");
@@ -108,10 +113,11 @@ struct EdifBackend : public Backend {
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing EDIF backend.\n");
+ log_header(design, "Executing EDIF backend.\n");
std::string top_module_name;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
+ bool nogndvcc = false;
CellTypes ct(design);
EdifNames edif_names;
@@ -122,6 +128,10 @@ struct EdifBackend : public Backend {
top_module_name = args[++argidx];
continue;
}
+ if (args[argidx] == "-nogndvcc") {
+ nogndvcc = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
@@ -143,7 +153,7 @@ struct EdifBackend : public Backend {
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0)
- log_error("Found munmapped emories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
+ log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
for (auto cell_it : module->cells_)
{
@@ -169,21 +179,24 @@ struct EdifBackend : public Backend {
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (technology (numberDefinition))\n");
- *f << stringf(" (cell GND\n");
- *f << stringf(" (cellType GENERIC)\n");
- *f << stringf(" (view VIEW_NETLIST\n");
- *f << stringf(" (viewType NETLIST)\n");
- *f << stringf(" (interface (port G (direction OUTPUT)))\n");
- *f << stringf(" )\n");
- *f << stringf(" )\n");
-
- *f << stringf(" (cell VCC\n");
- *f << stringf(" (cellType GENERIC)\n");
- *f << stringf(" (view VIEW_NETLIST\n");
- *f << stringf(" (viewType NETLIST)\n");
- *f << stringf(" (interface (port P (direction OUTPUT)))\n");
- *f << stringf(" )\n");
- *f << stringf(" )\n");
+ if (!nogndvcc)
+ {
+ *f << stringf(" (cell GND\n");
+ *f << stringf(" (cellType GENERIC)\n");
+ *f << stringf(" (view VIEW_NETLIST\n");
+ *f << stringf(" (viewType NETLIST)\n");
+ *f << stringf(" (interface (port G (direction OUTPUT)))\n");
+ *f << stringf(" )\n");
+ *f << stringf(" )\n");
+
+ *f << stringf(" (cell VCC\n");
+ *f << stringf(" (cellType GENERIC)\n");
+ *f << stringf(" (view VIEW_NETLIST\n");
+ *f << stringf(" (viewType NETLIST)\n");
+ *f << stringf(" (interface (port P (direction OUTPUT)))\n");
+ *f << stringf(" )\n");
+ *f << stringf(" )\n");
+ }
for (auto &cell_it : lib_cell_ports) {
*f << stringf(" (cell %s\n", EDIF_DEF(cell_it.first));
@@ -279,8 +292,10 @@ struct EdifBackend : public Backend {
}
*f << stringf(" )\n");
*f << stringf(" (contents\n");
- *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
- *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
+ if (!nogndvcc) {
+ *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
+ *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
+ }
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
*f << stringf(" (instance %s\n", EDIF_DEF(cell->name));
@@ -326,6 +341,8 @@ struct EdifBackend : public Backend {
for (auto &ref : it.second)
*f << stringf(" %s\n", ref.c_str());
if (sig.wire == NULL) {
+ if (nogndvcc)
+ log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
if (sig == RTLIL::State::S0)
*f << stringf(" (portRef G (instanceRef GND))\n");
if (sig == RTLIL::State::S1)
diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc
index adabf05e..03e29c52 100644
--- a/backends/ilang/ilang_backend.cc
+++ b/backends/ilang/ilang_backend.cc
@@ -391,7 +391,7 @@ struct IlangBackend : public Backend {
{
bool selected = false;
- log_header("Executing ILANG backend.\n");
+ log_header(design, "Executing ILANG backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc
index 72a70e38..34cb52fb 100644
--- a/backends/intersynth/intersynth.cc
+++ b/backends/intersynth/intersynth.cc
@@ -73,7 +73,7 @@ struct IntersynthBackend : public Backend {
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing INTERSYNTH backend.\n");
+ log_header(design, "Executing INTERSYNTH backend.\n");
log_push();
std::vector<std::string> libfiles;
@@ -113,7 +113,7 @@ struct IntersynthBackend : public Backend {
}
if (libs.size() > 0)
- log_header("Continuing INTERSYNTH backend.\n");
+ log_header(design, "Continuing INTERSYNTH backend.\n");
std::set<std::string> conntypes_code, celltypes_code;
std::string netlists_code;
diff --git a/backends/json/json.cc b/backends/json/json.cc
index 9bc936a6..4baffa33 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -83,12 +83,12 @@ struct JsonWriter
return str + " ]";
}
- void write_parameters(const dict<IdString, Const> &parameters)
+ void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
{
bool first = true;
for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ",");
- f << stringf(" %s: ", get_name(param.first).c_str());
+ f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str());
if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
f << get_string(param.second.decode_string());
else if (GetSize(param.second.bits) > 32)
@@ -111,6 +111,10 @@ struct JsonWriter
f << stringf(" %s: {\n", get_name(module->name).c_str());
+ f << stringf(" \"attributes\": {");
+ write_parameters(module->attributes, /*for_module=*/true);
+ f << stringf("\n },\n");
+
f << stringf(" \"ports\": {");
bool first = true;
for (auto n : module->ports) {
@@ -411,10 +415,10 @@ struct JsonBackend : public Backend {
log(" - the inverted value of the specified input port bit\n");
log("\n");
log(" [ \"and\", <node-index>, <node-index>, <out-list> ]\n");
- log(" - the ANDed value of the speciefied nodes\n");
+ log(" - the ANDed value of the specified nodes\n");
log("\n");
log(" [ \"nand\", <node-index>, <node-index>, <out-list> ]\n");
- log(" - the inverted ANDed value of the speciefied nodes\n");
+ log(" - the inverted ANDed value of the specified nodes\n");
log("\n");
log(" [ \"true\", <out-list> ]\n");
log(" - the constant value 1\n");
@@ -445,7 +449,7 @@ struct JsonBackend : public Backend {
log(" ]\n");
log("\n");
log("Future version of Yosys might add support for additional fields in the JSON\n");
- log("format. A program processing this format must ignore all unkown fields.\n");
+ log("format. A program processing this format must ignore all unknown fields.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
@@ -463,7 +467,7 @@ struct JsonBackend : public Backend {
}
extra_args(f, filename, args, argidx);
- log_header("Executing JSON backend.\n");
+ log_header(design, "Executing JSON backend.\n");
JsonWriter json_writer(*f, false, aig_mode);
json_writer.write_design(design);
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index c852921e..9a25f3a2 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -32,23 +32,43 @@ struct Smt2Worker
CellTypes ct;
SigMap sigmap;
RTLIL::Module *module;
- bool bvmode, memmode, regsmode, wiresmode, verbose;
+ bool bvmode, memmode, wiresmode, verbose;
int idcounter;
- std::vector<std::string> decls, trans;
+ std::vector<std::string> decls, trans, hier;
std::map<RTLIL::SigBit, RTLIL::Cell*> bit_driver;
- std::set<RTLIL::Cell*> exported_cells;
+ std::set<RTLIL::Cell*> exported_cells, hiercells, hiercells_queue;
pool<Cell*> recursive_cells, registers;
std::map<RTLIL::SigBit, std::pair<int, int>> fcache;
std::map<Cell*, int> memarrays;
std::map<int, int> bvsizes;
+ dict<IdString, char*> ids;
- Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool regsmode, bool wiresmode, bool verbose) :
+ const char *get_id(IdString n)
+ {
+ if (ids.count(n) == 0) {
+ std::string str = log_id(n);
+ for (int i = 0; i < GetSize(str); i++) {
+ if (str[i] == '\\')
+ str[i] = '/';
+ }
+ ids[n] = strdup(str.c_str());
+ }
+ return ids[n];
+ }
+
+ template<typename T>
+ const char *get_id(T *obj) {
+ return get_id(obj->name);
+ }
+
+ Smt2Worker(RTLIL::Module *module, bool bvmode, bool memmode, bool wiresmode, bool verbose) :
ct(module->design), sigmap(module), module(module), bvmode(bvmode), memmode(memmode),
- regsmode(regsmode), wiresmode(wiresmode), verbose(verbose), idcounter(0)
+ wiresmode(wiresmode), verbose(verbose), idcounter(0)
{
- decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module)));
+ decls.push_back(stringf("(declare-sort |%s_s| 0)\n", get_id(module)));
+ decls.push_back(stringf("(declare-fun |%s_is| (|%s_s|) Bool)\n", get_id(module), get_id(module)));
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
@@ -66,6 +86,28 @@ struct Smt2Worker
}
}
+ ~Smt2Worker()
+ {
+ for (auto &it : ids)
+ free(it.second);
+ ids.clear();
+ }
+
+ const char *get_id(Module *m)
+ {
+ return get_id(m->name);
+ }
+
+ const char *get_id(Cell *c)
+ {
+ return get_id(c->name);
+ }
+
+ const char *get_id(Wire *w)
+ {
+ return get_id(w->name);
+ }
+
void register_bool(RTLIL::SigBit bit, int id)
{
if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "",
@@ -121,14 +163,14 @@ struct Smt2Worker
if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "",
log_signal(bit));
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
- log_id(module), idcounter, log_id(module), log_signal(bit)));
+ get_id(module), idcounter, get_id(module), log_signal(bit)));
register_bool(bit, idcounter++);
}
auto f = fcache.at(bit);
if (f.second >= 0)
- return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, log_id(module), f.first, state_name);
- return stringf("(|%s#%d| %s)", log_id(module), f.first, state_name);
+ return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, get_id(module), f.first, state_name);
+ return stringf("(|%s#%d| %s)", get_id(module), f.first, state_name);
}
std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state")
@@ -180,10 +222,10 @@ struct Smt2Worker
j++;
}
if (t1.second == 0 && j == bvsizes.at(t1.first))
- subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), t1.first, state_name));
+ subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), t1.first, state_name));
else
subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))",
- t1.second + j - 1, t1.second, log_id(module), t1.first, state_name));
+ t1.second + j - 1, t1.second, get_id(module), t1.first, state_name));
continue;
}
@@ -196,8 +238,8 @@ struct Smt2Worker
for (auto bit : sig.extract(i, j))
log_assert(bit_driver.count(bit) == 0);
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
- log_id(module), idcounter, log_id(module), j, log_signal(sig.extract(i, j))));
- subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), idcounter, state_name));
+ get_id(module), idcounter, get_id(module), j, log_signal(sig.extract(i, j))));
+ subexpr.push_back(stringf("(|%s#%d| %s)", get_id(module), idcounter, state_name));
register_bv(sig.extract(i, j), idcounter++);
}
@@ -228,10 +270,11 @@ struct Smt2Worker
else processed_expr += ch;
}
- if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
- log_id(cell));
+ if (verbose)
+ log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
+
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
- log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(bit)));
+ get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(bit)));
register_bool(bit, idcounter++);
recursive_cells.erase(cell);
}
@@ -271,16 +314,16 @@ struct Smt2Worker
if (width != GetSize(sig_y) && type != 'b')
processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str());
- if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
- log_id(cell));
+ if (verbose)
+ log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
if (type == 'b') {
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
- log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
+ get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y)));
register_boolvec(sig_y, idcounter++);
} else {
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
- log_id(module), idcounter, log_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y)));
+ get_id(module), idcounter, get_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y)));
register_bv(sig_y, idcounter++);
}
@@ -302,21 +345,23 @@ struct Smt2Worker
} else
processed_expr += ch;
- if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
- log_id(cell));
+ if (verbose)
+ log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
+
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
- log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
+ get_id(module), idcounter, get_id(module), processed_expr.c_str(), log_signal(sig_y)));
register_boolvec(sig_y, idcounter++);
recursive_cells.erase(cell);
}
void export_cell(RTLIL::Cell *cell)
{
- if (verbose) log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "",
- log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new");
+ if (verbose)
+ log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "",
+ log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new");
if (recursive_cells.count(cell))
- log_error("Found logic loop in module %s! See cell %s.\n", log_id(module), log_id(cell));
+ log_error("Found logic loop in module %s! See cell %s.\n", get_id(module), get_id(cell));
if (exported_cells.count(cell))
return;
@@ -324,11 +369,21 @@ struct Smt2Worker
exported_cells.insert(cell);
recursive_cells.insert(cell);
+ if (cell->type == "$initstate")
+ {
+ SigBit bit = sigmap(cell->getPort("\\Y").as_bit());
+ decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (|%s_is| state)) ; %s\n",
+ get_id(module), idcounter, get_id(module), get_id(module), log_signal(bit)));
+ register_bool(bit, idcounter++);
+ recursive_cells.erase(cell);
+ return;
+ }
+
if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_")
{
registers.insert(cell);
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
- log_id(module), idcounter, log_id(module), log_signal(cell->getPort("\\Q"))));
+ get_id(module), idcounter, get_id(module), log_signal(cell->getPort("\\Q"))));
register_bool(cell->getPort("\\Q"), idcounter++);
recursive_cells.erase(cell);
return;
@@ -356,12 +411,24 @@ struct Smt2Worker
{
registers.insert(cell);
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
- log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
+ get_id(module), idcounter, get_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
register_bv(cell->getPort("\\Q"), idcounter++);
recursive_cells.erase(cell);
return;
}
+ if (cell->type == "$anyconst")
+ {
+ registers.insert(cell);
+ decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter,
+ cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
+ get_id(module), idcounter, get_id(module), GetSize(cell->getPort("\\Y")), log_signal(cell->getPort("\\Y"))));
+ register_bv(cell->getPort("\\Y"), idcounter++);
+ recursive_cells.erase(cell);
+ return;
+ }
+
if (cell->type == "$and") return export_bvop(cell, "(bvand A B)");
if (cell->type == "$or") return export_bvop(cell, "(bvor A B)");
if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)");
@@ -372,7 +439,13 @@ struct Smt2Worker
if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's');
if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's');
- // FIXME: $shift $shiftx
+ if (cell->type.in("$shift", "$shiftx")) {
+ if (cell->getParam("\\B_SIGNED").as_bool()) {
+ /* FIXME */
+ } else {
+ return export_bvop(cell, "(bvlshr A B)", 's');
+ }
+ }
if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b');
if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b');
@@ -418,11 +491,12 @@ struct Smt2Worker
processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(),
get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str());
- if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
- log_id(cell));
+ if (verbose)
+ log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "", log_id(cell));
+
RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y"));
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
- log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig)));
+ get_id(module), idcounter, get_id(module), width, processed_expr.c_str(), log_signal(sig)));
register_bv(sig, idcounter++);
recursive_cells.erase(cell);
return;
@@ -441,22 +515,27 @@ struct Smt2Worker
int rd_ports = cell->getParam("\\RD_PORTS").as_int();
decls.push_back(stringf("(declare-fun |%s#%d#0| (|%s_s|) (Array (_ BitVec %d) (_ BitVec %d))) ; %s\n",
- log_id(module), arrayid, log_id(module), abits, width, log_id(cell)));
+ get_id(module), arrayid, get_id(module), abits, width, get_id(cell)));
+ decls.push_back(stringf("; yosys-smt2-memory %s %d %d %d\n", get_id(cell), abits, width, rd_ports));
decls.push_back(stringf("(define-fun |%s_m %s| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) (|%s#%d#0| state))\n",
- log_id(module), log_id(cell), log_id(module), abits, width, log_id(module), arrayid));
+ get_id(module), get_id(cell), get_id(module), abits, width, get_id(module), arrayid));
for (int i = 0; i < rd_ports; i++)
{
- std::string addr = get_bv(cell->getPort("\\RD_ADDR").extract(abits*i, abits));
+ SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(abits*i, abits);
SigSpec data_sig = cell->getPort("\\RD_DATA").extract(width*i, width);
+ std::string addr = get_bv(addr_sig);
if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
log_error("Read port %d (%s) of memory %s.%s is clocked. This is not supported by \"write_smt2\"! "
"Call \"memory\" with -nordff to avoid this error.\n", i, log_signal(data_sig), log_id(cell), log_id(module));
+ decls.push_back(stringf("(define-fun |%s_m:%d %s| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
+ get_id(module), i, get_id(cell), get_id(module), abits, addr.c_str(), log_signal(addr_sig)));
+
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) (select (|%s#%d#0| state) %s)) ; %s\n",
- log_id(module), idcounter, log_id(module), width, log_id(module), arrayid, addr.c_str(), log_signal(data_sig)));
+ get_id(module), idcounter, get_id(module), width, get_id(module), arrayid, addr.c_str(), log_signal(data_sig)));
register_bv(data_sig, idcounter++);
}
@@ -465,6 +544,48 @@ struct Smt2Worker
return;
}
+ Module *m = module->design->module(cell->type);
+
+ if (m != nullptr)
+ {
+ decls.push_back(stringf("; yosys-smt2-cell %s %s\n", get_id(cell->type), get_id(cell->name)));
+ string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name));
+
+ for (auto &conn : cell->connections())
+ {
+ Wire *w = m->wire(conn.first);
+ SigSpec sig = sigmap(conn.second);
+
+ if (w->port_output && !w->port_input) {
+ if (GetSize(w) > 1) {
+ if (bvmode) {
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
+ get_id(module), idcounter, get_id(module), GetSize(w), log_signal(sig)));
+ register_bv(sig, idcounter++);
+ } else {
+ for (int i = 0; i < GetSize(w); i++) {
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
+ get_id(module), idcounter, get_id(module), log_signal(sig[i])));
+ register_bool(sig[i], idcounter++);
+ }
+ }
+ } else {
+ decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
+ get_id(module), idcounter, get_id(module), log_signal(sig)));
+ register_bool(sig, idcounter++);
+ }
+ }
+ }
+
+ decls.push_back(stringf("(declare-fun |%s_h %s| (|%s_s|) |%s_s|)\n",
+ get_id(module), get_id(cell->name), get_id(module), get_id(cell->type)));
+
+ hiercells.insert(cell);
+ hiercells_queue.insert(cell);
+ recursive_cells.erase(cell);
+ return;
+ }
+
log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv or -mem mode?)\n",
log_id(cell->type), log_id(module), log_id(cell));
}
@@ -474,42 +595,39 @@ struct Smt2Worker
if (verbose) log("=> export logic driving outputs\n");
pool<SigBit> reg_bits;
- if (regsmode) {
- for (auto cell : module->cells())
- if (cell->type.in("$_DFF_P_", "$_DFF_N_", "$dff")) {
- // not using sigmap -- we want the net directly at the dff output
- for (auto bit : cell->getPort("\\Q"))
- reg_bits.insert(bit);
- }
- }
+ for (auto cell : module->cells())
+ if (cell->type.in("$_DFF_P_", "$_DFF_N_", "$dff")) {
+ // not using sigmap -- we want the net directly at the dff output
+ for (auto bit : cell->getPort("\\Q"))
+ reg_bits.insert(bit);
+ }
for (auto wire : module->wires()) {
bool is_register = false;
- if (regsmode)
- for (auto bit : SigSpec(wire))
- if (reg_bits.count(bit))
- is_register = true;
+ for (auto bit : SigSpec(wire))
+ if (reg_bits.count(bit))
+ is_register = true;
if (wire->port_id || is_register || wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\')) {
RTLIL::SigSpec sig = sigmap(wire);
if (wire->port_input)
- decls.push_back(stringf("; yosys-smt2-input %s %d\n", log_id(wire), wire->width));
+ decls.push_back(stringf("; yosys-smt2-input %s %d\n", get_id(wire), wire->width));
if (wire->port_output)
- decls.push_back(stringf("; yosys-smt2-output %s %d\n", log_id(wire), wire->width));
+ decls.push_back(stringf("; yosys-smt2-output %s %d\n", get_id(wire), wire->width));
if (is_register)
- decls.push_back(stringf("; yosys-smt2-register %s %d\n", log_id(wire), wire->width));
+ decls.push_back(stringf("; yosys-smt2-register %s %d\n", get_id(wire), wire->width));
if (wire->get_bool_attribute("\\keep") || (wiresmode && wire->name[0] == '\\'))
- decls.push_back(stringf("; yosys-smt2-wire %s %d\n", log_id(wire), wire->width));
+ decls.push_back(stringf("; yosys-smt2-wire %s %d\n", get_id(wire), wire->width));
if (bvmode && GetSize(sig) > 1) {
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n",
- log_id(module), log_id(wire), log_id(module), GetSize(sig), get_bv(sig).c_str()));
+ get_id(module), get_id(wire), get_id(module), GetSize(sig), get_bv(sig).c_str()));
} else {
for (int i = 0; i < GetSize(sig); i++)
if (GetSize(sig) > 1)
decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n",
- log_id(module), log_id(wire), i, log_id(module), get_bool(sig[i]).c_str()));
+ get_id(module), get_id(wire), i, get_id(module), get_bool(sig[i]).c_str()));
else
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n",
- log_id(module), log_id(wire), log_id(module), get_bool(sig[i]).c_str()));
+ get_id(module), get_id(wire), get_id(module), get_bool(sig[i]).c_str()));
}
}
}
@@ -523,26 +641,28 @@ struct Smt2Worker
Const val = wire->attributes.at("\\init");
val.bits.resize(GetSize(sig));
if (bvmode && GetSize(sig) > 1) {
- init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), log_id(wire)));
+ init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), get_id(wire)));
} else {
for (int i = 0; i < GetSize(sig); i++)
- init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", log_id(wire)));
+ init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", get_id(wire)));
}
}
if (verbose) log("=> export logic driving asserts\n");
- vector<int> assert_list, assume_list;
+ vector<string> assert_list, assume_list;
for (auto cell : module->cells())
if (cell->type.in("$assert", "$assume")) {
string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN"));
+ decls.push_back(stringf("; yosys-smt2-%s %s#%d %s\n", cell->type.c_str() + 1, get_id(module), idcounter,
+ cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
- log_id(module), idcounter, log_id(module), name_a.c_str(), name_en.c_str(), log_id(cell)));
+ get_id(module), idcounter, get_id(module), name_a.c_str(), name_en.c_str(), get_id(cell)));
if (cell->type == "$assert")
- assert_list.push_back(idcounter++);
+ assert_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
else
- assume_list.push_back(idcounter++);
+ assume_list.push_back(stringf("(|%s#%d| state)", get_id(module), idcounter++));
}
for (int iter = 1; !registers.empty(); iter++)
@@ -558,14 +678,21 @@ struct Smt2Worker
{
std::string expr_d = get_bool(cell->getPort("\\D"));
std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state");
- trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
+ trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Q"))));
}
if (cell->type == "$dff")
{
std::string expr_d = get_bv(cell->getPort("\\D"));
std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state");
- trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
+ trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Q"))));
+ }
+
+ if (cell->type == "$anyconst")
+ {
+ std::string expr_d = get_bv(cell->getPort("\\Y"));
+ std::string expr_q = get_bv(cell->getPort("\\Y"), "next_state");
+ trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell), log_signal(cell->getPort("\\Y"))));
}
if (cell->type == "$mem")
@@ -583,56 +710,144 @@ struct Smt2Worker
std::string mask = get_bv(cell->getPort("\\WR_EN").extract(width*i, width));
data = stringf("(bvor (bvand %s %s) (bvand (select (|%s#%d#%d| state) %s) (bvnot %s)))",
- data.c_str(), mask.c_str(), log_id(module), arrayid, i, addr.c_str(), mask.c_str());
+ data.c_str(), mask.c_str(), get_id(module), arrayid, i, addr.c_str(), mask.c_str());
decls.push_back(stringf("(define-fun |%s#%d#%d| ((state |%s_s|)) (Array (_ BitVec %d) (_ BitVec %d)) "
"(store (|%s#%d#%d| state) %s %s)) ; %s\n",
- log_id(module), arrayid, i+1, log_id(module), abits, width,
- log_id(module), arrayid, i, addr.c_str(), data.c_str(), log_id(cell)));
+ get_id(module), arrayid, i+1, get_id(module), abits, width,
+ get_id(module), arrayid, i, addr.c_str(), data.c_str(), get_id(cell)));
+ }
+
+ std::string expr_d = stringf("(|%s#%d#%d| state)", get_id(module), arrayid, wr_ports);
+ std::string expr_q = stringf("(|%s#%d#0| next_state)", get_id(module), arrayid);
+ trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), get_id(cell)));
+
+ Const init_data = cell->getParam("\\INIT");
+ int memsize = cell->getParam("\\SIZE").as_int();
+
+ for (int i = 0; i < memsize; i++)
+ {
+ if (i*width >= GetSize(init_data))
+ break;
+
+ Const initword = init_data.extract(i*width, width, State::Sx);
+ bool gen_init_constr = false;
+
+ for (auto bit : initword.bits)
+ if (bit == State::S0 || bit == State::S1)
+ gen_init_constr = true;
+
+ if (gen_init_constr) {
+ init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
+ get_id(module), arrayid, Const(i, abits).as_string().c_str(),
+ initword.as_string().c_str(), get_id(cell), i));
+ }
}
+ }
+ }
+ }
+
+ if (verbose) log("=> export logic driving hierarchical cells\n");
- std::string expr_d = stringf("(|%s#%d#%d| state)", log_id(module), arrayid, wr_ports);
- std::string expr_q = stringf("(|%s#%d#0| next_state)", log_id(module), arrayid);
- trans.push_back(stringf(" (= %s %s) ; %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell)));
+ while (!hiercells_queue.empty())
+ {
+ std::set<RTLIL::Cell*> queue;
+ queue.swap(hiercells_queue);
+
+ for (auto cell : queue)
+ {
+ string cell_state = stringf("(|%s_h %s| state)", get_id(module), get_id(cell->name));
+ Module *m = module->design->module(cell->type);
+ log_assert(m != nullptr);
+
+ for (auto &conn : cell->connections())
+ {
+ Wire *w = m->wire(conn.first);
+ SigSpec sig = sigmap(conn.second);
+
+ if (bvmode || GetSize(w) == 1) {
+ hier.push_back(stringf(" (= %s (|%s_n %s| %s)) ; %s.%s\n", (GetSize(w) > 1 ? get_bv(sig) : get_bool(sig)).c_str(),
+ get_id(cell->type), get_id(w), cell_state.c_str(), get_id(cell->type), get_id(w)));
+ } else {
+ for (int i = 0; i < GetSize(w); i++)
+ hier.push_back(stringf(" (= %s (|%s_n %s %d| %s)) ; %s.%s[%d]\n", get_bool(sig[i]).c_str(),
+ get_id(cell->type), get_id(w), i, cell_state.c_str(), get_id(cell->type), get_id(w), i));
+ }
}
}
}
+ if (verbose) log("=> finalizing SMT2 representation of %s.\n", log_id(module));
+
+ for (auto c : hiercells) {
+ assert_list.push_back(stringf("(|%s_a| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name)));
+ assume_list.push_back(stringf("(|%s_u| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name)));
+ init_list.push_back(stringf("(|%s_i| (|%s_h %s| state))", get_id(c->type), get_id(module), get_id(c->name)));
+ hier.push_back(stringf(" (|%s_h| (|%s_h %s| state))\n", get_id(c->type), get_id(module), get_id(c->name)));
+ trans.push_back(stringf(" (|%s_t| (|%s_h %s| state) (|%s_h %s| next_state))\n",
+ get_id(c->type), get_id(module), get_id(c->name), get_id(module), get_id(c->name)));
+ }
+
string assert_expr = assert_list.empty() ? "true" : "(and";
if (!assert_list.empty()) {
- for (int i : assert_list)
- assert_expr += stringf(" (|%s#%d| state)", log_id(module), i);
- assert_expr += ")";
+ if (GetSize(assert_list) == 1) {
+ assert_expr = "\n " + assert_list.front() + "\n";
+ } else {
+ for (auto &str : assert_list)
+ assert_expr += stringf("\n %s", str.c_str());
+ assert_expr += "\n)";
+ }
}
decls.push_back(stringf("(define-fun |%s_a| ((state |%s_s|)) Bool %s)\n",
- log_id(module), log_id(module), assert_expr.c_str()));
+ get_id(module), get_id(module), assert_expr.c_str()));
string assume_expr = assume_list.empty() ? "true" : "(and";
if (!assume_list.empty()) {
- for (int i : assume_list)
- assume_expr += stringf(" (|%s#%d| state)", log_id(module), i);
- assume_expr += ")";
+ if (GetSize(assume_list) == 1) {
+ assume_expr = "\n " + assume_list.front() + "\n";
+ } else {
+ for (auto &str : assume_list)
+ assume_expr += stringf("\n %s", str.c_str());
+ assume_expr += "\n)";
+ }
}
decls.push_back(stringf("(define-fun |%s_u| ((state |%s_s|)) Bool %s)\n",
- log_id(module), log_id(module), assume_expr.c_str()));
+ get_id(module), get_id(module), assume_expr.c_str()));
string init_expr = init_list.empty() ? "true" : "(and";
if (!init_list.empty()) {
- for (auto &str : init_list)
- init_expr += stringf("\n\t%s", str.c_str());
- init_expr += "\n)";
+ if (GetSize(init_list) == 1) {
+ init_expr = "\n " + init_list.front() + "\n";
+ } else {
+ for (auto &str : init_list)
+ init_expr += stringf("\n %s", str.c_str());
+ init_expr += "\n)";
+ }
}
decls.push_back(stringf("(define-fun |%s_i| ((state |%s_s|)) Bool %s)\n",
- log_id(module), log_id(module), init_expr.c_str()));
+ get_id(module), get_id(module), init_expr.c_str()));
}
void write(std::ostream &f)
{
+ f << stringf("; yosys-smt2-module %s\n", get_id(module));
+
for (auto it : decls)
f << it;
- f << stringf("; yosys-smt2-module %s\n", log_id(module));
- f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", log_id(module), log_id(module), log_id(module));
+ f << stringf("(define-fun |%s_h| ((state |%s_s|)) Bool ", get_id(module), get_id(module));
+ if (GetSize(hier) > 1) {
+ f << "(and\n";
+ for (auto it : hier)
+ f << it;
+ f << "))\n";
+ } else
+ if (GetSize(hier) == 1)
+ f << "\n" + hier.front() + ")\n";
+ else
+ f << "true)\n";
+
+ f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", get_id(module), get_id(module), get_id(module));
if (GetSize(trans) > 1) {
f << "(and\n";
for (auto it : trans)
@@ -643,7 +858,7 @@ struct Smt2Worker
f << "\n" + trans.front() + ")";
else
f << "true)";
- f << stringf(" ; end of module %s\n", log_id(module));
+ f << stringf(" ; end of module %s\n", get_id(module));
}
};
@@ -661,10 +876,10 @@ struct Smt2Backend : public Backend {
log("\n");
log("The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions\n");
log("are provided that can be used to access the values of the signals in the module.\n");
- log("Only ports, and signals with the 'keep' attribute set are made available via\n");
- log("such functions. Without the -bv option, multi-bit wires are exported as\n");
- log("separate functions of type Bool for the individual bits. With the -bv option\n");
- log("multi-bit wires are exported as single functions of type BitVec.\n");
+ log("By default only ports, registers, and wires with the 'keep' attribute set are\n");
+ log("made available via such functions. With the -nobv option, multi-bit wires are\n");
+ log("exported as separate functions of type Bool for the individual bits. Without\n");
+ log("-nobv multi-bit wires are exported as single functions of type BitVec.\n");
log("\n");
log("The '<mod>_t' function evaluates to 'true' when the given pair of states\n");
log("describes a valid state transition.\n");
@@ -676,29 +891,33 @@ struct Smt2Backend : public Backend {
log("the assumptions in the module.\n");
log("\n");
log("The '<mod>_i' function evaluates to 'true' when the given state conforms\n");
- log("to the initial state.\n");
+ log("to the initial state. Furthermore the '<mod>_is' function should be asserted\n");
+ log("to be true for initial states in addition to '<mod>_i', and should be\n");
+ log("asserted to be false for non-initial states.\n");
+ log("\n");
+ log("For hierarchical designs, the '<mod>_h' function must be asserted for each\n");
+ log("state to establish the design hierarchy. The '<mod>_h <cellname>' function\n");
+ log("evaluates to the state corresponding to the given cell within <mod>.\n");
log("\n");
log(" -verbose\n");
log(" this will print the recursive walk used to export the modules.\n");
log("\n");
- log(" -bv\n");
- log(" enable support for BitVec (FixedSizeBitVectors theory). with this\n");
- log(" option set multi-bit wires are represented using the BitVec sort and\n");
+ log(" -nobv\n");
+ log(" disable support for BitVec (FixedSizeBitVectors theory). without this\n");
+ log(" option multi-bit wires are represented using the BitVec sort and\n");
log(" support for coarse grain cells (incl. arithmetic) is enabled.\n");
log("\n");
- log(" -mem\n");
- log(" enable support for memories (via ArraysEx theory). this option\n");
- log(" also implies -bv. only $mem cells without merged registers in\n");
+ log(" -nomem\n");
+ log(" disable support for memories (via ArraysEx theory). this option is\n");
+ log(" implied by -nobv. only $mem cells without merged registers in\n");
log(" read ports are supported. call \"memory\" with -nordff to make sure\n");
log(" that no registers are merged into $mem read ports. '<mod>_m' functions\n");
log(" will be generated for accessing the arrays that are used to represent\n");
log(" memories.\n");
log("\n");
- log(" -regs\n");
- log(" also create '<mod>_n' functions for all registers.\n");
- log("\n");
log(" -wires\n");
- log(" also create '<mod>_n' functions for all public wires.\n");
+ log(" create '<mod>_n' functions for all public wires. by default only ports,\n");
+ log(" registers, and wires with the 'keep' attribute are exported.\n");
log("\n");
log(" -tpl <template_file>\n");
log(" use the given template file. the line containing only the token '%%%%'\n");
@@ -756,9 +975,9 @@ struct Smt2Backend : public Backend {
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::ifstream template_f;
- bool bvmode = false, memmode = false, regsmode = false, wiresmode = false, verbose = false;
+ bool bvmode = true, memmode = true, wiresmode = false, verbose = false;
- log_header("Executing SMT2 backend.\n");
+ log_header(design, "Executing SMT2 backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -769,17 +988,17 @@ struct Smt2Backend : public Backend {
log_error("Can't open template file `%s'.\n", args[argidx].c_str());
continue;
}
- if (args[argidx] == "-bv") {
- bvmode = true;
+ if (args[argidx] == "-bv" || args[argidx] == "-mem") {
+ log_warning("Options -bv and -mem are now the default. Support for -bv and -mem will be removed in the future.\n");
continue;
}
- if (args[argidx] == "-mem") {
- bvmode = true;
- memmode = true;
+ if (args[argidx] == "-nobv") {
+ bvmode = false;
+ memmode = false;
continue;
}
- if (args[argidx] == "-regs") {
- regsmode = true;
+ if (args[argidx] == "-nomem") {
+ memmode = false;
continue;
}
if (args[argidx] == "-wires") {
@@ -808,18 +1027,62 @@ struct Smt2Backend : public Backend {
*f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str);
- for (auto module : design->modules())
+ if (!bvmode)
+ *f << stringf("; yosys-smt2-nobv\n");
+
+ if (!memmode)
+ *f << stringf("; yosys-smt2-nomem\n");
+
+ std::vector<RTLIL::Module*> sorted_modules;
+
+ // extract module dependencies
+ std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps;
+ for (auto &mod_it : design->modules_) {
+ module_deps[mod_it.second] = std::set<RTLIL::Module*>();
+ for (auto &cell_it : mod_it.second->cells_)
+ if (design->modules_.count(cell_it.second->type) > 0)
+ module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type));
+ }
+
+ // simple good-enough topological sort
+ // (O(n*m) on n elements and depth m)
+ while (module_deps.size() > 0) {
+ size_t sorted_modules_idx = sorted_modules.size();
+ for (auto &it : module_deps) {
+ for (auto &dep : it.second)
+ if (module_deps.count(dep) > 0)
+ goto not_ready_yet;
+ // log("Next in topological sort: %s\n", RTLIL::id2cstr(it.first->name));
+ sorted_modules.push_back(it.first);
+ not_ready_yet:;
+ }
+ if (sorted_modules_idx == sorted_modules.size())
+ log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", RTLIL::id2cstr(module_deps.begin()->first->name));
+ while (sorted_modules_idx < sorted_modules.size())
+ module_deps.erase(sorted_modules.at(sorted_modules_idx++));
+ }
+
+ Module *topmod = design->top_module();
+ std::string topmod_id;
+
+ for (auto module : sorted_modules)
{
if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
continue;
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
- Smt2Worker worker(module, bvmode, memmode, regsmode, wiresmode, verbose);
+ Smt2Worker worker(module, bvmode, memmode, wiresmode, verbose);
worker.run();
worker.write(*f);
+
+ if (module == topmod)
+ topmod_id = worker.get_id(module);
}
+ if (topmod)
+ *f << stringf("; yosys-smt2-topmod %s\n", topmod_id.c_str());
+
*f << stringf("; end of yosys output\n");
if (template_f.is_open()) {
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py
index f2911b3e..bb763647 100644
--- a/backends/smt2/smtbmc.py
+++ b/backends/smt2/smtbmc.py
@@ -19,66 +19,119 @@
import os, sys, getopt, re
##yosys-sys-path##
-from smtio import smtio, smtopts, mkvcd
+from smtio import SmtIo, SmtOpts, MkVcd
+from collections import defaultdict
skip_steps = 0
step_size = 1
num_steps = 20
vcdfile = None
+vlogtbfile = None
+inconstr = list()
+outconstr = None
+gentrace = False
tempind = False
+dumpall = False
assume_skipped = None
+final_only = False
topmod = None
-so = smtopts()
+noinfo = False
+so = SmtOpts()
def usage():
print("""
yosys-smtbmc [options] <yosys_smt2_output>
- -t <num_steps>, -t <skip_steps>:<num_steps>
- default: skip_steps=0, num_steps=20
+ -t <num_steps>
+ -t <skip_steps>:<num_steps>
+ -t <skip_steps>:<step_size>:<num_steps>
+ default: skip_steps=0, step_size=1, num_steps=20
- -u <start_step>
- assume asserts in skipped steps in BMC
-
- -S <step_size>
- proof <step_size> time steps at once
-
- -c <vcd_filename>
- write counter-example to this VCD file
- (hint: use 'write_smt2 -wires' for maximum
- coverage of signals in generated VCD file)
+ -g
+ generate an arbitrary trace that satisfies
+ all assertions and assumptions.
-i
instead of BMC run temporal induction
-m <module_name>
name of the top module
+
+ --smtc <constr_filename>
+ read constraints file
+
+ --noinfo
+ only run the core proof, do not collect and print any
+ additional information (e.g. which assert failed)
+
+ --final-only
+ only check final constraints, assume base case
+
+ --assume-skipped <start_step>
+ assume asserts in skipped steps in BMC.
+ no assumptions are created for skipped steps
+ before <start_step>.
+
+ --dump-vcd <vcd_filename>
+ write trace to this VCD file
+ (hint: use 'write_smt2 -wires' for maximum
+ coverage of signals in generated VCD file)
+
+ --dump-vlogtb <verilog_filename>
+ write trace as Verilog test bench
+
+ --dump-smtc <constr_filename>
+ write trace as constraints file
+
+ --dump-all
+ when using -g or -i, create a dump file for each
+ step. The character '%' is replaces in all dump
+ filenames with the step number.
""" + so.helpmsg())
sys.exit(1)
try:
- opts, args = getopt.getopt(sys.argv[1:], so.optstr + "t:u:S:c:im:")
+ opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igm:", so.longopts +
+ ["final-only", "assume-skipped=", "smtc=", "dump-vcd=", "dump-vlogtb=", "dump-smtc=", "dump-all", "noinfo"])
except:
usage()
for o, a in opts:
if o == "-t":
- match = re.match(r"(\d+):(.*)", a)
- if match:
- skip_steps = int(match.group(1))
- num_steps = int(match.group(2))
+ a = a.split(":")
+ if len(a) == 1:
+ num_steps = int(a[0])
+ elif len(a) == 2:
+ skip_steps = int(a[0])
+ num_steps = int(a[1])
+ elif len(a) == 3:
+ skip_steps = int(a[0])
+ step_size = int(a[1])
+ num_steps = int(a[2])
else:
- num_steps = int(a)
- elif o == "-u":
+ assert 0
+ elif o == "--assume-skipped":
assume_skipped = int(a)
- elif o == "-S":
- step_size = int(a)
- elif o == "-c":
+ elif o == "--final-only":
+ final_only = True
+ elif o == "--smtc":
+ inconstr.append(a)
+ elif o == "--dump-vcd":
vcdfile = a
+ elif o == "--dump-vlogtb":
+ vlogtbfile = a
+ elif o == "--dump-smtc":
+ outconstr = a
+ elif o == "--dump-all":
+ dumpall = True
+ elif o == "--noinfo":
+ noinfo = True
elif o == "-i":
tempind = True
+ elif o == "-g":
+ gentrace = True
elif o == "-m":
topmod = a
elif so.handle(o, a):
@@ -90,73 +143,422 @@ if len(args) != 1:
usage()
-smt = smtio(opts=so)
+constr_final_start = None
+constr_asserts = defaultdict(list)
+constr_assumes = defaultdict(list)
+
+for fn in inconstr:
+ current_states = None
+ current_line = 0
+
+ with open(fn, "r") as f:
+ for line in f:
+ current_line += 1
+
+ if line.startswith("#"):
+ continue
+
+ tokens = line.split()
+
+ if len(tokens) == 0:
+ continue
+
+ if tokens[0] == "initial":
+ current_states = set()
+ if not tempind:
+ current_states.add(0)
+ continue
+
+ if tokens[0] == "final":
+ constr_final = True
+ if len(tokens) == 1:
+ current_states = set(["final-%d" % i for i in range(0, num_steps+1)])
+ constr_final_start = 0
+ elif len(tokens) == 2:
+ i = int(tokens[1])
+ assert i < 0
+ current_states = set(["final-%d" % i for i in range(-i, num_steps+1)])
+ constr_final_start = -i if constr_final_start is None else min(constr_final_start, -i)
+ else:
+ assert 0
+ continue
+
+ if tokens[0] == "state":
+ current_states = set()
+ if not tempind:
+ for token in tokens[1:]:
+ tok = token.split(":")
+ if len(tok) == 1:
+ current_states.add(int(token))
+ elif len(tok) == 2:
+ lower = int(tok[0])
+ if tok[1] == "*":
+ upper = num_steps
+ else:
+ upper = int(tok[1])
+ for i in range(lower, upper+1):
+ current_states.add(i)
+ else:
+ assert 0
+ continue
+
+ if tokens[0] == "always":
+ if len(tokens) == 1:
+ current_states = set(range(0, num_steps+1))
+ elif len(tokens) == 2:
+ i = int(tokens[1])
+ assert i < 0
+ current_states = set(range(-i, num_steps+1))
+ else:
+ assert 0
+ continue
+
+ if tokens[0] == "assert":
+ assert current_states is not None
+
+ for state in current_states:
+ constr_asserts[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:])))
+
+ continue
+
+ if tokens[0] == "assume":
+ assert current_states is not None
+
+ for state in current_states:
+ constr_assumes[state].append(("%s:%d" % (fn, current_line), " ".join(tokens[1:])))
+
+ continue
+
+ assert 0
+
+
+def get_constr_expr(db, state, final=False, getvalues=False):
+ if final:
+ if ("final-%d" % state) not in db:
+ return ([], [], []) if getvalues else "true"
+ else:
+ if state not in db:
+ return ([], [], []) if getvalues else "true"
+
+ netref_regex = re.compile(r'(^|[( ])\[(-?[0-9]+:|)([^\]]+)\](?=[ )]|$)')
+
+ def replace_netref(match):
+ state_sel = match.group(2)
+
+ if state_sel == "":
+ st = state
+ elif state_sel[0] == "-":
+ st = state + int(state_sel[:-1])
+ else:
+ st = int(state_sel[:-1])
+
+ expr = smt.net_expr(topmod, "s%d" % st, smt.get_path(topmod, match.group(3)))
+
+ return match.group(1) + expr
+
+ expr_list = list()
+ for loc, expr in db[("final-%d" % state) if final else state]:
+ actual_expr = netref_regex.sub(replace_netref, expr)
+ if getvalues:
+ expr_list.append((loc, expr, actual_expr))
+ else:
+ expr_list.append(actual_expr)
+
+ if getvalues:
+ loc_list, expr_list, acual_expr_list = zip(*expr_list)
+ value_list = smt.get_list(acual_expr_list)
+ return loc_list, expr_list, value_list
+
+ if len(expr_list) == 0:
+ return "true"
+
+ if len(expr_list) == 1:
+ return expr_list[0]
+
+ return "(and %s)" % " ".join(expr_list)
-print("%s Solver: %s" % (smt.timestamp(), so.solver))
-smt.setup("QF_AUFBV")
-debug_nets = set()
-debug_nets_re = re.compile(r"^; yosys-smt2-(input|output|register|wire) (\S+) (\d+)")
+smt = SmtIo(opts=so)
+
+def print_msg(msg):
+ print("%s %s" % (smt.timestamp(), msg))
+ sys.stdout.flush()
+
+print_msg("Solver: %s" % (so.solver))
with open(args[0], "r") as f:
for line in f:
- match = debug_nets_re.match(line)
- if match:
- debug_nets.add(match.group(2))
- if line.startswith("; yosys-smt2-module") and topmod is None:
- topmod = line.split()[2]
smt.write(line)
+if topmod is None:
+ topmod = smt.topmod
+
assert topmod is not None
+assert topmod in smt.modinfo
+
+
+def write_vcd_trace(steps_start, steps_stop, index):
+ filename = vcdfile.replace("%", index)
+ print_msg("Writing trace to VCD file: %s" % (filename))
+
+ with open(filename, "w") as vcd_file:
+ vcd = MkVcd(vcd_file)
+ path_list = list()
+
+ for netpath in sorted(smt.hiernets(topmod)):
+ hidden_net = False
+ for n in netpath:
+ if n.startswith("$"):
+ hidden_net = True
+ if not hidden_net:
+ vcd.add_net([topmod] + netpath, smt.net_width(topmod, netpath))
+ path_list.append(netpath)
+
+ for i in range(steps_start, steps_stop):
+ vcd.set_time(i)
+ value_list = smt.get_net_bin_list(topmod, path_list, "s%d" % i)
+ for path, value in zip(path_list, value_list):
+ vcd.set_net([topmod] + path, value)
+
+ vcd.set_time(steps_stop)
+
+
+def write_vlogtb_trace(steps_start, steps_stop, index):
+ filename = vlogtbfile.replace("%", index)
+ print_msg("Writing trace to Verilog testbench: %s" % (filename))
+
+ with open(filename, "w") as f:
+ print("module testbench;", file=f)
+ print(" reg [4095:0] vcdfile;", file=f)
+ print(" reg clock = 0, genclock = 1;", file=f)
+
+ primary_inputs = list()
+ clock_inputs = set()
+
+ for name in smt.modinfo[topmod].inputs:
+ if name in ["clk", "clock", "CLK", "CLOCK"]:
+ clock_inputs.add(name)
+ width = smt.modinfo[topmod].wsize[name]
+ primary_inputs.append((name, width))
+
+ for name, width in primary_inputs:
+ if name in clock_inputs:
+ print(" wire [%d:0] PI_%s = clock;" % (width-1, name), file=f)
+ else:
+ print(" reg [%d:0] PI_%s;" % (width-1, name), file=f)
+
+ print(" %s UUT (" % topmod, file=f)
+ print(",\n".join(" .{name}(PI_{name})".format(name=name) for name, _ in primary_inputs), file=f)
+ print(" );", file=f)
+
+ print(" initial begin", file=f)
+ print(" if ($value$plusargs(\"vcd=%s\", vcdfile)) begin", file=f)
+ print(" $dumpfile(vcdfile);", file=f)
+ print(" $dumpvars(0, testbench);", file=f)
+ print(" end", file=f)
+ print(" while (genclock) begin", file=f)
+ print(" #5; clock = 0;", file=f)
+ print(" #5; clock = 1;", file=f)
+ print(" end", file=f)
+ print(" end", file=f)
+
+ print(" initial begin", file=f)
+
+ regs = sorted(smt.hiernets(topmod, regs_only=True))
+ regvals = smt.get_net_bin_list(topmod, regs, "s%d" % steps_start)
+
+ print(" #1;", file=f)
+ for reg, val in zip(regs, regvals):
+ hidden_net = False
+ for n in reg:
+ if n.startswith("$"):
+ hidden_net = True
+ print(" %sUUT.%s = %d'b%s;" % ("// " if hidden_net else "", ".".join(reg), len(val), val), file=f)
+
+ mems = sorted(smt.hiermems(topmod))
+ for mempath in mems:
+ abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
+ mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
+
+ addr_expr_list = list()
+ for i in range(steps_start, steps_stop):
+ for j in range(ports):
+ addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j))
+
+ addr_list = set()
+ for val in smt.get_list(addr_expr_list):
+ addr_list.add(smt.bv2int(val))
+
+ expr_list = list()
+ for i in addr_list:
+ expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits)))
+
+ for i, val in zip(addr_list, smt.get_list(expr_list)):
+ val = smt.bv2bin(val)
+ print(" UUT.%s[%d] = %d'b%s;" % (".".join(mempath), i, len(val), val), file=f)
+
+ for i in range(steps_start, steps_stop):
+ pi_names = [[name] for name, _ in primary_inputs if name not in clock_inputs]
+ pi_values = smt.get_net_bin_list(topmod, pi_names, "s%d" % i)
+
+ print(" #1;", file=f)
+ print(" // state %d" % i, file=f)
+ if i > 0:
+ print(" @(posedge clock);", file=f)
+ for name, val in zip(pi_names, pi_values):
+ print(" PI_%s <= %d'b%s;" % (".".join(name), len(val), val), file=f)
+
+ print(" genclock = 0;", file=f)
+ print(" end", file=f)
+
+ print("endmodule", file=f)
+
+
+def write_constr_trace(steps_start, steps_stop, index):
+ filename = outconstr.replace("%", index)
+ print_msg("Writing trace to constraints file: %s" % (filename))
+
+ with open(filename, "w") as f:
+ primary_inputs = list()
+
+ for name in smt.modinfo[topmod].inputs:
+ width = smt.modinfo[topmod].wsize[name]
+ primary_inputs.append((name, width))
+
+ if steps_start == 0:
+ print("initial", file=f)
+ else:
+ print("state %d" % steps_start, file=f)
+
+ regnames = sorted(smt.hiernets(topmod, regs_only=True))
+ regvals = smt.get_net_list(topmod, regnames, "s%d" % steps_start)
+
+ for name, val in zip(regnames, regvals):
+ print("assume (= [%s] %s)" % (".".join(name), val), file=f)
+
+ mems = sorted(smt.hiermems(topmod))
+ for mempath in mems:
+ abits, width, ports = smt.mem_info(topmod, "s%d" % steps_start, mempath)
+ mem = smt.mem_expr(topmod, "s%d" % steps_start, mempath)
+
+ addr_expr_list = list()
+ for i in range(steps_start, steps_stop):
+ for j in range(ports):
+ addr_expr_list.append(smt.mem_expr(topmod, "s%d" % i, mempath, j))
+
+ addr_list = set((smt.bv2int(val) for val in smt.get_list(addr_expr_list)))
+
+ expr_list = list()
+ for i in addr_list:
+ expr_list.append("(select %s #b%s)" % (mem, format(i, "0%db" % abits)))
+
+ for i, val in zip(addr_list, smt.get_list(expr_list)):
+ print("assume (= (select [%s] #b%s) %s)" % (".".join(mempath), format(i, "0%db" % abits), val), file=f)
+
+ for k in range(steps_start, steps_stop):
+ print("", file=f)
+ print("state %d" % k, file=f)
+
+ pi_names = [[name] for name, _ in sorted(primary_inputs)]
+ pi_values = smt.get_net_list(topmod, pi_names, "s%d" % k)
+
+ for name, val in zip(pi_names, pi_values):
+ print("assume (= [%s] %s)" % (".".join(name), val), file=f)
+
+
+def write_trace(steps_start, steps_stop, index):
+ if vcdfile is not None:
+ write_vcd_trace(steps_start, steps_stop, index)
+
+ if vlogtbfile is not None:
+ write_vlogtb_trace(steps_start, steps_stop, index)
+
+ if outconstr is not None:
+ write_constr_trace(steps_start, steps_stop, index)
+
+
+def print_failed_asserts_worker(mod, state, path):
+ assert mod in smt.modinfo
+
+ if smt.get("(|%s_a| %s)" % (mod, state)) in ["true", "#b1"]:
+ return
+
+ for cellname, celltype in smt.modinfo[mod].cells.items():
+ print_failed_asserts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
+
+ for assertfun, assertinfo in smt.modinfo[mod].asserts.items():
+ if smt.get("(|%s| %s)" % (assertfun, state)) in ["false", "#b0"]:
+ print_msg("Assert failed in %s: %s" % (path, assertinfo))
-def write_vcd_model(steps):
- print("%s Writing model to VCD file." % smt.timestamp())
+def print_failed_asserts(state, final=False):
+ if noinfo: return
+ loc_list, expr_list, value_list = get_constr_expr(constr_asserts, state, final=final, getvalues=True)
- vcd = mkvcd(open(vcdfile, "w"))
- for netname in sorted(debug_nets):
- width = len(smt.get_net_bin(topmod, netname, "s0"))
- vcd.add_net(netname, width)
+ for loc, expr, value in zip(loc_list, expr_list, value_list):
+ if smt.bv2int(value) == 0:
+ print_msg("Assert %s failed: %s" % (loc, expr))
- for i in range(steps):
- vcd.set_time(i)
- for netname in debug_nets:
- vcd.set_net(netname, smt.get_net_bin(topmod, netname, "s%d" % i))
+ if not final:
+ print_failed_asserts_worker(topmod, "s%d" % state, topmod)
- vcd.set_time(steps)
+
+def print_anyconsts_worker(mod, state, path):
+ assert mod in smt.modinfo
+
+ for cellname, celltype in smt.modinfo[mod].cells.items():
+ print_anyconsts_worker(celltype, "(|%s_h %s| %s)" % (mod, cellname, state), path + "." + cellname)
+
+ for fun, info in smt.modinfo[mod].anyconsts.items():
+ print_msg("Value for anyconst in %s (%s): %d" % (path, info, smt.bv2int(smt.get("(|%s| %s)" % (fun, state)))))
+
+
+def print_anyconsts(state):
+ if noinfo: return
+ print_anyconsts_worker(topmod, "s%d" % state, topmod)
if tempind:
retstatus = False
skip_counter = step_size
for step in range(num_steps, -1, -1):
- smt.write("(declare-fun s%d () %s_s)" % (step, topmod))
- smt.write("(assert (%s_u s%d))" % (topmod, step))
+ smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
+ smt.write("(assert (|%s_u| s%d))" % (topmod, step))
+ smt.write("(assert (|%s_h| s%d))" % (topmod, step))
+ smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step))
+ smt.write("(assert %s)" % get_constr_expr(constr_assumes, step))
if step == num_steps:
- smt.write("(assert (not (%s_a s%d)))" % (topmod, step))
+ smt.write("(assert (not (and (|%s_a| s%d) %s)))" % (topmod, step, get_constr_expr(constr_asserts, step)))
else:
- smt.write("(assert (%s_t s%d s%d))" % (topmod, step, step+1))
- smt.write("(assert (%s_a s%d))" % (topmod, step))
+ smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step, step+1))
+ smt.write("(assert (|%s_a| s%d))" % (topmod, step))
+ smt.write("(assert %s)" % get_constr_expr(constr_asserts, step))
if step > num_steps-skip_steps:
- print("%s Skipping induction in step %d.." % (smt.timestamp(), step))
+ print_msg("Skipping induction in step %d.." % (step))
continue
skip_counter += 1
if skip_counter < step_size:
- print("%s Skipping induction in step %d.." % (smt.timestamp(), step))
+ print_msg("Skipping induction in step %d.." % (step))
continue
skip_counter = 0
- print("%s Trying induction in step %d.." % (smt.timestamp(), step))
+ print_msg("Trying induction in step %d.." % (step))
if smt.check_sat() == "sat":
if step == 0:
print("%s Temporal induction failed!" % smt.timestamp())
- if vcdfile is not None:
- write_vcd_model(num_steps+1)
+ print_anyconsts(num_steps)
+ print_failed_asserts(num_steps)
+ write_trace(step, num_steps+1, '%')
+
+ elif dumpall:
+ print_anyconsts(num_steps)
+ print_failed_asserts(num_steps)
+ write_trace(step, num_steps+1, "%d" % step)
else:
print("%s Temporal induction successful." % smt.timestamp())
@@ -164,62 +566,116 @@ if tempind:
break
-else: # not tempind
+else: # not tempind
step = 0
retstatus = True
while step < num_steps:
- smt.write("(declare-fun s%d () %s_s)" % (step, topmod))
- smt.write("(assert (%s_u s%d))" % (topmod, step))
+ smt.write("(declare-fun s%d () |%s_s|)" % (step, topmod))
+ smt.write("(assert (|%s_u| s%d))" % (topmod, step))
+ smt.write("(assert (|%s_h| s%d))" % (topmod, step))
+ smt.write("(assert %s)" % get_constr_expr(constr_assumes, step))
if step == 0:
- smt.write("(assert (%s_i s0))" % (topmod))
+ smt.write("(assert (|%s_i| s0))" % (topmod))
+ smt.write("(assert (|%s_is| s0))" % (topmod))
else:
- smt.write("(assert (%s_t s%d s%d))" % (topmod, step-1, step))
+ smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step-1, step))
+ smt.write("(assert (not (|%s_is| s%d)))" % (topmod, step))
if step < skip_steps:
if assume_skipped is not None and step >= assume_skipped:
- print("%s Skipping step %d (and assuming pass).." % (smt.timestamp(), step))
- smt.write("(assert (%s_a s%d))" % (topmod, step))
+ print_msg("Skipping step %d (and assuming pass).." % (step))
+ smt.write("(assert (|%s_a| s%d))" % (topmod, step))
+ smt.write("(assert %s)" % get_constr_expr(constr_asserts, step))
else:
- print("%s Skipping step %d.." % (smt.timestamp(), step))
+ print_msg("Skipping step %d.." % (step))
step += 1
continue
last_check_step = step
for i in range(1, step_size):
if step+i < num_steps:
- smt.write("(declare-fun s%d () %s_s)" % (step+i, topmod))
- smt.write("(assert (%s_u s%d))" % (topmod, step+i))
- smt.write("(assert (%s_t s%d s%d))" % (topmod, step+i-1, step+i))
+ smt.write("(declare-fun s%d () |%s_s|)" % (step+i, topmod))
+ smt.write("(assert (|%s_u| s%d))" % (topmod, step+i))
+ smt.write("(assert (|%s_h| s%d))" % (topmod, step+i))
+ smt.write("(assert (|%s_t| s%d s%d))" % (topmod, step+i-1, step+i))
+ smt.write("(assert %s)" % get_constr_expr(constr_assumes, step+i))
last_check_step = step+i
- if last_check_step == step:
- print("%s Checking asserts in step %d.." % (smt.timestamp(), step))
- else:
- print("%s Checking asserts in steps %d to %d.." % (smt.timestamp(), step, last_check_step))
- smt.write("(push 1)")
+ if not gentrace:
+ if not final_only:
+ if last_check_step == step:
+ print_msg("Checking asserts in step %d.." % (step))
+ else:
+ print_msg("Checking asserts in steps %d to %d.." % (step, last_check_step))
+ smt.write("(push 1)")
- smt.write("(assert (not (and %s)))" % " ".join(["(%s_a s%d)" % (topmod, i) for i in range(step, last_check_step+1)]))
+ smt.write("(assert (not (and %s)))" % " ".join(["(|%s_a| s%d)" % (topmod, i) for i in range(step, last_check_step+1)] +
+ [get_constr_expr(constr_asserts, i) for i in range(step, last_check_step+1)]))
- if smt.check_sat() == "sat":
- print("%s BMC failed!" % smt.timestamp())
- if vcdfile is not None:
- write_vcd_model(step+step_size)
- retstatus = False
- break
+ if smt.check_sat() == "sat":
+ print("%s BMC failed!" % smt.timestamp())
+ print_anyconsts(step)
+ for i in range(step, last_check_step+1):
+ print_failed_asserts(i)
+ write_trace(0, last_check_step+1, '%')
+ retstatus = False
+ break
+
+ smt.write("(pop 1)")
- else: # unsat
- smt.write("(pop 1)")
for i in range(step, last_check_step+1):
- smt.write("(assert (%s_a s%d))" % (topmod, i))
+ smt.write("(assert (|%s_a| s%d))" % (topmod, i))
+ smt.write("(assert %s)" % get_constr_expr(constr_asserts, i))
+
+ if constr_final_start is not None:
+ for i in range(step, last_check_step+1):
+ if i < constr_final_start:
+ continue
+
+ print_msg("Checking final constraints in step %d.." % (i))
+ smt.write("(push 1)")
+
+ smt.write("(assert %s)" % get_constr_expr(constr_assumes, i, final=True))
+ smt.write("(assert (not %s))" % get_constr_expr(constr_asserts, i, final=True))
+
+ if smt.check_sat() == "sat":
+ print("%s BMC failed!" % smt.timestamp())
+ print_anyconsts(i)
+ print_failed_asserts(i, final=True)
+ write_trace(0, i+1, '%')
+ retstatus = False
+ break
+
+ smt.write("(pop 1)")
+ if not retstatus:
+ break
+
+ else: # gentrace
+ for i in range(step, last_check_step+1):
+ smt.write("(assert (|%s_a| s%d))" % (topmod, i))
+ smt.write("(assert %s)" % get_constr_expr(constr_asserts, i))
+
+ print_msg("Solving for step %d.." % (last_check_step))
+ if smt.check_sat() != "sat":
+ print("%s No solution found!" % smt.timestamp())
+ retstatus = False
+ break
+
+ elif dumpall:
+ print_anyconsts(0)
+ write_trace(0, last_check_step+1, "%d" % step)
step += step_size
+ if gentrace:
+ print_anyconsts(0)
+ write_trace(0, num_steps, '%')
+
smt.write("(exit)")
smt.wait()
-print("%s Status: %s" % (smt.timestamp(), "PASSED" if retstatus else "FAILED (!)"))
+print_msg("Status: %s" % ("PASSED" if retstatus else "FAILED (!)"))
sys.exit(0 if retstatus else 1)
-
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 6e8bded7..58554572 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -17,36 +17,59 @@
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
-import sys
-import subprocess
+import sys, subprocess, re
+from copy import deepcopy
from select import select
from time import time
-class smtio:
- def __init__(self, solver=None, debug_print=None, debug_file=None, timeinfo=None, opts=None):
+
+hex_dict = {
+ "0": "0000", "1": "0001", "2": "0010", "3": "0011",
+ "4": "0100", "5": "0101", "6": "0110", "7": "0111",
+ "8": "1000", "9": "1001", "A": "1010", "B": "1011",
+ "C": "1100", "D": "1101", "E": "1110", "F": "1111",
+ "a": "1010", "b": "1011", "c": "1100", "d": "1101",
+ "e": "1110", "f": "1111"
+}
+
+
+class SmtModInfo:
+ def __init__(self):
+ self.inputs = set()
+ self.outputs = set()
+ self.registers = set()
+ self.memories = dict()
+ self.wires = set()
+ self.wsize = dict()
+ self.cells = dict()
+ self.asserts = dict()
+ self.anyconsts = dict()
+
+
+class SmtIo:
+ def __init__(self, opts=None):
+ self.logic = None
+ self.logic_qf = True
+ self.logic_ax = True
+ self.logic_uf = True
+ self.logic_bv = True
+
if opts is not None:
+ self.logic = opts.logic
self.solver = opts.solver
self.debug_print = opts.debug_print
self.debug_file = opts.debug_file
+ self.dummy_file = opts.dummy_file
self.timeinfo = opts.timeinfo
+ self.unroll = opts.unroll
else:
self.solver = "z3"
self.debug_print = False
self.debug_file = None
+ self.dummy_file = None
self.timeinfo = True
-
- if solver is not None:
- self.solver = solver
-
- if debug_print is not None:
- self.debug_print = debug_print
-
- if debug_file is not None:
- self.debug_file = debug_file
-
- if timeinfo is not None:
- self.timeinfo = timeinfo
+ self.unroll = False
if self.solver == "yices":
popen_vargs = ['yices-smt2', '--incremental']
@@ -60,44 +83,265 @@ class smtio:
if self.solver == "mathsat":
popen_vargs = ['mathsat']
- self.p = subprocess.Popen(popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ if self.solver == "boolector":
+ popen_vargs = ['boolector', '--smt2', '-i']
+ self.unroll = True
+
+ if self.solver == "dummy":
+ assert self.dummy_file is not None
+ self.dummy_fd = open(self.dummy_file, "r")
+ else:
+ if self.dummy_file is not None:
+ self.dummy_fd = open(self.dummy_file, "w")
+ self.p = subprocess.Popen(popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+ if self.unroll:
+ self.logic_uf = False
+ self.unroll_idcnt = 0
+ self.unroll_buffer = ""
+ self.unroll_sorts = set()
+ self.unroll_objs = set()
+ self.unroll_decls = dict()
+ self.unroll_cache = dict()
+ self.unroll_stack = list()
+
self.start_time = time()
- def setup(self, logic="ALL", info=None):
- self.write("(set-logic %s)" % logic)
- if info is not None:
- self.write("(set-info :source |%s|)" % info)
- self.write("(set-info :smt-lib-version 2.5)")
- self.write("(set-info :category \"industrial\")")
+ self.modinfo = dict()
+ self.curmod = None
+ self.topmod = None
+ self.setup_done = False
+
+ def setup(self):
+ assert not self.setup_done
+
+ if self.logic is None:
+ self.logic = ""
+ if self.logic_qf: self.logic += "QF_"
+ if self.logic_ax: self.logic += "A"
+ if self.logic_uf: self.logic += "UF"
+ if self.logic_bv: self.logic += "BV"
+
+ self.setup_done = True
+ self.write("(set-option :produce-models true)")
+ self.write("(set-logic %s)" % self.logic)
def timestamp(self):
secs = int(time() - self.start_time)
return "## %6d %3d:%02d:%02d " % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
- def write(self, stmt):
+ def replace_in_stmt(self, stmt, pat, repl):
+ if stmt == pat:
+ return repl
+
+ if isinstance(stmt, list):
+ return [self.replace_in_stmt(s, pat, repl) for s in stmt]
+
+ return stmt
+
+ def unroll_stmt(self, stmt):
+ if not isinstance(stmt, list):
+ return stmt
+
+ stmt = [self.unroll_stmt(s) for s in stmt]
+
+ if len(stmt) >= 2 and not isinstance(stmt[0], list) and stmt[0] in self.unroll_decls:
+ assert stmt[1] in self.unroll_objs
+
+ key = tuple(stmt)
+ if key not in self.unroll_cache:
+ decl = deepcopy(self.unroll_decls[key[0]])
+
+ self.unroll_cache[key] = "|UNROLL#%d|" % self.unroll_idcnt
+ decl[1] = self.unroll_cache[key]
+ self.unroll_idcnt += 1
+
+ if decl[0] == "declare-fun":
+ if isinstance(decl[3], list) or decl[3] not in self.unroll_sorts:
+ self.unroll_objs.add(decl[1])
+ decl[2] = list()
+ else:
+ self.unroll_objs.add(decl[1])
+ decl = list()
+
+ elif decl[0] == "define-fun":
+ arg_index = 1
+ for arg_name, arg_sort in decl[2]:
+ decl[4] = self.replace_in_stmt(decl[4], arg_name, key[arg_index])
+ arg_index += 1
+ decl[2] = list()
+
+ if len(decl) > 0:
+ decl = self.unroll_stmt(decl)
+ self.write(self.unparse(decl), unroll=False)
+
+ return self.unroll_cache[key]
+
+ return stmt
+
+ def write(self, stmt, unroll=True):
+ if stmt.startswith(";"):
+ self.info(stmt)
+ elif not self.setup_done:
+ self.setup()
+
stmt = stmt.strip()
+
+ if unroll and self.unroll:
+ if stmt.startswith(";"):
+ return
+
+ stmt = re.sub(r" ;.*", "", stmt)
+ stmt = self.unroll_buffer + stmt
+ self.unroll_buffer = ""
+
+ s = re.sub(r"\|[^|]*\|", "", stmt)
+ if s.count("(") != s.count(")"):
+ self.unroll_buffer = stmt + " "
+ return
+
+ s = self.parse(stmt)
+
+ if self.debug_print:
+ print("-> %s" % s)
+
+ if len(s) == 3 and s[0] == "declare-sort" and s[2] == "0":
+ self.unroll_sorts.add(s[1])
+ return
+
+ elif len(s) == 4 and s[0] == "declare-fun" and s[2] == [] and s[3] in self.unroll_sorts:
+ self.unroll_objs.add(s[1])
+ return
+
+ elif len(s) >= 4 and s[0] == "declare-fun":
+ for arg_sort in s[2]:
+ if arg_sort in self.unroll_sorts:
+ self.unroll_decls[s[1]] = s
+ return
+
+ elif len(s) >= 4 and s[0] == "define-fun":
+ for arg_name, arg_sort in s[2]:
+ if arg_sort in self.unroll_sorts:
+ self.unroll_decls[s[1]] = s
+ return
+
+ stmt = self.unparse(self.unroll_stmt(s))
+
+ if stmt == "(push 1)":
+ self.unroll_stack.append((
+ deepcopy(self.unroll_sorts),
+ deepcopy(self.unroll_objs),
+ deepcopy(self.unroll_decls),
+ deepcopy(self.unroll_cache),
+ ))
+
+ if stmt == "(pop 1)":
+ self.unroll_sorts, self.unroll_objs, self.unroll_decls, self.unroll_cache = self.unroll_stack.pop()
+
if self.debug_print:
print("> %s" % stmt)
+
if self.debug_file:
print(stmt, file=self.debug_file)
self.debug_file.flush()
- self.p.stdin.write(bytes(stmt + "\n", "ascii"))
- self.p.stdin.flush()
+
+ if self.solver != "dummy":
+ self.p.stdin.write(bytes(stmt + "\n", "ascii"))
+ self.p.stdin.flush()
+
+ def info(self, stmt):
+ if not stmt.startswith("; yosys-smt2-"):
+ return
+
+ fields = stmt.split()
+
+ if fields[1] == "yosys-smt2-nomem":
+ if self.logic is None:
+ self.logic_ax = False
+
+ if fields[1] == "yosys-smt2-nobv":
+ if self.logic is None:
+ self.logic_bv = False
+
+ if fields[1] == "yosys-smt2-module":
+ self.curmod = fields[2]
+ self.modinfo[self.curmod] = SmtModInfo()
+
+ if fields[1] == "yosys-smt2-cell":
+ self.modinfo[self.curmod].cells[fields[3]] = fields[2]
+
+ if fields[1] == "yosys-smt2-topmod":
+ self.topmod = fields[2]
+
+ if fields[1] == "yosys-smt2-input":
+ self.modinfo[self.curmod].inputs.add(fields[2])
+ self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-output":
+ self.modinfo[self.curmod].outputs.add(fields[2])
+ self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-register":
+ self.modinfo[self.curmod].registers.add(fields[2])
+ self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-memory":
+ self.modinfo[self.curmod].memories[fields[2]] = (int(fields[3]), int(fields[4]), int(fields[5]))
+
+ if fields[1] == "yosys-smt2-wire":
+ self.modinfo[self.curmod].wires.add(fields[2])
+ self.modinfo[self.curmod].wsize[fields[2]] = int(fields[3])
+
+ if fields[1] == "yosys-smt2-assert":
+ self.modinfo[self.curmod].asserts[fields[2]] = fields[3]
+
+ if fields[1] == "yosys-smt2-anyconst":
+ self.modinfo[self.curmod].anyconsts[fields[2]] = fields[3]
+
+ def hiernets(self, top, regs_only=False):
+ def hiernets_worker(nets, mod, cursor):
+ for netname in sorted(self.modinfo[mod].wsize.keys()):
+ if not regs_only or netname in self.modinfo[mod].registers:
+ nets.append(cursor + [netname])
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ hiernets_worker(nets, celltype, cursor + [cellname])
+
+ nets = list()
+ hiernets_worker(nets, top, [])
+ return nets
+
+ def hiermems(self, top):
+ def hiermems_worker(mems, mod, cursor):
+ for memname in sorted(self.modinfo[mod].memories.keys()):
+ mems.append(cursor + [memname])
+ for cellname, celltype in sorted(self.modinfo[mod].cells.items()):
+ hiermems_worker(mems, celltype, cursor + [cellname])
+
+ mems = list()
+ hiermems_worker(mems, top, [])
+ return mems
def read(self):
stmt = []
count_brackets = 0
while True:
- line = self.p.stdout.readline().decode("ascii").strip()
+ if self.solver == "dummy":
+ line = self.dummy_fd.readline().strip()
+ else:
+ line = self.p.stdout.readline().decode("ascii").strip()
+ if self.dummy_file is not None:
+ self.dummy_fd.write(line + "\n")
+
count_brackets += line.count("(")
count_brackets -= line.count(")")
stmt.append(line)
+
if self.debug_print:
print("< %s" % line)
if count_brackets == 0:
break
- if not self.p.poll():
+ if self.solver != "dummy" and self.p.poll():
print("SMT Solver terminated unexpectedly: %s" % "".join(stmt))
sys.exit(1)
@@ -115,43 +359,44 @@ class smtio:
print("; running check-sat..", file=self.debug_file)
self.debug_file.flush()
- self.p.stdin.write(bytes("(check-sat)\n", "ascii"))
- self.p.stdin.flush()
+ if self.solver != "dummy":
+ self.p.stdin.write(bytes("(check-sat)\n", "ascii"))
+ self.p.stdin.flush()
- if self.timeinfo:
- i = 0
- s = "/-\|"
+ if self.timeinfo:
+ i = 0
+ s = "/-\|"
- count = 0
- num_bs = 0
- while select([self.p.stdout], [], [], 0.1) == ([], [], []):
- count += 1
+ count = 0
+ num_bs = 0
+ while select([self.p.stdout], [], [], 0.1) == ([], [], []):
+ count += 1
- if count < 25:
- continue
+ if count < 25:
+ continue
- if count % 10 == 0 or count == 25:
- secs = count // 10
+ if count % 10 == 0 or count == 25:
+ secs = count // 10
- if secs < 60:
- m = "(%d seconds)" % secs
- elif secs < 60*60:
- m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60)
- else:
- m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
+ if secs < 60:
+ m = "(%d seconds)" % secs
+ elif secs < 60*60:
+ m = "(%d seconds -- %d:%02d)" % (secs, secs // 60, secs % 60)
+ else:
+ m = "(%d seconds -- %d:%02d:%02d)" % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
- print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr)
- num_bs = len(m) + 3
+ print("%s %s %c" % ("\b \b" * num_bs, m, s[i]), end="", file=sys.stderr)
+ num_bs = len(m) + 3
- else:
- print("\b" + s[i], end="", file=sys.stderr)
+ else:
+ print("\b" + s[i], end="", file=sys.stderr)
- sys.stderr.flush()
- i = (i + 1) % len(s)
+ sys.stderr.flush()
+ i = (i + 1) % len(s)
- if num_bs != 0:
- print("\b \b" * num_bs, end="", file=sys.stderr)
- sys.stderr.flush()
+ if num_bs != 0:
+ print("\b \b" * num_bs, end="", file=sys.stderr)
+ sys.stderr.flush()
result = self.read()
if self.debug_file:
@@ -192,9 +437,14 @@ class smtio:
return expr, cursor
return worker(stmt)[0]
+ def unparse(self, stmt):
+ if isinstance(stmt, list):
+ return "(" + " ".join([self.unparse(s) for s in stmt]) + ")"
+ return stmt
+
def bv2hex(self, v):
h = ""
- v = bv2bin(v)
+ v = self.bv2bin(v)
while len(v) > 0:
d = 0
if len(v) > 0 and v[-1] == "1": d += 1
@@ -212,66 +462,130 @@ class smtio:
if v.startswith("#b"):
return v[2:]
if v.startswith("#x"):
- digits = []
- for d in v[2:]:
- if d == "0": digits.append("0000")
- if d == "1": digits.append("0001")
- if d == "2": digits.append("0010")
- if d == "3": digits.append("0011")
- if d == "4": digits.append("0100")
- if d == "5": digits.append("0101")
- if d == "6": digits.append("0110")
- if d == "7": digits.append("0111")
- if d == "8": digits.append("1000")
- if d == "9": digits.append("1001")
- if d in ("a", "A"): digits.append("1010")
- if d in ("b", "B"): digits.append("1011")
- if d in ("c", "C"): digits.append("1100")
- if d in ("d", "D"): digits.append("1101")
- if d in ("e", "E"): digits.append("1110")
- if d in ("f", "F"): digits.append("1111")
- return "".join(digits)
+ return "".join(hex_dict.get(x) for x in v[2:])
assert False
+ def bv2int(self, v):
+ return int(self.bv2bin(v), 2)
+
def get(self, expr):
self.write("(get-value (%s))" % (expr))
return self.parse(self.read())[0][1]
- def get_net(self, mod_name, net_name, state_name):
- return self.get("(|%s_n %s| %s)" % (mod_name, net_name, state_name))
+ def get_list(self, expr_list):
+ if len(expr_list) == 0:
+ return []
+ self.write("(get-value (%s))" % " ".join(expr_list))
+ return [n[1] for n in self.parse(self.read())]
+
+ def get_path(self, mod, path):
+ assert mod in self.modinfo
+ path = path.split(".")
+
+ for i in range(len(path)-1):
+ first = ".".join(path[0:i+1])
+ second = ".".join(path[i+1:])
+
+ if first in self.modinfo[mod].cells:
+ nextmod = self.modinfo[mod].cells[first]
+ return [first] + self.get_path(nextmod, second)
+
+ return [".".join(path)]
+
+ def net_expr(self, mod, base, path):
+ if len(path) == 1:
+ assert mod in self.modinfo
+ if path[0] in self.modinfo[mod].wsize:
+ return "(|%s_n %s| %s)" % (mod, path[0], base)
+ if path[0] in self.modinfo[mod].memories:
+ return "(|%s_m %s| %s)" % (mod, path[0], base)
+ assert 0
+
+ assert mod in self.modinfo
+ assert path[0] in self.modinfo[mod].cells
+
+ nextmod = self.modinfo[mod].cells[path[0]]
+ nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
+ return self.net_expr(nextmod, nextbase, path[1:])
+
+ def net_width(self, mod, net_path):
+ for i in range(len(net_path)-1):
+ assert mod in self.modinfo
+ assert net_path[i] in self.modinfo[mod].cells
+ mod = self.modinfo[mod].cells[net_path[i]]
- def get_net_bool(self, mod_name, net_name, state_name):
- v = self.get_net(mod_name, net_name, state_name)
- assert v in ["true", "false"]
- return 1 if v == "true" else 0
+ assert mod in self.modinfo
+ assert net_path[-1] in self.modinfo[mod].wsize
+ return self.modinfo[mod].wsize[net_path[-1]]
- def get_net_hex(self, mod_name, net_name, state_name):
- return self.bv2hex(self.get_net(mod_name, net_name, state_name))
+ def mem_expr(self, mod, base, path, portidx=None, infomode=False):
+ if len(path) == 1:
+ assert mod in self.modinfo
+ assert path[0] in self.modinfo[mod].memories
+ if infomode:
+ return self.modinfo[mod].memories[path[0]]
+ return "(|%s_m%s %s| %s)" % (mod, "" if portidx is None else ":%d" % portidx, path[0], base)
- def get_net_bin(self, mod_name, net_name, state_name):
- return self.bv2bin(self.get_net(mod_name, net_name, state_name))
+ assert mod in self.modinfo
+ assert path[0] in self.modinfo[mod].cells
+
+ nextmod = self.modinfo[mod].cells[path[0]]
+ nextbase = "(|%s_h %s| %s)" % (mod, path[0], base)
+ return self.mem_expr(nextmod, nextbase, path[1:], portidx=portidx, infomode=infomode)
+
+ def mem_info(self, mod, base, path):
+ return self.mem_expr(mod, base, path, infomode=True)
+
+ def get_net(self, mod_name, net_path, state_name):
+ return self.get(self.net_expr(mod_name, state_name, net_path))
+
+ def get_net_list(self, mod_name, net_path_list, state_name):
+ return self.get_list([self.net_expr(mod_name, state_name, n) for n in net_path_list])
+
+ def get_net_hex(self, mod_name, net_path, state_name):
+ return self.bv2hex(self.get_net(mod_name, net_path, state_name))
+
+ def get_net_hex_list(self, mod_name, net_path_list, state_name):
+ return [self.bv2hex(v) for v in self.get_net_list(mod_name, net_path_list, state_name)]
+
+ def get_net_bin(self, mod_name, net_path, state_name):
+ return self.bv2bin(self.get_net(mod_name, net_path, state_name))
+
+ def get_net_bin_list(self, mod_name, net_path_list, state_name):
+ return [self.bv2bin(v) for v in self.get_net_list(mod_name, net_path_list, state_name)]
def wait(self):
- self.p.wait()
+ if self.solver != "dummy":
+ self.p.wait()
-class smtopts:
+class SmtOpts:
def __init__(self):
- self.optstr = "s:d:vp"
+ self.shortopts = "s:v"
+ self.longopts = ["unroll", "no-progress", "dump-smt2=", "logic=", "dummy="]
self.solver = "z3"
self.debug_print = False
self.debug_file = None
+ self.dummy_file = None
+ self.unroll = False
self.timeinfo = True
+ self.logic = None
def handle(self, o, a):
if o == "-s":
self.solver = a
elif o == "-v":
self.debug_print = True
- elif o == "-p":
+ elif o == "--unroll":
+ self.unroll = True
+ elif o == "--no-progress":
self.timeinfo = True
- elif o == "-d":
+ elif o == "--dump-smt2":
self.debug_file = open(a, "w")
+ elif o == "--logic":
+ self.logic = a
+ elif o == "--dummy":
+ self.dummy_file = a
else:
return False
return True
@@ -279,47 +593,70 @@ class smtopts:
def helpmsg(self):
return """
-s <solver>
- set SMT solver: z3, cvc4, yices, mathsat
+ set SMT solver: z3, cvc4, yices, mathsat, boolector, dummy
default: z3
+ --logic <smt2_logic>
+ use the specified SMT2 logic (e.g. QF_AUFBV)
+
+ --dummy <filename>
+ if solver is "dummy", read solver output from that file
+ otherwise: write solver output to that file
+
-v
enable debug output
- -p
+ --unroll
+ unroll uninterpreted functions
+
+ --no-progress
disable timer display during solving
- -d <filename>
+ --dump-smt2 <filename>
write smt2 statements to file
"""
-class mkvcd:
+class MkVcd:
def __init__(self, f):
self.f = f
self.t = -1
self.nets = dict()
- def add_net(self, name, width):
+ def add_net(self, path, width):
+ path = tuple(path)
assert self.t == -1
key = "n%d" % len(self.nets)
- self.nets[name] = (key, width)
+ self.nets[path] = (key, width)
- def set_net(self, name, bits):
- assert name in self.nets
+ def set_net(self, path, bits):
+ path = tuple(path)
assert self.t >= 0
- print("b%s %s" % (bits, self.nets[name][0]), file=self.f)
+ assert path in self.nets
+ print("b%s %s" % (bits, self.nets[path][0]), file=self.f)
def set_time(self, t):
assert t >= self.t
if t != self.t:
if self.t == -1:
+ print("$var integer 32 t smt_step $end", file=self.f)
print("$var event 1 ! smt_clock $end", file=self.f)
- for name in sorted(self.nets):
- key, width = self.nets[name]
- print("$var wire %d %s %s $end" % (width, key, name), file=self.f)
+ scope = []
+ for path in sorted(self.nets):
+ while len(scope)+1 > len(path) or (len(scope) > 0 and scope[-1] != path[len(scope)-1]):
+ print("$upscope $end", file=self.f)
+ scope = scope[:-1]
+ while len(scope)+1 < len(path):
+ print("$scope module %s $end" % path[len(scope)], file=self.f)
+ scope.append(path[len(scope)-1])
+ key, width = self.nets[path]
+ print("$var wire %d %s %s $end" % (width, key, path[-1]), file=self.f)
+ for i in range(len(scope)):
+ print("$upscope $end", file=self.f)
print("$enddefinitions $end", file=self.f)
self.t = t
assert self.t >= 0
- print("#%d" % self.t, file=self.f)
+ print("#%d" % (10 * self.t), file=self.f)
print("1!", file=self.f)
+ print("b%s t" % format(self.t, "032b"), file=self.f)
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index b29a88ac..162ce490 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -694,7 +694,7 @@ struct SmvBackend : public Backend {
std::ifstream template_f;
bool verbose = false;
- log_header("Executing SMV backend.\n");
+ log_header(design, "Executing SMV backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc
index 12e2c669..4101cbf9 100644
--- a/backends/spice/spice.cc
+++ b/backends/spice/spice.cc
@@ -27,13 +27,33 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
+static string spice_id2str(IdString id)
+{
+ static const char *escape_chars = "$\\[]()<>=";
+ string s = RTLIL::unescape_id(id);
+
+ for (auto &ch : s)
+ if (strchr(escape_chars, ch) != nullptr) ch = '_';
+
+ return s;
+}
+
+static string spice_id2str(IdString id, bool use_inames, idict<IdString, 1> &inums)
+{
+ if (!use_inames && *id.c_str() == '$')
+ return stringf("%d", inums(id));
+ return spice_id2str(id);
+}
+
+static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter, bool use_inames, idict<IdString, 1> &inums)
{
if (s.wire) {
+ if (s.wire->port_id)
+ use_inames = true;
if (s.wire->width > 1)
- f << stringf(" %s[%d]", RTLIL::id2cstr(s.wire->name), s.offset);
+ f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset);
else
- f << stringf(" %s", RTLIL::id2cstr(s.wire->name));
+ f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str());
} else {
if (s == RTLIL::State::S0)
f << stringf(" %s", neg.c_str());
@@ -44,9 +64,10 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg,
}
}
-static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian)
+static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian, bool use_inames)
{
SigMap sigmap(module);
+ idict<IdString, 1> inums;
int cell_counter = 0, conn_counter = 0, nc_counter = 0;
for (auto &cell_it : module->cells_)
@@ -59,7 +80,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
if (design->modules_.count(cell->type) == 0)
{
log_warning("no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
- RTLIL::id2cstr(cell->type), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name));
+ log_id(cell->type), log_id(module), log_id(cell));
for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
port_sigs.push_back(sig);
@@ -93,18 +114,18 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
for (auto &sig : port_sigs) {
for (int i = 0; i < sig.size(); i++) {
RTLIL::SigSpec s = sig.extract(big_endian ? sig.size() - 1 - i : i, 1);
- print_spice_net(f, s, neg, pos, ncpf, nc_counter);
+ print_spice_net(f, s, neg, pos, ncpf, nc_counter, use_inames, inums);
}
}
- f << stringf(" %s\n", RTLIL::id2cstr(cell->type));
+ f << stringf(" %s\n", spice_id2str(cell->type).c_str());
}
for (auto &conn : module->connections())
for (int i = 0; i < conn.first.size(); i++) {
f << stringf("V%d", conn_counter++);
- print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter);
- print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter);
+ print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
+ print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums);
f << stringf(" DC 0\n");
}
}
@@ -132,6 +153,10 @@ struct SpiceBackend : public Backend {
log(" -nc_prefix\n");
log(" prefix for not-connected nets (default: _NC)\n");
log("\n");
+ log(" -inames\n");
+ log(" include names of internal ($-prefixed) nets in outputs\n");
+ log(" (default is to use net numbers instead)\n");
+ log("\n");
log(" -top top_module\n");
log(" set the specified module as design top module\n");
log("\n");
@@ -140,10 +165,10 @@ struct SpiceBackend : public Backend {
{
std::string top_module_name;
RTLIL::Module *top_module = NULL;
- bool big_endian = false;
+ bool big_endian = false, use_inames = false;
std::string neg = "Vss", pos = "Vdd", ncpf = "_NC";
- log_header("Executing SPICE backend.\n");
+ log_header(design, "Executing SPICE backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -152,6 +177,10 @@ struct SpiceBackend : public Backend {
big_endian = true;
continue;
}
+ if (args[argidx] == "-inames") {
+ use_inames = true;
+ continue;
+ }
if (args[argidx] == "-neg" && argidx+1 < args.size()) {
neg = args[++argidx];
continue;
@@ -187,9 +216,9 @@ struct SpiceBackend : public Backend {
continue;
if (module->processes.size() != 0)
- log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", RTLIL::id2cstr(module->name));
+ log_error("Found unmapped processes in module %s: unmapped processes are not supported in SPICE backend!\n", log_id(module));
if (module->memories.size() != 0)
- log_error("Found munmapped emories in module %s: unmapped memories are not supported in SPICE backend!\n", RTLIL::id2cstr(module->name));
+ log_error("Found unmapped memories in module %s: unmapped memories are not supported in SPICE backend!\n", log_id(module));
if (module->name == RTLIL::escape_id(top_module_name)) {
top_module = module;
@@ -206,24 +235,24 @@ struct SpiceBackend : public Backend {
ports.at(wire->port_id-1) = wire;
}
- *f << stringf(".SUBCKT %s", RTLIL::id2cstr(module->name));
+ *f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str());
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
if (wire->width > 1) {
for (int i = 0; i < wire->width; i++)
- *f << stringf(" %s[%d]", RTLIL::id2cstr(wire->name), big_endian ? wire->width - 1 - i : i);
+ *f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i);
} else
- *f << stringf(" %s", RTLIL::id2cstr(wire->name));
+ *f << stringf(" %s", spice_id2str(wire->name).c_str());
}
*f << stringf("\n");
- print_spice_module(*f, module, design, neg, pos, ncpf, big_endian);
- *f << stringf(".ENDS %s\n\n", RTLIL::id2cstr(module->name));
+ print_spice_module(*f, module, design, neg, pos, ncpf, big_endian, use_inames);
+ *f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str());
}
if (!top_module_name.empty()) {
if (top_module == NULL)
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
- print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian);
+ print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian, use_inames);
*f << stringf("\n");
}
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 10f10e3c..52cf861d 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -19,11 +19,6 @@
*
* A simple and straightforward Verilog backend.
*
- * Note that RTLIL processes can't always be mapped easily to a Verilog
- * process. Therefore this frontend should only be used to export a
- * Verilog netlist (i.e. after the "proc" pass has converted all processes
- * to logic networks and registers).
- *
*/
#include "kernel/register.h"
@@ -38,7 +33,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-bool norename, noattr, attr2comment, noexpr;
+bool norename, noattr, attr2comment, noexpr, nodec, nostr, defparam;
int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<RTLIL::IdString, int> auto_name_map;
std::set<RTLIL::IdString> reg_wires, reg_ct;
@@ -146,6 +141,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
if (sig.size() != chunk.wire->width) {
if (sig.size() == 1)
reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset);
+ else if (chunk.wire->upto)
+ reg_name += stringf("[%d:%d]", (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
+ (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
else
reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
chunk.wire->start_offset + chunk.offset);
@@ -158,8 +156,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
{
if (width < 0)
width = data.bits.size() - offset;
+ if (nostr)
+ goto dump_bits;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
- if (width == 32 && !no_decimal) {
+ if (width == 32 && !no_decimal && !nodec) {
int32_t val = 0;
for (int i = offset+width-1; i >= offset; i--) {
log_assert(i < (int)data.bits.size());
@@ -169,9 +169,9 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
val |= 1 << (i - offset);
}
if (set_signed && val < 0)
- f << stringf("-32'sd %u", -val);
+ f << stringf("-32'sd%u", -val);
else
- f << stringf("32'%sd %u", set_signed ? "s" : "", val);
+ f << stringf("32'%sd%u", set_signed ? "s" : "", val);
} else {
dump_bits:
f << stringf("%d'%sb", width, set_signed ? "s" : "");
@@ -827,12 +827,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::vector<std::string> lof_reg_declarations;
int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
- RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr;
+ RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr;
bool use_rd_clk, rd_clk_posedge, rd_transparent;
// read ports
for (int i=0; i < nread_ports; i++)
{
sig_rd_clk = cell->getPort("\\RD_CLK").extract(i);
+ sig_rd_en = cell->getPort("\\RD_EN").extract(i);
sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width);
sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
@@ -850,15 +851,22 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
// for clocked read ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
- // temp_id <= array_reg[r_addr];
+ // if (rd_en) temp_id <= array_reg[r_addr];
// assign r_data = temp_id;
std::string temp_id = next_auto_id();
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
std::ostringstream os;
+ if (sig_rd_en != RTLIL::SigBit(true))
+ {
+ os << stringf("if (");
+ dump_sigspec(os, sig_rd_en);
+ os << stringf(") ");
+ }
+ os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
dump_sigspec(os, sig_rd_addr);
- std::string line = stringf("%s <= %s[%s];\n", temp_id.c_str(), mem_id.c_str(), os.str().c_str());
- clk_to_lof_body[clk_domain_str].push_back(line);
+ os << stringf("];\n");
+ clk_to_lof_body[clk_domain_str].push_back(os.str());
}
{
std::ostringstream os;
@@ -900,13 +908,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
}
int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
- RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit;
- RTLIL::SigBit last_bit;
+ RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
bool wr_clk_posedge;
- RTLIL::SigSpec lof_wen;
- dict<RTLIL::SigSpec, int> wen_to_width;
SigMap sigmap(active_module);
- int n, wen_width;
// write ports
for (int i=0; i < nwrite_ports; i++)
{
@@ -914,7 +918,6 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width);
- sig_wr_en_bit = sig_wr_en.extract(0);
wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
{
std::ostringstream os;
@@ -923,48 +926,37 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if( clk_to_lof_body.count(clk_domain_str) == 0 )
clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
}
- // group the wen bits
- last_bit = sig_wr_en.extract(0);
- lof_wen = RTLIL::SigSpec(last_bit);
- wen_to_width.clear();
- wen_to_width[last_bit] = 0;
- for (auto &current_bit : sig_wr_en.bits())
- {
- if (sigmap(current_bit) == sigmap(last_bit)){
- wen_to_width[current_bit] += 1;
- } else {
- lof_wen.append_bit(current_bit);
- wen_to_width[current_bit] = 1;
- }
- last_bit = current_bit;
- }
// make something like:
// always @(posedge clk)
// if (wr_en_bit) memid[w_addr][??] <= w_data[??];
// ...
- n = 0;
- for (auto &wen_bit : lof_wen) {
- wen_width = wen_to_width[wen_bit];
- if (!(wen_bit == RTLIL::SigBit(false)))
+ for (int i = 0; i < GetSize(sig_wr_en); i++)
+ {
+ int start_i = i, width = 1;
+ SigBit wen_bit = sig_wr_en[i];
+
+ while (i+1 < GetSize(sig_wr_en) && sigmap(sig_wr_en[i+1]) == sigmap(wen_bit))
+ i++, width++;
+
+ if (wen_bit == State::S0)
+ continue;
+
+ std::ostringstream os;
+ if (wen_bit != State::S1)
{
- std::ostringstream os;
- if (!(wen_bit == RTLIL::SigBit(true)))
- {
- os << stringf("if (");
- dump_sigspec(os, wen_bit);
- os << stringf(") ");
- }
- os << stringf("%s[", mem_id.c_str());
- dump_sigspec(os, sig_wr_addr);
- if (wen_width == width)
- os << stringf("] <= ");
- else
- os << stringf("][%d:%d] <= ", n+wen_width-1, n);
- dump_sigspec(os, sig_wr_data.extract(n, wen_width));
- os << stringf(";\n");
- clk_to_lof_body[clk_domain_str].push_back(os.str());
+ os << stringf("if (");
+ dump_sigspec(os, wen_bit);
+ os << stringf(") ");
}
- n += wen_width;
+ os << stringf("%s[", mem_id.c_str());
+ dump_sigspec(os, sig_wr_addr);
+ if (width == GetSize(sig_wr_en))
+ os << stringf("] <= ");
+ else
+ os << stringf("][%d:%d] <= ", i, start_i);
+ dump_sigspec(os, sig_wr_data.extract(start_i, width));
+ os << stringf(";\n");
+ clk_to_lof_body[clk_domain_str].push_back(os.str());
}
}
// Output Verilog that looks something like this:
@@ -1029,7 +1021,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
dump_attributes(f, indent, cell->attributes);
f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
- if (cell->parameters.size() > 0) {
+ if (!defparam && cell->parameters.size() > 0) {
f << stringf(" #(");
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
if (it != cell->parameters.begin())
@@ -1079,6 +1071,16 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf(")");
}
f << stringf("\n%s" ");\n", indent.c_str());
+
+ if (defparam && cell->parameters.size() > 0) {
+ for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
+ f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
+ bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
+ dump_const(f, it->second, -1, 0, false, is_signed);
+ f << stringf(";\n");
+ }
+ }
+
}
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
@@ -1135,11 +1137,15 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
dump_sigspec(f, sw->signal);
f << stringf(")\n");
+ bool got_default = false;
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
- f << stringf("%s ", indent.c_str());
- if ((*it)->compare.size() == 0)
- f << stringf("default");
- else {
+ if ((*it)->compare.size() == 0) {
+ if (got_default)
+ continue;
+ f << stringf("%s default", indent.c_str());
+ got_default = true;
+ } else {
+ f << stringf("%s ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
f << stringf(", ");
@@ -1244,6 +1250,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
reset_auto_counter(module);
active_module = module;
+ if (!module->processes.empty())
+ log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
+ "can't always be mapped directly to Verilog always blocks. Unintended\n"
+ "changes in simulation behavior are possible! Use \"proc\" to convert\n"
+ "processes to logic networks and registers.", log_id(module));
+
f << stringf("\n");
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
dump_process(f, indent + " ", it->second, true);
@@ -1340,6 +1352,21 @@ struct VerilogBackend : public Backend {
log(" without this option all internal cells are converted to Verilog\n");
log(" expressions.\n");
log("\n");
+ log(" -nodec\n");
+ log(" 32-bit constant values are by default dumped as decimal numbers,\n");
+ log(" not bit pattern. This option decativates this feature and instead\n");
+ log(" will write out all constants in binary.\n");
+ log("\n");
+ log(" -nostr\n");
+ log(" Parameters and attributes that are specified as strings in the\n");
+ log(" original input will be output as strings by this back-end. This\n");
+ log(" decativates this feature and instead will write string constants\n");
+ log(" as binary numbers.\n");
+ log("\n");
+ log(" -defparam\n");
+ log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
+ log(" cell parameters.\n");
+ log("\n");
log(" -blackboxes\n");
log(" usually modules with the 'blackbox' attribute are ignored. with\n");
log(" this option set only the modules with the 'blackbox' attribute\n");
@@ -1349,15 +1376,24 @@ struct VerilogBackend : public Backend {
log(" only write selected modules. modules must be selected entirely or\n");
log(" not at all.\n");
log("\n");
+ log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
+ log("always blocks. This frontend should only be used to export an RTLIL\n");
+ log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
+ log("processes to logic networks and registers. A warning is generated when\n");
+ log("this command is called on a design with RTLIL processes.\n");
+ log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing Verilog backend.\n");
+ log_header(design, "Executing Verilog backend.\n");
norename = false;
noattr = false;
attr2comment = false;
noexpr = false;
+ nodec = false;
+ nostr = false;
+ defparam = false;
bool blackboxes = false;
bool selected = false;
@@ -1407,6 +1443,18 @@ struct VerilogBackend : public Backend {
noexpr = true;
continue;
}
+ if (arg == "-nodec") {
+ nodec = true;
+ continue;
+ }
+ if (arg == "-nostr") {
+ nostr = true;
+ continue;
+ }
+ if (arg == "-defparam") {
+ defparam = true;
+ continue;
+ }
if (arg == "-blackboxes") {
blackboxes = true;
continue;
diff --git a/examples/cmos/.gitignore b/examples/cmos/.gitignore
new file mode 100644
index 00000000..f58d9501
--- /dev/null
+++ b/examples/cmos/.gitignore
@@ -0,0 +1,4 @@
+counter_tb
+counter_tb.vcd
+synth.sp
+synth.v
diff --git a/examples/cmos/README b/examples/cmos/README
new file mode 100644
index 00000000..c459b4b5
--- /dev/null
+++ b/examples/cmos/README
@@ -0,0 +1,13 @@
+
+In this directory contains an example for generating a spice output using two
+different spice modes, normal analog transient simulation and event-driven
+digital simulation as supported by ngspice xspice sub-module.
+
+Each test bench can be run separately by either running:
+
+- testbench.sh, to start analog simulation or
+- testbench_digital.sh for mixed-signal digital simulation.
+
+The later case also includes pure verilog simulation using the iverilog
+and gtkwave for comparison.
+
diff --git a/examples/cmos/cmos_cells_digital.sp b/examples/cmos/cmos_cells_digital.sp
new file mode 100644
index 00000000..e1cb82a2
--- /dev/null
+++ b/examples/cmos/cmos_cells_digital.sp
@@ -0,0 +1,31 @@
+
+.SUBCKT BUF A Y
+.model buffer1 d_buffer
+Abuf A Y buffer1
+.ENDS NOT
+
+.SUBCKT NOT A Y
+.model not1 d_inverter
+Anot A Y not1
+.ENDS NOT
+
+.SUBCKT NAND A B Y
+.model nand1 d_nand
+Anand [A B] Y nand1
+.ENDS NAND
+
+.SUBCKT NOR A B Y
+.model nor1 d_nor
+Anand [A B] Y nor1
+.ENDS NOR
+
+.SUBCKT DLATCH E D Q
+.model latch1 d_latch
+Alatch D E null null Q nQ latch1
+.ENDS DLATCH
+
+.SUBCKT DFF C D Q
+.model dff1 d_dff
+Adff D C null null Q nQ dff1
+.ENDS DFF
+
diff --git a/examples/cmos/counter_digital.ys b/examples/cmos/counter_digital.ys
new file mode 100644
index 00000000..a5e728e0
--- /dev/null
+++ b/examples/cmos/counter_digital.ys
@@ -0,0 +1,16 @@
+
+read_verilog counter.v
+read_verilog -lib cmos_cells.v
+
+proc;; memory;; techmap;;
+
+dfflibmap -liberty cmos_cells.lib
+abc -liberty cmos_cells.lib;;
+
+# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
+# dfflibmap -liberty osu025_stdcells.lib
+# abc -liberty osu025_stdcells.lib;;
+
+write_verilog synth.v
+write_spice -neg 0s -pos 1s synth.sp
+
diff --git a/examples/cmos/counter_tb.gtkw b/examples/cmos/counter_tb.gtkw
new file mode 100644
index 00000000..4a2eac40
--- /dev/null
+++ b/examples/cmos/counter_tb.gtkw
@@ -0,0 +1,5 @@
+[dumpfile] "counter_tb.vcd"
+counter_tb.clk
+counter_tb.count[2:0]
+counter_tb.en
+counter_tb.reset
diff --git a/examples/cmos/counter_tb.v b/examples/cmos/counter_tb.v
new file mode 100644
index 00000000..bcd7d992
--- /dev/null
+++ b/examples/cmos/counter_tb.v
@@ -0,0 +1,33 @@
+module counter_tb;
+
+ /* Make a reset pulse and specify dump file */
+ reg reset = 0;
+ initial begin
+ $dumpfile("counter_tb.vcd");
+ $dumpvars(0,counter_tb);
+
+ # 0 reset = 1;
+ # 4 reset = 0;
+ # 36 reset = 1;
+ # 4 reset = 0;
+ # 6 $finish;
+ end
+
+ /* Make enable with period of 8 and 6,7 low */
+ reg en = 1;
+ always begin
+ en = 1;
+ #6;
+ en = 0;
+ #2;
+ end
+
+ /* Make a regular pulsing clock. */
+ reg clk = 0;
+ always #1 clk = !clk;
+
+ /* UUT */
+ wire [2:0] count;
+ counter c1 (clk, reset, en, count);
+
+endmodule
diff --git a/examples/cmos/testbench.sp b/examples/cmos/testbench.sp
index 95d2f67c..e571d281 100644
--- a/examples/cmos/testbench.sp
+++ b/examples/cmos/testbench.sp
@@ -9,8 +9,8 @@ Vdd Vdd 0 DC 3
.MODEL cmosp PMOS LEVEL=1 VT0=-0.7 KP=50U GAMMA=0.57 LAMBDA=0.05 PHI=0.8
* load design and library
-.include synth.sp
.include cmos_cells.sp
+.include synth.sp
* input signals
Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2)
diff --git a/examples/cmos/testbench_digital.sh b/examples/cmos/testbench_digital.sh
new file mode 100644
index 00000000..afaaf4d4
--- /dev/null
+++ b/examples/cmos/testbench_digital.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -ex
+
+# iverlog simulation
+echo "Doing Verilog simulation with iverilog"
+iverilog -o counter_tb counter.v counter_tb.v
+./counter_tb; gtkwave counter_tb.gtkw &
+
+# yosys synthesis
+../../yosys counter_digital.ys
+
+# requires ngspice with xspice support enabled:
+ngspice testbench_digital.sp
+
diff --git a/examples/cmos/testbench_digital.sp b/examples/cmos/testbench_digital.sp
new file mode 100644
index 00000000..c5f9d598
--- /dev/null
+++ b/examples/cmos/testbench_digital.sp
@@ -0,0 +1,26 @@
+
+* load design and library
+.include cmos_cells_digital.sp
+.include synth.sp
+
+* input signals
+Vclk clk 0 PULSE(0 3 1 0.1 0.1 0.8 2)
+Vrst rst 0 PULSE(0 3 0.5 0.1 0.1 2.9 40)
+Ven en 0 PULSE(0 3 0.5 0.1 0.1 5.9 8)
+
+Xuut dclk drst den dout0 dout1 dout2 counter
+* Bridge to digital
+.model adc_buff adc_bridge(in_low = 0.8 in_high=2)
+.model dac_buff dac_bridge(out_high = 3.5)
+Aad [clk rst en] [dclk drst den] adc_buff
+Ada [dout0 dout1 dout2] [out0 out1 out2] dac_buff
+
+
+.tran 0.01 50
+
+.control
+run
+plot v(clk) v(rst)+5 v(en)+10 v(out0)+20 v(out1)+25 v(out2)+30
+.endc
+
+.end
diff --git a/examples/cxx-api/evaldemo.cc b/examples/cxx-api/evaldemo.cc
new file mode 100644
index 00000000..e5cc8d8e
--- /dev/null
+++ b/examples/cxx-api/evaldemo.cc
@@ -0,0 +1,55 @@
+/* A simple Yosys plugin. (Copy&paste from http://stackoverflow.com/questions/32093541/how-does-the-yosys-consteval-api-work)
+
+Usage example:
+
+$ cat > evaldemo.v <<EOT
+module main(input [1:0] A, input [7:0] B, C, D, output [7:0] Y);
+ assign Y = A == 0 ? B : A == 1 ? C : A == 2 ? D : 42;
+endmodule
+EOT
+
+$ yosys-config --build evaldemo.so evaldemo.cc
+$ yosys -m evaldemo.so -p evaldemo evaldemo.v
+*/
+
+#include "kernel/yosys.h"
+#include "kernel/consteval.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct EvalDemoPass : public Pass
+{
+ EvalDemoPass() : Pass("evaldemo") { }
+
+ virtual void execute(vector<string>, Design *design)
+ {
+ Module *module = design->top_module();
+
+ if (module == nullptr)
+ log_error("No top module found!\n");
+
+ Wire *wire_a = module->wire("\\A");
+ Wire *wire_y = module->wire("\\Y");
+
+ if (wire_a == nullptr)
+ log_error("No wire A found!\n");
+
+ if (wire_y == nullptr)
+ log_error("No wire Y found!\n");
+
+ ConstEval ce(module);
+ for (int v = 0; v < 4; v++) {
+ ce.push();
+ ce.set(wire_a, Const(v, GetSize(wire_a)));
+ SigSpec sig_y = wire_y, sig_undef;
+ if (ce.eval(sig_y, sig_undef))
+ log("Eval results for A=%d: Y=%s\n", v, log_signal(sig_y));
+ else
+ log("Eval failed for A=%d: Missing value for %s\n", v, log_signal(sig_undef));
+ ce.pop();
+ }
+ }
+} EvalDemoPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/examples/smtbmc/.gitignore b/examples/smtbmc/.gitignore
new file mode 100644
index 00000000..a3f4f0f2
--- /dev/null
+++ b/examples/smtbmc/.gitignore
@@ -0,0 +1,22 @@
+demo1.smt2
+demo1.yslog
+demo2.smt2
+demo2.smtc
+demo2.vcd
+demo2.yslog
+demo2_tb
+demo2_tb.v
+demo2_tb.vcd
+demo3.smt2
+demo3.vcd
+demo3.yslog
+demo4.smt2
+demo4.vcd
+demo4.yslog
+demo5.smt2
+demo5.vcd
+demo5.yslog
+demo6.smt2
+demo6.yslog
+demo7.smt2
+demo7.yslog
diff --git a/examples/smtbmc/Makefile b/examples/smtbmc/Makefile
new file mode 100644
index 00000000..2f7060bd
--- /dev/null
+++ b/examples/smtbmc/Makefile
@@ -0,0 +1,59 @@
+
+all: demo1 demo2 demo3 demo4 demo5 demo6 demo7
+
+demo1: demo1.smt2
+ yosys-smtbmc --dump-vcd demo1.vcd demo1.smt2
+ yosys-smtbmc -i --dump-vcd demo1.vcd demo1.smt2
+
+demo2: demo2.smt2
+ yosys-smtbmc -g --dump-vcd demo2.vcd --dump-smtc demo2.smtc --dump-vlogtb demo2_tb.v demo2.smt2
+ iverilog -g2012 -o demo2_tb demo2_tb.v demo2.v
+ vvp demo2_tb +vcd=demo2_tb.vcd
+
+demo3: demo3.smt2
+ yosys-smtbmc --dump-vcd demo3.vcd --smtc demo3.smtc demo3.smt2
+
+demo4: demo4.smt2
+ yosys-smtbmc -s yices --dump-vcd demo4.vcd --smtc demo4.smtc demo4.smt2
+
+demo5: demo5.smt2
+ yosys-smtbmc -g -t 50 --dump-vcd demo5.vcd demo5.smt2
+
+demo6: demo6.smt2
+ yosys-smtbmc -t 1 demo6.smt2
+
+demo7: demo7.smt2
+ yosys-smtbmc -t 10 demo7.smt2
+
+demo1.smt2: demo1.v
+ yosys -ql demo1.yslog -p 'read_verilog -formal demo1.v; prep -top demo1 -nordff; write_smt2 -wires demo1.smt2'
+
+demo2.smt2: demo2.v
+ yosys -ql demo2.yslog -p 'read_verilog -formal demo2.v; prep -top demo2 -nordff; write_smt2 -wires demo2.smt2'
+
+demo3.smt2: demo3.v
+ yosys -ql demo3.yslog -p 'read_verilog -formal demo3.v; prep -top demo3 -nordff; write_smt2 -wires demo3.smt2'
+
+demo4.smt2: demo4.v
+ yosys -ql demo4.yslog -p 'read_verilog -formal demo4.v; prep -top demo4 -nordff; write_smt2 -wires demo4.smt2'
+
+demo5.smt2: demo5.v
+ yosys -ql demo5.yslog -p 'read_verilog -formal demo5.v; prep -top demo5 -nordff; write_smt2 -wires demo5.smt2'
+
+demo6.smt2: demo6.v
+ yosys -ql demo6.yslog -p 'read_verilog demo6.v; prep -top demo6 -nordff; assertpmux; opt -keepdc -fast; write_smt2 -wires demo6.smt2'
+
+demo7.smt2: demo7.v
+ yosys -ql demo7.yslog -p 'read_verilog -formal demo7.v; prep -top demo7 -nordff; write_smt2 -wires demo7.smt2'
+
+clean:
+ rm -f demo1.yslog demo1.smt2 demo1.vcd
+ rm -f demo2.yslog demo2.smt2 demo2.vcd demo2.smtc demo2_tb.v demo2_tb demo2_tb.vcd
+ rm -f demo3.yslog demo3.smt2 demo3.vcd
+ rm -f demo4.yslog demo4.smt2 demo4.vcd
+ rm -f demo5.yslog demo5.smt2 demo5.vcd
+ rm -f demo6.yslog demo6.smt2
+ rm -f demo7.yslog demo7.smt2
+
+.PHONY: demo1 demo2 demo3 demo4 demo5 demo6 demo7 clean
+
diff --git a/examples/smtbmc/demo1.v b/examples/smtbmc/demo1.v
new file mode 100644
index 00000000..567dde14
--- /dev/null
+++ b/examples/smtbmc/demo1.v
@@ -0,0 +1,19 @@
+module demo1(input clk, input addtwo, output iseven);
+ reg [3:0] cnt;
+ wire [3:0] next_cnt;
+
+ inc inc_inst (addtwo, iseven, cnt, next_cnt);
+
+ always @(posedge clk)
+ cnt = (iseven ? cnt == 10 : cnt == 11) ? 0 : next_cnt;
+
+`ifdef FORMAL
+ assert property (cnt != 15);
+ initial assume (!cnt[2]);
+`endif
+endmodule
+
+module inc(input addtwo, output iseven, input [3:0] a, output [3:0] y);
+ assign iseven = !a[0];
+ assign y = a + (addtwo ? 2 : 1);
+endmodule
diff --git a/examples/smtbmc/demo2.v b/examples/smtbmc/demo2.v
new file mode 100644
index 00000000..34745e89
--- /dev/null
+++ b/examples/smtbmc/demo2.v
@@ -0,0 +1,29 @@
+// Nothing to prove in this demo.
+// Just an example for memories, vcd dumps and vlog testbench dumps.
+
+`ifdef FORMAL
+`define assume(_expr_) assume(_expr_)
+`else
+`define assume(_expr_)
+`endif
+
+module demo2(input clk, input [4:0] addr, output reg [31:0] data);
+ reg [31:0] mem [0:31];
+ always @(posedge clk)
+ data <= mem[addr];
+
+ reg [31:0] used_addr = 0;
+ reg [31:0] used_dbits = 0;
+ reg initstate = 1;
+
+ always @(posedge clk) begin
+ initstate <= 0;
+ `assume(!used_addr[addr]);
+ used_addr[addr] <= 1;
+ if (!initstate) begin
+ `assume(data != 0);
+ `assume((used_dbits & data) == 0);
+ used_dbits <= used_dbits | data;
+ end
+ end
+endmodule
diff --git a/examples/smtbmc/demo3.smtc b/examples/smtbmc/demo3.smtc
new file mode 100644
index 00000000..f5e017cf
--- /dev/null
+++ b/examples/smtbmc/demo3.smtc
@@ -0,0 +1,5 @@
+initial
+assume [rst]
+
+always -1
+assert (= [-1:mem] [mem])
diff --git a/examples/smtbmc/demo3.v b/examples/smtbmc/demo3.v
new file mode 100644
index 00000000..13b3a197
--- /dev/null
+++ b/examples/smtbmc/demo3.v
@@ -0,0 +1,18 @@
+// Whatever the initial content of this memory is at reset, it will never change
+// see demo3.smtc for assumptions and assertions
+
+module demo3(input clk, rst, input [15:0] addr, output reg [31:0] data);
+ reg [31:0] mem [0:2**16-1];
+ reg [15:0] addr_q;
+
+ always @(posedge clk) begin
+ if (rst) begin
+ data <= mem[0] ^ 123456789;
+ addr_q <= 0;
+ end else begin
+ mem[addr_q] <= data ^ 123456789;
+ data <= mem[addr] ^ 123456789;
+ addr_q <= addr;
+ end
+ end
+endmodule
diff --git a/examples/smtbmc/demo4.smtc b/examples/smtbmc/demo4.smtc
new file mode 100644
index 00000000..2f91f816
--- /dev/null
+++ b/examples/smtbmc/demo4.smtc
@@ -0,0 +1,11 @@
+initial
+assume [rst]
+
+always -1
+assume (not [rst])
+assume (=> [-1:inv2] [inv2])
+
+final -2
+assume [-1:inv2]
+assume (not [-2:inv2])
+assert (= [r1] [r2])
diff --git a/examples/smtbmc/demo4.v b/examples/smtbmc/demo4.v
new file mode 100644
index 00000000..3f1b4727
--- /dev/null
+++ b/examples/smtbmc/demo4.v
@@ -0,0 +1,13 @@
+// Demo for "final" smtc constraints
+
+module demo4(input clk, rst, inv2, input [15:0] in, output reg [15:0] r1, r2);
+ always @(posedge clk) begin
+ if (rst) begin
+ r1 <= in;
+ r2 <= -in;
+ end else begin
+ r1 <= r1 + in;
+ r2 <= inv2 ? -(r2 - in) : (r2 - in);
+ end
+ end
+endmodule
diff --git a/examples/smtbmc/demo5.v b/examples/smtbmc/demo5.v
new file mode 100644
index 00000000..63ace307
--- /dev/null
+++ b/examples/smtbmc/demo5.v
@@ -0,0 +1,18 @@
+// Demo for $anyconst
+
+module demo5 (input clk);
+ wire [7:0] step_size = $anyconst;
+ reg [7:0] state = 0, count = 0;
+ reg [31:0] hash = 0;
+
+ always @(posedge clk) begin
+ count <= count + 1;
+ hash <= ((hash << 5) + hash) ^ state;
+ state <= state + step_size;
+ end
+
+ always @* begin
+ if (count == 42)
+ assert(hash == 32'h A18FAC0A);
+ end
+endmodule
diff --git a/examples/smtbmc/demo6.v b/examples/smtbmc/demo6.v
new file mode 100644
index 00000000..62a72e2a
--- /dev/null
+++ b/examples/smtbmc/demo6.v
@@ -0,0 +1,14 @@
+// Demo for assertpmux
+
+module demo6 (input A, B, C, D, E, output reg Y);
+ always @* begin
+ Y = 0;
+ if (A != B) begin
+ (* parallel_case *)
+ case (C)
+ A: Y = D;
+ B: Y = E;
+ endcase
+ end
+ end
+endmodule
diff --git a/examples/smtbmc/demo7.v b/examples/smtbmc/demo7.v
new file mode 100644
index 00000000..75b3865c
--- /dev/null
+++ b/examples/smtbmc/demo7.v
@@ -0,0 +1,18 @@
+// Demo for memory initialization
+
+module demo7 (input [2:0] addr);
+ reg [15:0] memory [0:7];
+
+ initial begin
+ memory[0] = 1331;
+ memory[1] = 1331 + 1;
+ memory[2] = 1331 + 2;
+ memory[3] = 1331 + 4;
+ memory[4] = 1331 + 8;
+ memory[5] = 1331 + 16;
+ memory[6] = 1331 + 32;
+ memory[7] = 1331 + 64;
+ end
+
+ assert property (1000 < memory[addr] && memory[addr] < 2000);
+endmodule
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 834ee82a..fd272400 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -30,15 +30,6 @@
#include "libs/sha1/sha1.h"
#include "ast.h"
-#include <sstream>
-#include <stdarg.h>
-
-#if defined(__APPLE__)
-# include <cmath>
-#else
-# include <math.h>
-#endif
-
YOSYS_NAMESPACE_BEGIN
using namespace AST;
@@ -53,13 +44,15 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
- bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
+ bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
AstNode *current_always, *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
+ bool current_always_clocked;
}
// convert node types to string
@@ -146,6 +139,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_ASSIGN_LE)
X(AST_CASE)
X(AST_COND)
+ X(AST_CONDX)
+ X(AST_CONDZ)
X(AST_DEFAULT)
X(AST_FOR)
X(AST_WHILE)
@@ -158,6 +153,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_POSEDGE)
X(AST_NEGEDGE)
X(AST_EDGE)
+ X(AST_PACKAGE)
#undef X
default:
log_abort();
@@ -180,7 +176,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
// create new node (AstNode constructor)
// (the optional child arguments make it easier to create AST trees)
-AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
+AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3)
{
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
@@ -208,6 +204,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
children.push_back(child1);
if (child2)
children.push_back(child2);
+ if (child3)
+ children.push_back(child3);
}
// create a (deep recursive) copy of a node
@@ -311,6 +309,8 @@ void AstNode::dumpAst(FILE *f, std::string indent)
for (size_t i = 0; i < children.size(); i++)
children[i]->dumpAst(f, indent + " ");
+
+ fflush(f);
}
// helper function for AstNode::dumpVlog()
@@ -435,16 +435,15 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_ALWAYS:
- fprintf(f, "%s" "always @(", indent.c_str());
+ fprintf(f, "%s" "always @", indent.c_str());
for (auto child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
continue;
- if (!first)
- fprintf(f, ", ");
+ fprintf(f, first ? "(" : ", ");
child->dumpVlog(f, "");
first = false;
}
- fprintf(f, ")\n");
+ fprintf(f, first ? "*\n" : ")\n");
for (auto child : children) {
if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE)
child->dumpVlog(f, indent + " ");
@@ -501,7 +500,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_CASE:
- fprintf(f, "%s" "case (", indent.c_str());
+ if (!children.empty() && children[0]->type == AST_CONDX)
+ fprintf(f, "%s" "casex (", indent.c_str());
+ else if (!children.empty() && children[0]->type == AST_CONDZ)
+ fprintf(f, "%s" "casez (", indent.c_str());
+ else
+ fprintf(f, "%s" "case (", indent.c_str());
children[0]->dumpVlog(f, "");
fprintf(f, ")\n");
for (size_t i = 1; i < children.size(); i++) {
@@ -512,6 +516,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
break;
case AST_COND:
+ case AST_CONDX:
+ case AST_CONDZ:
for (auto child : children) {
if (child->type == AST_BLOCK) {
fprintf(f, ":\n");
@@ -528,6 +534,14 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
}
break;
+ case AST_ASSIGN:
+ fprintf(f, "%sassign ", indent.c_str());
+ children[0]->dumpVlog(f, "");
+ fprintf(f, " = ");
+ children[1]->dumpVlog(f, "");
+ fprintf(f, ";\n");
+ break;
+
case AST_ASSIGN_EQ:
case AST_ASSIGN_LE:
fprintf(f, "%s", indent.c_str());
@@ -616,6 +630,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
fprintf(f, "%s" "/** %s **/%s", indent.c_str(), type_name.c_str(), indent.empty() ? "" : "\n");
// dumpAst(f, indent, NULL);
}
+
+ fflush(f);
}
// check if two AST nodes are identical
@@ -967,16 +983,25 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->icells = flag_icells;
current_module->autowire = flag_autowire;
current_module->fixup_ports();
+
+ if (flag_dump_rtlil) {
+ log("Dumping generated RTLIL:\n");
+ log_module(current_module);
+ log("--- END OF RTLIL DUMP ---\n");
+ }
+
return current_module;
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
-void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
+void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil,
+ bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_dump_vlog = dump_vlog;
+ flag_dump_rtlil = dump_rtlil;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
@@ -996,6 +1021,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
for (auto n : global_decls)
(*it)->children.push_back(n->clone());
+ for (auto n : design->verilog_packages){
+ for (auto o : n->children) {
+ AstNode *cloned_node = o->clone();
+ cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
+ (*it)->children.push_back(cloned_node);
+ }
+ }
+
if (flag_icells && (*it)->str.substr(0, 2) == "\\$")
(*it)->str = (*it)->str.substr(1);
@@ -1013,6 +1046,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
design->add(process_module(*it, defer));
}
+ else if ((*it)->type == AST_PACKAGE)
+ design->verilog_packages.push_back((*it)->clone());
else
global_decls.push_back(*it);
}
@@ -1033,7 +1068,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R
if (stripped_name.substr(0, 9) == "$abstract")
stripped_name = stripped_name.substr(9);
- log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
+ log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());
current_ast = NULL;
flag_dump_ast1 = false;
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index b5349db5..cd6e264e 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -122,6 +122,8 @@ namespace AST
AST_ASSIGN_LE,
AST_CASE,
AST_COND,
+ AST_CONDX,
+ AST_CONDZ,
AST_DEFAULT,
AST_FOR,
AST_WHILE,
@@ -135,7 +137,9 @@ namespace AST
AST_POSEDGE,
AST_NEGEDGE,
- AST_EDGE
+ AST_EDGE,
+
+ AST_PACKAGE
};
// convert an node type to a string (e.g. for debug output)
@@ -182,7 +186,7 @@ namespace AST
int linenum;
// creating and deleting nodes
- AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL);
+ AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL);
AstNode *clone();
void cloneInto(AstNode *other);
void delete_children();
@@ -215,8 +219,9 @@ namespace AST
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
- bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
+ bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
+ void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
@@ -266,7 +271,8 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
- void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
+ void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
+ bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
@@ -296,13 +302,15 @@ namespace AST
namespace AST_INTERNAL
{
// internal state variables
- extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
+ extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
+ extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
+ extern bool current_always_clocked;
struct ProcessGenerator;
}
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 9fc59037..3c57162a 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -241,6 +241,8 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
syncrule->signal = child->children[0]->genRTLIL();
+ if (GetSize(syncrule->signal) != 1)
+ log_error("Found posedge/negedge event on a signal that is not 1 bit wide at %s:%d!\n", always->filename.c_str(), always->linenum);
addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
proc->syncs.push_back(syncrule);
}
@@ -338,12 +340,14 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CASE:
for (auto child : ast->children)
if (child != ast->children[0]) {
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
collect_lvalues(reg, child, type_eq, type_le, false);
}
break;
case AST_COND:
+ case AST_CONDX:
+ case AST_CONDZ:
case AST_ALWAYS:
case AST_INITIAL:
for (auto child : ast->children)
@@ -427,6 +431,17 @@ struct AST_INTERNAL::ProcessGenerator
{
RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue;
RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap());
+
+ pool<SigBit> lvalue_sigbits;
+ for (int i = 0; i < GetSize(lvalue); i++) {
+ if (lvalue_sigbits.count(lvalue[i]) > 0) {
+ unmapped_lvalue.remove(i);
+ lvalue.remove(i);
+ rvalue.remove(i--);
+ } else
+ lvalue_sigbits.insert(lvalue[i]);
+ }
+
lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
@@ -443,6 +458,7 @@ struct AST_INTERNAL::ProcessGenerator
case AST_CASE:
{
RTLIL::SwitchRule *sw = new RTLIL::SwitchRule;
+ sw->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap());
current_case->switches.push_back(sw);
@@ -467,7 +483,7 @@ struct AST_INTERNAL::ProcessGenerator
{
if (child == ast->children[0])
continue;
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
subst_lvalue_map.save();
subst_rvalue_map.save();
@@ -525,6 +541,7 @@ struct AST_INTERNAL::ProcessGenerator
log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
break;
+ case AST_NONE:
case AST_TCALL:
case AST_FOR:
break;
@@ -589,7 +606,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
- log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
}
} else {
this_width = id_ast->range_left - id_ast->range_right + 1;
@@ -600,7 +617,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = 32;
} else if (id_ast->type == AST_MEMORY) {
if (!id_ast->children[0]->range_valid)
- log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
} else
log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
@@ -732,11 +749,34 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id2ast->is_signed)
sign_hint = false;
if (!id2ast->children[0]->range_valid)
- log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
width_hint = max(width_hint, this_width);
break;
+ case AST_FCALL:
+ if (str == "\\$anyconst") {
+ if (GetSize(children) == 1) {
+ while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
+ if (children[0]->type != AST_CONSTANT)
+ log_error("System function %s called with non-const argument at %s:%d!\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ width_hint = max(width_hint, int(children[0]->asInt(true)));
+ }
+ break;
+ }
+ if (str == "\\$past") {
+ if (GetSize(children) > 0) {
+ sub_width_hint = 0;
+ sub_sign_hint = true;
+ children.at(0)->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
+ width_hint = max(width_hint, sub_width_hint);
+ sign_hint = false;
+ }
+ break;
+ }
+ /* fall through */
+
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
@@ -782,6 +822,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// simply ignore this nodes.
// they are either leftovers from simplify() or are referenced by other nodes
// and are only accessed here thru this references
+ case AST_NONE:
case AST_TASK:
case AST_FUNCTION:
case AST_DPI_FUNCTION:
@@ -793,6 +834,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENBLOCK:
case AST_GENIF:
case AST_GENCASE:
+ case AST_PACKAGE:
break;
// remember the parameter, needed for example in techmap
@@ -1224,13 +1266,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
+ RTLIL::SigSpec addr_sig = children[0]->genRTLIL();
+
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1));
- cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
+ cell->setPort("\\ADDR", addr_sig);
cell->setPort("\\DATA", RTLIL::SigSpec(wire));
cell->parameters["\\MEMID"] = RTLIL::Const(str);
- cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
+ cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig));
cell->parameters["\\WIDTH"] = RTLIL::Const(wire->width);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
@@ -1261,11 +1305,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
}
- cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
+ SigSpec addr_sig = children[0]->genRTLIL();
+
+ cell->setPort("\\ADDR", addr_sig);
cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words));
cell->parameters["\\MEMID"] = RTLIL::Const(str);
- cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
+ cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig));
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
if (type == AST_MEMWR) {
@@ -1283,6 +1329,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_ASSERT:
case AST_ASSUME:
{
+ const char *celltype = "$assert";
+ if (type == AST_ASSUME) celltype = "$assume";
+
log_assert(children.size() == 2);
RTLIL::SigSpec check = children[0]->genRTLIL();
@@ -1294,9 +1343,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr;
- sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
- RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");
+ RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
@@ -1408,6 +1457,40 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
delete always;
} break;
+ case AST_FCALL: {
+ if (str == "\\$anyconst")
+ {
+ string myid = stringf("%s$%d", str.c_str() + 1, autoidx++);
+ int width = width_hint;
+
+ if (GetSize(children) > 1)
+ log_error("System function %s got %d arguments, expected 1 or 0 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), GetSize(children), filename.c_str(), linenum);
+
+ if (GetSize(children) == 1) {
+ if (children[0]->type != AST_CONSTANT)
+ log_error("System function %s called with non-const argument at %s:%d!\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ width = children[0]->asInt(true);
+ }
+
+ if (width <= 0)
+ log_error("Failed to detect width of %s at %s:%d!\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+ Cell *cell = current_module->addCell(myid, str.substr(1));
+ cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ cell->parameters["\\WIDTH"] = width;
+
+ Wire *wire = current_module->addWire(myid + "_wire", width);
+ wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ cell->setPort("\\Y", wire);
+
+ is_signed = sign_hint;
+ return SigSpec(wire);
+ }
+ } /* fall through */
+
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 2621be49..57aa648c 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -63,7 +63,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
#if 0
log("-------------\n");
- log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
+ log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), linenum, type2str(type).c_str(), this);
log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
// dumpAst(NULL, "> ");
@@ -148,14 +148,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
- while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL)) { }
+ AstNode *async_block = NULL;
+ while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL, async_block)) { }
- for (size_t i = 0; i < children.size(); i++) {
- if (mem2reg_set.count(children[i]) > 0) {
- delete children[i];
- children.erase(children.begin() + (i--));
- }
- }
+ vector<AstNode*> delnodes;
+ mem2reg_remove(mem2reg_set, delnodes);
+
+ for (auto node : delnodes)
+ delete node;
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
@@ -174,8 +174,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
// deactivate all calls to non-synthesis system tasks
- // note that $display and $finish are used for synthesis-time DRC so they're not in this list
- if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" ||
+ // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
+ if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||
str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);
delete_children();
@@ -193,13 +193,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// but should be good enough for most uses
if ((type == AST_TCALL) && ((str == "$display") || (str == "$write")))
{
- size_t nargs = GetSize(children);
- if(nargs < 1)
+ int nargs = GetSize(children);
+ if (nargs < 1)
log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n",
str.c_str(), int(children.size()), filename.c_str(), linenum);
// First argument is the format string
- AstNode *node_string = children[0]->clone();
+ AstNode *node_string = children[0];
while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_string->type != AST_CONSTANT)
log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
@@ -207,37 +207,57 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// Other arguments are placeholders. Process the string as we go through it
std::string sout;
- size_t next_arg = 1;
- for(size_t i=0; i<sformat.length(); i++)
+ int next_arg = 1;
+ for (size_t i = 0; i < sformat.length(); i++)
{
// format specifier
- if(sformat[i] == '%')
+ if (sformat[i] == '%')
{
// If there's no next character, that's a problem
- if(i+1 >= sformat.length())
+ if (i+1 >= sformat.length())
log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
char cformat = sformat[++i];
// %% is special, does not need a matching argument
- if(cformat == '%')
+ if (cformat == '%')
{
sout += '%';
continue;
}
- // If we're out of arguments, that's a problem!
- if(next_arg >= nargs)
- log_error("System task `%s' called with more format specifiers than arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
-
// Simplify the argument
- AstNode *node_arg = children[next_arg ++]->clone();
- while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
- if (node_arg->type != AST_CONSTANT)
- log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ AstNode *node_arg = nullptr;
// Everything from here on depends on the format specifier
- switch(cformat)
+ switch (cformat)
+ {
+ case 's':
+ case 'S':
+ case 'd':
+ case 'D':
+ case 'x':
+ case 'X':
+ if (next_arg >= GetSize(children))
+ log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n",
+ cformat, str.c_str(), filename.c_str(), linenum);
+
+ node_arg = children[next_arg++];
+ while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (node_arg->type != AST_CONSTANT)
+ log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ break;
+
+ case 'm':
+ case 'M':
+ break;
+
+ default:
+ log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ break;
+ }
+
+ switch (cformat)
{
case 's':
case 'S':
@@ -262,9 +282,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
break;
- default:
- log_error("System task `%s' called with invalid format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ case 'm':
+ case 'M':
+ sout += log_id(current_module->name);
break;
+
+ default:
+ log_abort();
}
}
@@ -275,7 +299,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// Finally, print the message (only include a \n for $display, not for $write)
log("%s", sout.c_str());
- if(str == "$display")
+ if (str == "$display")
log("\n");
delete_children();
str = std::string();
@@ -373,9 +397,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
auto backup_current_block_child = current_block_child;
auto backup_current_top_block = current_top_block;
auto backup_current_always = current_always;
+ auto backup_current_always_clocked = current_always_clocked;
if (type == AST_ALWAYS || type == AST_INITIAL)
+ {
current_always = this;
+ current_always_clocked = false;
+
+ if (type == AST_ALWAYS)
+ for (auto child : children)
+ if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE)
+ current_always_clocked = true;
+ }
int backup_width_hint = width_hint;
bool backup_sign_hint = sign_hint;
@@ -489,6 +522,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children_are_self_determined = true;
break;
+ case AST_FCALL:
+ case AST_TCALL:
+ children_are_self_determined = true;
+ break;
+
default:
width_hint = -1;
sign_hint = false;
@@ -504,6 +542,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
detectSignWidth(width_hint, sign_hint);
}
+ if (type == AST_FCALL && str == "\\$past")
+ detectSignWidth(width_hint, sign_hint);
+
if (type == AST_TERNARY) {
int width_hint_left, width_hint_right;
bool sign_hint_left, sign_hint_right;
@@ -516,6 +557,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
+ if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) {
+ for (auto &bit : children.at(0)->bits)
+ if (bit == State::Sz || bit == State::Sx)
+ bit = State::Sa;
+ }
+
+ if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) {
+ for (auto &bit : children.at(0)->bits)
+ if (bit == State::Sz)
+ bit = State::Sa;
+ }
+
if (const_fold && type == AST_CASE)
{
while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
@@ -524,7 +577,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
new_children.push_back(children[0]);
for (int i = 1; i < GetSize(children); i++) {
AstNode *child = children[i];
- log_assert(child->type == AST_COND);
+ log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);
for (auto v : child->children) {
if (v->type == AST_DEFAULT)
goto keep_const_cond;
@@ -616,6 +669,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_block_child = backup_current_block_child;
current_top_block = backup_current_top_block;
current_always = backup_current_always;
+ current_always_clocked = backup_current_always_clocked;
for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
if (it->second == NULL)
@@ -794,7 +848,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
RTLIL::SigSpec sig(children[0]->bits);
sig.extend_u0(width, children[0]->is_signed);
AstNode *old_child_0 = children[0];
- children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed);
+ children[0] = mkconst_bits(sig.as_const().bits, is_signed);
delete old_child_0;
}
children[0]->is_signed = is_signed;
@@ -847,11 +901,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
+ int data_range_left = id2ast->children[0]->range_left;
+ int data_range_right = id2ast->children[0]->range_right;
+
std::stringstream sstr;
- sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string wire_id = sstr.str();
- AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
+ AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
wire->str = wire_id;
if (current_block)
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
@@ -1101,7 +1158,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *selected_case = NULL;
for (size_t i = 1; i < children.size(); i++)
{
- log_assert(children.at(i)->type == AST_COND);
+ log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ);
AstNode *this_genblock = NULL;
for (auto child : children.at(i)->children) {
@@ -1316,7 +1373,7 @@ skip_dynamic_range_lvalue_expansion:;
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
{
std::stringstream sstr;
- sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";
AstNode *wire_check = new AstNode(AST_WIRE);
@@ -1328,8 +1385,10 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *wire_en = new AstNode(AST_WIRE);
wire_en->str = id_en;
current_ast_mod->children.push_back(wire_en);
- current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)))));
- current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en;
+ if (current_always_clocked) {
+ current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)))));
+ current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en;
+ }
current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
@@ -1350,7 +1409,12 @@ skip_dynamic_range_lvalue_expansion:;
assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone()));
assign_check->children[0]->str = id_check;
- assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
+ if (current_always == nullptr || current_always->type != AST_INITIAL) {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
+ } else {
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_FCALL));
+ assign_en->children[1]->str = "\\$initstate";
+ }
assign_en->children[0]->str = id_en;
newNode = new AstNode(AST_BLOCK);
@@ -1383,6 +1447,50 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
+ // assignment with nontrivial member in left-hand concat expression -> split assignment
+ if ((type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_CONCAT && width_hint > 0)
+ {
+ bool found_nontrivial_member = false;
+
+ for (auto child : children[0]->children) {
+ if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY)
+ found_nontrivial_member = true;
+ }
+
+ if (found_nontrivial_member)
+ {
+ newNode = new AstNode(AST_BLOCK);
+
+ AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true)));
+ wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), linenum, autoidx++);
+ current_ast_mod->children.push_back(wire_tmp);
+ current_scope[wire_tmp->str] = wire_tmp;
+ wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
+
+ AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
+ wire_tmp_id->str = wire_tmp->str;
+
+ newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone()));
+
+ int cursor = 0;
+ for (auto child : children[0]->children)
+ {
+ int child_width_hint = -1;
+ bool child_sign_hint = true;
+ child->detectSignWidth(child_width_hint, child_sign_hint);
+
+ AstNode *rhs = wire_tmp_id->clone();
+ rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true)));
+ newNode->children.push_back(new AstNode(type, child->clone(), rhs));
+
+ cursor += child_width_hint;
+ }
+
+ goto apply_newNode;
+ }
+ }
+
// assignment with memory in left-hand side expression -> replace with memory write port
if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER &&
children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 &&
@@ -1404,6 +1512,15 @@ skip_dynamic_range_lvalue_expansion:;
int mem_width, mem_size, addr_bits;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
+ int data_range_left = children[0]->id2ast->children[0]->range_left;
+ int data_range_right = children[0]->id2ast->children[0]->range_right;
+ int mem_data_range_offset = std::min(data_range_left, data_range_right);
+
+ int addr_width_hint = -1;
+ bool addr_sign_hint = true;
+ children[0]->children[0]->children[0]->detectSignWidthWorker(addr_width_hint, addr_sign_hint);
+ addr_bits = std::max(addr_bits, addr_width_hint);
+
AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
wire_addr->str = id_addr;
current_ast_mod->children.push_back(wire_addr);
@@ -1461,6 +1578,7 @@ skip_dynamic_range_lvalue_expansion:;
{
int offset = children[0]->children[1]->range_right;
int width = children[0]->children[1]->range_left - offset + 1;
+ offset -= mem_data_range_offset;
std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
@@ -1482,6 +1600,9 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *right_at_zero_ast = the_range->children.size() >= 2 ? the_range->children[1]->clone() : left_at_zero_ast->clone();
AstNode *offset_ast = right_at_zero_ast->clone();
+ if (mem_data_range_offset)
+ offset_ast = new AstNode(AST_SUB, offset_ast, mkconst_int(mem_data_range_offset, true));
+
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
@@ -1545,6 +1666,153 @@ skip_dynamic_range_lvalue_expansion:;
{
if (type == AST_FCALL)
{
+ if (str == "\\$initstate")
+ {
+ int myidx = autoidx++;
+
+ AstNode *wire = new AstNode(AST_WIRE);
+ wire->str = stringf("$initstate$%d_wire", myidx);
+ current_ast_mod->children.push_back(wire);
+ while (wire->simplify(true, false, false, 1, -1, false, false)) { }
+
+ AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER)));
+ cell->str = stringf("$initstate$%d", myidx);
+ cell->children[0]->str = "$initstate";
+ cell->children[1]->str = "\\Y";
+ cell->children[1]->children[0]->str = wire->str;
+ cell->children[1]->children[0]->id2ast = wire;
+ current_ast_mod->children.push_back(cell);
+ while (cell->simplify(true, false, false, 1, -1, false, false)) { }
+
+ newNode = new AstNode(AST_IDENTIFIER);
+ newNode->str = wire->str;
+ newNode->id2ast = wire;
+ goto apply_newNode;
+ }
+
+ if (str == "\\$past")
+ {
+ if (width_hint <= 0)
+ goto replace_fcall_later;
+
+ int num_steps = 1;
+
+ if (GetSize(children) != 1 && GetSize(children) != 2)
+ log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+ if (!current_always_clocked)
+ log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+ if (GetSize(children) == 2)
+ {
+ AstNode *buf = children[1]->clone();
+ while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
+ if (buf->type != AST_CONSTANT)
+ log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+
+ num_steps = buf->asInt(true);
+ delete buf;
+ }
+
+ AstNode *block = nullptr;
+
+ for (auto child : current_always->children)
+ if (child->type == AST_BLOCK)
+ block = child;
+
+ log_assert(block != nullptr);
+
+ int myidx = autoidx++;
+ AstNode *outreg = nullptr;
+
+ for (int i = 0; i < num_steps; i++)
+ {
+ AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
+ mkconst_int(width_hint-1, true), mkconst_int(0, true)));
+
+ reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), linenum, myidx, i);
+ reg->is_reg = true;
+
+ current_ast_mod->children.push_back(reg);
+
+ while (reg->simplify(true, false, false, 1, -1, false, false)) { }
+
+ AstNode *regid = new AstNode(AST_IDENTIFIER);
+ regid->str = reg->str;
+ regid->id2ast = reg;
+
+ AstNode *rhs = nullptr;
+
+ if (outreg == nullptr) {
+ rhs = children.at(0)->clone();
+ } else {
+ rhs = new AstNode(AST_IDENTIFIER);
+ rhs->str = outreg->str;
+ rhs->id2ast = outreg;
+ }
+
+ block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs));
+ outreg = reg;
+ }
+
+ newNode = new AstNode(AST_IDENTIFIER);
+ newNode->str = outreg->str;
+ newNode->id2ast = outreg;
+ goto apply_newNode;
+ }
+
+ if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell")
+ {
+ if (GetSize(children) != 1)
+ log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+ if (!current_always_clocked)
+ log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+ AstNode *present = children.at(0)->clone();
+ AstNode *past = clone();
+ past->str = "\\$past";
+
+ if (str == "\\$stable")
+ newNode = new AstNode(AST_EQ, past, present);
+
+ else if (str == "\\$rose")
+ newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present);
+
+ else if (str == "\\$fell")
+ newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present));
+
+ else
+ log_abort();
+
+ goto apply_newNode;
+ }
+
+ if (str == "\\$rose" || str == "\\$fell")
+ {
+ if (GetSize(children) != 1)
+ log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+
+ if (!current_always_clocked)
+ log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
+ RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+
+ newNode = new AstNode(AST_EQ, children.at(0)->clone(), clone());
+ newNode->children.at(1)->str = "\\$past";
+ goto apply_newNode;
+ }
+
+ // $anyconst is mapped in AstNode::genRTLIL()
+ if (str == "\\$anyconst") {
+ recursion_counter--;
+ return false;
+ }
+
if (str == "\\$clog2")
{
if (children.size() != 1)
@@ -1674,12 +1942,12 @@ skip_dynamic_range_lvalue_expansion:;
if (type == AST_TCALL)
{
- if (str == "$finish")
+ if (str == "$finish" || str == "$stop")
{
if (!current_always || current_always->type != AST_INITIAL)
- log_error("System task `$finish' outside initial block is unsupported at %s:%d.\n", filename.c_str(), linenum);
+ log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
- log_error("System task `$finish' executed at %s:%d.\n", filename.c_str(), linenum);
+ log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
if (str == "\\$readmemh" || str == "\\$readmemb")
@@ -1889,6 +2157,8 @@ skip_dynamic_range_lvalue_expansion:;
wire->port_id = 0;
wire->is_input = false;
wire->is_output = false;
+ if (!child->is_output)
+ wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
wire_cache[child->str] = wire;
current_ast_mod->children.push_back(wire);
@@ -1949,6 +2219,8 @@ skip_dynamic_range_lvalue_expansion:;
did_something = true;
}
+replace_fcall_later:;
+
// perform const folding when activated
if (const_fold)
{
@@ -2347,12 +2619,12 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
block->children.back()->children[0]->id2ast = memory;
}
- if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
- break;
cursor += increment;
+ if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
+ break;
}
- if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
+ if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))
break;
}
@@ -2568,16 +2840,54 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
return true;
}
+void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes)
+{
+ log_assert(mem2reg_set.count(this) == 0);
+
+ if (mem2reg_set.count(id2ast))
+ id2ast = nullptr;
+
+ for (size_t i = 0; i < children.size(); i++) {
+ if (mem2reg_set.count(children[i]) > 0) {
+ delnodes.push_back(children[i]);
+ children.erase(children.begin() + (i--));
+ } else {
+ children[i]->mem2reg_remove(mem2reg_set, delnodes);
+ }
+ }
+}
+
// actually replace memories with registers
-bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
+bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block)
{
bool did_something = false;
if (type == AST_BLOCK)
block = this;
- if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL &&
- children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT)
+ if (type == AST_FUNCTION || type == AST_TASK)
+ return false;
+
+ if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
+ {
+ if (async_block == NULL) {
+ async_block = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK));
+ mod->children.push_back(async_block);
+ }
+
+ AstNode *newNode = clone();
+ newNode->type = AST_ASSIGN_EQ;
+ async_block->children[0]->children.push_back(newNode);
+
+ newNode = new AstNode(AST_NONE);
+ newNode->cloneInto(this);
+ delete newNode;
+
+ did_something = true;
+ }
+
+ if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->mem2reg_check(mem2reg_set) &&
+ children[0]->children[0]->children[0]->type != AST_CONSTANT)
{
std::stringstream sstr;
sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
@@ -2653,7 +2963,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
else
{
std::stringstream sstr;
- sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
+ sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";
int mem_width, mem_size, addr_bits;
@@ -2733,7 +3043,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
auto children_list = children;
for (size_t i = 0; i < children_list.size(); i++)
- if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block))
+ if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, async_block))
did_something = true;
return did_something;
@@ -2958,7 +3268,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
for (size_t i = 1; i < stmt->children.size(); i++)
{
bool found_match = false;
- log_assert(stmt->children.at(i)->type == AST_COND);
+ log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ);
if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) {
sel_case = stmt->children.at(i)->children.back();
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index ee0e771e..3717a1e5 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -49,12 +49,13 @@ static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count,
}
}
-void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean)
+void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode)
{
RTLIL::Module *module = nullptr;
RTLIL::Const *lutptr = NULL;
+ RTLIL::Cell *sopcell = NULL;
RTLIL::State lut_default_state = RTLIL::State::Sx;
- int blif_maxnum = 0;
+ int blif_maxnum = 0, sopmode = -1;
auto blif_wire = [&](const std::string &wire_name) -> Wire*
{
@@ -116,6 +117,11 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
lut_default_state = RTLIL::State::Sx;
}
+ if (sopcell) {
+ sopcell = NULL;
+ sopmode = -1;
+ }
+
char *cmd = strtok(buffer, " \t\r\n");
if (!strcmp(cmd, ".model")) {
@@ -235,7 +241,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
}
if (init != nullptr && (init[0] == '0' || init[0] == '1'))
- blif_wire(d)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1);
+ blif_wire(q)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1);
if (clock == nullptr)
goto no_latch_clock;
@@ -244,6 +250,10 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
else if (!strcmp(edge, "fe"))
cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
+ else if (!strcmp(edge, "ah"))
+ cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q));
+ else if (!strcmp(edge, "al"))
+ cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false);
else {
no_latch_clock:
cell = module->addCell(NEW_ID, dff_name);
@@ -340,20 +350,33 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
goto continue_without_read;
}
- RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut");
- cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
- cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
- cell->setPort("\\A", input_sig);
- cell->setPort("\\Y", output_sig);
- lutptr = &cell->parameters.at("\\LUT");
- lut_default_state = RTLIL::State::Sx;
+ if (sop_mode)
+ {
+ sopcell = module->addCell(NEW_ID, "$sop");
+ sopcell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
+ sopcell->parameters["\\DEPTH"] = 0;
+ sopcell->parameters["\\TABLE"] = RTLIL::Const();
+ sopcell->setPort("\\A", input_sig);
+ sopcell->setPort("\\Y", output_sig);
+ sopmode = -1;
+ }
+ else
+ {
+ RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut");
+ cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size());
+ cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size());
+ cell->setPort("\\A", input_sig);
+ cell->setPort("\\Y", output_sig);
+ lutptr = &cell->parameters.at("\\LUT");
+ lut_default_state = RTLIL::State::Sx;
+ }
continue;
}
goto error;
}
- if (lutptr == NULL)
+ if (lutptr == NULL && sopcell == NULL)
goto error;
char *input = strtok(buffer, " \t\r\n");
@@ -363,23 +386,60 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
goto error;
int input_len = strlen(input);
- if (input_len > 8)
- goto error;
- for (int i = 0; i < (1 << input_len); i++) {
- for (int j = 0; j < input_len; j++) {
- char c1 = input[j];
- if (c1 != '-') {
- char c2 = (i & (1 << j)) != 0 ? '1' : '0';
- if (c1 != c2)
- goto try_next_value;
+ if (sopcell)
+ {
+ log_assert(sopcell->parameters["\\WIDTH"].as_int() == input_len);
+ sopcell->parameters["\\DEPTH"] = sopcell->parameters["\\DEPTH"].as_int() + 1;
+
+ for (int i = 0; i < input_len; i++)
+ switch (input[i]) {
+ case '0':
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S1);
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ break;
+ case '1':
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S1);
+ break;
+ default:
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ sopcell->parameters["\\TABLE"].bits.push_back(State::S0);
+ break;
+ }
+
+ if (sopmode == -1) {
+ sopmode = (*output == '1');
+ if (!sopmode) {
+ SigSpec outnet = sopcell->getPort("\\Y");
+ SigSpec tempnet = module->addWire(NEW_ID);
+ module->addNotGate(NEW_ID, tempnet, outnet);
+ sopcell->setPort("\\Y", tempnet);
}
- }
- lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1;
- try_next_value:;
+ } else
+ log_assert(sopmode == (*output == '1'));
}
- lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0;
+ if (lutptr)
+ {
+ if (input_len > 8)
+ goto error;
+
+ for (int i = 0; i < (1 << input_len); i++) {
+ for (int j = 0; j < input_len; j++) {
+ char c1 = input[j];
+ if (c1 != '-') {
+ char c2 = (i & (1 << j)) != 0 ? '1' : '0';
+ if (c1 != c2)
+ goto try_next_value;
+ }
+ }
+ lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1;
+ try_next_value:;
+ }
+
+ lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0;
+ }
}
error:
@@ -396,23 +456,28 @@ struct BlifFrontend : public Frontend {
log("\n");
log("Load modules from a BLIF file into the current design.\n");
log("\n");
+ log(" -sop\n");
+ log(" Create $sop cells instead of $lut cells\n");
+ log("\n");
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing BLIF frontend.\n");
+ bool sop_mode = false;
+
+ log_header(design, "Executing BLIF frontend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
- // if (arg == "-lib") {
- // flag_lib = true;
- // continue;
- // }
+ if (arg == "-sop") {
+ sop_mode = true;
+ continue;
+ }
break;
}
extra_args(f, filename, args, argidx);
- parse_blif(design, *f, "\\DFF", true);
+ parse_blif(design, *f, "\\DFF", true, sop_mode);
}
} BlifFrontend;
diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h
index 3c01ed37..058087d8 100644
--- a/frontends/blif/blifparse.h
+++ b/frontends/blif/blifparse.h
@@ -24,7 +24,7 @@
YOSYS_NAMESPACE_BEGIN
-extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false);
+extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false, bool sop_mode = false);
YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc
index 7361a254..ed678998 100644
--- a/frontends/ilang/ilang_frontend.cc
+++ b/frontends/ilang/ilang_frontend.cc
@@ -47,7 +47,7 @@ struct IlangFrontend : public Frontend {
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing ILANG frontend.\n");
+ log_header(design, "Executing ILANG frontend.\n");
extra_args(f, filename, args, 1);
log("Input filename: %s\n", filename.c_str());
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index f02a7323..73d927fa 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -437,7 +437,7 @@ struct LibertyFrontend : public Frontend {
bool flag_ignore_miss_dir = false;
std::vector<std::string> attributes;
- log_header("Executing Liberty frontend.\n");
+ log_header(design, "Executing Liberty frontend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -469,6 +469,46 @@ struct LibertyFrontend : public Frontend {
LibertyParser parser(*f);
int cell_count = 0;
+ std::map<std::string, std::tuple<int, int, bool>> type_map;
+
+ for (auto type_node : parser.ast->children)
+ {
+ if (type_node->id != "type" || type_node->args.size() != 1)
+ continue;
+
+ std::string type_name = type_node->args.at(0);
+ int bit_width = -1, bit_from = -1, bit_to = -1;
+ bool upto = false;
+
+ for (auto child : type_node->children)
+ {
+ if (child->id == "base_type" && child->value != "array")
+ goto next_type;
+
+ if (child->id == "data_type" && child->value != "bit")
+ goto next_type;
+
+ if (child->id == "bit_width")
+ bit_width = atoi(child->value.c_str());
+
+ if (child->id == "bit_from")
+ bit_from = atoi(child->value.c_str());
+
+ if (child->id == "bit_to")
+ bit_to = atoi(child->value.c_str());
+
+ if (child->id == "downto" && (child->value == "0" || child->value == "false" || child->value == "FALSE"))
+ upto = true;
+ }
+
+ if (bit_width != (std::max(bit_from, bit_to) - std::min(bit_from, bit_to) + 1))
+ log_error("Incompatible array type '%s': bit_width=%d, bit_from=%d, bit_to=%d.\n",
+ type_name.c_str(), bit_width, bit_from, bit_to);
+
+ type_map[type_name] = std::tuple<int, int, bool>(bit_width, std::min(bit_from, bit_to), upto);
+ next_type:;
+ }
+
for (auto cell : parser.ast->children)
{
if (cell->id != "cell" || cell->args.size() != 1)
@@ -494,13 +534,14 @@ struct LibertyFrontend : public Frontend {
module->attributes[attr] = 1;
for (auto node : cell->children)
+ {
if (node->id == "pin" && node->args.size() == 1) {
LibertyAst *dir = node->find("direction");
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
{
if (!flag_ignore_miss_dir)
{
- log_error("Missing or invalid direction for pin %s of cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
+ log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
} else {
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str());
delete module;
@@ -511,6 +552,41 @@ struct LibertyFrontend : public Frontend {
module->addWire(RTLIL::escape_id(node->args.at(0)));
}
+ if (node->id == "bus" && node->args.size() == 1)
+ {
+ if (!flag_lib)
+ log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
+
+ LibertyAst *dir = node->find("direction");
+
+ if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
+ log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
+
+ if (dir->value == "internal")
+ continue;
+
+ LibertyAst *bus_type_node = node->find("bus_type");
+
+ if (!bus_type_node || !type_map.count(bus_type_node->value))
+ log_error("Unkown or unsupported type for bus interface %s on cell %s.\n",
+ node->args.at(0).c_str(), log_id(cell_name));
+
+ int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
+ int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value));
+ bool bus_type_upto = std::get<2>(type_map.at(bus_type_node->value));
+
+ Wire *wire = module->addWire(RTLIL::escape_id(node->args.at(0)), bus_type_width);
+ wire->start_offset = bus_type_offset;
+ wire->upto = bus_type_upto;
+
+ if (dir->value == "input" || dir->value == "inout")
+ wire->port_input = true;
+
+ if (dir->value == "output" || dir->value == "inout")
+ wire->port_output = true;
+ }
+ }
+
for (auto node : cell->children)
{
if (!flag_lib) {
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index b0fdedcc..7dd36a74 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -850,7 +850,7 @@ struct VerificPass : public Pass {
#ifdef YOSYS_ENABLE_VERIFIC
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
+ log_header(design, "Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
Message::SetConsoleOutput(0);
Message::RegisterCallBackMsg(msg_func);
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index cd8b586c..894723c8 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -63,9 +63,15 @@ struct VerilogFrontend : public Frontend {
log(" of SystemVerilog is supported)\n");
log("\n");
log(" -formal\n");
- log(" enable support for assert() and assume() from SystemVerilog\n");
+ log(" enable support for SystemVerilog assertions and some Yosys extensions\n");
log(" replace the implicit -D SYNTHESIS with -D FORMAL\n");
log("\n");
+ log(" -norestrict\n");
+ log(" ignore restrict() assertions\n");
+ log("\n");
+ log(" -assume-asserts\n");
+ log(" treat all assert() statements like assume() statements\n");
+ log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@@ -75,6 +81,9 @@ struct VerilogFrontend : public Frontend {
log(" -dump_vlog\n");
log(" dump ast as Verilog code (after simplification)\n");
log("\n");
+ log(" -dump_rtlil\n");
+ log(" dump generated RTLIL netlist\n");
+ log("\n");
log(" -yydebug\n");
log(" enable parser debug output\n");
log("\n");
@@ -159,12 +168,16 @@ struct VerilogFrontend : public Frontend {
log("recommended to use a simulator (for example Icarus Verilog) for checking\n");
log("the syntax of the code, rather than to rely on read_verilog for that.\n");
log("\n");
+ log("See the Yosys README file for a list of non-standard Verilog features\n");
+ log("supported by the Yosys Verilog front-end.\n");
+ log("\n");
}
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
bool flag_dump_vlog = false;
+ bool flag_dump_rtlil = false;
bool flag_nolatches = false;
bool flag_nomeminit = false;
bool flag_nomem2reg = false;
@@ -172,7 +185,6 @@ struct VerilogFrontend : public Frontend {
bool flag_ppdump = false;
bool flag_nopp = false;
bool flag_nodpi = false;
- bool flag_lib = false;
bool flag_noopt = false;
bool flag_icells = false;
bool flag_ignore_redef = false;
@@ -184,9 +196,12 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yydebug = false;
sv_mode = false;
formal_mode = false;
+ norestrict_mode = false;
+ assume_asserts_mode = false;
+ lib_mode = false;
default_nettype_wire = true;
- log_header("Executing Verilog-2005 frontend.\n");
+ log_header(design, "Executing Verilog-2005 frontend.\n");
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
@@ -201,6 +216,14 @@ struct VerilogFrontend : public Frontend {
formal_mode = true;
continue;
}
+ if (arg == "-norestrict") {
+ norestrict_mode = true;
+ continue;
+ }
+ if (arg == "-assume-asserts") {
+ assume_asserts_mode = true;
+ continue;
+ }
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@@ -213,6 +236,10 @@ struct VerilogFrontend : public Frontend {
flag_dump_vlog = true;
continue;
}
+ if (arg == "-dump_rtlil") {
+ flag_dump_rtlil = true;
+ continue;
+ }
if (arg == "-yydebug") {
frontend_verilog_yydebug = true;
continue;
@@ -246,7 +273,7 @@ struct VerilogFrontend : public Frontend {
continue;
}
if (arg == "-lib") {
- flag_lib = true;
+ lib_mode = true;
defines_map["BLACKBOX"] = string();
continue;
}
@@ -339,7 +366,7 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
@@ -362,13 +389,13 @@ struct VerilogDefaults : public Pass {
log("Add the specified options to the list of default options to read_verilog.\n");
log("\n");
log("\n");
- log(" verilog_defaults -clear");
+ log(" verilog_defaults -clear\n");
log("\n");
log("Clear the list of Verilog default options.\n");
log("\n");
log("\n");
- log(" verilog_defaults -push");
- log(" verilog_defaults -pop");
+ log(" verilog_defaults -push\n");
+ log(" verilog_defaults -pop\n");
log("\n");
log("Push or pop the list of default options to a stack. Note that -push does\n");
log("not imply -clear.\n");
diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h
index fb98f4af..606ec20a 100644
--- a/frontends/verilog/verilog_frontend.h
+++ b/frontends/verilog/verilog_frontend.h
@@ -54,6 +54,15 @@ namespace VERILOG_FRONTEND
// running in -formal mode
extern bool formal_mode;
+ // running in -norestrict mode
+ extern bool norestrict_mode;
+
+ // running in -assume-asserts mode
+ extern bool assume_asserts_mode;
+
+ // running in -lib mode
+ extern bool lib_mode;
+
// lexer input stream
extern std::istream *lexin;
}
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 69a8ddaa..405aeb97 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -63,6 +63,10 @@ YOSYS_NAMESPACE_END
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \
return TOK_ID;
+#define NON_KEYWORD() \
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \
+ return TOK_ID;
+
#define YY_INPUT(buf,result,max_size) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
@@ -141,6 +145,8 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
+"package" { SV_KEYWORD(TOK_PACKAGE); }
+"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
"parameter" { return TOK_PARAMETER; }
"localparam" { return TOK_LOCALPARAM; }
"defparam" { return TOK_DEFPARAM; }
@@ -171,6 +177,7 @@ YOSYS_NAMESPACE_END
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
+"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
@@ -351,6 +358,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"<<<" { return OP_SSHL; }
">>>" { return OP_SSHR; }
+"::" { SV_KEYWORD(TOK_PACKAGESEP); }
+
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 863fee59..c730ce5b 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -57,7 +57,8 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
- bool sv_mode, formal_mode;
+ bool sv_mode, formal_mode, lib_mode;
+ bool norestrict_mode, assume_asserts_mode;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -102,6 +103,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
+%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
@@ -111,7 +113,8 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
-%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY
+%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
+%token TOK_RESTRICT TOK_PROPERTY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
@@ -133,6 +136,9 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%left OP_POW
%right UNARY_OPS
+%define parse.error verbose
+%define parse.lac full
+
%expect 2
%debug
@@ -155,6 +161,7 @@ design:
task_func_decl design |
param_decl design |
localparam_decl design |
+ package design |
/* empty */;
attr:
@@ -212,6 +219,14 @@ hierarchical_id:
TOK_ID {
$$ = $1;
} |
+ hierarchical_id TOK_PACKAGESEP TOK_ID {
+ if ($3->substr(0, 1) == "\\")
+ *$1 += "::" + $3->substr(1);
+ else
+ *$1 += "::" + *$3;
+ delete $3;
+ $$ = $1;
+ } |
hierarchical_id '.' TOK_ID {
if ($3->substr(0, 1) == "\\")
*$1 += "." + $3->substr(1);
@@ -246,11 +261,10 @@ module_para_opt:
'#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
module_para_list:
- single_module_para |
- single_module_para ',' module_para_list |
- /* empty */;
+ single_module_para | module_para_list ',' single_module_para;
single_module_para:
+ /* empty */ |
TOK_PARAMETER {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
@@ -302,7 +316,7 @@ module_arg:
node->children.push_back($3);
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str());
- if (node->is_reg && node->is_input && !node->is_output)
+ if (node->is_reg && node->is_input && !node->is_output && !sv_mode)
frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str());
ast_stack.back()->children.push_back(node);
append_attr(node, $1);
@@ -312,6 +326,25 @@ module_arg:
do_not_require_port_stubs = true;
};
+package:
+ attr TOK_PACKAGE TOK_ID {
+ AstNode *mod = new AstNode(AST_PACKAGE);
+ ast_stack.back()->children.push_back(mod);
+ ast_stack.push_back(mod);
+ current_ast_mod = mod;
+ mod->str = *$3;
+ append_attr(mod, $1);
+ } ';' package_body TOK_ENDPACKAGE {
+ ast_stack.pop_back();
+ current_ast_mod = NULL;
+ };
+
+package_body:
+ package_body package_body_stmt |;
+
+package_body_stmt:
+ localparam_decl;
+
non_opt_delay:
'#' '(' expr ')' { delete $3; } |
'#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; };
@@ -736,7 +769,7 @@ wire_name:
if (port_stubs.count(*$1) != 0) {
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str());
- if (node->is_reg && node->is_input && !node->is_output)
+ if (node->is_reg && node->is_input && !node->is_output && !sv_mode)
frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str());
node->port_id = port_stubs[*$1];
port_stubs.erase(*$1);
@@ -825,10 +858,10 @@ cell_parameter_list_opt:
'#' '(' cell_parameter_list ')' | /* empty */;
cell_parameter_list:
- /* empty */ | cell_parameter |
- cell_parameter ',' cell_parameter_list;
+ cell_parameter | cell_parameter_list ',' cell_parameter;
cell_parameter:
+ /* empty */ |
expr {
AstNode *node = new AstNode(AST_PARASET);
astbuf1->children.push_back(node);
@@ -843,14 +876,40 @@ cell_parameter:
};
cell_port_list:
- /* empty */ | cell_port |
- cell_port ',' cell_port_list |
- /* empty */ ',' {
- AstNode *node = new AstNode(AST_ARGUMENT);
- astbuf2->children.push_back(node);
- } cell_port_list;
+ cell_port_list_rules {
+ // remove empty args from end of list
+ while (!astbuf2->children.empty()) {
+ AstNode *node = astbuf2->children.back();
+ if (node->type != AST_ARGUMENT) break;
+ if (!node->children.empty()) break;
+ if (!node->str.empty()) break;
+ astbuf2->children.pop_back();
+ delete node;
+ }
+
+ // check port types
+ bool has_positional_args = false;
+ bool has_named_args = false;
+ for (auto node : astbuf2->children) {
+ if (node->type != AST_ARGUMENT) continue;
+ if (node->str.empty())
+ has_positional_args = true;
+ else
+ has_named_args = true;
+ }
+
+ if (has_positional_args && has_named_args)
+ frontend_verilog_yyerror("Mix of positional and named cell ports.");
+ };
+
+cell_port_list_rules:
+ cell_port | cell_port_list_rules ',' cell_port;
cell_port:
+ /* empty */ {
+ AstNode *node = new AstNode(AST_ARGUMENT);
+ astbuf2->children.push_back(node);
+ } |
expr {
AstNode *node = new AstNode(AST_ARGUMENT);
astbuf2->children.push_back(node);
@@ -937,18 +996,30 @@ opt_label:
assert:
TOK_ASSERT '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $3));
} |
TOK_ASSUME '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
+ } |
+ TOK_RESTRICT '(' expr ')' ';' {
+ if (norestrict_mode)
+ delete $3;
+ else
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
};
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
} |
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
+ } |
+ TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
+ if (norestrict_mode)
+ delete $4;
+ else
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
};
simple_behavioral_stmt:
@@ -1099,7 +1170,9 @@ case_body:
case_item:
{
- AstNode *node = new AstNode(AST_COND);
+ AstNode *node = new AstNode(
+ case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX :
+ case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} case_select {
@@ -1119,7 +1192,9 @@ gen_case_body:
gen_case_item:
{
- AstNode *node = new AstNode(AST_COND);
+ AstNode *node = new AstNode(
+ case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX :
+ case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} case_select {
@@ -1154,6 +1229,8 @@ rvalue:
$$ = new AstNode(AST_IDENTIFIER, $2);
$$->str = *$1;
delete $1;
+ if ($2 == nullptr && formal_mode && ($$->str == "\\$initstate" || $$->str == "\\$anyconst"))
+ $$->type = AST_FCALL;
} |
hierarchical_id non_opt_multirange {
$$ = new AstNode(AST_IDENTIFIER, $2);
@@ -1278,7 +1355,7 @@ basic_expr:
if ($4->substr(0, 1) != "'")
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = $2;
- AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
+ AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $4->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1289,7 +1366,7 @@ basic_expr:
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
- AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
+ AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $2->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@@ -1297,24 +1374,24 @@ basic_expr:
delete $2;
} |
TOK_CONST TOK_CONST {
- $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
+ $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if ($$ == NULL || (*$2)[0] != '\'')
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
delete $1;
delete $2;
} |
TOK_CONST {
- $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
+ $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
} |
TOK_REALVAL {
$$ = new AstNode(AST_REALVALUE);
- char *p = strdup($1->c_str()), *q;
- for (int i = 0, j = 0; !p[j]; j++)
- if (p[j] != '_')
- p[i++] = p[j], p[i] = 0;
+ char *p = (char*)malloc(GetSize(*$1) + 1), *q;
+ for (int i = 0, j = 0; j < GetSize(*$1); j++)
+ if ((*$1)[j] != '_')
+ p[i++] = (*$1)[j], p[i] = 0;
$$->realvalue = strtod(p, &q);
log_assert(*q == 0);
delete $1;
diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc
index 80bf243f..6f9c0e3f 100644
--- a/frontends/vhdl2verilog/vhdl2verilog.cc
+++ b/frontends/vhdl2verilog/vhdl2verilog.cc
@@ -74,7 +74,7 @@ struct Vhdl2verilogPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
+ log_header(design, "Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
log_push();
std::string out_file, top_entity;
@@ -173,7 +173,7 @@ struct Vhdl2verilogPass : public Pass {
Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog");
}
- log_header("Removing temp directory `%s':\n", tempdir_name.c_str());
+ log_header(design, "Removing temp directory `%s':\n", tempdir_name.c_str());
remove_directory(tempdir_name);
log_pop();
}
diff --git a/kernel/celledges.cc b/kernel/celledges.cc
new file mode 100644
index 00000000..556e8b82
--- /dev/null
+++ b/kernel/celledges.cc
@@ -0,0 +1,209 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/celledges.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", Y = "\\Y";
+
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int a_width = GetSize(cell->getPort(A));
+ int y_width = GetSize(cell->getPort(Y));
+
+ for (int i = 0; i < y_width; i++)
+ {
+ if (i < a_width)
+ db->add_edge(cell, A, i, Y, i, -1);
+ else if (is_signed && a_width > 0)
+ db->add_edge(cell, A, a_width-1, Y, i, -1);
+ }
+}
+
+void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", B = "\\B", Y = "\\Y";
+
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int a_width = GetSize(cell->getPort(A));
+ int b_width = GetSize(cell->getPort(B));
+ int y_width = GetSize(cell->getPort(Y));
+
+ if (cell->type == "$and" && !is_signed) {
+ if (a_width > b_width)
+ a_width = b_width;
+ else
+ b_width = a_width;
+ }
+
+ for (int i = 0; i < y_width; i++)
+ {
+ if (i < a_width)
+ db->add_edge(cell, A, i, Y, i, -1);
+ else if (is_signed && a_width > 0)
+ db->add_edge(cell, A, a_width-1, Y, i, -1);
+
+ if (i < b_width)
+ db->add_edge(cell, B, i, Y, i, -1);
+ else if (is_signed && b_width > 0)
+ db->add_edge(cell, B, b_width-1, Y, i, -1);
+ }
+}
+
+void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", Y = "\\Y";
+
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int a_width = GetSize(cell->getPort(A));
+ int y_width = GetSize(cell->getPort(Y));
+
+ if (is_signed && a_width == 1)
+ y_width = std::min(y_width, 1);
+
+ for (int i = 0; i < y_width; i++)
+ for (int k = 0; k <= i && k < a_width; k++)
+ db->add_edge(cell, A, k, Y, i, -1);
+}
+
+void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", B = "\\B", Y = "\\Y";
+
+ bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+ int a_width = GetSize(cell->getPort(A));
+ int b_width = GetSize(cell->getPort(B));
+ int y_width = GetSize(cell->getPort(Y));
+
+ if (!is_signed && cell->type != "$sub") {
+ int ab_width = std::max(a_width, b_width);
+ y_width = std::min(y_width, ab_width+1);
+ }
+
+ for (int i = 0; i < y_width; i++)
+ {
+ for (int k = 0; k <= i; k++)
+ {
+ if (k < a_width)
+ db->add_edge(cell, A, k, Y, i, -1);
+
+ if (k < b_width)
+ db->add_edge(cell, B, k, Y, i, -1);
+ }
+ }
+}
+
+void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", Y = "\\Y";
+
+ int a_width = GetSize(cell->getPort(A));
+
+ for (int i = 0; i < a_width; i++)
+ db->add_edge(cell, A, i, Y, 0, -1);
+}
+
+void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", B = "\\B", Y = "\\Y";
+
+ int a_width = GetSize(cell->getPort(A));
+ int b_width = GetSize(cell->getPort(B));
+
+ for (int i = 0; i < a_width; i++)
+ db->add_edge(cell, A, i, Y, 0, -1);
+
+ for (int i = 0; i < b_width; i++)
+ db->add_edge(cell, B, i, Y, 0, -1);
+}
+
+void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
+{
+ IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y";
+
+ int a_width = GetSize(cell->getPort(A));
+ int b_width = GetSize(cell->getPort(B));
+ int s_width = GetSize(cell->getPort(S));
+
+ for (int i = 0; i < a_width; i++)
+ {
+ db->add_edge(cell, A, i, Y, i, -1);
+
+ for (int k = i; k < b_width; k += a_width)
+ db->add_edge(cell, B, k, Y, i, -1);
+
+ for (int k = 0; k < s_width; k++)
+ db->add_edge(cell, S, k, Y, i, -1);
+ }
+}
+
+PRIVATE_NAMESPACE_END
+
+bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
+{
+ if (cell->type.in("$not", "$pos")) {
+ bitwise_unary_op(this, cell);
+ return true;
+ }
+
+ if (cell->type.in("$and", "$or", "$xor", "$xnor")) {
+ bitwise_binary_op(this, cell);
+ return true;
+ }
+
+ if (cell->type == "$neg") {
+ arith_neg_op(this, cell);
+ return true;
+ }
+
+ if (cell->type.in("$add", "$sub")) {
+ arith_binary_op(this, cell);
+ return true;
+ }
+
+ if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$logic_not")) {
+ reduce_op(this, cell);
+ return true;
+ }
+
+ // FIXME:
+ // if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) {
+ // shift_op(this, cell);
+ // return true;
+ // }
+
+ if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) {
+ compare_op(this, cell);
+ return true;
+ }
+
+ if (cell->type.in("$mux", "$pmux")) {
+ mux_op(this, cell);
+ return true;
+ }
+
+ // FIXME: $mul $div $mod $slice $concat
+ // FIXME: $lut $sop $alu $lcu $macc $fa
+
+ return false;
+}
+
diff --git a/kernel/celledges.h b/kernel/celledges.h
new file mode 100644
index 00000000..6aab9ed4
--- /dev/null
+++ b/kernel/celledges.h
@@ -0,0 +1,63 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef CELLEDGES_H
+#define CELLEDGES_H
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+struct AbstractCellEdgesDatabase
+{
+ virtual ~AbstractCellEdgesDatabase() { }
+ virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int delay) = 0;
+ bool add_edges_from_cell(RTLIL::Cell *cell);
+};
+
+struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase
+{
+ SigMap &sigmap;
+ dict<SigBit, pool<SigBit>> db;
+ FwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }
+
+ virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {
+ SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);
+ SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);
+ db[from_sigbit].insert(to_sigbit);
+ }
+};
+
+struct RevCellEdgesDatabase : AbstractCellEdgesDatabase
+{
+ SigMap &sigmap;
+ dict<SigBit, pool<SigBit>> db;
+ RevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { }
+
+ virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override {
+ SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]);
+ SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]);
+ db[to_sigbit].insert(from_sigbit);
+ }
+};
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 40fdca36..900c12d0 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -85,7 +85,7 @@ struct CellTypes
std::vector<RTLIL::IdString> unary_ops = {
"$not", "$pos", "$neg",
"$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
- "$logic_not", "$slice", "$lut"
+ "$logic_not", "$slice", "$lut", "$sop"
};
std::vector<RTLIL::IdString> binary_ops = {
@@ -116,6 +116,8 @@ struct CellTypes
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
+ setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
+ setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
}
@@ -357,6 +359,44 @@ struct CellTypes
return t;
}
+ if (cell->type == "$sop")
+ {
+ int width = cell->parameters.at("\\WIDTH").as_int();
+ int depth = cell->parameters.at("\\DEPTH").as_int();
+ std::vector<RTLIL::State> t = cell->parameters.at("\\TABLE").bits;
+
+ while (GetSize(t) < width*depth*2)
+ t.push_back(RTLIL::S0);
+
+ RTLIL::State default_ret = State::S0;
+
+ for (int i = 0; i < depth; i++)
+ {
+ bool match = true;
+ bool match_x = true;
+
+ for (int j = 0; j < width; j++) {
+ RTLIL::State a = arg1.bits.at(j);
+ if (t.at(2*width*i + 2*j + 0) == State::S1) {
+ if (a == State::S1) match_x = false;
+ if (a != State::S0) match = false;
+ }
+ if (t.at(2*width*i + 2*j + 1) == State::S1) {
+ if (a == State::S0) match_x = false;
+ if (a != State::S1) match = false;
+ }
+ }
+
+ if (match)
+ return State::S1;
+
+ if (match_x)
+ default_ret = State::Sx;
+ }
+
+ return default_ret;
+ }
+
bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool();
bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool();
int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1;
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 02e332f9..5cfc4171 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -183,8 +183,8 @@ int main(int argc, char **argv)
printf(" -b backend\n");
printf(" use this backend for the output file specified on the command line\n");
printf("\n");
- printf(" -f backend\n");
- printf(" use the specified front for the input files on the command line\n");
+ printf(" -f frontend\n");
+ printf(" use the specified frontend for the input files on the command line\n");
printf("\n");
printf(" -H\n");
printf(" print the command list\n");
@@ -213,6 +213,11 @@ int main(int argc, char **argv)
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
+ printf(" -D <header_id>[:<filename>]\n");
+ printf(" dump the design when printing the specified log header to a file.\n");
+ printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
+ printf(" Use 'ALL' as <header_id> to dump at every header.\n");
+ printf("\n");
printf(" -V\n");
printf(" print version information and exit\n");
printf("\n");
@@ -233,7 +238,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:D:")) != -1)
{
switch (opt)
{
@@ -315,6 +320,28 @@ int main(int argc, char **argv)
scriptfile = optarg;
scriptfile_tcl = true;
break;
+ case 'D':
+ {
+ auto args = split_tokens(optarg, ":");
+ if (!args.empty() && args[0] == "ALL") {
+ if (GetSize(args) != 1) {
+ fprintf(stderr, "Invalid number of tokens in -D ALL.\n");
+ exit(1);
+ }
+ log_hdump_all = true;
+ } else {
+ if (!args.empty() && !args[0].empty() && args[0].back() == '.')
+ args[0].pop_back();
+ if (GetSize(args) == 1)
+ args.push_back("yosys_dump_" + args[0] + ".il");
+ if (GetSize(args) != 2) {
+ fprintf(stderr, "Invalid number of tokens in -D.\n");
+ exit(1);
+ }
+ log_hdump[args[0]].insert(args[1]);
+ }
+ }
+ break;
default:
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
exit(1);
@@ -482,6 +509,11 @@ int main(int argc, char **argv)
free(hist_list);
#endif
+ log_flush();
+#ifdef _WIN32
+ _Exit(0);
+#endif
+
yosys_shutdown();
return 0;
diff --git a/kernel/hashlib.h b/kernel/hashlib.h
index 280b1693..3c824b8c 100644
--- a/kernel/hashlib.h
+++ b/kernel/hashlib.h
@@ -10,6 +10,7 @@
// -------------------------------------------------------
#ifndef HASHLIB_H
+#define HASHLIB_H
#include <stdexcept>
#include <algorithm>
@@ -136,8 +137,8 @@ struct hash_cstr_ops {
static inline unsigned int hash(const char *a) {
unsigned int hash = mkhash_init;
while (*a)
- hash = mkhash(hash, *(a++));
- return hash;
+ hash = mkhash(hash, *(a++));
+ return hash;
}
};
@@ -156,7 +157,7 @@ struct hash_obj_ops {
}
template<typename T>
static inline unsigned int hash(const T *a) {
- return a->hash();
+ return a ? a->hash() : 0;
}
};
diff --git a/kernel/log.cc b/kernel/log.cc
index 4f395c75..3f1d8881 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -40,6 +40,8 @@ YOSYS_NAMESPACE_BEGIN
std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
+std::map<std::string, std::set<std::string>> log_hdump;
+bool log_hdump_all = false;
FILE *log_errfile = NULL;
SHA1 *log_hasher = NULL;
@@ -136,7 +138,7 @@ void logv(const char *format, va_list ap)
*f << str;
}
-void logv_header(const char *format, va_list ap)
+void logv_header(RTLIL::Design *design, const char *format, va_list ap)
{
bool pop_errfile = false;
@@ -149,12 +151,24 @@ void logv_header(const char *format, va_list ap)
pop_errfile = true;
}
+ std::string header_id;
+
for (int c : header_count)
- log("%d.", c);
- log(" ");
+ header_id += stringf("%s%d", header_id.empty() ? "" : ".", c);
+
+ log("%s. ", header_id.c_str());
logv(format, ap);
log_flush();
+ if (log_hdump_all)
+ log_hdump[header_id].insert("yosys_dump_" + header_id + ".il");
+
+ if (log_hdump.count(header_id) && design != nullptr)
+ for (auto &filename : log_hdump.at(header_id)) {
+ log("Dumping current design to '%s'.\n", filename.c_str());
+ Pass::call(design, {"dump", "-o", filename});
+ }
+
if (pop_errfile)
log_files.pop_back();
}
@@ -194,7 +208,7 @@ void logv_error(const char *format, va_list ap)
log_files = backup_log_files;
throw 0;
#else
- exit(1);
+ _Exit(1);
#endif
}
@@ -206,11 +220,11 @@ void log(const char *format, ...)
va_end(ap);
}
-void log_header(const char *format, ...)
+void log_header(RTLIL::Design *design, const char *format, ...)
{
va_list ap;
va_start(ap, format);
- logv_header(format, ap);
+ logv_header(design, format, ap);
va_end(ap);
}
@@ -400,6 +414,24 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
}
}
+const char *log_const(const RTLIL::Const &value, bool autoint)
+{
+ if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0)
+ return log_signal(value, autoint);
+
+ std::string str = "\"" + value.decode_string() + "\"";
+
+ if (string_buf.size() < 100) {
+ string_buf.push_back(str);
+ return string_buf.back().c_str();
+ } else {
+ if (++string_buf_index == 100)
+ string_buf_index = 0;
+ string_buf[string_buf_index] = str;
+ return string_buf[string_buf_index].c_str();
+ }
+}
+
const char *log_id(RTLIL::IdString str)
{
log_id_cache.insert(str);
@@ -413,6 +445,13 @@ const char *log_id(RTLIL::IdString str)
return p+1;
}
+void log_module(RTLIL::Module *module, std::string indent)
+{
+ std::stringstream buf;
+ ILANG_BACKEND::dump_module(buf, indent, module, module->design, false);
+ log("%s", buf.str().c_str());
+}
+
void log_cell(RTLIL::Cell *cell, std::string indent)
{
std::stringstream buf;
diff --git a/kernel/log.h b/kernel/log.h
index 28baf988..53480db3 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -47,6 +47,8 @@ struct log_cmd_error_exception { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
+extern std::map<std::string, std::set<std::string>> log_hdump;
+extern bool log_hdump_all;
extern FILE *log_errfile;
extern SHA1 *log_hasher;
@@ -58,12 +60,12 @@ extern int log_verbose_level;
extern string log_last_error;
void logv(const char *format, va_list ap);
-void logv_header(const char *format, va_list ap);
+void logv_header(RTLIL::Design *design, const char *format, va_list ap);
void logv_warning(const char *format, va_list ap);
YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn);
void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
-void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
+void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
@@ -77,12 +79,14 @@ void log_reset_stack();
void log_flush();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
+const char *log_const(const RTLIL::Const &value, bool autoint = true);
const char *log_id(RTLIL::IdString id);
template<typename T> static inline const char *log_id(T *obj) {
return log_id(obj->name);
}
+void log_module(RTLIL::Module *module, std::string indent = "");
void log_cell(RTLIL::Cell *cell, std::string indent = "");
#ifndef NDEBUG
@@ -161,11 +165,13 @@ struct PerformanceTimer
}
static int64_t query() {
-#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
+# if _WIN32
+ return 0;
+# elif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec;
-#elif defined(RUSAGE_SELF)
+# elif defined(RUSAGE_SELF)
struct rusage rusage;
int64_t t;
if (getrusage(RUSAGE_SELF, &rusage) == -1) {
@@ -175,11 +181,9 @@ struct PerformanceTimer
t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;
t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL;
return t;
-#elif _WIN32
- return 0;
-#else
- #error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
-#endif
+# else
+# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
+# endif
}
void reset() {
@@ -230,6 +234,32 @@ static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { lo
void log_dump_val_worker(RTLIL::IdString v);
void log_dump_val_worker(RTLIL::SigSpec v);
+template<typename K, typename T, typename OPS>
+static inline void log_dump_val_worker(dict<K, T, OPS> &v) {
+ log("{");
+ bool first = true;
+ for (auto &it : v) {
+ log(first ? " " : ", ");
+ log_dump_val_worker(it.first);
+ log(": ");
+ log_dump_val_worker(it.second);
+ first = false;
+ }
+ log(" }");
+}
+
+template<typename K, typename OPS>
+static inline void log_dump_val_worker(pool<K, OPS> &v) {
+ log("{");
+ bool first = true;
+ for (auto &it : v) {
+ log(first ? " " : ", ");
+ log_dump_val_worker(it);
+ first = false;
+ }
+ log(" }");
+}
+
template<typename T>
static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }
diff --git a/kernel/register.cc b/kernel/register.cc
index 49a67324..7a1d0b44 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -80,6 +80,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
state.begin_ns = PerformanceTimer::query();
state.parent_pass = current_pass;
current_pass = this;
+ clear_flags();
return state;
}
@@ -99,6 +100,10 @@ void Pass::help()
log("\n");
}
+void Pass::clear_flags()
+{
+}
+
void Pass::cmd_log_args(const std::vector<std::string> &args)
{
if (args.size() <= 1)
@@ -160,7 +165,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' ||
cmd_buf.back() == '\r' || cmd_buf.back() == '\n'))
cmd_buf.resize(cmd_buf.size()-1);
- log_header("Shell command: %s\n", cmd_buf.c_str());
+ log_header(design, "Shell command: %s\n", cmd_buf.c_str());
int retCode = run_command(cmd_buf);
if (retCode != 0)
log_cmd_error("Shell command returned error code %d.\n", retCode);
@@ -282,6 +287,60 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec
design->selected_active_module = backup_selected_active_module;
}
+bool ScriptPass::check_label(std::string label, std::string info)
+{
+ if (active_design == nullptr) {
+ log("\n");
+ if (info.empty())
+ log(" %s:\n", label.c_str());
+ else
+ log(" %s: %s\n", label.c_str(), info.c_str());
+ return true;
+ } else {
+ if (!active_run_from.empty() && active_run_from == active_run_to) {
+ block_active = (label == active_run_from);
+ } else {
+ if (label == active_run_from)
+ block_active = true;
+ if (label == active_run_to)
+ block_active = false;
+ }
+ return block_active;
+ }
+}
+
+void ScriptPass::run(std::string command, std::string info)
+{
+ if (active_design == nullptr) {
+ if (info.empty())
+ log(" %s\n", command.c_str());
+ else
+ log(" %s %s\n", command.c_str(), info.c_str());
+ } else
+ Pass::call(active_design, command);
+}
+
+void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to)
+{
+ help_mode = false;
+ active_design = design;
+ block_active = run_from.empty();
+ active_run_from = run_from;
+ active_run_to = run_to;
+ script();
+}
+
+void ScriptPass::help_script()
+{
+ clear_flags();
+ help_mode = true;
+ active_design = nullptr;
+ block_active = true;
+ active_run_from.clear();
+ active_run_to.clear();
+ script();
+}
+
Frontend::Frontend(std::string name, std::string short_help) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help),
frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
@@ -323,7 +382,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
bool called_with_fp = f != NULL;
next_args.clear();
- for (; argidx < args.size(); argidx++)
+
+ if (argidx < args.size())
{
std::string arg = args[argidx];
@@ -360,6 +420,12 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
f = new std::istringstream(last_here_document);
} else {
rewrite_filename(filename);
+ vector<string> filenames = glob_filename(filename);
+ filename = filenames.front();
+ if (GetSize(filenames) > 1) {
+ next_args.insert(next_args.end(), args.begin(), args.begin()+argidx);
+ next_args.insert(next_args.end(), filenames.begin()+1, filenames.end());
+ }
std::ifstream *ff = new std::ifstream;
ff->open(filename.c_str());
if (ff->fail())
@@ -375,12 +441,13 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
cmd_error(args, i, "Found option, expected arguments.");
if (argidx+1 < args.size()) {
- next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx);
- next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end());
+ if (next_args.empty())
+ next_args.insert(next_args.end(), args.begin(), args.begin()+argidx);
+ next_args.insert(next_args.end(), args.begin()+argidx+1, args.end());
args.erase(args.begin()+argidx+1, args.end());
}
- break;
}
+
if (f == NULL)
cmd_error(args, argidx, "No filename given.");
diff --git a/kernel/register.h b/kernel/register.h
index 0ef07b76..8024c56a 100644
--- a/kernel/register.h
+++ b/kernel/register.h
@@ -31,6 +31,7 @@ struct Pass
virtual ~Pass();
virtual void help();
+ virtual void clear_flags();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
int call_counter;
@@ -63,6 +64,22 @@ struct Pass
static void done_register();
};
+struct ScriptPass : Pass
+{
+ bool block_active, help_mode;
+ RTLIL::Design *active_design;
+ std::string active_run_from, active_run_to;
+
+ ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { }
+
+ virtual void script() = 0;
+
+ bool check_label(std::string label, std::string info = std::string());
+ void run(std::string command, std::string info = std::string());
+ void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string());
+ void help_script();
+};
+
struct Frontend : Pass
{
// for reading of here documents
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a706491e..32efe4f0 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -304,6 +304,8 @@ RTLIL::Design::~Design()
{
for (auto it = modules_.begin(); it != modules_.end(); ++it)
delete it->second;
+ for (auto n : verilog_packages)
+ delete n;
}
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
@@ -845,6 +847,15 @@ namespace {
return;
}
+ if (cell->type == "$sop") {
+ param("\\DEPTH");
+ param("\\TABLE");
+ port("\\A", param("\\WIDTH"));
+ port("\\Y", 1);
+ check_expected();
+ return;
+ }
+
if (cell->type == "$sr") {
param_bool("\\SET_POLARITY");
param_bool("\\CLR_POLARITY");
@@ -1006,16 +1017,21 @@ namespace {
return;
}
- if (cell->type == "$assert") {
+ if (cell->type.in("$assert", "$assume")) {
port("\\A", 1);
port("\\EN", 1);
check_expected();
return;
}
- if (cell->type == "$assume") {
- port("\\A", 1);
- port("\\EN", 1);
+ if (cell->type == "$initstate") {
+ port("\\Y", 1);
+ check_expected();
+ return;
+ }
+
+ if (cell->type == "$anyconst") {
+ port("\\Y", param("\\WIDTH"));
check_expected();
return;
}
@@ -1466,6 +1482,7 @@ void RTLIL::Module::connect(const RTLIL::SigSig &conn)
log_backtrace("-X- ", yosys_xtrace-1);
}
+ log_assert(GetSize(conn.first) == GetSize(conn.second));
connections_.push_back(conn);
}
@@ -1784,6 +1801,14 @@ RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a
return cell;
}
+RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en)
+{
+ RTLIL::Cell *cell = addCell(name, "$assume");
+ cell->setPort("\\A", sig_a);
+ cell->setPort("\\EN", sig_en);
+ return cell;
+}
+
RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y)
{
RTLIL::Cell *cell = addCell(name, "$equiv");
@@ -1950,6 +1975,22 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec
return cell;
}
+RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width)
+{
+ RTLIL::SigSpec sig = addWire(NEW_ID, width);
+ Cell *cell = addCell(name, "$anyconst");
+ cell->setParam("\\WIDTH", width);
+ cell->setPort("\\Y", sig);
+ return sig;
+}
+
+RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name)
+{
+ RTLIL::SigSpec sig = addWire(NEW_ID);
+ Cell *cell = addCell(name, "$initstate");
+ cell->setPort("\\Y", sig);
+ return sig;
+}
RTLIL::Wire::Wire()
{
@@ -2133,7 +2174,7 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
return;
}
- if (type == "$lut") {
+ if (type == "$lut" || type == "$sop") {
parameters["\\WIDTH"] = GetSize(connections_["\\A"]);
return;
}
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 940e36ab..a426e0bd 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -792,6 +792,7 @@ struct RTLIL::Design
int refcount_modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
+ std::vector<AST::AstNode*> verilog_packages;
std::vector<RTLIL::Selection> selection_stack;
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
@@ -1003,6 +1004,7 @@ public:
RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut);
RTLIL::Cell* addTribuf (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y);
RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
+ RTLIL::Cell* addAssume (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
@@ -1101,6 +1103,9 @@ public:
RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c);
RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d);
RTLIL::SigBit Oai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d);
+
+ RTLIL::SigSpec Anyconst (RTLIL::IdString name, int width = 1);
+ RTLIL::SigSpec Initstate (RTLIL::IdString name);
};
struct RTLIL::Wire : public RTLIL::AttrObject
diff --git a/kernel/satgen.h b/kernel/satgen.h
index d44d61f1..0a65b490 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -70,6 +70,7 @@ struct SatGen
std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;
std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en;
std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals;
+ std::map<std::pair<std::string, int>, bool> initstates;
bool ignore_div_by_zero;
bool model_undef;
@@ -266,6 +267,13 @@ struct SatGen
ez->assume(ez->OR(undef, ez->IFF(y, yy)));
}
+ void setInitState(int timestep)
+ {
+ auto key = make_pair(prefix, timestep);
+ log_assert(initstates.count(key) == 0 || initstates.at(key) == true);
+ initstates[key] = true;
+ }
+
bool importCell(RTLIL::Cell *cell, int timestep = -1)
{
bool arith_undef_handled = false;
@@ -1048,6 +1056,88 @@ struct SatGen
return true;
}
+ if (cell->type == "$sop")
+ {
+ std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
+ int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+
+ int width = cell->getParam("\\WIDTH").as_int();
+ int depth = cell->getParam("\\DEPTH").as_int();
+
+ vector<State> table_raw = cell->getParam("\\TABLE").bits;
+ while (GetSize(table_raw) < 2*width*depth)
+ table_raw.push_back(State::S0);
+
+ vector<vector<int>> table(depth);
+
+ for (int i = 0; i < depth; i++)
+ for (int j = 0; j < width; j++)
+ {
+ bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1);
+ bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1);
+
+ if (pat0 && !pat1)
+ table.at(i).push_back(0);
+ else if (!pat0 && pat1)
+ table.at(i).push_back(1);
+ else
+ table.at(i).push_back(-1);
+ }
+
+ if (model_undef)
+ {
+ std::vector<int> products, undef_products;
+ std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
+ int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
+
+ for (int i = 0; i < depth; i++)
+ {
+ std::vector<int> cmp_a, cmp_ua, cmp_b;
+
+ for (int j = 0; j < width; j++)
+ if (table.at(i).at(j) >= 0) {
+ cmp_a.push_back(a.at(j));
+ cmp_ua.push_back(undef_a.at(j));
+ cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE);
+ }
+
+ std::vector<int> masked_a = ez->vec_or(cmp_a, cmp_ua);
+ std::vector<int> masked_b = ez->vec_or(cmp_b, cmp_ua);
+
+ int masked_eq = ez->vec_eq(masked_a, masked_b);
+ int any_undef = ez->expression(ezSAT::OpOr, cmp_ua);
+
+ undef_products.push_back(ez->AND(any_undef, masked_eq));
+ products.push_back(ez->AND(ez->NOT(any_undef), masked_eq));
+ }
+
+ int yy = ez->expression(ezSAT::OpOr, products);
+ ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products)));
+ undefGating(y, yy, undef_y);
+ }
+ else
+ {
+ std::vector<int> products;
+
+ for (int i = 0; i < depth; i++)
+ {
+ std::vector<int> cmp_a, cmp_b;
+
+ for (int j = 0; j < width; j++)
+ if (table.at(i).at(j) >= 0) {
+ cmp_a.push_back(a.at(j));
+ cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE);
+ }
+
+ products.push_back(ez->vec_eq(cmp_a, cmp_b));
+ }
+
+ ez->SET(y, ez->expression(ezSAT::OpOr, products));
+ }
+
+ return true;
+ }
+
if (cell->type == "$fa")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
@@ -1229,6 +1319,28 @@ struct SatGen
return true;
}
+ if (cell->type == "$anyconst")
+ {
+ if (timestep < 2)
+ return true;
+
+ std::vector<int> d = importDefSigSpec(cell->getPort("\\Y"), timestep-1);
+ std::vector<int> q = importDefSigSpec(cell->getPort("\\Y"), timestep);
+
+ std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
+ ez->assume(ez->vec_eq(d, qq));
+
+ if (model_undef)
+ {
+ std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1);
+ std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep);
+
+ ez->assume(ez->vec_eq(undef_d, undef_q));
+ undefGating(q, qq, undef_q);
+ }
+ return true;
+ }
+
if (cell->type == "$_BUF_" || cell->type == "$equiv")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
@@ -1248,6 +1360,25 @@ struct SatGen
return true;
}
+ if (cell->type == "$initstate")
+ {
+ auto key = make_pair(prefix, timestep);
+ if (initstates.count(key) == 0)
+ initstates[key] = false;
+
+ std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
+ log_assert(GetSize(y) == 1);
+ ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE);
+
+ if (model_undef) {
+ std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
+ log_assert(GetSize(undef_y) == 1);
+ ez->SET(undef_y[0], ez->CONST_FALSE);
+ }
+
+ return true;
+ }
+
if (cell->type == "$assert")
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index eba1aef1..08fee974 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -37,11 +37,13 @@
# include <unistd.h>
# include <dirent.h>
# include <sys/stat.h>
+# include <glob.h>
#else
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
# include <sys/stat.h>
+# include <glob.h>
#endif
#include <limits.h>
@@ -104,7 +106,7 @@ void yosys_banner()
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
- log(" | Copyright (C) 2012 - 2015 Clifford Wolf <clifford@clifford.at> |\n");
+ log(" | Copyright (C) 2012 - 2016 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
@@ -547,6 +549,29 @@ const char *create_prompt(RTLIL::Design *design, int recursion_counter)
return buffer;
}
+std::vector<std::string> glob_filename(const std::string &filename_pattern)
+{
+ std::vector<std::string> results;
+
+#ifdef _WIN32
+ results.push_back(filename_pattern);
+#else
+ glob_t globbuf;
+
+ int err = glob(filename_pattern.c_str(), 0, NULL, &globbuf);
+
+ if(err == 0) {
+ for (size_t i = 0; i < globbuf.gl_pathc; i++)
+ results.push_back(globbuf.gl_pathv[i]);
+ globfree(&globbuf);
+ } else {
+ results.push_back(filename_pattern);
+ }
+#endif
+
+ return results;
+}
+
void rewrite_filename(std::string &filename)
{
if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"")
@@ -622,7 +647,7 @@ struct TclPass : public Pass {
} TclPass;
#endif
-#if defined(__linux__)
+#if defined(__linux__) || defined(__CYGWIN__)
std::string proc_self_dirname()
{
char path[PATH_MAX];
@@ -687,7 +712,7 @@ std::string proc_share_dirname()
std::string proc_share_dirname()
{
std::string proc_self_path = proc_self_dirname();
-# ifdef _WIN32
+# if defined(_WIN32) && !defined(YOSYS_WIN32_UNIX_DIR)
std::string proc_share_path = proc_self_path + "share\\";
if (check_file_exists(proc_share_path, true))
return proc_share_path;
@@ -701,6 +726,11 @@ std::string proc_share_dirname()
proc_share_path = proc_self_path + "../share/yosys/";
if (check_file_exists(proc_share_path, true))
return proc_share_path;
+# ifdef YOSYS_DATDIR
+ proc_share_path = YOSYS_DATDIR "/";
+ if (check_file_exists(proc_share_path, true))
+ return proc_share_path;
+# endif
# endif
log_error("proc_share_dirname: unable to determine share/ directory!\n");
}
@@ -758,6 +788,8 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "verilog";
else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
command = "verilog -sv";
+ else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd")
+ command = "vhdl";
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
@@ -1093,8 +1125,8 @@ struct HistoryPass : public Pass {
} HistoryPass;
#endif
-struct ScriptPass : public Pass {
- ScriptPass() : Pass("script", "execute commands from script file") { }
+struct ScriptCmdPass : public Pass {
+ ScriptCmdPass() : Pass("script", "execute commands from script file") { }
virtual void help() {
log("\n");
log(" script <filename> [<from_label>:<to_label>]\n");
@@ -1120,7 +1152,6 @@ struct ScriptPass : public Pass {
else
extra_args(args, 2, design, false);
}
-} ScriptPass;
+} ScriptCmdPass;
YOSYS_NAMESPACE_END
-
diff --git a/kernel/yosys.h b/kernel/yosys.h
index c8bc46b6..aab6b584 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -51,6 +51,7 @@
#include <initializer_list>
#include <stdexcept>
#include <memory>
+#include <cmath>
#include <sstream>
#include <fstream>
@@ -91,9 +92,9 @@
# define mkdir _mkdir
# define popen _popen
# define pclose _pclose
-# define PATH_MAX MAX_PATH
# ifndef __MINGW32__
+# define PATH_MAX MAX_PATH
# define isatty _isatty
# define fileno _fileno
# endif
@@ -279,6 +280,7 @@ RTLIL::Design *yosys_get_design();
std::string proc_self_dirname();
std::string proc_share_dirname();
const char *create_prompt(RTLIL::Design *design, int recursion_counter);
+std::vector<std::string> glob_filename(const std::string &filename_pattern);
void rewrite_filename(std::string &filename);
void run_pass(std::string command, RTLIL::Design *design = nullptr);
diff --git a/manual/APPNOTE_012_Verilog_to_BTOR.tex b/manual/APPNOTE_012_Verilog_to_BTOR.tex
index 245a6b0b..1bc27787 100644
--- a/manual/APPNOTE_012_Verilog_to_BTOR.tex
+++ b/manual/APPNOTE_012_Verilog_to_BTOR.tex
@@ -208,7 +208,7 @@ read_verilog -sv $1;
hierarchy -top $3; hierarchy -libdir $DIR;
hierarchy -check;
proc; opt;
-opt_const -mux_undef; opt;
+opt_expr -mux_undef; opt;
rename -hide;;;
splice; opt;
memory_dff -wr_only; memory_collect;;
@@ -263,7 +263,7 @@ read_verilog -sv $1;
hierarchy -top $3; hierarchy -libdir $DIR;
hierarchy -check;
proc; opt;
-opt_const -mux_undef; opt;
+opt_expr -mux_undef; opt;
rename -hide;;;
splice; opt;
memory;;
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index c648eb1f..bd73ae23 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -421,7 +421,7 @@ pass. The combinatorial logic cells can be mapped to physical cells from a Liber
using the {\tt abc} pass.
\begin{fixme}
-Add information about {\tt \$assert}, {\tt \$assume}, and {\tt \$equiv} cells.
+Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$equiv}, {\tt \$initstate}, and {\tt \$anyconst} cells.
\end{fixme}
\begin{fixme}
@@ -429,6 +429,10 @@ Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme}
\begin{fixme}
+Add information about {\tt \$lut} and {\tt \$sop} cells.
+\end{fixme}
+
+\begin{fixme}
Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells.
\end{fixme}
diff --git a/manual/CHAPTER_Optimize.tex b/manual/CHAPTER_Optimize.tex
index d09b3c47..eee92ef5 100644
--- a/manual/CHAPTER_Optimize.tex
+++ b/manual/CHAPTER_Optimize.tex
@@ -15,23 +15,23 @@ passes that each perform a simple optimization:
\begin{itemize}
\item Once at the beginning of {\tt opt}:
\begin{itemize}
-\item {\tt opt\_const}
-\item {\tt opt\_share -nomux}
+\item {\tt opt\_expr}
+\item {\tt opt\_merge -nomux}
\end{itemize}
\item Repeat until result is stable:
\begin{itemize}
\item {\tt opt\_muxtree}
\item {\tt opt\_reduce}
-\item {\tt opt\_share}
+\item {\tt opt\_merge}
\item {\tt opt\_rmdff}
\item {\tt opt\_clean}
-\item {\tt opt\_const}
+\item {\tt opt\_expr}
\end{itemize}
\end{itemize}
The following section describes each of the {\tt opt\_*} passes.
-\subsection{The opt\_const pass}
+\subsection{The opt\_expr pass}
This pass performs const folding on the internal combinational cell types
described in Chap.~\ref{chapter:celllib}. This means a cell with all constant
@@ -57,11 +57,11 @@ this pass can also optimize cells with some constant inputs.
$a$ & 1 & $a$ \\
1 & $b$ & $b$ \\
\end{tabular}
- \caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_const}.}
- \label{tab:opt_const_and}
+ \caption{Const folding rules for {\tt\$\_AND\_} cells as used in {\tt opt\_expr}.}
+ \label{tab:opt_expr_and}
\end{table}
-Table~\ref{tab:opt_const_and} shows the replacement rules used for optimizing
+Table~\ref{tab:opt_expr_and} shows the replacement rules used for optimizing
an {\tt\$\_AND\_} gate. The first three rules implement the obvious const folding
rules. Note that `any' might include dynamic values calculated by other parts
of the circuit. The following three lines propagate undef (X) states.
@@ -76,10 +76,10 @@ an undef value or a 1 and therefore the output can be set to undef.
The last two lines simply replace an {\tt\$\_AND\_} gate with one constant-1
input with a buffer.
-Besides this basic const folding the {\tt opt\_const} pass can replace 1-bit wide
+Besides this basic const folding the {\tt opt\_expr} pass can replace 1-bit wide
{\tt \$eq} and {\tt \$ne} cells with buffers or not-gates if one input is constant.
-The {\tt opt\_const} pass is very conservative regarding optimizing {\tt \$mux} cells,
+The {\tt opt\_expr} pass is very conservative regarding optimizing {\tt \$mux} cells,
as these cells are often used to model decision-trees and breaking these trees can
interfere with other optimizations.
@@ -130,7 +130,7 @@ This pass identifies unused signals and cells and removes them from the design.
creates an \B{unused\_bits} attribute on wires with unused bits. This attribute can be
used for debugging or by other optimization passes.
-\subsection{The opt\_share pass}
+\subsection{The opt\_merge pass}
This pass performs trivial resource sharing. This means that this pass identifies cells
with identical inputs and replaces them with a single instance of the cell.
@@ -222,6 +222,10 @@ This heuristic has proven to work very well. It is possible to overwrite it by s
and setting \B{fsm\_encoding}{\tt = "none"} on registers that match the above criteria
but should not be considered FSM state registers.
+Note however that marking state registers with \B{fsm\_encoding} that are not
+suitable for FSM recoding can cause synthesis to fail or produce invalid
+results.
+
\subsection{FSM Extraction}
The {\tt fsm\_extract} pass operates on all state signals marked with the
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex
index 032c0f8c..964875d5 100644
--- a/manual/CHAPTER_Overview.tex
+++ b/manual/CHAPTER_Overview.tex
@@ -488,8 +488,8 @@ select.cc}, {\tt show.cc}, \dots) and a couple of other small utility libraries.
\item {\tt passes/} \\
This directory contains a subdirectory for each pass or group of passes. For example as
of this writing the directory {\tt passes/opt/} contains the code for seven
-passes: {\tt opt}, {\tt opt\_const}, {\tt opt\_muxtree}, {\tt opt\_reduce},
-{\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_share}.
+passes: {\tt opt}, {\tt opt\_expr}, {\tt opt\_muxtree}, {\tt opt\_reduce},
+{\tt opt\_rmdff}, {\tt opt\_rmunused} and {\tt opt\_merge}.
\item {\tt techlibs/} \\
This directory contains simulation models and standard implementations for the
@@ -513,7 +513,7 @@ Yosys. So it is not needed to add additional commands to a central list of comma
\end{sloppypar}
Good starting points for reading example source code to learn how to write passes
-are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_share.cc}.
+are {\tt passes/opt/opt\_rmdff.cc} and {\tt passes/opt/opt\_merge.cc}.
See the top-level README file for a quick {\it Getting Started} guide and build
instructions. The Yosys build is based solely on Makefiles.
diff --git a/manual/CHAPTER_Prog/stubnets.cc b/manual/CHAPTER_Prog/stubnets.cc
index 976107fb..eb77bd40 100644
--- a/manual/CHAPTER_Prog/stubnets.cc
+++ b/manual/CHAPTER_Prog/stubnets.cc
@@ -103,7 +103,7 @@ struct StubnetsPass : public Pass {
// variables to mirror information from passed options
bool report_bits = 0;
- log_header("Executing STUBNETS pass (find stub nets).\n");
+ log_header(design, "Executing STUBNETS pass (find stub nets).\n");
// parse options
size_t argidx;
diff --git a/manual/PRESENTATION_ExSyn.tex b/manual/PRESENTATION_ExSyn.tex
index 1b56374d..655720eb 100644
--- a/manual/PRESENTATION_ExSyn.tex
+++ b/manual/PRESENTATION_ExSyn.tex
@@ -144,16 +144,16 @@ The {\tt opt} command implements a series of simple optimizations. It also
is a macro command that calls other commands:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
-opt_const # const folding
-opt_share -nomux # merging identical cells
+opt_expr # const folding and simple expression rewriting
+opt_merge -nomux # merging identical cells
do
opt_muxtree # remove never-active branches from multiplexer tree
opt_reduce # consolidate trees of boolean ops to reduce functions
- opt_share # merging identical cells
+ opt_merge # merging identical cells
opt_rmdff # remove/simplify registers with constant inputs
opt_clean # remove unused objects (cells, wires) from design
- opt_const # const folding
+ opt_expr # const folding and simple expression rewriting
while [changed design]
\end{lstlisting}
@@ -161,7 +161,7 @@ The command {\tt clean} can be used as alias for {\tt opt\_clean}. And {\tt ;;}
can be used as shortcut for {\tt clean}. For example:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
-proc; opt; memory; opt_const;; fsm;;
+proc; opt; memory; opt_expr;; fsm;;
\end{lstlisting}
\end{frame}
diff --git a/manual/PRESENTATION_Prog.tex b/manual/PRESENTATION_Prog.tex
index 6b105a70..b85eda89 100644
--- a/manual/PRESENTATION_Prog.tex
+++ b/manual/PRESENTATION_Prog.tex
@@ -477,7 +477,7 @@ log("Name of this module: %s\n", log_id(module->name));
\medskip
Use {\tt log\_header()} and {\tt log\_push()}/{\tt log\_pop()} to structure log messages:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
-log_header("Doing important stuff!\n");
+log_header(design, "Doing important stuff!\n");
log_push();
for (int i = 0; i < 10; i++)
log("Log message #%d.\n", i);
@@ -534,7 +534,7 @@ struct MyPass : public Pass {
log("Modules in current design:\n");
for (auto mod : design->modules())
log(" %s (%d wires, %d cells)\n", log_id(mod),
- GetSize(mod->wires), GetSize(mod->cells));
+ GetSize(mod->wires()), GetSize(mod->cells()));
}
} MyPass;
\end{lstlisting}
diff --git a/manual/PRESENTATION_Prog/my_cmd.cc b/manual/PRESENTATION_Prog/my_cmd.cc
index 1d28ce97..d99bfe1e 100644
--- a/manual/PRESENTATION_Prog/my_cmd.cc
+++ b/manual/PRESENTATION_Prog/my_cmd.cc
@@ -65,7 +65,7 @@ struct Test2Pass : public Pass {
log("Mapped signal x: %s\n", log_signal(sigmap(x)));
- log_header("Doing important stuff!\n");
+ log_header(design, "Doing important stuff!\n");
log_push();
for (int i = 0; i < 10; i++)
log("Log message #%d.\n", i);
diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex
index 99d4a1fa..425d89b6 100644
--- a/manual/command-reference-manual.tex
+++ b/manual/command-reference-manual.tex
@@ -3783,10 +3783,10 @@ The following node-types may be used:
- the inverted value of the specified input port bit
[ "and", <node-index>, <node-index>, <out-list> ]
- - the ANDed value of the speciefied nodes
+ - the ANDed value of the specified nodes
[ "nand", <node-index>, <node-index>, <out-list> ]
- - the inverted ANDed value of the speciefied nodes
+ - the inverted ANDed value of the specified nodes
[ "true", <out-list> ]
- the constant value 1
@@ -3817,7 +3817,7 @@ inferred by the following code:
]
Future version of Yosys might add support for additional fields in the JSON
-format. A program processing this format must ignore all unkown fields.
+format. A program processing this format must ignore all unknown fields.
\end{lstlisting}
\section{write\_smt2 -- write design to SMT-LIBv2 file}
diff --git a/manual/manual.tex b/manual/manual.tex
index ecc7e4c9..67982cbc 100644
--- a/manual/manual.tex
+++ b/manual/manual.tex
@@ -151,14 +151,14 @@ availability of a Free and Open Source (FOSS) synthesis tool that can be used
as basis for custom tools would be helpful.
In the absence of such a tool, the Yosys Open SYnthesis Suite (Yosys) was
-developped. This document covers the design and implementation of this tool.
+developed. This document covers the design and implementation of this tool.
At the moment the main focus of Yosys lies on the high-level aspects of
digital synthesis. The pre-existing FOSS logic-synthesis tool ABC is used
by Yosys to perform advanced gate-level optimizations.
An evaluation of Yosys based on real-world designs is included. It is shown
that Yosys can be used as-is to synthesize such designs. The results produced
-by Yosys in this tests where successflly verified using formal verification
+by Yosys in this tests where successfully verified using formal verification
and are comparable in quality to the results produced by a commercial
synthesis tool.
@@ -172,7 +172,7 @@ University of Technology \cite{BACC}.
AIG & And-Inverter-Graph \\
ASIC & Application-Specific Integrated Circuit \\
AST & Abstract Syntax Tree \\
-BDD & Binary Decicion Diagram \\
+BDD & Binary Decision Diagram \\
BLIF & Berkeley Logic Interchange Format \\
EDA & Electronic Design Automation \\
EDIF & Electronic Design Interchange Format \\
diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc
index 2ad84838..b3622cb1 100644
--- a/passes/cmds/check.cc
+++ b/passes/cmds/check.cc
@@ -68,7 +68,7 @@ struct CheckPass : public Pass {
}
extra_args(args, argidx, design);
- log_header("Executing CHECK pass (checking for obvious problems).\n");
+ log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
for (auto module : design->selected_whole_modules_warn())
{
diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc
index 7828dce1..c9ab226d 100644
--- a/passes/cmds/connwrappers.cc
+++ b/passes/cmds/connwrappers.cc
@@ -198,7 +198,7 @@ struct ConnwrappersPass : public Pass {
}
extra_args(args, argidx, design);
- log_header("Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
+ log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 5644066a..1475475c 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -124,7 +124,7 @@ struct CoverPass : public Pass {
extra_args(args, argidx, design);
if (do_log) {
- log_header("Printing code coverage counters.\n");
+ log_header(design, "Printing code coverage counters.\n");
log("\n");
}
diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc
index e2d80d9b..828c671d 100644
--- a/passes/cmds/plugin.cc
+++ b/passes/cmds/plugin.cc
@@ -31,19 +31,23 @@ std::map<std::string, std::string> loaded_plugin_aliases;
#ifdef YOSYS_ENABLE_PLUGINS
void load_plugin(std::string filename, std::vector<std::string> aliases)
{
+ std::string orig_filename = filename;
+
if (filename.find('/') == std::string::npos)
filename = "./" + filename;
if (!loaded_plugins.count(filename)) {
void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
+ if (hdl == NULL && orig_filename.find('/') == std::string::npos)
+ hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL);
if (hdl == NULL)
log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
- loaded_plugins[filename] = hdl;
+ loaded_plugins[orig_filename] = hdl;
Pass::init_register();
}
for (auto &alias : aliases)
- loaded_plugin_aliases[alias] = filename;
+ loaded_plugin_aliases[alias] = orig_filename;
}
#else
void load_plugin(std::string, std::vector<std::string>)
diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc
index 8ec815a7..1b800b6d 100644
--- a/passes/cmds/qwp.cc
+++ b/passes/cmds/qwp.cc
@@ -40,6 +40,7 @@ struct QwpConfig
{
bool ltr;
bool alpha;
+ bool verbose;
double grid;
std::ofstream dump_file;
@@ -47,6 +48,7 @@ struct QwpConfig
QwpConfig() {
ltr = false;
alpha = false;
+ verbose = false;
grid = 1.0 / 16;
}
};
@@ -211,10 +213,16 @@ struct QwpWorker
//
// M := [AA Ay]
+ if (config.verbose)
+ log("> System size: %d^2\n", GetSize(nodes));
+
// Row major order
int N = GetSize(nodes), N1 = N+1;
vector<double> M(N * N1);
+ if (config.verbose)
+ log("> Edge constraints: %d\n", GetSize(edges));
+
// Edge constraints:
// A[i,:] := [ 0 0 .... 0 weight 0 ... 0 -weight 0 ... 0 0], y[i] := 0
//
@@ -232,6 +240,9 @@ struct QwpWorker
M[idx2 + idx1*N1] += -weight * weight;
}
+ if (config.verbose)
+ log("> Node constraints: %d\n", GetSize(nodes));
+
// Node constraints:
// A[i,:] := [ 0 0 .... 0 weight 0 ... 0 0], y[i] := weight * pos
//
@@ -263,6 +274,9 @@ struct QwpWorker
}
#endif
+ if (config.verbose)
+ log("> Solving\n");
+
// Solve "AA*x = Ay"
// (least squares fit for "A*x = y")
//
@@ -277,6 +291,9 @@ struct QwpWorker
// gaussian elimination
for (int i = 0; i < N; i++)
{
+ if (config.verbose && ((i+1) % (N/15)) == 0)
+ log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N);
+
// find best row
int best_row = queue.front();
int best_row_queue_idx = 0;
@@ -312,6 +329,9 @@ struct QwpWorker
}
}
+ if (config.verbose)
+ log("> Solved\n");
+
log_assert(queue.empty());
log_assert(GetSize(pivot_cache) == N);
@@ -334,6 +354,9 @@ struct QwpWorker
}
#endif
+ if (config.verbose)
+ log("> Update nodes\n");
+
// update node positions
for (int i = 0; i < N; i++)
{
@@ -778,6 +801,9 @@ struct QwpPass : public Pass {
log(" -dump <html_file_name>\n");
log(" Dump a protocol of the placement algorithm to the html file.\n");
log("\n");
+ log(" -v\n");
+ log(" Verbose solver output for profiling or debugging\n");
+ log("\n");
log("Note: This implementation of a quadratic wirelength placer uses exact\n");
log("dense matrix operations. It is only a toy-placer for small circuits.\n");
log("\n");
@@ -787,7 +813,7 @@ struct QwpPass : public Pass {
QwpConfig config;
xorshift32_state = 123456789;
- log_header("Executing QWP pass (quadratic wirelength placer).\n");
+ log_header(design, "Executing QWP pass (quadratic wirelength placer).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -799,6 +825,10 @@ struct QwpPass : public Pass {
config.alpha = true;
continue;
}
+ if (args[argidx] == "-v") {
+ config.verbose = true;
+ continue;
+ }
if (args[argidx] == "-grid" && argidx+1 < args.size()) {
config.grid = 1.0 / atoi(args[++argidx].c_str());
continue;
diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc
index 532026f2..bb6d7447 100644
--- a/passes/cmds/scc.cc
+++ b/passes/cmds/scc.cc
@@ -181,10 +181,10 @@ struct SccWorker
cell2scc[cell] = sccList.size();
scc.insert(cell);
sccList.push_back(scc);
- workQueue.erase(cell);
log("\n");
- } else
- run(cell, 0, maxDepth);
+ }
+
+ run(cell, 0, maxDepth);
}
log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
@@ -264,7 +264,7 @@ struct SccPass : public Pass {
int maxDepth = -1;
int expect = -1;
- log_header("Executing SCC pass (detecting logic loops).\n");
+ log_header(design, "Executing SCC pass (detecting logic loops).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc
index 3e64dd84..d2e1a2e2 100644
--- a/passes/cmds/select.cc
+++ b/passes/cmds/select.cc
@@ -952,7 +952,7 @@ struct SelectPass : public Pass {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" select [ -add | -del | -set <name> ] {-read <filename> | <selection>}\n");
- log(" select [ -assert-none | -assert-any ] {-read <filename> | <selection>}\n");
+ log(" select [ <assert_option> ] {-read <filename> | <selection>}\n");
log(" select [ -list | -write <filename> | -count | -clear ]\n");
log(" select -module <modname>\n");
log("\n");
@@ -988,6 +988,14 @@ struct SelectPass : public Pass {
log(" do not modify the current selection. instead assert that the given\n");
log(" selection contains exactly N objects.\n");
log("\n");
+ log(" -assert-max N\n");
+ log(" do not modify the current selection. instead assert that the given\n");
+ log(" selection contains less than or exactly N objects.\n");
+ log("\n");
+ log(" -assert-min N\n");
+ log(" do not modify the current selection. instead assert that the given\n");
+ log(" selection contains at least N objects.\n");
+ log("\n");
log(" -list\n");
log(" list all objects in the current selection\n");
log("\n");
@@ -1168,6 +1176,8 @@ struct SelectPass : public Pass {
bool assert_none = false;
bool assert_any = false;
int assert_count = -1;
+ int assert_max = -1;
+ int assert_min = -1;
std::string write_file, read_file;
std::string set_name, sel_str;
@@ -1197,6 +1207,14 @@ struct SelectPass : public Pass {
assert_count = atoi(args[++argidx].c_str());
continue;
}
+ if (arg == "-assert-max" && argidx+1 < args.size()) {
+ assert_max = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (arg == "-assert-min" && argidx+1 < args.size()) {
+ assert_min = atoi(args[++argidx].c_str());
+ continue;
+ }
if (arg == "-clear") {
clear_mode = true;
continue;
@@ -1273,14 +1291,14 @@ struct SelectPass : public Pass {
if (none_mode && args.size() != 2)
log_cmd_error("Option -none can not be combined with any other options.\n");
- if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) > 1)
- log_cmd_error("Options -add, -del, -assert-none, -assert-any or -assert-count can not be combined.\n");
+ if (add_mode + del_mode + assert_none + assert_any + (assert_count >= 0) + (assert_max >= 0) + (assert_min >= 0) > 1)
+ log_cmd_error("Options -add, -del, -assert-none, -assert-any, assert-count, -assert-max or -assert-min can not be combined.\n");
- if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
- log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any or -assert-count.\n");
+ if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Options -list, -write and -count can not be combined with -add, -del, -assert-none, -assert-any, assert-count, -assert-max, or -assert-min.\n");
- if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0))
- log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any or -assert-count.\n");
+ if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode || assert_none || assert_any || assert_count >= 0 || assert_max >= 0 || assert_min >= 0))
+ log_cmd_error("Option -set can not be combined with -list, -write, -count, -add, -del, -assert-none, -assert-any, -assert-count, -assert-max, or -assert-min.\n");
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
@@ -1385,7 +1403,7 @@ struct SelectPass : public Pass {
return;
}
- if (assert_count >= 0)
+ if (assert_count >= 0 || assert_max >= 0 || assert_min >= 0)
{
int total_count = 0;
if (work_stack.size() == 0)
@@ -1407,9 +1425,15 @@ struct SelectPass : public Pass {
if (sel->selected_member(mod_it.first, it.first))
total_count++;
}
- if (assert_count != total_count)
+ if (assert_count >= 0 && assert_count != total_count)
log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n",
total_count, assert_count, sel_str.c_str());
+ if (assert_max >= 0 && assert_max < total_count)
+ log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n",
+ total_count, assert_max, sel_str.c_str());
+ if (assert_min >= 0 && assert_min > total_count)
+ log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n",
+ total_count, assert_min, sel_str.c_str());
return;
}
diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc
index 75c738b6..9b05ae32 100644
--- a/passes/cmds/setattr.cc
+++ b/passes/cmds/setattr.cc
@@ -215,6 +215,12 @@ struct ChparamPass : public Pass {
}
break;
}
+
+ for (int i = argidx; i < GetSize(args); i++)
+ if (design->module("$abstract\\" + args[i]) != nullptr &&
+ design->module(RTLIL::escape_id(args[i])) == nullptr)
+ args[i] = "$abstract\\" + args[i];
+
extra_args(args, argidx, design);
do_setunset(new_parameters, setunset_list);
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 9ca2e874..26b2eb87 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -79,11 +79,15 @@ struct SetundefPass : public Pass {
log(" replace with random bits using the specified integer als seed\n");
log(" value for the random number generator.\n");
log("\n");
+ log(" -init\n");
+ log(" also create/update init values for flip-flops\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
bool got_value = false;
bool undriven_mode = false;
+ bool init_mode = false;
SetundefWorker worker;
size_t argidx;
@@ -103,6 +107,10 @@ struct SetundefPass : public Pass {
worker.next_bit_mode = 1;
continue;
}
+ if (args[argidx] == "-init") {
+ init_mode = true;
+ continue;
+ }
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
worker.next_bit_mode = 2;
@@ -118,12 +126,8 @@ struct SetundefPass : public Pass {
if (!got_value)
log_cmd_error("One of the options -zero, -one, or -random <seed> must be specified.\n");
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- RTLIL::Module *module = mod_it.second;
- if (!design->selected(module))
- continue;
-
if (undriven_mode)
{
if (!module->processes.empty())
@@ -151,6 +155,86 @@ struct SetundefPass : public Pass {
}
}
+ if (init_mode)
+ {
+ SigMap sigmap(module);
+ pool<SigBit> ffbits;
+ pool<Wire*> initwires;
+
+ pool<IdString> fftypes;
+ fftypes.insert("$dff");
+ fftypes.insert("$dffe");
+ fftypes.insert("$dffsr");
+ fftypes.insert("$adff");
+
+ std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
+
+ for (auto c1 : list_np)
+ fftypes.insert(stringf("$_DFF_%c_", c1));
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ fftypes.insert(stringf("$_DFFE_%c%c_", c1, c2));
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_01)
+ fftypes.insert(stringf("$_DFF_%c%c%c_", c1, c2, c3));
+
+ for (auto c1 : list_np)
+ for (auto c2 : list_np)
+ for (auto c3 : list_np)
+ fftypes.insert(stringf("$_DFFSR_%c%c%c_", c1, c2, c3));
+
+ for (auto cell : module->cells())
+ {
+ if (!fftypes.count(cell->type))
+ continue;
+
+ for (auto bit : sigmap(cell->getPort("\\Q")))
+ ffbits.insert(bit);
+ }
+
+ for (auto wire : module->wires())
+ {
+ if (!wire->attributes.count("\\init"))
+ continue;
+
+ for (auto bit : sigmap(wire))
+ ffbits.erase(bit);
+
+ initwires.insert(wire);
+ }
+
+ for (int wire_types = 0; wire_types < 2; wire_types++)
+ for (auto wire : module->wires())
+ {
+ if (wire->name[0] == (wire_types ? '\\' : '$'))
+ next_wire:
+ continue;
+
+ for (auto bit : sigmap(wire))
+ if (!ffbits.count(bit))
+ goto next_wire;
+
+ for (auto bit : sigmap(wire))
+ ffbits.erase(bit);
+
+ initwires.insert(wire);
+ }
+
+ for (auto wire : initwires)
+ {
+ Const &initval = wire->attributes["\\init"];
+
+ for (int i = 0; i < GetSize(wire); i++)
+ if (GetSize(initval) <= i)
+ initval.bits.push_back(worker.next_bit());
+ else if (initval.bits[i] == State::Sx)
+ initval.bits[i] = worker.next_bit();
+ }
+ }
+
module->rewrite_sigspecs(worker);
}
}
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index 3b03d680..3a3939a8 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -582,8 +582,9 @@ struct ShowPass : public Pass {
log(" Run the specified command with the graphics file as parameter.\n");
log("\n");
log(" -format <format>\n");
- log(" Generate a graphics file in the specified format.\n");
- log(" Usually <format> is 'svg' or 'ps'.\n");
+ log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
+ log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n");
+ log(" to generate files in other formats (this calls the 'dot' command).\n");
log("\n");
log(" -lib <verilog_or_ilang_file>\n");
log(" Use the specified library file for determining whether cell ports are\n");
@@ -646,12 +647,13 @@ struct ShowPass : public Pass {
log("unless another prefix is specified using -prefix <prefix>.\n");
log("\n");
log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
- log("to 'show.dot' in the current directory and new viewer is launched.\n");
+ log("to 'show.dot' in the current directory and new viewer is launched each time\n");
+ log("the 'show' command is executed.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Generating Graphviz representation of design.\n");
+ log_header(design, "Generating Graphviz representation of design.\n");
log_push();
std::vector<std::pair<std::string, RTLIL::Selection>> color_selections;
@@ -759,7 +761,7 @@ struct ShowPass : public Pass {
}
extra_args(args, argidx, design);
- if (format != "ps") {
+ if (format != "ps" && format != "dot") {
int modcount = 0;
for (auto &mod_it : design->modules_) {
if (mod_it.second->get_bool_attribute("\\blackbox"))
@@ -770,7 +772,7 @@ struct ShowPass : public Pass {
modcount++;
}
if (modcount > 1)
- log_cmd_error("For formats different than 'ps' only one module must be selected.\n");
+ log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n");
}
for (auto filename : libfiles) {
@@ -784,7 +786,7 @@ struct ShowPass : public Pass {
}
if (libs.size() > 0)
- log_header("Continuing show pass.\n");
+ log_header(design, "Continuing show pass.\n");
std::string dot_file = stringf("%s.dot", prefix.c_str());
std::string out_file = stringf("%s.%s", prefix.c_str(), format.empty() ? "svg" : format.c_str());
@@ -806,7 +808,7 @@ struct ShowPass : public Pass {
log_cmd_error("Nothing there to show.\n");
if (format != "dot" && !format.empty()) {
- std::string cmd = stringf("dot -T%s -o '%s.new' '%s' && mv '%s.new' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str());
+ std::string cmd = stringf("dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'", format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str());
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc
index 2556fb74..7418ec4d 100644
--- a/passes/cmds/splice.cc
+++ b/passes/cmds/splice.cc
@@ -341,7 +341,7 @@ struct SplicePass : public Pass {
if (!ports.empty() && !no_ports.empty())
log_cmd_error("The options -port and -no_port are exclusive!\n");
- log_header("Executing SPLICE pass (creating cells for signal splicing).\n");
+ log_header(design, "Executing SPLICE pass (creating cells for signal splicing).\n");
for (auto &mod_it : design->modules_)
{
diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc
index 0d7892d7..14eeb066 100644
--- a/passes/cmds/splitnets.cc
+++ b/passes/cmds/splitnets.cc
@@ -109,7 +109,7 @@ struct SplitnetsPass : public Pass {
bool flag_driver = false;
std::string format = "[]:";
- log_header("Executing SPLITNETS pass (splitting up multi-bit signals).\n");
+ log_header(design, "Executing SPLITNETS pass (splitting up multi-bit signals).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 048933fc..362a0edf 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -232,7 +232,7 @@ struct StatPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Printing statistics.\n");
+ log_header(design, "Printing statistics.\n");
bool width_mode = false;
RTLIL::Module *top_mod = NULL;
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc
index a0484090..3db2dbf0 100644
--- a/passes/cmds/tee.cc
+++ b/passes/cmds/tee.cc
@@ -45,10 +45,14 @@ struct TeePass : public Pass {
log(" -a logfile\n");
log(" Write output to this file, append if exists.\n");
log("\n");
+ log(" +INT, -INT\n");
+ log(" Add/subract INT from the -v setting for this command.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::vector<FILE*> backup_log_files, files_to_close;
+ int backup_log_verbose_level = log_verbose_level;
backup_log_files = log_files;
size_t argidx;
@@ -70,6 +74,10 @@ struct TeePass : public Pass {
files_to_close.push_back(f);
continue;
}
+ if (GetSize(args[argidx]) >= 2 && (args[argidx][0] == '-' || args[argidx][0] == '+') && args[argidx][1] >= '0' && args[argidx][1] <= '9') {
+ log_verbose_level += atoi(args[argidx].c_str());
+ continue;
+ }
break;
}
@@ -85,6 +93,8 @@ struct TeePass : public Pass {
for (auto cf : files_to_close)
fclose(cf);
+
+ log_verbose_level = backup_log_verbose_level;
log_files = backup_log_files;
}
} TeePass;
diff --git a/passes/cmds/torder.cc b/passes/cmds/torder.cc
index 50317c02..56223610 100644
--- a/passes/cmds/torder.cc
+++ b/passes/cmds/torder.cc
@@ -48,7 +48,7 @@ struct TorderPass : public Pass {
bool noautostop = false;
dict<IdString, pool<IdString>> stop_db;
- log_header("Executing TORDER pass (print cells in topological order).\n");
+ log_header(design, "Executing TORDER pass (print cells in topological order).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc
index cdb951ec..c958c3de 100644
--- a/passes/equiv/equiv_induct.cc
+++ b/passes/equiv/equiv_induct.cc
@@ -198,7 +198,7 @@ struct EquivInductPass : public Pass {
bool model_undef = false;
int max_seq = 4;
- log_header("Executing EQUIV_INDUCT pass.\n");
+ log_header(design, "Executing EQUIV_INDUCT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc
index 8b063c54..40ca4262 100644
--- a/passes/equiv/equiv_make.cc
+++ b/passes/equiv/equiv_make.cc
@@ -464,7 +464,7 @@ struct EquivMakePass : public Pass {
worker.read_blacklists();
worker.read_encfiles();
- log_header("Executing EQUIV_MAKE pass (creating equiv checking module).\n");
+ log_header(design, "Executing EQUIV_MAKE pass (creating equiv checking module).\n");
worker.equiv_mod = design->addModule(RTLIL::escape_id(args[argidx+2]));
worker.run();
diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc
index 3e9819d1..22c50176 100644
--- a/passes/equiv/equiv_mark.cc
+++ b/passes/equiv/equiv_mark.cc
@@ -218,7 +218,7 @@ struct EquivMarkPass : public Pass {
}
virtual void execute(std::vector<std::string> args, Design *design)
{
- log_header("Executing EQUIV_MARK pass.\n");
+ log_header(design, "Executing EQUIV_MARK pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc
index 982176c4..eb2e5a17 100644
--- a/passes/equiv/equiv_miter.cc
+++ b/passes/equiv/equiv_miter.cc
@@ -333,7 +333,7 @@ struct EquivMiterPass : public Pass {
found_two_modules:
log_cmd_error("Exactly one module must be selected for 'equiv_miter'!\n");
- log_header("Executing EQUIV_MITER pass.\n");
+ log_header(design, "Executing EQUIV_MITER pass.\n");
worker.miter_module = design->addModule(worker.miter_name);
worker.run();
diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc
index f4141ad4..163b1009 100644
--- a/passes/equiv/equiv_purge.cc
+++ b/passes/equiv/equiv_purge.cc
@@ -189,7 +189,7 @@ struct EquivPurgePass : public Pass {
}
virtual void execute(std::vector<std::string> args, Design *design)
{
- log_header("Executing EQUIV_PURGE pass.\n");
+ log_header(design, "Executing EQUIV_PURGE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc
index b5c383b6..770497a5 100644
--- a/passes/equiv/equiv_remove.cc
+++ b/passes/equiv/equiv_remove.cc
@@ -46,7 +46,7 @@ struct EquivRemovePass : public Pass {
bool mode_gate = false;
int remove_count = 0;
- log_header("Executing EQUIV_REMOVE pass.\n");
+ log_header(design, "Executing EQUIV_REMOVE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc
index fa22dc62..49963ed6 100644
--- a/passes/equiv/equiv_simple.cc
+++ b/passes/equiv/equiv_simple.cc
@@ -277,7 +277,7 @@ struct EquivSimplePass : public Pass {
int success_counter = 0;
int max_seq = 1;
- log_header("Executing EQUIV_SIMPLE pass.\n");
+ log_header(design, "Executing EQUIV_SIMPLE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc
index 8a2f5e05..7b9230b3 100644
--- a/passes/equiv/equiv_status.cc
+++ b/passes/equiv/equiv_status.cc
@@ -41,7 +41,7 @@ struct EquivStatusPass : public Pass {
bool assert_mode = false;
int unproven_count = 0;
- log_header("Executing EQUIV_STATUS pass.\n");
+ log_header(design, "Executing EQUIV_STATUS pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc
index 2c85d2d3..c4ced6a7 100644
--- a/passes/equiv/equiv_struct.cc
+++ b/passes/equiv/equiv_struct.cc
@@ -321,7 +321,7 @@ struct EquivStructPass : public Pass {
bool mode_fwd = false;
int max_iter = -1;
- log_header("Executing EQUIV_STRUCT pass.\n");
+ log_header(design, "Executing EQUIV_STRUCT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc
index 3f5564fc..3b537ecd 100644
--- a/passes/fsm/fsm.cc
+++ b/passes/fsm/fsm.cc
@@ -76,7 +76,7 @@ struct FsmPass : public Pass {
std::string encfile_opt;
std::string encoding_opt;
- log_header("Executing FSM pass (extract and optimize FSM).\n");
+ log_header(design, "Executing FSM pass (extract and optimize FSM).\n");
log_push();
size_t argidx;
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 740113e3..6a560f16 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -36,18 +36,21 @@ static SigPool sig_at_port;
static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor)
{
- if (sig_at_port.check_any(assign_map(sig)))
- return false;
-
- if (sig.is_fully_const() || old_sig == sig)
+ if (sig.is_fully_const() || old_sig == sig) {
return true;
+ }
+
+ if (sig_at_port.check_any(assign_map(sig))) {
+ return false;
+ }
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(sig, cellport_list);
for (auto &cellport : cellport_list)
{
- if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y")
+ if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") {
return false;
+ }
if (recursion_monitor.count(cellport.first)) {
log_warning("logic loop in mux tree at signal %s in module %s.\n",
@@ -110,28 +113,134 @@ static bool check_state_users(RTLIL::SigSpec sig)
static void detect_fsm(RTLIL::Wire *wire)
{
- if (wire->attributes.count("\\init") > 0)
- return;
- if (wire->attributes.count("\\fsm_encoding") > 0 || wire->width <= 1)
+ bool has_fsm_encoding_attr = wire->attributes.count("\\fsm_encoding") > 0 && wire->attributes.at("\\fsm_encoding").decode_string() != "none";
+ bool has_fsm_encoding_none = wire->attributes.count("\\fsm_encoding") > 0 && wire->attributes.at("\\fsm_encoding").decode_string() == "none";
+ bool has_init_attr = wire->attributes.count("\\init") > 0;
+ bool is_module_port = sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire)));
+ bool looks_like_state_reg = false, looks_like_good_state_reg = false;
+ bool is_self_resetting = false;
+
+ if (has_fsm_encoding_none)
return;
- if (sig_at_port.check_any(assign_map(RTLIL::SigSpec(wire))))
+
+ if (wire->width <= 1) {
+ if (has_fsm_encoding_attr) {
+ log_warning("Removing fsm_encoding attribute from 1-bit net: %s.%s\n", log_id(wire->module), log_id(wire));
+ wire->attributes.erase("\\fsm_encoding");
+ }
return;
+ }
std::set<sig2driver_entry_t> cellport_list;
sig2driver.find(RTLIL::SigSpec(wire), cellport_list);
- for (auto &cellport : cellport_list) {
+
+ for (auto &cellport : cellport_list)
+ {
if ((cellport.first->type != "$dff" && cellport.first->type != "$adff") || cellport.second != "\\Q")
continue;
+
muxtree_cells.clear();
pool<Cell*> recursion_monitor;
RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q"));
RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D"));
- if (sig_q == RTLIL::SigSpec(wire) && check_state_mux_tree(sig_q, sig_d, recursion_monitor) && check_state_users(sig_q)) {
- log("Found FSM state register %s in module %s.\n", wire->name.c_str(), module->name.c_str());
- wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
- return;
+
+ if (sig_q != assign_map(wire))
+ continue;
+
+ looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor);
+ looks_like_good_state_reg = check_state_users(sig_q);
+
+ if (!looks_like_state_reg)
+ break;
+
+ ConstEval ce(wire->module);
+
+ std::set<sig2driver_entry_t> cellport_list;
+ sig2user.find(sig_q, cellport_list);
+
+ for (auto &cellport : cellport_list)
+ {
+ RTLIL::Cell *cell = cellport.first;
+ bool set_output = false, clr_output = false;
+
+ if (cell->type == "$ne")
+ set_output = true;
+
+ if (cell->type == "$eq")
+ clr_output = true;
+
+ if (!set_output && !clr_output) {
+ clr_output = true;
+ for (auto &port_it : cell->connections())
+ if (port_it.first != "\\A" || port_it.first != "\\Y")
+ clr_output = false;
+ }
+
+ if (set_output || clr_output) {
+ for (auto &port_it : cell->connections())
+ if (cell->output(port_it.first)) {
+ SigSpec sig = assign_map(port_it.second);
+ Const val(set_output ? State::S1 : State::S0, GetSize(sig));
+ ce.set(sig, val);
+ }
+ }
+ }
+
+ SigSpec sig_y = sig_d, sig_undef;
+ if (ce.eval(sig_y, sig_undef))
+ is_self_resetting = true;
+ }
+
+ if (has_fsm_encoding_attr)
+ {
+ vector<string> warnings;
+
+ if (is_module_port)
+ warnings.push_back("Forcing fsm recoding on module port might result in larger circuit.\n");
+
+ if (!looks_like_good_state_reg)
+ warnings.push_back("Users of state reg look like fsm recoding might result in larger circuit.\n");
+
+ if (has_init_attr)
+ warnings.push_back("Init value on fsm state registers are ignored. Possible simulation-synthesis mismatch!");
+
+ if (!looks_like_state_reg)
+ warnings.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n");
+
+ if (is_self_resetting)
+ warnings.push_back("FSM seems to be self-resetting. Possible simulation-synthesis mismatch!\n");
+
+ if (!warnings.empty()) {
+ string warnmsg = stringf("Regarding the user-specified fsm_encoding attribute on %s.%s:\n", log_id(wire->module), log_id(wire));
+ for (auto w : warnings) warnmsg += " " + w;
+ log_warning("%s", warnmsg.c_str());
+ } else {
+ log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire->module), log_id(wire));
}
}
+ else
+ if (looks_like_state_reg && looks_like_good_state_reg && !has_init_attr && !is_module_port && !is_self_resetting)
+ {
+ log("Found FSM state register %s.%s.\n", log_id(wire->module), log_id(wire));
+ wire->attributes["\\fsm_encoding"] = RTLIL::Const("auto");
+ }
+ else
+ if (looks_like_state_reg)
+ {
+ log("Not marking %s.%s as FSM state register:\n", log_id(wire->module), log_id(wire));
+
+ if (is_module_port)
+ log(" Register is connected to module port.\n");
+
+ if (!looks_like_good_state_reg)
+ log(" Users of register don't seem to benefit from recoding.\n");
+
+ if (has_init_attr)
+ log(" Register has an initialization value.");
+
+ if (is_self_resetting)
+ log(" Circuit seems to be self-resetting.\n");
+ }
}
struct FsmDetectPass : public Pass {
@@ -154,7 +263,7 @@ struct FsmDetectPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_DETECT pass (finding FSMs in design).\n");
+ log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n");
extra_args(args, 1, design);
CellTypes ct;
diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc
index 43c9a792..3ded3f37 100644
--- a/passes/fsm/fsm_expand.cc
+++ b/passes/fsm/fsm_expand.cc
@@ -258,7 +258,7 @@ struct FsmExpandPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
+ log_header(design, "Executing FSM_EXPAND pass (merging auxiliary logic into FSMs).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_) {
diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc
index 0eff2884..1cbfcfae 100644
--- a/passes/fsm/fsm_export.cc
+++ b/passes/fsm/fsm_export.cc
@@ -152,7 +152,7 @@ struct FsmExportPass : public Pass {
bool flag_origenc = false;
size_t argidx;
- log_header("Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n");
+ log_header(design, "Executing FSM_EXPORT pass (exporting FSMs in KISS2 file format).\n");
for (argidx = 1; argidx < args.size(); argidx++) {
arg = args[argidx];
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc
index d61ac568..8a4ee3f2 100644
--- a/passes/fsm/fsm_extract.cc
+++ b/passes/fsm/fsm_extract.cc
@@ -92,12 +92,15 @@ static bool find_states(RTLIL::SigSpec sig, const RTLIL::SigSpec &dff_out, RTLIL
if (reset_state && RTLIL::SigSpec(*reset_state).is_fully_undef())
do {
+ SigSpec new_reset_state;
if (sig_aa.is_fully_def())
- *reset_state = sig_aa.as_const();
+ new_reset_state = sig_aa.as_const();
else if (sig_bb.is_fully_def())
- *reset_state = sig_bb.as_const();
+ new_reset_state = sig_bb.as_const();
else
break;
+ new_reset_state.extend_u0(GetSize(*reset_state));
+ *reset_state = new_reset_state.as_const();
log(" found reset state: %s (guessed from mux tree)\n", log_signal(*reset_state));
} while (0);
@@ -416,7 +419,7 @@ struct FsmExtractPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_EXTRACT pass (extracting FSM from design).\n");
+ log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n");
extra_args(args, 1, design);
CellTypes ct;
diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc
index 20db82c1..2cc1a7d5 100644
--- a/passes/fsm/fsm_info.cc
+++ b/passes/fsm/fsm_info.cc
@@ -43,7 +43,7 @@ struct FsmInfoPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
+ log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc
index 574b9a20..5b32ed59 100644
--- a/passes/fsm/fsm_map.cc
+++ b/passes/fsm/fsm_map.cc
@@ -335,7 +335,7 @@ struct FsmMapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
+ log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_) {
diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc
index a7cc95ff..5b1da44f 100644
--- a/passes/fsm/fsm_opt.cc
+++ b/passes/fsm/fsm_opt.cc
@@ -336,7 +336,7 @@ struct FsmOptPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FSM_OPT pass (simple optimizations of FSMs).\n");
+ log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_) {
diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc
index a4b45295..5102d833 100644
--- a/passes/fsm/fsm_recode.cc
+++ b/passes/fsm/fsm_recode.cc
@@ -157,7 +157,7 @@ struct FsmRecodePass : public Pass {
FILE *encfile = NULL;
std::string default_encoding;
- log_header("Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
+ log_header(design, "Executing FSM_RECODE pass (re-assigning FSM state encoding).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index fcc30d17..4d1e3987 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -261,7 +261,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
return did_something;
}
-void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTLIL::Module *mod, int indent)
+void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> &used, RTLIL::Module *mod, int indent)
{
if (used.count(mod) > 0)
return;
@@ -287,7 +287,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &used, RTL
void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
{
- std::set<RTLIL::Module*> used;
+ std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used;
hierarchy_worker(design, used, top, 0);
std::vector<RTLIL::Module*> del_modules;
@@ -297,8 +297,6 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
int del_counter = 0;
for (auto mod : del_modules) {
- if (mod->name.substr(0, 9) == "$abstract")
- continue;
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
@@ -324,10 +322,12 @@ bool set_keep_assert(std::map<RTLIL::Module*, bool> &cache, RTLIL::Module *mod)
int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
{
if (db.count(module) == 0) {
+ int score = 0;
db[module] = 0;
for (auto cell : module->cells())
if (design->module(cell->type))
- db[module] = max(db[module], find_top_mod_score(design, design->module(cell->type), db) + 1);
+ score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
+ db[module] = score;
}
return db.at(module);
}
@@ -398,7 +398,7 @@ struct HierarchyPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HIERARCHY pass (managing design hierarchy).\n");
+ log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
bool flag_check = false;
bool purge_lib = false;
@@ -508,7 +508,7 @@ struct HierarchyPass : public Pass {
top_mod = mod_it.second;
if (top_mod == nullptr && auto_top_mode) {
- log_header("Finding top of design hierarchy..\n");
+ log_header(design, "Finding top of design hierarchy..\n");
dict<Module*, int> db;
for (Module *mod : design->selected_modules()) {
int score = find_top_mod_score(design, mod, db);
@@ -525,9 +525,9 @@ struct HierarchyPass : public Pass {
{
did_something = false;
- std::set<RTLIL::Module*> used_modules;
+ std::set<RTLIL::Module*, IdString::compare_ptr_by_name<Module>> used_modules;
if (top_mod != NULL) {
- log_header("Analyzing design hierarchy..\n");
+ log_header(design, "Analyzing design hierarchy..\n");
hierarchy_worker(design, used_modules, top_mod, 0);
} else {
for (auto mod : design->modules())
@@ -541,7 +541,7 @@ struct HierarchyPass : public Pass {
}
if (top_mod != NULL) {
- log_header("Analyzing design hierarchy..\n");
+ log_header(design, "Analyzing design hierarchy..\n");
hierarchy_clean(design, top_mod, purge_lib);
}
diff --git a/passes/hierarchy/singleton.cc b/passes/hierarchy/singleton.cc
index 5715c0eb..03c365fb 100644
--- a/passes/hierarchy/singleton.cc
+++ b/passes/hierarchy/singleton.cc
@@ -43,7 +43,7 @@ struct SingletonPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SINGLETON pass (creating singleton modules).\n");
+ log_header(design, "Executing SINGLETON pass (creating singleton modules).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc
index d4e8c96c..9f312f82 100644
--- a/passes/hierarchy/submod.cc
+++ b/passes/hierarchy/submod.cc
@@ -298,7 +298,7 @@ struct SubmodPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
+ log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
log_push();
std::string opt_name;
@@ -321,7 +321,7 @@ struct SubmodPass : public Pass {
if (opt_name.empty())
{
Pass::call(design, "opt_clean");
- log_header("Continuing SUBMOD pass.\n");
+ log_header(design, "Continuing SUBMOD pass.\n");
std::set<RTLIL::IdString> handled_modules;
@@ -356,7 +356,7 @@ struct SubmodPass : public Pass {
log("Nothing selected -> do nothing.\n");
else {
Pass::call_on_module(design, module, "opt_clean");
- log_header("Continuing SUBMOD pass.\n");
+ log_header(design, "Continuing SUBMOD pass.\n");
SubmodWorker worker(design, module, copy_mode, opt_name);
}
}
diff --git a/passes/memory/Makefile.inc b/passes/memory/Makefile.inc
index aeff225d..ad359c01 100644
--- a/passes/memory/Makefile.inc
+++ b/passes/memory/Makefile.inc
@@ -6,4 +6,5 @@ OBJS += passes/memory/memory_collect.o
OBJS += passes/memory/memory_unpack.o
OBJS += passes/memory/memory_bram.o
OBJS += passes/memory/memory_map.o
+OBJS += passes/memory/memory_memx.o
diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc
index 4e74d1a4..947d598b 100644
--- a/passes/memory/memory.cc
+++ b/passes/memory/memory.cc
@@ -31,14 +31,15 @@ struct MemoryPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" memory [-nomap] [-nordff] [-bram <bram_rules>] [selection]\n");
+ log(" memory [-nomap] [-nordff] [-memx] [-bram <bram_rules>] [selection]\n");
log("\n");
log("This pass calls all the other memory_* passes in a useful order:\n");
log("\n");
- log(" memory_dff [-nordff]\n");
+ log(" memory_dff [-nordff] (-memx implies -nordff)\n");
log(" opt_clean\n");
log(" memory_share\n");
log(" opt_clean\n");
+ log(" memory_memx (when called with -memx)\n");
log(" memory_collect\n");
log(" memory_bram -rules <bram_rules> (when called with -bram)\n");
log(" memory_map (skipped if called with -nomap)\n");
@@ -51,9 +52,10 @@ struct MemoryPass : public Pass {
{
bool flag_nomap = false;
bool flag_nordff = false;
+ bool flag_memx = false;
string memory_bram_opts;
- log_header("Executing MEMORY pass.\n");
+ log_header(design, "Executing MEMORY pass.\n");
log_push();
size_t argidx;
@@ -66,6 +68,11 @@ struct MemoryPass : public Pass {
flag_nordff = true;
continue;
}
+ if (args[argidx] == "-memx") {
+ flag_nordff = true;
+ flag_memx = true;
+ continue;
+ }
if (argidx+1 < args.size() && args[argidx] == "-bram") {
memory_bram_opts += " -rules " + args[++argidx];
continue;
@@ -77,6 +84,8 @@ struct MemoryPass : public Pass {
Pass::call(design, flag_nordff ? "memory_dff -nordff" : "memory_dff");
Pass::call(design, "opt_clean");
Pass::call(design, "memory_share");
+ if (flag_memx)
+ Pass::call(design, "memory_memx");
Pass::call(design, "opt_clean");
Pass::call(design, "memory_collect");
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index f2d9b584..a7f9cf38 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -656,6 +656,9 @@ grow_read_ports:;
bool transp = rd_transp[cell_port_i] == State::S1;
SigBit clksig = rd_clk[cell_port_i];
+ if (wr_ports == 0)
+ transp = false;
+
pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false);
@@ -826,7 +829,7 @@ grow_read_ports:;
State padding = State::Sx;
for (int j = 0; j < bram.dbits; j++)
if (init_offset+i < GetSize(initdata) && init_shift+j < GetSize(initdata[init_offset+i]))
- padding = initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j];
+ initparam[i*bram.dbits+j] = initdata[init_offset+i][init_shift+j];
else
initparam[i*bram.dbits+j] = padding;
}
@@ -1211,7 +1214,7 @@ struct MemoryBramPass : public Pass {
{
rules_t rules;
- log_header("Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
+ log_header(design, "Executing MEMORY_BRAM pass (mapping $mem cells to block memories).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc
index 5c0acb3e..ab66e3fb 100644
--- a/passes/memory/memory_collect.cc
+++ b/passes/memory/memory_collect.cc
@@ -37,8 +37,6 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
log("Collecting $memrd, $memwr and $meminit for memory `%s' in module `%s':\n",
memory->name.c_str(), module->name.c_str());
- int addr_bits = 0;
-
Const init_data(State::Sx, memory->size * memory->width);
SigMap sigmap(module);
@@ -59,16 +57,28 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory)
SigSpec sig_rd_data;
SigSpec sig_rd_en;
+ int addr_bits = 0;
std::vector<Cell*> memcells;
for (auto &cell_it : module->cells_) {
Cell *cell = cell_it.second;
if (cell->type.in("$memrd", "$memwr", "$meminit") && memory->name == cell->parameters["\\MEMID"].decode_string()) {
- addr_bits = max(addr_bits, cell->getParam("\\ABITS").as_int());
+ SigSpec addr = sigmap(cell->getPort("\\ADDR"));
+ for (int i = 0; i < GetSize(addr); i++)
+ if (addr[i] != State::S0)
+ addr_bits = std::max(addr_bits, i+1);
memcells.push_back(cell);
}
}
+ if (memory->start_offset == 0 && addr_bits < 30 && (1 << addr_bits) < memory->size)
+ memory->size = 1 << addr_bits;
+
+ if (memory->start_offset >= 0)
+ addr_bits = std::min(addr_bits, ceil_log2(memory->size + memory->start_offset));
+
+ addr_bits = std::max(addr_bits, 1);
+
if (memcells.empty()) {
log(" no cells found. removing memory.\n");
return nullptr;
@@ -247,7 +257,7 @@ struct MemoryCollectPass : public Pass {
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_COLLECT pass (generating $mem cells).\n");
+ log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index beb2016a..40691d16 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -283,7 +283,7 @@ struct MemoryDffPass : public Pass {
{
bool flag_wr_only = false;
- log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
+ log_header(design, "Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc
index 0b8ccb36..bffeec85 100644
--- a/passes/memory/memory_map.cc
+++ b/passes/memory/memory_map.cc
@@ -363,7 +363,7 @@ struct MemoryMapPass : public Pass {
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
+ log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n");
extra_args(args, 1, design);
for (auto mod : design->selected_modules())
MemoryMapWorker(design, mod);
diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc
new file mode 100644
index 00000000..2b02e249
--- /dev/null
+++ b/passes/memory/memory_memx.cc
@@ -0,0 +1,92 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/log.h"
+#include <sstream>
+#include <set>
+#include <stdlib.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct MemoryMemxPass : public Pass {
+ MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" memory_memx [selection]\n");
+ log("\n");
+ log("This pass adds additional circuitry that emulates the Verilog simulation\n");
+ log("behavior for out-of-bounds memory reads and writes.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
+ log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n");
+ extra_args(args, 1, design);
+
+ for (auto module : design->selected_modules())
+ {
+ vector<Cell*> mem_port_cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type.in("$memrd", "$memwr"))
+ mem_port_cells.push_back(cell);
+
+ for (auto cell : mem_port_cells)
+ {
+ IdString memid = cell->getParam("\\MEMID").decode_string();
+ RTLIL::Memory *mem = module->memories.at(memid);
+
+ int lowest_addr = mem->start_offset;
+ int highest_addr = mem->start_offset + mem->size - 1;
+
+ SigSpec addr = cell->getPort("\\ADDR");
+ addr.extend_u0(32);
+
+ SigSpec addr_ok = module->Nex(NEW_ID, module->ReduceXor(NEW_ID, addr), module->ReduceXor(NEW_ID, {addr, State::S1}));
+ if (lowest_addr != 0)
+ addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Ge(NEW_ID, addr, lowest_addr));
+ addr_ok = module->LogicAnd(NEW_ID, addr_ok, module->Le(NEW_ID, addr, highest_addr));
+
+ if (cell->type == "$memrd")
+ {
+ if (cell->getParam("\\CLK_ENABLE").as_bool())
+ log_error("Cell %s.%s (%s) has an enabled clock. Clocked $memrd cells are not supported by memory_memx!\n",
+ log_id(module), log_id(cell), log_id(cell->type));
+
+ SigSpec rdata = cell->getPort("\\DATA");
+ Wire *raw_rdata = module->addWire(NEW_ID, GetSize(rdata));
+ module->addMux(NEW_ID, SigSpec(State::Sx, GetSize(rdata)), raw_rdata, addr_ok, rdata);
+ cell->setPort("\\DATA", raw_rdata);
+ }
+
+ if (cell->type == "$memwr")
+ {
+ SigSpec en = cell->getPort("\\EN");
+ en = module->And(NEW_ID, en, addr_ok.repeat(GetSize(en)));
+ cell->setPort("\\EN", en);
+ }
+ }
+ }
+ }
+} MemoryMemxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc
index 3a6fd0b4..ca09ac52 100644
--- a/passes/memory/memory_share.cc
+++ b/passes/memory/memory_share.cc
@@ -43,7 +43,7 @@ struct MemoryShareWorker
CellTypes cone_ct;
std::map<RTLIL::SigBit, std::pair<RTLIL::Cell*, int>> sig_to_mux;
- std::map<std::set<std::map<RTLIL::SigBit, bool>>, RTLIL::SigBit> conditions_logic_cache;
+ std::map<pair<std::set<std::map<SigBit, bool>>, SigBit>, SigBit> conditions_logic_cache;
// -----------------------------------------------------------------
@@ -109,10 +109,12 @@ struct MemoryShareWorker
return false;
}
- RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, int &created_conditions)
+ RTLIL::SigBit conditions_to_logic(std::set<std::map<RTLIL::SigBit, bool>> &conditions, SigBit olden, int &created_conditions)
{
- if (conditions_logic_cache.count(conditions))
- return conditions_logic_cache.at(conditions);
+ auto key = make_pair(conditions, olden);
+
+ if (conditions_logic_cache.count(key))
+ return conditions_logic_cache.at(key);
RTLIL::SigSpec terms;
for (auto &cond : conditions) {
@@ -125,13 +127,16 @@ struct MemoryShareWorker
created_conditions++;
}
- if (terms.size() == 0)
+ if (olden.wire != nullptr || olden != State::S1)
+ terms.append(olden);
+
+ if (GetSize(terms) == 0)
terms = State::S1;
- if (terms.size() > 1)
+ if (GetSize(terms) > 1)
terms = module->ReduceAnd(NEW_ID, terms);
- return conditions_logic_cache[conditions] = terms;
+ return conditions_logic_cache[key] = terms;
}
void translate_rd_feedback_to_en(std::string memid, std::vector<RTLIL::Cell*> &rd_ports, std::vector<RTLIL::Cell*> &wr_ports)
@@ -140,15 +145,14 @@ struct MemoryShareWorker
std::map<RTLIL::SigBit, std::set<RTLIL::SigBit>> muxtree_upstream_map;
std::set<RTLIL::SigBit> non_feedback_nets;
- for (auto wire_it : module->wires_)
- if (wire_it.second->port_output) {
- std::vector<RTLIL::SigBit> bits = RTLIL::SigSpec(wire_it.second);
+ for (auto wire : module->wires())
+ if (wire->port_output) {
+ std::vector<RTLIL::SigBit> bits = sigmap(wire);
non_feedback_nets.insert(bits.begin(), bits.end());
}
- for (auto cell_it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = cell_it.second;
bool ignore_data_port = false;
if (cell->type == "$mux" || cell->type == "$pmux")
@@ -173,7 +177,7 @@ struct MemoryShareWorker
cell->parameters.at("\\MEMID").decode_string() == memid)
ignore_data_port = true;
- for (auto conn : cell_it.second->connections())
+ for (auto conn : cell->connections())
{
if (ignore_data_port && conn.first == "\\DATA")
continue;
@@ -240,13 +244,8 @@ struct MemoryShareWorker
std::map<RTLIL::SigBit, bool> state;
std::set<std::map<RTLIL::SigBit, bool>> conditions;
- if (cell_en[i].wire != NULL) {
- state[cell_en[i]] = false;
- conditions.insert(state);
- }
-
find_data_feedback(async_rd_bits.at(sig_addr).at(i), cell_data[i], state, conditions);
- cell_en[i] = conditions_to_logic(conditions, created_conditions);
+ cell_en[i] = conditions_to_logic(conditions, cell_en[i], created_conditions);
}
if (created_conditions) {
@@ -620,6 +619,12 @@ struct MemoryShareWorker
RTLIL::SigBit this_en_active = module->ReduceOr(NEW_ID, this_en);
+ if (GetSize(last_addr) < GetSize(this_addr))
+ last_addr.extend_u0(GetSize(this_addr));
+ else
+ this_addr.extend_u0(GetSize(last_addr));
+
+ wr_ports[i]->setParam("\\ABITS", GetSize(this_addr));
wr_ports[i]->setPort("\\ADDR", module->Mux(NEW_ID, last_addr, this_addr, this_en_active));
wr_ports[i]->setPort("\\DATA", module->Mux(NEW_ID, last_data, this_data, this_en_active));
@@ -666,10 +671,8 @@ struct MemoryShareWorker
std::map<std::string, std::pair<std::vector<RTLIL::Cell*>, std::vector<RTLIL::Cell*>>> memindex;
sigmap_xmux = sigmap;
- for (auto &it : module->cells_)
+ for (auto cell : module->cells())
{
- RTLIL::Cell *cell = it.second;
-
if (cell->type == "$memrd")
memindex[cell->parameters.at("\\MEMID").decode_string()].first.push_back(cell);
@@ -746,11 +749,11 @@ struct MemorySharePass : public Pass {
log("\n");
log("Note that in addition to the algorithms implemented in this pass, the $memrd\n");
log("and $memwr cells are also subject to generic resource sharing passes (and other\n");
- log("optimizations) such as opt_share.\n");
+ log("optimizations) such as \"share\" and \"opt_merge\".\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_SHARE pass (consolidating $memrc/$memwr cells).\n");
+ log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n");
extra_args(args, 1, design);
for (auto module : design->selected_modules())
MemoryShareWorker(design, module);
diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc
index 60724da7..a0fc31b5 100644
--- a/passes/memory/memory_unpack.cc
+++ b/passes/memory/memory_unpack.cc
@@ -138,7 +138,7 @@ struct MemoryUnpackPass : public Pass {
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
- log_header("Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
+ log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n");
extra_args(args, 1, design);
for (auto &mod_it : design->modules_)
if (design->selected(mod_it.second))
diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc
index 43defb78..a8b1537b 100644
--- a/passes/opt/Makefile.inc
+++ b/passes/opt/Makefile.inc
@@ -1,11 +1,11 @@
OBJS += passes/opt/opt.o
-OBJS += passes/opt/opt_share.o
+OBJS += passes/opt/opt_merge.o
OBJS += passes/opt/opt_muxtree.o
OBJS += passes/opt/opt_reduce.o
OBJS += passes/opt/opt_rmdff.o
OBJS += passes/opt/opt_clean.o
-OBJS += passes/opt/opt_const.o
+OBJS += passes/opt/opt_expr.o
ifneq ($(SMALL),1)
OBJS += passes/opt/share.o
diff --git a/passes/opt/opt.cc b/passes/opt/opt.cc
index f5389d8e..13ea5469 100644
--- a/passes/opt/opt.cc
+++ b/passes/opt/opt.cc
@@ -37,23 +37,23 @@ struct OptPass : public Pass {
log("a series of trivial optimizations and cleanups. This pass executes the other\n");
log("passes in the following order:\n");
log("\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
- log(" opt_share [-share_all] -nomux\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_merge [-share_all] -nomux\n");
log("\n");
log(" do\n");
log(" opt_muxtree\n");
log(" opt_reduce [-fine] [-full]\n");
- log(" opt_share [-share_all]\n");
+ log(" opt_merge [-share_all]\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
log(" while <changed design>\n");
log("\n");
log("When called with -fast the following script is used instead:\n");
log("\n");
log(" do\n");
- log(" opt_const [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
- log(" opt_share [-share_all]\n");
+ log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n");
+ log(" opt_merge [-share_all]\n");
log(" opt_rmdff\n");
log(" opt_clean [-purge]\n");
log(" while <changed design in opt_rmdff>\n");
@@ -66,12 +66,12 @@ struct OptPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string opt_clean_args;
- std::string opt_const_args;
+ std::string opt_expr_args;
std::string opt_reduce_args;
- std::string opt_share_args;
+ std::string opt_merge_args;
bool fast_mode = false;
- log_header("Executing OPT pass (performing simple optimizations).\n");
+ log_header(design, "Executing OPT pass (performing simple optimizations).\n");
log_push();
size_t argidx;
@@ -81,37 +81,37 @@ struct OptPass : public Pass {
continue;
}
if (args[argidx] == "-mux_undef") {
- opt_const_args += " -mux_undef";
+ opt_expr_args += " -mux_undef";
continue;
}
if (args[argidx] == "-mux_bool") {
- opt_const_args += " -mux_bool";
+ opt_expr_args += " -mux_bool";
continue;
}
if (args[argidx] == "-undriven") {
- opt_const_args += " -undriven";
+ opt_expr_args += " -undriven";
continue;
}
if (args[argidx] == "-clkinv") {
- opt_const_args += " -clkinv";
+ opt_expr_args += " -clkinv";
continue;
}
if (args[argidx] == "-fine") {
- opt_const_args += " -fine";
+ opt_expr_args += " -fine";
opt_reduce_args += " -fine";
continue;
}
if (args[argidx] == "-full") {
- opt_const_args += " -full";
+ opt_expr_args += " -full";
opt_reduce_args += " -full";
continue;
}
if (args[argidx] == "-keepdc") {
- opt_const_args += " -keepdc";
+ opt_expr_args += " -keepdc";
continue;
}
if (args[argidx] == "-share_all") {
- opt_share_args += " -share_all";
+ opt_merge_args += " -share_all";
continue;
}
if (args[argidx] == "-fast") {
@@ -125,32 +125,32 @@ struct OptPass : public Pass {
if (fast_mode)
{
while (1) {
- Pass::call(design, "opt_const" + opt_const_args);
- Pass::call(design, "opt_share" + opt_share_args);
+ Pass::call(design, "opt_expr" + opt_expr_args);
+ Pass::call(design, "opt_merge" + opt_merge_args);
design->scratchpad_unset("opt.did_something");
Pass::call(design, "opt_rmdff");
if (design->scratchpad_get_bool("opt.did_something") == false)
break;
Pass::call(design, "opt_clean" + opt_clean_args);
- log_header("Rerunning OPT passes. (Removed registers in this run.)\n");
+ log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n");
}
Pass::call(design, "opt_clean" + opt_clean_args);
}
else
{
- Pass::call(design, "opt_const" + opt_const_args);
- Pass::call(design, "opt_share -nomux" + opt_share_args);
+ Pass::call(design, "opt_expr" + opt_expr_args);
+ Pass::call(design, "opt_merge -nomux" + opt_merge_args);
while (1) {
design->scratchpad_unset("opt.did_something");
Pass::call(design, "opt_muxtree");
Pass::call(design, "opt_reduce" + opt_reduce_args);
- Pass::call(design, "opt_share" + opt_share_args);
+ Pass::call(design, "opt_merge" + opt_merge_args);
Pass::call(design, "opt_rmdff");
Pass::call(design, "opt_clean" + opt_clean_args);
- Pass::call(design, "opt_const" + opt_const_args);
+ Pass::call(design, "opt_expr" + opt_expr_args);
if (design->scratchpad_get_bool("opt.did_something") == false)
break;
- log_header("Rerunning OPT passes. (Maybe there is more to do..)\n");
+ log_header(design, "Rerunning OPT passes. (Maybe there is more to do..)\n");
}
}
@@ -158,7 +158,7 @@ struct OptPass : public Pass {
design->sort();
design->check();
- log_header(fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n");
+ log_header(design, fast_mode ? "Finished fast OPT passes.\n" : "Finished OPT passes. (There is nothing left to do.)\n");
log_pop();
}
} OptPass;
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 175e8e11..6600ffa2 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -156,6 +156,9 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if (w1->port_input != w2->port_input)
return w2->port_input;
+ if ((w1->port_input && w1->port_output) != (w2->port_input && w2->port_output))
+ return !(w2->port_input && w2->port_output);
+
if (w1->name[0] == '\\' && w2->name[0] == '\\') {
if (regs.check_any(s1) != regs.check_any(s2))
return regs.check_any(s2);
@@ -380,7 +383,7 @@ struct OptCleanPass : public Pass {
{
bool purge_mode = false;
- log_header("Executing OPT_CLEAN pass (remove unused cells and wires).\n");
+ log_header(design, "Executing OPT_CLEAN pass (remove unused cells and wires).\n");
log_push();
size_t argidx;
diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_expr.cc
index 0fcacf0a..b62eae28 100644
--- a/passes/opt/opt_const.cc
+++ b/passes/opt/opt_expr.cc
@@ -179,7 +179,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
log("\n");
}
- cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
+ cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
module->remove(cell);
did_something = true;
@@ -304,7 +304,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : cells.sorted)
{
-#define ACTION_DO(_p_, _s_) do { cover("opt.opt_const.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
+#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_))
if (clkinv)
@@ -342,6 +342,68 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map);
}
+ bool detect_const_and = false;
+ bool detect_const_or = false;
+
+ if (cell->type.in("$reduce_and", "$_AND_"))
+ detect_const_and = true;
+
+ if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ detect_const_and = true;
+
+ if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_"))
+ detect_const_or = true;
+
+ if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1)
+ detect_const_or = true;
+
+ if (detect_const_and || detect_const_or)
+ {
+ pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
+ bool found_zero = false, found_one = false, found_inv = false;
+
+ if (cell->hasPort("\\B")) {
+ vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
+ input_bits.insert(more_bits.begin(), more_bits.end());
+ }
+
+ for (auto bit : input_bits) {
+ if (bit == State::S0)
+ found_zero = true;
+ if (bit == State::S1)
+ found_one = true;
+ if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
+ found_inv = true;
+ }
+
+ if (detect_const_and && (found_zero || found_inv)) {
+ cover("opt.opt_expr.const_and");
+ replace_cell(assign_map, module, cell, "const_and", "\\Y", RTLIL::State::S0);
+ goto next_cell;
+ }
+
+ if (detect_const_or && (found_one || found_inv)) {
+ cover("opt.opt_expr.const_or");
+ replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
+ goto next_cell;
+ }
+ }
+
+ if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
+ GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\Y")) == 1)
+ {
+ if (cell->type == "$reduce_xnor") {
+ cover("opt.opt_expr.reduce_xnor_not");
+ log("Replacing %s cell `%s' in module `%s' with $not cell.\n",
+ log_id(cell->type), log_id(cell->name), log_id(module));
+ cell->type = "$not";
+ } else {
+ cover("opt.opt_expr.unary_buffer");
+ replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
+ }
+ goto next_cell;
+ }
+
if (do_fine)
{
if (cell->type == "$not" || cell->type == "$pos" ||
@@ -366,7 +428,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
- cover("opt.opt_const.fine.$reduce_and");
+ cover("opt.opt_expr.fine.$reduce_and");
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a);
@@ -392,7 +454,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
- cover_list("opt.opt_const.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
+ cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a);
@@ -418,7 +480,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
- cover_list("opt.opt_const.fine.B", "$logic_and", "$logic_or", cell->type.str());
+ cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
cell->setPort("\\B", sig_b = new_b);
@@ -428,18 +490,6 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
- if (cell->type == "$logic_or" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S1 || assign_map(cell->getPort("\\B")) == RTLIL::State::S1)) {
- cover("opt.opt_const.one_high");
- replace_cell(assign_map, module, cell, "one high", "\\Y", RTLIL::State::S1);
- goto next_cell;
- }
-
- if (cell->type == "$logic_and" && (assign_map(cell->getPort("\\A")) == RTLIL::State::S0 || assign_map(cell->getPort("\\B")) == RTLIL::State::S0)) {
- cover("opt.opt_const.one_low");
- replace_cell(assign_map, module, cell, "one low", "\\Y", RTLIL::State::S0);
- goto next_cell;
- }
-
if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" ||
cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" ||
@@ -462,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (0) {
found_the_x_bit:
- cover_list("opt.opt_const.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
+ cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str());
if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" ||
cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt")
@@ -475,13 +525,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 &&
invert_map.count(assign_map(cell->getPort("\\A"))) != 0) {
- cover_list("opt.opt_const.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
+ cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A"))));
goto next_cell;
}
if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
- cover_list("opt.opt_const.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
+ cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
RTLIL::SigSpec tmp = cell->getPort("\\A");
cell->setPort("\\A", cell->getPort("\\B"));
@@ -564,7 +614,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1));
if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1));
if (input.match("10 ")) {
- cover("opt.opt_const.mux_to_inv");
+ cover("opt.opt_expr.mux_to_inv");
cell->type = "$_NOT_";
cell->setPort("\\A", input.extract(0, 1));
cell->unsetPort("\\B");
@@ -599,7 +649,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
log_assert(GetSize(a) == GetSize(b));
for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
- cover_list("opt.opt_const.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1);
new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y);
@@ -612,7 +662,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a.size() == 0) {
- cover_list("opt.opt_const.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0);
new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false);
replace_cell(assign_map, module, cell, "empty", "\\Y", new_y);
@@ -620,7 +670,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (new_a.size() < a.size() || new_b.size() < b.size()) {
- cover_list("opt.opt_const.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b);
cell->parameters["\\A_WIDTH"] = new_a.size();
@@ -635,7 +685,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec b = assign_map(cell->getPort("\\B"));
if (a.is_fully_const() && !b.is_fully_const()) {
- cover_list("opt.opt_const.eqneq.swapconst", "$eq", "$ne", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
cell->setPort("\\A", b);
cell->setPort("\\B", a);
std::swap(a, b);
@@ -646,7 +696,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec input = b;
ACTION_DO("\\Y", cell->getPort("\\A"));
} else {
- cover_list("opt.opt_const.eqneq.isnot", "$eq", "$ne", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not";
cell->parameters.erase("\\B_WIDTH");
@@ -661,7 +711,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$eq" || cell->type == "$ne") &&
(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
{
- cover_list("opt.opt_const.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
+ cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
@@ -699,7 +749,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
sig_y[i] = sig_a[GetSize(sig_a)-1];
}
- cover_list("opt.opt_const.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
+ cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
@@ -760,9 +810,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (identity_wrt_a || identity_wrt_b)
{
if (identity_wrt_a)
- cover_list("opt.opt_const.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+ cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
if (identity_wrt_b)
- cover_list("opt.opt_const.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
+ cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
@@ -786,14 +836,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
- cover_list("opt.opt_const.mux_bool", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S"));
goto next_cell;
}
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
- cover_list("opt.opt_const.mux_invert", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\B");
@@ -812,7 +862,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
- cover_list("opt.opt_const.mux_and", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S");
@@ -832,7 +882,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
- cover_list("opt.opt_const.mux_or", "$mux", "$_MUX_", cell->type.str());
+ cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S");
@@ -856,7 +906,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
int width = cell->getPort("\\A").size();
if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) ||
cell->getPort("\\S").is_fully_undef()) {
- cover_list("opt.opt_const.mux_undef", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A"));
goto next_cell;
}
@@ -875,17 +925,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
new_s = new_s.extract(0, new_s.size()-1);
}
if (new_s.size() == 0) {
- cover_list("opt.opt_const.mux_empty", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a);
goto next_cell;
}
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
- cover_list("opt.opt_const.mux_sel01", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s);
goto next_cell;
}
if (cell->getPort("\\S").size() != new_s.size()) {
- cover_list("opt.opt_const.mux_reduce", "$mux", "$pmux", cell->type.str());
+ cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a);
@@ -911,7 +961,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
cell->parameters["\\A_SIGNED"].as_bool(), false, \
cell->parameters["\\Y_WIDTH"].as_int())); \
- cover("opt.opt_const.const.$" #_t); \
+ cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \
goto next_cell; \
} \
@@ -926,7 +976,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cell->parameters["\\A_SIGNED"].as_bool(), \
cell->parameters["\\B_SIGNED"].as_bool(), \
cell->parameters["\\Y_WIDTH"].as_int())); \
- cover("opt.opt_const.const.$" #_t); \
+ cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \
goto next_cell; \
} \
@@ -1002,7 +1052,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_val == 0)
{
- cover("opt.opt_const.mul_shift.zero");
+ cover("opt.opt_expr.mul_shift.zero");
log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str());
@@ -1018,9 +1068,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_val == (1 << i))
{
if (swapped_ab)
- cover("opt.opt_const.mul_shift.swapped");
+ cover("opt.opt_expr.mul_shift.swapped");
else
- cover("opt.opt_const.mul_shift.unswapped");
+ cover("opt.opt_expr.mul_shift.unswapped");
log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
a_val, cell->name.c_str(), module->name.c_str(), i);
@@ -1048,6 +1098,75 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ if (!keepdc && cell->type.in("$div", "$mod"))
+ {
+ bool b_signed = cell->parameters["\\B_SIGNED"].as_bool();
+ SigSpec sig_b = assign_map(cell->getPort("\\B"));
+ SigSpec sig_y = assign_map(cell->getPort("\\Y"));
+
+ if (sig_b.is_fully_def() && sig_b.size() <= 32)
+ {
+ int b_val = sig_b.as_int();
+
+ if (b_val == 0)
+ {
+ cover("opt.opt_expr.divmod_zero");
+
+ log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
+ cell->name.c_str(), module->name.c_str());
+
+ module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
+ module->remove(cell);
+
+ did_something = true;
+ goto next_cell;
+ }
+
+ for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
+ if (b_val == (1 << i))
+ {
+ if (cell->type == "$div")
+ {
+ cover("opt.opt_expr.div_shift");
+
+ log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
+ b_val, cell->name.c_str(), module->name.c_str(), i);
+
+ std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
+
+ while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
+ new_b.pop_back();
+
+ cell->type = "$shr";
+ cell->parameters["\\B_WIDTH"] = GetSize(new_b);
+ cell->parameters["\\B_SIGNED"] = false;
+ cell->setPort("\\B", new_b);
+ cell->check();
+ }
+ else
+ {
+ cover("opt.opt_expr.mod_mask");
+
+ log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
+ b_val, cell->name.c_str(), module->name.c_str());
+
+ std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
+
+ if (b_signed)
+ new_b.push_back(State::S0);
+
+ cell->type = "$and";
+ cell->parameters["\\B_WIDTH"] = GetSize(new_b);
+ cell->setPort("\\B", new_b);
+ cell->check();
+ }
+
+ did_something = true;
+ goto next_cell;
+ }
+ }
+ }
+
next_cell:;
#undef ACTION_DO
#undef ACTION_DO_Y
@@ -1056,15 +1175,16 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
-struct OptConstPass : public Pass {
- OptConstPass() : Pass("opt_const", "perform const folding") { }
+struct OptExprPass : public Pass {
+ OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_const [options] [selection]\n");
+ log(" opt_expr [options] [selection]\n");
log("\n");
log("This pass performs const folding on internal cell types with constant inputs.\n");
+ log("It also performs some simple expression rewritring.\n");
log("\n");
log(" -mux_undef\n");
log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
@@ -1100,7 +1220,7 @@ struct OptConstPass : public Pass {
bool do_fine = false;
bool keepdc = false;
- log_header("Executing OPT_CONST pass (perform const folding).\n");
+ log_header(design, "Executing OPT_EXPR pass (perform const folding).\n");
log_push();
size_t argidx;
@@ -1158,6 +1278,6 @@ struct OptConstPass : public Pass {
log_pop();
}
-} OptConstPass;
+} OptExprPass;
PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_merge.cc
index 46752e43..97989d27 100644
--- a/passes/opt/opt_share.cc
+++ b/passes/opt/opt_merge.cc
@@ -31,7 +31,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct OptShareWorker
+struct OptMergeWorker
{
RTLIL::Design *design;
RTLIL::Module *module;
@@ -45,6 +45,29 @@ struct OptShareWorker
dict<const RTLIL::Cell*, std::string> cell_hash_cache;
#endif
+ static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn)
+ {
+ SigSpec sig_s = conn.at("\\S");
+ SigSpec sig_b = conn.at("\\B");
+
+ int s_width = GetSize(sig_s);
+ int width = GetSize(sig_b) / s_width;
+
+ vector<pair<SigBit, SigSpec>> sb_pairs;
+ for (int i = 0; i < s_width; i++)
+ sb_pairs.push_back(pair<SigBit, SigSpec>(sig_s[i], sig_b.extract(i*width, width)));
+
+ std::sort(sb_pairs.begin(), sb_pairs.end());
+
+ conn["\\S"] = SigSpec();
+ conn["\\B"] = SigSpec();
+
+ for (auto &it : sb_pairs) {
+ conn["\\S"].append(it.first);
+ conn["\\B"].append(it.second);
+ }
+ }
+
#ifdef USE_CELL_HASH_CACHE
std::string int_to_hash_string(unsigned int v)
{
@@ -91,25 +114,40 @@ struct OptShareWorker
assign_map.apply(alt_conn.at("\\A"));
alt_conn.at("\\A").sort_and_unify();
conn = &alt_conn;
+ } else
+ if (cell->type == "$pmux") {
+ alt_conn = *conn;
+ assign_map.apply(alt_conn.at("\\A"));
+ assign_map.apply(alt_conn.at("\\B"));
+ assign_map.apply(alt_conn.at("\\S"));
+ sort_pmux_conn(alt_conn);
+ conn = &alt_conn;
}
+ vector<string> hash_conn_strings;
+
for (auto &it : *conn) {
if (cell->output(it.first))
continue;
RTLIL::SigSpec sig = it.second;
assign_map.apply(sig);
- hash_string += "C " + it.first.str() + "=";
+ string s = "C " + it.first.str() + "=";
for (auto &chunk : sig.chunks()) {
if (chunk.wire)
- hash_string += "{" + chunk.wire->name.str() + " " +
+ s += "{" + chunk.wire->name.str() + " " +
int_to_hash_string(chunk.offset) + " " +
int_to_hash_string(chunk.width) + "}";
else
- hash_string += RTLIL::Const(chunk.data).as_string();
+ s += RTLIL::Const(chunk.data).as_string();
}
- hash_string += "\n";
+ hash_conn_strings.push_back(s + "\n");
}
+ std::sort(hash_conn_strings.begin(), hash_conn_strings.end());
+
+ for (auto it : hash_conn_strings)
+ hash_string += it;
+
cell_hash_cache[cell] = sha1(hash_string);
return cell_hash_cache[cell];
}
@@ -171,6 +209,10 @@ struct OptShareWorker
if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") {
conn1["\\A"].sort_and_unify();
conn2["\\A"].sort_and_unify();
+ } else
+ if (cell1->type == "$pmux") {
+ sort_pmux_conn(conn1);
+ sort_pmux_conn(conn2);
}
if (conn1 != conn2) {
@@ -212,14 +254,14 @@ struct OptShareWorker
}
struct CompareCells {
- OptShareWorker *that;
- CompareCells(OptShareWorker *that) : that(that) {}
+ OptMergeWorker *that;
+ CompareCells(OptMergeWorker *that) : that(that) {}
bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const {
return that->compare_cells(cell1, cell2);
}
};
- OptShareWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) :
+ OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all) :
design(design), module(module), assign_map(module), mode_share_all(mode_share_all)
{
total_count = 0;
@@ -286,13 +328,13 @@ struct OptShareWorker
}
};
-struct OptSharePass : public Pass {
- OptSharePass() : Pass("opt_share", "consolidate identical cells") { }
+struct OptMergePass : public Pass {
+ OptMergePass() : Pass("opt_merge", "consolidate identical cells") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" opt_share [options] [selection]\n");
+ log(" opt_merge [options] [selection]\n");
log("\n");
log("This pass identifies cells with identical type and input signals. Such cells\n");
log("are then merged to one cell.\n");
@@ -306,7 +348,7 @@ struct OptSharePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing OPT_SHARE pass (detect identical cells).\n");
+ log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n");
bool mode_nomux = false;
bool mode_share_all = false;
@@ -328,7 +370,7 @@ struct OptSharePass : public Pass {
int total_count = 0;
for (auto module : design->selected_modules()) {
- OptShareWorker worker(design, module, mode_nomux, mode_share_all);
+ OptMergeWorker worker(design, module, mode_nomux, mode_share_all);
total_count += worker.total_count;
}
@@ -336,6 +378,6 @@ struct OptSharePass : public Pass {
design->scratchpad_set_bool("opt.did_something", true);
log("Removed a total of %d cells.\n", total_count);
}
-} OptSharePass;
+} OptMergePass;
PRIVATE_NAMESPACE_END
diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc
index 905a0162..f5ddc2af 100644
--- a/passes/opt/opt_muxtree.cc
+++ b/passes/opt/opt_muxtree.cc
@@ -68,7 +68,7 @@ struct OptMuxtreeWorker
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module) :
design(design), module(module), assign_map(module), removed_count(0)
{
- log("Running muxtree optimizier on module %s..\n", module->name.c_str());
+ log("Running muxtree optimizer on module %s..\n", module->name.c_str());
log(" Creating internal representation of mux trees.\n");
@@ -464,7 +464,7 @@ struct OptMuxtreePass : public Pass {
}
virtual void execute(vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
+ log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
extra_args(args, 1, design);
int total_count = 0;
diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc
index 98b7b2e1..eb9d02ad 100644
--- a/passes/opt/opt_reduce.cc
+++ b/passes/opt/opt_reduce.cc
@@ -354,7 +354,7 @@ struct OptReducePass : public Pass {
{
bool do_fine = false;
- log_header("Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
+ log_header(design, "Executing OPT_REDUCE pass (consolidate $*mux and $reduce_* inputs).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc
index e1b184af..fa954afa 100644
--- a/passes/opt/opt_rmdff.cc
+++ b/passes/opt/opt_rmdff.cc
@@ -60,7 +60,7 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)
return false;
delete_dlatch:
- log("Removing %s (%s) from module %s.\n", dlatch->name.c_str(), dlatch->type.c_str(), mod->name.c_str());
+ log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod));
remove_init_attr(dlatch->getPort("\\Q"));
mod->remove(dlatch);
return true;
@@ -170,7 +170,7 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff)
return false;
delete_dff:
- log("Removing %s (%s) from module %s.\n", dff->name.c_str(), dff->type.c_str(), mod->name.c_str());
+ log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod));
remove_init_attr(dff->getPort("\\Q"));
mod->remove(dff);
return true;
@@ -190,73 +190,116 @@ struct OptRmdffPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- int total_count = 0;
- log_header("Executing OPT_RMDFF pass (remove dff with constant values).\n");
+ int total_count = 0, total_initdrv = 0;
+ log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n");
extra_args(args, 1, design);
- for (auto &mod_it : design->modules_)
+ for (auto module : design->selected_modules())
{
- if (!design->selected(mod_it.second))
- continue;
-
- assign_map.set(mod_it.second);
- dff_init_map.set(mod_it.second);
- for (auto &it : mod_it.second->wires_)
- if (it.second->attributes.count("\\init") != 0) {
- dff_init_map.add(it.second, it.second->attributes.at("\\init"));
- for (int i = 0; i < GetSize(it.second); i++) {
- SigBit wire_bit(it.second, i), mapped_bit = assign_map(wire_bit);
- if (mapped_bit.wire)
+ pool<SigBit> driven_bits;
+ dict<SigBit, State> init_bits;
+
+ assign_map.set(module);
+ dff_init_map.set(module);
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init") != 0) {
+ Const initval = wire->attributes.at("\\init");
+ dff_init_map.add(wire, initval);
+ for (int i = 0; i < GetSize(wire); i++) {
+ SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
+ if (mapped_bit.wire) {
init_attributes[mapped_bit].insert(wire_bit);
+ if (i < GetSize(initval))
+ init_bits[mapped_bit] = initval[i];
+ }
}
}
+
+ if (wire->port_input) {
+ for (auto bit : assign_map(wire))
+ driven_bits.insert(bit);
+ }
+ }
mux_drivers.clear();
std::vector<RTLIL::IdString> dff_list;
std::vector<RTLIL::IdString> dlatch_list;
- for (auto &it : mod_it.second->cells_) {
- if (it.second->type == "$mux" || it.second->type == "$pmux") {
- if (it.second->getPort("\\A").size() == it.second->getPort("\\B").size())
- mux_drivers.insert(assign_map(it.second->getPort("\\Y")), it.second);
+ for (auto cell : module->cells())
+ {
+ for (auto &conn : cell->connections())
+ if (cell->output(conn.first) || !cell->known())
+ for (auto bit : assign_map(conn.second))
+ driven_bits.insert(bit);
+
+ if (cell->type == "$mux" || cell->type == "$pmux") {
+ if (cell->getPort("\\A").size() == cell->getPort("\\B").size())
+ mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell);
continue;
}
- if (!design->selected(mod_it.second, it.second))
+
+ if (!design->selected(module, cell))
continue;
- if (it.second->type == "$_DFF_N_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_P_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NN0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NN1_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NP0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_NP1_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PN0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PN1_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PP0_") dff_list.push_back(it.first);
- if (it.second->type == "$_DFF_PP1_") dff_list.push_back(it.first);
- if (it.second->type == "$dff") dff_list.push_back(it.first);
- if (it.second->type == "$adff") dff_list.push_back(it.first);
- if (it.second->type == "$dlatch") dlatch_list.push_back(it.first);
+
+ if (cell->type.in("$_DFF_N_", "$_DFF_P_",
+ "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
+ "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_",
+ "$dff", "$adff"))
+ dff_list.push_back(cell->name);
+
+ if (cell->type == "$dlatch")
+ dlatch_list.push_back(cell->name);
}
for (auto &id : dff_list) {
- if (mod_it.second->cells_.count(id) > 0 &&
- handle_dff(mod_it.second, mod_it.second->cells_[id]))
+ if (module->cell(id) != nullptr &&
+ handle_dff(module, module->cells_[id]))
total_count++;
}
for (auto &id : dlatch_list) {
- if (mod_it.second->cells_.count(id) > 0 &&
- handle_dlatch(mod_it.second, mod_it.second->cells_[id]))
+ if (module->cell(id) != nullptr &&
+ handle_dlatch(module, module->cells_[id]))
total_count++;
}
+
+ SigSpec const_init_sigs;
+
+ for (auto bit : init_bits)
+ if (!driven_bits.count(bit.first))
+ const_init_sigs.append(bit.first);
+
+ const_init_sigs.sort_and_unify();
+
+ for (SigSpec sig : const_init_sigs.chunks())
+ {
+ Const val;
+
+ for (auto bit : sig)
+ val.bits.push_back(init_bits.at(bit));
+
+ log("Promoting init spec %s = %s to constant driver in module %s.\n",
+ log_signal(sig), log_signal(val), log_id(module));
+
+ module->connect(sig, val);
+ remove_init_attr(sig);
+ total_initdrv++;
+ }
}
assign_map.clear();
mux_drivers.clear();
- if (total_count)
+ if (total_count || total_initdrv)
design->scratchpad_set_bool("opt.did_something", true);
- log("Replaced %d DFF cells.\n", total_count);
+
+ if (total_initdrv)
+ log("Promoted %d init specs to constant drivers.\n", total_initdrv);
+
+ if (total_count)
+ log("Replaced %d DFF cells.\n", total_count);
}
} OptRmdffPass;
diff --git a/passes/opt/share.cc b/passes/opt/share.cc
index 1d9b1006..22914eaa 100644
--- a/passes/opt/share.cc
+++ b/passes/opt/share.cc
@@ -793,10 +793,59 @@ struct ShareWorker
return true;
}
- void optimize_activation_patterns(pool<ssc_pair_t> & /* patterns */)
+ void optimize_activation_patterns(pool<ssc_pair_t> &patterns)
{
// TODO: Remove patterns that are contained in other patterns
- // TODO: Consolidate pairs of patterns that only differ in the value for one signal bit
+
+ dict<SigSpec, pool<Const>> db;
+ bool did_something = false;
+
+ for (auto const &p : patterns)
+ {
+ auto &sig = p.first;
+ auto &val = p.second;
+ int len = GetSize(sig);
+
+ for (int i = 0; i < len; i++)
+ {
+ auto otherval = val;
+
+ if (otherval.bits[i] == State::S0)
+ otherval.bits[i] = State::S1;
+ else if (otherval.bits[i] == State::S1)
+ otherval.bits[i] = State::S0;
+ else
+ continue;
+
+ if (db[sig].count(otherval))
+ {
+ auto newsig = sig;
+ newsig.remove(i);
+
+ auto newval = val;
+ newval.bits.erase(newval.bits.begin() + i);
+
+ db[newsig].insert(newval);
+ db[sig].erase(otherval);
+
+ did_something = true;
+ goto next_pattern;
+ }
+ }
+
+ db[sig].insert(val);
+ next_pattern:;
+ }
+
+ if (!did_something)
+ return;
+
+ patterns.clear();
+ for (auto &it : db)
+ for (auto &val : it.second)
+ patterns.insert(make_pair(it.first, val));
+
+ optimize_activation_patterns(patterns);
}
const pool<ssc_pair_t> &find_cell_activation_patterns(RTLIL::Cell *cell, const char *indent)
@@ -1451,7 +1500,7 @@ struct SharePass : public Pass {
config.generic_other_ops.insert("$alu");
config.generic_other_ops.insert("$macc");
- log_header("Executing SHARE pass (SAT-based resource sharing).\n");
+ log_header(design, "Executing SHARE pass (SAT-based resource sharing).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 4f08da67..07503fbb 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -366,15 +366,26 @@ struct WreducePass : public Pass {
log(" assign y = a + b + c + 1;\n");
log(" endmodule\n");
log("\n");
+ log("Options:\n");
+ log("\n");
+ log(" -memx\n");
+ log(" Do not change the width of memory address ports. Use this options in\n");
+ log(" flows that use the 'memory_memx' pass.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, Design *design)
{
WreduceConfig config;
+ bool opt_memx = false;
- log_header("Executing WREDUCE pass (reducing word size of cells).\n");
+ log_header(design, "Executing WREDUCE pass (reducing word size of cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-memx") {
+ opt_memx = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -385,6 +396,7 @@ struct WreducePass : public Pass {
continue;
for (auto c : module->selected_cells())
+ {
if (c->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$logic_not", "$logic_and", "$logic_or") && GetSize(c->getPort("\\Y")) > 1) {
@@ -396,6 +408,23 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig)));
}
}
+ if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
+ IdString memid = c->getParam("\\MEMID").decode_string();
+ RTLIL::Memory *mem = module->memories.at(memid);
+ if (mem->start_offset >= 0) {
+ int cur_addrbits = c->getParam("\\ABITS").as_int();
+ int max_addrbits = ceil_log2(mem->start_offset + mem->size);
+ if (cur_addrbits > max_addrbits) {
+ log("Removed top %d address bits (of %d) from memory %s port %s.%s (%s).\n",
+ cur_addrbits-max_addrbits, cur_addrbits,
+ c->type == "$memrd" ? "read" : c->type == "$memwr" ? "write" : "init",
+ log_id(module), log_id(c), log_id(memid));
+ c->setParam("\\ABITS", max_addrbits);
+ c->setPort("\\ADDR", c->getPort("\\ADDR").extract(0, max_addrbits));
+ }
+ }
+ }
+ }
WreduceWorker worker(&config, module);
worker.run();
diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc
index 577ff6bf..d5366f26 100644
--- a/passes/proc/proc.cc
+++ b/passes/proc/proc.cc
@@ -52,12 +52,17 @@ struct ProcPass : public Pass {
log(" -global_arst [!]<netname>\n");
log(" This option is passed through to proc_arst.\n");
log("\n");
+ log(" -ifx\n");
+ log(" This option is passed through to proc_mux. proc_rmdead is not\n");
+ log(" executed in -ifx mode.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string global_arst;
+ bool ifxmode = false;
- log_header("Executing PROC pass (convert processes to netlists).\n");
+ log_header(design, "Executing PROC pass (convert processes to netlists).\n");
log_push();
size_t argidx;
@@ -67,18 +72,23 @@ struct ProcPass : public Pass {
global_arst = args[++argidx];
continue;
}
+ if (args[argidx] == "-ifx") {
+ ifxmode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
Pass::call(design, "proc_clean");
- Pass::call(design, "proc_rmdead");
+ if (!ifxmode)
+ Pass::call(design, "proc_rmdead");
Pass::call(design, "proc_init");
if (global_arst.empty())
Pass::call(design, "proc_arst");
else
Pass::call(design, "proc_arst -global_arst " + global_arst);
- Pass::call(design, "proc_mux");
+ Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
Pass::call(design, "proc_dlatch");
Pass::call(design, "proc_dff");
Pass::call(design, "proc_clean");
diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc
index 1da23728..216b00dd 100644
--- a/passes/proc/proc_arst.cc
+++ b/passes/proc/proc_arst.cc
@@ -226,7 +226,7 @@ struct ProcArstPass : public Pass {
std::string global_arst;
bool global_arst_neg = false;
- log_header("Executing PROC_ARST pass (detect async resets in processes).\n");
+ log_header(design, "Executing PROC_ARST pass (detect async resets in processes).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc
index 35801951..7dbabc21 100644
--- a/passes/proc/proc_clean.cc
+++ b/passes/proc/proc_clean.cc
@@ -156,7 +156,7 @@ struct ProcCleanPass : public Pass {
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
int total_count = 0;
- log_header("Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
+ log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
extra_args(args, 1, design);
diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc
index 63713139..f532990c 100644
--- a/passes/proc/proc_dff.cc
+++ b/passes/proc/proc_dff.cc
@@ -369,7 +369,7 @@ struct ProcDffPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_DFF pass (convert process syncs to FFs).\n");
+ log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n");
extra_args(args, 1, design);
diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc
index e37d81dd..6621afd3 100644
--- a/passes/proc/proc_dlatch.cc
+++ b/passes/proc/proc_dlatch.cc
@@ -33,6 +33,8 @@ struct proc_dlatch_db_t
Module *module;
SigMap sigmap;
+ pool<Cell*> generated_dlatches;
+ dict<Cell*, vector<SigBit>> mux_srcbits;
dict<SigBit, pair<Cell*, int>> mux_drivers;
dict<SigBit, int> sigusers;
@@ -40,10 +42,24 @@ struct proc_dlatch_db_t
{
for (auto cell : module->cells())
{
- if (cell->type.in("$mux", "$pmux")) {
+ if (cell->type.in("$mux", "$pmux"))
+ {
auto sig_y = sigmap(cell->getPort("\\Y"));
for (int i = 0; i < GetSize(sig_y); i++)
mux_drivers[sig_y[i]] = pair<Cell*, int>(cell, i);
+
+ pool<SigBit> mux_srcbits_pool;
+ for (auto bit : sigmap(cell->getPort("\\A")))
+ mux_srcbits_pool.insert(bit);
+ for (auto bit : sigmap(cell->getPort("\\B")))
+ mux_srcbits_pool.insert(bit);
+
+ vector<SigBit> mux_srcbits_vec;
+ for (auto bit : mux_srcbits_pool)
+ if (bit.wire != nullptr)
+ mux_srcbits_vec.push_back(bit);
+
+ mux_srcbits[cell].swap(mux_srcbits_vec);
}
for (auto &conn : cell->connections())
@@ -58,6 +74,42 @@ struct proc_dlatch_db_t
sigusers[bit]++;
}
+ bool quickcheck(const SigSpec &haystack, const SigSpec &needle)
+ {
+ pool<SigBit> haystack_bits = sigmap(haystack).to_sigbit_pool();
+ pool<SigBit> needle_bits = sigmap(needle).to_sigbit_pool();
+
+ pool<Cell*> cells_queue, cells_visited;
+ pool<SigBit> bits_queue, bits_visited;
+
+ bits_queue = haystack_bits;
+ while (!bits_queue.empty())
+ {
+ for (auto &bit : bits_queue) {
+ auto it = mux_drivers.find(bit);
+ if (it != mux_drivers.end())
+ if (!cells_visited.count(it->second.first))
+ cells_queue.insert(it->second.first);
+ bits_visited.insert(bit);
+ }
+
+ bits_queue.clear();
+
+ for (auto c : cells_queue) {
+ for (auto bit : mux_srcbits[c]) {
+ if (needle_bits.count(bit))
+ return true;
+ if (!bits_visited.count(bit))
+ bits_queue.insert(bit);
+ }
+ }
+
+ cells_queue.clear();
+ }
+
+ return false;
+ }
+
struct rule_node_t
{
// a node is true if "signal" equals "match" and [any
@@ -202,6 +254,84 @@ struct proc_dlatch_db_t
rules_sig[n] = and_bits[0];
return and_bits[0];
}
+
+ void fixup_mux(Cell *cell)
+ {
+ SigSpec sig_a = cell->getPort("\\A");
+ SigSpec sig_b = cell->getPort("\\B");
+ SigSpec sig_s = cell->getPort("\\S");
+ SigSpec sig_any_valid_b;
+
+ SigSpec sig_new_b, sig_new_s;
+ for (int i = 0; i < GetSize(sig_s); i++) {
+ SigSpec b = sig_b.extract(i*GetSize(sig_a), GetSize(sig_a));
+ if (!b.is_fully_undef()) {
+ sig_any_valid_b = b;
+ sig_new_b.append(b);
+ sig_new_s.append(sig_s[i]);
+ }
+ }
+
+ if (sig_new_s.empty()) {
+ sig_new_b = sig_a;
+ sig_new_s = State::S0;
+ }
+
+ if (sig_a.is_fully_undef() && !sig_any_valid_b.empty())
+ cell->setPort("\\A", sig_any_valid_b);
+
+ if (GetSize(sig_new_s) == 1) {
+ cell->type = "$mux";
+ cell->unsetParam("\\S_WIDTH");
+ } else {
+ cell->type = "$pmux";
+ cell->setParam("\\S_WIDTH", GetSize(sig_new_s));
+ }
+
+ cell->setPort("\\B", sig_new_b);
+ cell->setPort("\\S", sig_new_s);
+ }
+
+ void fixup_muxes()
+ {
+ pool<Cell*> visited, queue;
+ dict<Cell*, pool<SigBit>> upstream_cell2net;
+ dict<SigBit, pool<Cell*>> upstream_net2cell;
+
+ CellTypes ct;
+ ct.setup_internals();
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections()) {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ upstream_cell2net[cell].insert(bit);
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ upstream_net2cell[bit].insert(cell);
+ }
+
+ queue = generated_dlatches;
+ while (!queue.empty())
+ {
+ pool<Cell*> next_queue;
+
+ for (auto cell : queue) {
+ if (cell->type.in("$mux", "$pmux"))
+ fixup_mux(cell);
+ for (auto bit : upstream_cell2net[cell])
+ for (auto cell : upstream_net2cell[bit])
+ next_queue.insert(cell);
+ visited.insert(cell);
+ }
+
+ queue.clear();
+ for (auto cell : next_queue) {
+ if (!visited.count(cell) && ct.cell_known(cell->type))
+ queue.insert(cell);
+ }
+ }
+ }
};
void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
@@ -218,9 +348,17 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
continue;
}
- for (auto ss : sr->actions) {
+ for (auto ss : sr->actions)
+ {
db.sigmap.apply(ss.first);
db.sigmap.apply(ss.second);
+
+ if (!db.quickcheck(ss.second, ss.first)) {
+ nolatches_bits.first.append(ss.first);
+ nolatches_bits.second.append(ss.second);
+ continue;
+ }
+
for (int i = 0; i < GetSize(ss.first); i++)
latches_out_in[ss.first[i]] = ss.second[i];
}
@@ -268,6 +406,8 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc)
SigSpec rhs = latches_bits.second.extract(offset, width);
Cell *cell = db.module->addDlatch(NEW_ID, db.module->Not(NEW_ID, db.make_hold(n)), rhs, lhs);
+ db.generated_dlatches.insert(cell);
+
log("Latch inferred for signal `%s.%s' from process `%s.%s': %s\n",
db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str(), log_id(cell));
}
@@ -292,7 +432,7 @@ struct ProcDlatchPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_DLATCH pass (convert process syncs to latches).\n");
+ log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n");
extra_args(args, 1, design);
@@ -301,6 +441,7 @@ struct ProcDlatchPass : public Pass {
for (auto &proc_it : module->processes)
if (design->selected(module, proc_it.second))
proc_dlatch(db, proc_it.second);
+ db.fixup_muxes();
}
}
} ProcDlatchPass;
diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc
index 633d4e58..0c8fb83d 100644
--- a/passes/proc/proc_init.cc
+++ b/passes/proc/proc_init.cc
@@ -61,13 +61,28 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc)
log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs));
int offset = 0;
- for (auto &lhs_c : lhs.chunks()) {
- if (lhs_c.wire != NULL) {
- RTLIL::SigSpec value = rhs.extract(offset, lhs_c.width);
- if (value.size() != lhs_c.wire->width)
- log_cmd_error("Init value is not for the entire wire: %s = %s\n", log_signal(lhs_c), log_signal(value));
- log(" Setting init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(value));
- lhs_c.wire->attributes["\\init"] = value.as_const();
+ for (auto &lhs_c : lhs.chunks())
+ {
+ if (lhs_c.wire != nullptr)
+ {
+ SigSpec valuesig = rhs.extract(offset, lhs_c.width);
+ if (!valuesig.is_fully_const())
+ log_cmd_error("Non-const initialization value: %s = %s\n", log_signal(lhs_c), log_signal(valuesig));
+
+ Const value = valuesig.as_const();
+ Const &wireinit = lhs_c.wire->attributes["\\init"];
+
+ while (GetSize(wireinit.bits) < lhs_c.wire->width)
+ wireinit.bits.push_back(State::Sx);
+
+ for (int i = 0; i < lhs_c.width; i++) {
+ auto &initbit = wireinit.bits[i + lhs_c.offset];
+ if (initbit != State::Sx && initbit != value[i])
+ log_cmd_error("Conflicting initialization values for %s.\n", log_signal(lhs_c));
+ initbit = value[i];
+ }
+
+ log(" Set init value: %s = %s\n", log_signal(lhs_c.wire), log_signal(wireinit));
}
offset += lhs_c.width;
}
@@ -100,7 +115,7 @@ struct ProcInitPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_INIT pass (extract init attributes).\n");
+ log_header(design, "Executing PROC_INIT pass (extract init attributes).\n");
extra_args(args, 1, design);
diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc
index 943e8c56..57e131ca 100644
--- a/passes/proc/proc_mux.cc
+++ b/passes/proc/proc_mux.cc
@@ -143,7 +143,7 @@ struct SnippetSwCache
}
};
-RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, bool ifxmode)
{
std::stringstream sstr;
sstr << "$procmux$" << (autoidx++);
@@ -164,14 +164,14 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
if (comp.size() == 0)
return RTLIL::SigSpec();
- if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1))
+ if (sig.size() == 1 && comp == RTLIL::SigSpec(1,1) && !ifxmode)
{
mod->connect(RTLIL::SigSig(RTLIL::SigSpec(cmp_wire, cmp_wire->width++), sig));
}
else
{
// create compare cell
- RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), "$eq");
+ RTLIL::Cell *eq_cell = mod->addCell(stringf("%s_CMP%d", sstr.str().c_str(), cmp_wire->width), ifxmode ? "$eqx" : "$eq");
eq_cell->attributes = sw->attributes;
eq_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
@@ -211,7 +211,7 @@ RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return RTLIL::SigSpec(ctrl_wire);
}
-RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw)
+RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::SigSpec else_signal, RTLIL::Cell *&last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode)
{
log_assert(when_signal.size() == else_signal.size());
@@ -223,7 +223,7 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return when_signal;
// compare results
- RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
+ RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode);
if (ctrl_sig.size() == 0)
return when_signal;
log_assert(ctrl_sig.size() == 1);
@@ -245,12 +245,15 @@ RTLIL::SigSpec gen_mux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const s
return RTLIL::SigSpec(result_wire);
}
-void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw)
+void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &compare, RTLIL::SigSpec when_signal, RTLIL::Cell *last_mux_cell, RTLIL::SwitchRule *sw, bool ifxmode)
{
log_assert(last_mux_cell != NULL);
log_assert(when_signal.size() == last_mux_cell->getPort("\\A").size());
- RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw);
+ if (when_signal == last_mux_cell->getPort("\\A"))
+ return;
+
+ RTLIL::SigSpec ctrl_sig = gen_cmp(mod, signal, compare, sw, ifxmode);
log_assert(ctrl_sig.size() == 1);
last_mux_cell->type = "$pmux";
@@ -266,7 +269,7 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
}
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
- RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval)
+ RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
{
RTLIL::SigSpec result = defval;
@@ -329,7 +332,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
for (auto pat : cs2->compare)
if (!pat.is_fully_const())
extra_group_for_next_case = true;
- else
+ else if (!ifxmode)
pool.take(pat);
}
}
@@ -340,18 +343,18 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
for (size_t i = 0; i < sw->cases.size(); i++) {
int case_idx = sw->cases.size() - i - 1;
RTLIL::CaseRule *cs2 = sw->cases[case_idx];
- RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val);
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, cs2, sig, initial_val, ifxmode);
if (last_mux_cell && pgroups[case_idx] == pgroups[case_idx+1])
- append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw);
+ append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode);
else
- result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw);
+ result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode);
}
}
return result;
}
-void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
+void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode)
{
log("Creating decoders for process `%s.%s'.\n", mod->name.c_str(), proc->name.c_str());
@@ -372,7 +375,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc)
log("%6d/%d: %s\n", ++cnt, GetSize(sigsnip.snippets), log_signal(sig));
- RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()));
+ RTLIL::SigSpec value = signal_to_mux_tree(mod, swcache, swpara, &proc->root_case, sig, RTLIL::SigSpec(RTLIL::State::Sx, sig.size()), ifxmode);
mod->connect(RTLIL::SigSig(sig, value));
}
}
@@ -383,23 +386,37 @@ struct ProcMuxPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" proc_mux [selection]\n");
+ log(" proc_mux [options] [selection]\n");
log("\n");
log("This pass converts the decision trees in processes (originating from if-else\n");
log("and case statements) to trees of multiplexer cells.\n");
log("\n");
+ log(" -ifx\n");
+ log(" Use Verilog simulation behavior with respect to undef values in\n");
+ log(" 'case' expressions and 'if' conditions.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
+ bool ifxmode = false;
+ log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n");
- extra_args(args, 1, design);
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-ifx") {
+ ifxmode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
for (auto mod : design->modules())
if (design->selected(mod))
for (auto &proc_it : mod->processes)
if (design->selected(mod, proc_it.second))
- proc_mux(mod, proc_it.second);
+ proc_mux(mod, proc_it.second, ifxmode);
}
} ProcMuxPass;
diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc
index f60d4b30..5672fb47 100644
--- a/passes/proc/proc_rmdead.cc
+++ b/passes/proc/proc_rmdead.cc
@@ -51,8 +51,8 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
counter++;
continue;
}
- if (pool.empty())
- sw->cases[i]->compare.clear();
+ // if (pool.empty())
+ // sw->cases[i]->compare.clear();
}
for (auto switch_it : sw->cases[i]->switches)
@@ -76,7 +76,7 @@ struct ProcRmdeadPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
+ log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n");
extra_args(args, 1, design);
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 4fa6bf0d..0c5f6fc6 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -4,4 +4,5 @@ OBJS += passes/sat/freduce.o
OBJS += passes/sat/eval.o
OBJS += passes/sat/miter.o
OBJS += passes/sat/expose.o
+OBJS += passes/sat/assertpmux.o
diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc
new file mode 100644
index 00000000..63a90767
--- /dev/null
+++ b/passes/sat/assertpmux.cc
@@ -0,0 +1,240 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct AssertpmuxWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ bool flag_noinit;
+ bool flag_always;
+
+ // get<0> ... mux cell
+ // get<1> ... mux port index
+ // get<2> ... mux bit index
+ dict<SigBit, pool<tuple<Cell*, int, int>>> sigbit_muxusers;
+
+ dict<SigBit, SigBit> sigbit_actsignals;
+ dict<SigSpec, SigBit> sigspec_actsignals;
+ dict<tuple<Cell*, int>, SigBit> muxport_actsignal;
+
+ AssertpmuxWorker(Module *module, bool flag_noinit, bool flag_always) :
+ module(module), sigmap(module), flag_noinit(flag_noinit), flag_always(flag_always)
+ {
+ for (auto wire : module->wires())
+ {
+ if (wire->port_output)
+ for (auto bit : sigmap(wire))
+ sigbit_actsignals[bit] = State::S1;
+ }
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type.in("$mux", "$pmux"))
+ {
+ int width = cell->getParam("\\WIDTH").as_int();
+ int numports = cell->type == "$mux" ? 2 : cell->getParam("\\S_WIDTH").as_int() + 1;
+
+ SigSpec sig_a = sigmap(cell->getPort("\\A"));
+ SigSpec sig_b = sigmap(cell->getPort("\\B"));
+ SigSpec sig_s = sigmap(cell->getPort("\\S"));
+
+ for (int i = 0; i < numports; i++) {
+ SigSpec bits = i == 0 ? sig_a : sig_b.extract(width*(i-1), width);
+ for (int k = 0; k < width; k++) {
+ tuple<Cell*, int, int> muxuser(cell, i, k);
+ sigbit_muxusers[bits[k]].insert(muxuser);
+ }
+ }
+ }
+ else
+ {
+ for (auto &conn : cell->connections()) {
+ if (!cell->known() || cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigbit_actsignals[bit] = State::S1;
+ }
+ }
+ }
+ }
+
+ SigBit get_bit_activation(SigBit bit)
+ {
+ sigmap.apply(bit);
+
+ if (sigbit_actsignals.count(bit) == 0)
+ {
+ SigSpec output;
+
+ for (auto muxuser : sigbit_muxusers.at(bit))
+ {
+ Cell *cell = std::get<0>(muxuser);
+ int portidx = std::get<1>(muxuser);
+ int bitidx = std::get<2>(muxuser);
+
+ tuple<Cell*, int> muxport(cell, portidx);
+
+ if (muxport_actsignal.count(muxport) == 0) {
+ if (portidx == 0)
+ muxport_actsignal[muxport] = module->LogicNot(NEW_ID, cell->getPort("\\S"));
+ else
+ muxport_actsignal[muxport] = cell->getPort("\\S")[portidx-1];
+ }
+
+ output.append(module->LogicAnd(NEW_ID, muxport_actsignal.at(muxport), get_bit_activation(cell->getPort("\\Y")[bitidx])));
+ }
+
+ output.sort_and_unify();
+
+ if (GetSize(output) == 0)
+ output = State::S0;
+ else if (GetSize(output) > 1)
+ output = module->ReduceOr(NEW_ID, output);
+
+ sigbit_actsignals[bit] = output.as_bit();
+ }
+
+ return sigbit_actsignals.at(bit);
+ }
+
+ SigBit get_activation(SigSpec sig)
+ {
+ sigmap.apply(sig);
+ sig.sort_and_unify();
+
+ if (sigspec_actsignals.count(sig) == 0)
+ {
+ SigSpec output;
+
+ for (auto bit : sig)
+ output.append(get_bit_activation(bit));
+
+ output.sort_and_unify();
+
+ if (GetSize(output) == 0)
+ output = State::S0;
+ else if (GetSize(output) > 1)
+ output = module->ReduceOr(NEW_ID, output);
+
+ sigspec_actsignals[sig] = output.as_bit();
+ }
+
+ return sigspec_actsignals.at(sig);
+ }
+
+ void run(Cell *pmux)
+ {
+ log("Adding assert for $pmux cell %s.%s.\n", log_id(module), log_id(pmux));
+
+ int swidth = pmux->getParam("\\S_WIDTH").as_int();
+ int cntbits = ceil_log2(swidth+1);
+
+ SigSpec sel = pmux->getPort("\\S");
+ SigSpec cnt(State::S0, cntbits);
+
+ for (int i = 0; i < swidth; i++)
+ cnt = module->Add(NEW_ID, cnt, sel[i]);
+
+ SigSpec assert_a = module->Le(NEW_ID, cnt, SigSpec(1, cntbits));
+ SigSpec assert_en;
+
+ if (flag_noinit)
+ assert_en.append(module->LogicNot(NEW_ID, module->Initstate(NEW_ID)));
+
+ if (!flag_always)
+ assert_en.append(get_activation(pmux->getPort("\\Y")));
+
+ if (GetSize(assert_en) == 0)
+ assert_en = State::S1;
+
+ if (GetSize(assert_en) == 2)
+ assert_en = module->LogicAnd(NEW_ID, assert_en[0], assert_en[1]);
+
+ Cell *assert_cell = module->addAssert(NEW_ID, assert_a, assert_en);
+
+ if (pmux->attributes.count("\\src") != 0)
+ assert_cell->attributes["\\src"] = pmux->attributes.at("\\src");
+ }
+};
+
+struct AssertpmuxPass : public Pass {
+ AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" assertpmux [options] [selection]\n");
+ log("\n");
+ log("This command adds asserts to the design that assert that all parallel muxes\n");
+ log("($pmux cells) have a maximum of one of their inputs enable at any time.\n");
+ log("\n");
+ log(" -noinit\n");
+ log(" do not enforce the pmux condition during the init state\n");
+ log("\n");
+ log(" -always\n");
+ log(" usually the $pmux condition is only checked when the $pmux output\n");
+ log(" is used be the mux tree it drives. this option will deactivate this\n");
+ log(" additional constrained and check the $pmux condition always.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool flag_noinit = false;
+ bool flag_always = false;
+
+ log_header(design, "Executing ASSERTPMUX pass (add asserts for $pmux cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-noinit") {
+ flag_noinit = true;
+ continue;
+ }
+ if (args[argidx] == "-always") {
+ flag_always = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ AssertpmuxWorker worker(module, flag_noinit, flag_always);
+ vector<Cell*> pmux_cells;
+
+ for (auto cell : module->selected_cells())
+ if (cell->type == "$pmux")
+ pmux_cells.push_back(cell);
+
+ for (auto cell : pmux_cells)
+ worker.run(cell);
+ }
+
+ }
+} AssertpmuxPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc
index 614a1bd3..09f69cc5 100644
--- a/passes/sat/eval.cc
+++ b/passes/sat/eval.cc
@@ -389,7 +389,7 @@ struct EvalPass : public Pass {
std::vector<std::string> shows, tables;
bool set_undef = false;
- log_header("Executing EVAL pass (evaluate the circuit given an input).\n");
+ log_header(design, "Executing EVAL pass (evaluate the circuit given an input).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index ebdf2ed5..9427547f 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -262,7 +262,7 @@ struct ExposePass : public Pass {
bool flag_evert_dff = false;
std::string sep = ".";
- log_header("Executing EXPOSE pass (exposing internal signals as outputs).\n");
+ log_header(design, "Executing EXPOSE pass (exposing internal signals as outputs).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc
index 373b8048..77263f6a 100644
--- a/passes/sat/freduce.cc
+++ b/passes/sat/freduce.cc
@@ -798,7 +798,7 @@ struct FreducePass : public Pass {
inv_mode = false;
dump_prefix = std::string();
- log_header("Executing FREDUCE pass (perform functional reduction).\n");
+ log_header(design, "Executing FREDUCE pass (perform functional reduction).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc
index 682299ef..4854e19b 100644
--- a/passes/sat/miter.cc
+++ b/passes/sat/miter.cc
@@ -32,7 +32,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
bool flag_make_assert = false;
bool flag_flatten = false;
- log_header("Executing MITER pass (creating miter circuit).\n");
+ log_header(design, "Executing MITER pass (creating miter circuit).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
@@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_flatten) {
log_push();
- Pass::call_on_module(design, miter_module, "flatten; opt_const -keepdc -undriven;;");
+ Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;");
log_pop();
}
}
@@ -264,7 +264,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
bool flag_make_outputs = false;
bool flag_flatten = false;
- log_header("Executing MITER pass (creating miter circuit).\n");
+ log_header(design, "Executing MITER pass (creating miter circuit).\n");
size_t argidx;
for (argidx = 2; argidx < args.size(); argidx++)
@@ -327,7 +327,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
if (flag_flatten) {
log_push();
- Pass::call_on_module(design, module, "opt_const -keepdc -undriven;;");
+ Pass::call_on_module(design, module, "opt_expr -keepdc -undriven;;");
log_pop();
}
}
@@ -361,7 +361,7 @@ struct MiterPass : public Pass {
log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n");
log(" -flatten\n");
- log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
+ log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
log("\n");
log(" miter -assert [options] module [miter_name]\n");
@@ -375,7 +375,7 @@ struct MiterPass : public Pass {
log(" keep module output ports.\n");
log("\n");
log(" -flatten\n");
- log(" call 'flatten; opt_const -keepdc -undriven;;' on the miter circuit.\n");
+ log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index 2e9c6d2f..a6ac7afd 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -90,106 +90,16 @@ struct SatHelper
log_cmd_error("Bit %d of %s is undef but option -enable_undef is missing!\n", int(i), log_signal(sig));
}
- void setup_init()
- {
- log ("\nSetting up initial state:\n");
-
- RTLIL::SigSpec big_lhs, big_rhs;
-
- for (auto &it : module->wires_)
- {
- if (it.second->attributes.count("\\init") == 0)
- continue;
-
- RTLIL::SigSpec lhs = sigmap(it.second);
- RTLIL::SigSpec rhs = it.second->attributes.at("\\init");
- log_assert(lhs.size() == rhs.size());
-
- RTLIL::SigSpec removed_bits;
- for (int i = 0; i < lhs.size(); i++) {
- RTLIL::SigSpec bit = lhs.extract(i, 1);
- if (!satgen.initial_state.check_all(bit)) {
- removed_bits.append(bit);
- lhs.remove(i, 1);
- rhs.remove(i, 1);
- i--;
- }
- }
-
- if (removed_bits.size())
- log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits));
-
- if (lhs.size()) {
- log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
- big_lhs.remove2(lhs, &big_rhs);
- big_lhs.append(lhs);
- big_rhs.append(rhs);
- }
- }
-
- for (auto &s : sets_init)
- {
- RTLIL::SigSpec lhs, rhs;
-
- if (!RTLIL::SigSpec::parse_sel(lhs, design, module, s.first))
- log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.first.c_str());
- if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second))
- log_cmd_error("Failed to parse rhs set expression `%s'.\n", s.second.c_str());
- show_signal_pool.add(sigmap(lhs));
- show_signal_pool.add(sigmap(rhs));
-
- if (lhs.size() != rhs.size())
- log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
- s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
-
- log("Import set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
- big_lhs.remove2(lhs, &big_rhs);
- big_lhs.append(lhs);
- big_rhs.append(rhs);
- }
-
- if (!satgen.initial_state.check_all(big_lhs)) {
- RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs);
- log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem));
- }
-
- if (set_init_def) {
- RTLIL::SigSpec rem = satgen.initial_state.export_all();
- std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1);
- ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem)));
- }
-
- if (set_init_undef) {
- RTLIL::SigSpec rem = satgen.initial_state.export_all();
- rem.remove(big_lhs);
- big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size()));
- }
-
- if (set_init_zero) {
- RTLIL::SigSpec rem = satgen.initial_state.export_all();
- rem.remove(big_lhs);
- big_lhs.append(rem);
- big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size()));
- }
-
- if (big_lhs.size() == 0) {
- log("No constraints for initial state found.\n\n");
- return;
- }
-
- log("Final constraint equation: %s = %s\n\n", log_signal(big_lhs), log_signal(big_rhs));
- check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
- ez->assume(satgen.signals_eq(big_lhs, big_rhs, 1));
- }
-
- void setup(int timestep = -1)
+ void setup(int timestep = -1, bool initstate = false)
{
if (timestep > 0)
log ("\nSetting up time step %d:\n", timestep);
else
log ("\nSetting up SAT problem:\n");
+ if (initstate)
+ satgen.setInitState(timestep);
+
if (timestep > max_timestep)
max_timestep = timestep;
@@ -341,6 +251,97 @@ struct SatHelper
log("Import constraint from assume cell: %s when %s.\n", log_signal(assumes_a[i]), log_signal(assumes_en[i]));
ez->assume(satgen.importAssumes(timestep));
}
+
+ if (initstate)
+ {
+ RTLIL::SigSpec big_lhs, big_rhs;
+
+ for (auto &it : module->wires_)
+ {
+ if (it.second->attributes.count("\\init") == 0)
+ continue;
+
+ RTLIL::SigSpec lhs = sigmap(it.second);
+ RTLIL::SigSpec rhs = it.second->attributes.at("\\init");
+ log_assert(lhs.size() == rhs.size());
+
+ RTLIL::SigSpec removed_bits;
+ for (int i = 0; i < lhs.size(); i++) {
+ RTLIL::SigSpec bit = lhs.extract(i, 1);
+ if (!satgen.initial_state.check_all(bit)) {
+ removed_bits.append(bit);
+ lhs.remove(i, 1);
+ rhs.remove(i, 1);
+ i--;
+ }
+ }
+
+ if (removed_bits.size())
+ log_warning("ignoring initial value on non-register: %s\n", log_signal(removed_bits));
+
+ if (lhs.size()) {
+ log("Import set-constraint from init attribute: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ big_lhs.remove2(lhs, &big_rhs);
+ big_lhs.append(lhs);
+ big_rhs.append(rhs);
+ }
+ }
+
+ for (auto &s : sets_init)
+ {
+ RTLIL::SigSpec lhs, rhs;
+
+ if (!RTLIL::SigSpec::parse_sel(lhs, design, module, s.first))
+ log_cmd_error("Failed to parse lhs set expression `%s'.\n", s.first.c_str());
+ if (!RTLIL::SigSpec::parse_rhs(lhs, rhs, module, s.second))
+ log_cmd_error("Failed to parse rhs set expression `%s'.\n", s.second.c_str());
+ show_signal_pool.add(sigmap(lhs));
+ show_signal_pool.add(sigmap(rhs));
+
+ if (lhs.size() != rhs.size())
+ log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
+ s.first.c_str(), log_signal(lhs), lhs.size(), s.second.c_str(), log_signal(rhs), rhs.size());
+
+ log("Import init set-constraint: %s = %s\n", log_signal(lhs), log_signal(rhs));
+ big_lhs.remove2(lhs, &big_rhs);
+ big_lhs.append(lhs);
+ big_rhs.append(rhs);
+ }
+
+ if (!satgen.initial_state.check_all(big_lhs)) {
+ RTLIL::SigSpec rem = satgen.initial_state.remove(big_lhs);
+ log_cmd_error("Found -set-init bits that are not part of the initial_state: %s\n", log_signal(rem));
+ }
+
+ if (set_init_def) {
+ RTLIL::SigSpec rem = satgen.initial_state.export_all();
+ std::vector<int> undef_rem = satgen.importUndefSigSpec(rem, 1);
+ ez->assume(ez->NOT(ez->expression(ezSAT::OpOr, undef_rem)));
+ }
+
+ if (set_init_undef) {
+ RTLIL::SigSpec rem = satgen.initial_state.export_all();
+ rem.remove(big_lhs);
+ big_lhs.append(rem);
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::Sx, rem.size()));
+ }
+
+ if (set_init_zero) {
+ RTLIL::SigSpec rem = satgen.initial_state.export_all();
+ rem.remove(big_lhs);
+ big_lhs.append(rem);
+ big_rhs.append(RTLIL::SigSpec(RTLIL::State::S0, rem.size()));
+ }
+
+ if (big_lhs.size() == 0) {
+ log("No constraints for initial state found.\n\n");
+ return;
+ }
+
+ log("Final init constraint equation: %s = %s\n", log_signal(big_lhs), log_signal(big_rhs));
+ check_undef_enabled(big_lhs), check_undef_enabled(big_rhs);
+ ez->assume(satgen.signals_eq(big_lhs, big_rhs, timestep));
+ }
}
int setup_proof(int timestep = -1)
@@ -630,11 +631,11 @@ struct SatHelper
"---------------------------------------------------------------------------------------------------";
if (last_timestep == -2) {
log(max_timestep > 0 ? " Time " : " ");
- log("%-*s %10s %10s %*s\n", maxModelName+10, "Signal Name", "Dec", "Hex", maxModelWidth+5, "Bin");
+ log("%-*s %11s %9s %*s\n", maxModelName+5, "Signal Name", "Dec", "Hex", maxModelWidth+3, "Bin");
}
log(max_timestep > 0 ? " ---- " : " ");
- log("%*.*s %10.10s %10.10s %*.*s\n", maxModelName+10, maxModelName+10,
- hline, hline, hline, maxModelWidth+5, maxModelWidth+5, hline);
+ log("%*.*s %11.11s %9.9s %*.*s\n", maxModelName+5, maxModelName+5,
+ hline, hline, hline, maxModelWidth+3, maxModelWidth+3, hline);
last_timestep = info.timestep;
}
@@ -647,9 +648,9 @@ struct SatHelper
log(" ");
if (info.width <= 32 && !found_undef)
- log("%-*s %10d %10x %*s\n", maxModelName+10, info.description.c_str(), value.as_int(), value.as_int(), maxModelWidth+5, value.as_string().c_str());
+ log("%-*s %11d %9x %*s\n", maxModelName+5, info.description.c_str(), value.as_int(), value.as_int(), maxModelWidth+3, value.as_string().c_str());
else
- log("%-*s %10s %10s %*s\n", maxModelName+10, info.description.c_str(), "--", "--", maxModelWidth+5, value.as_string().c_str());
+ log("%-*s %11s %9s %*s\n", maxModelName+5, info.description.c_str(), "--", "--", maxModelWidth+3, value.as_string().c_str());
}
if (last_timestep == -2)
@@ -1073,7 +1074,7 @@ struct SatPass : public Pass {
int tempinduct_skip = 0, stepsize = 1;
std::string vcd_file_name, json_file_name, cnf_file_name;
- log_header("Executing SAT pass (solving SAT problems in the circuit).\n");
+ log_header(design, "Executing SAT pass (solving SAT problems in the circuit).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
@@ -1377,7 +1378,6 @@ struct SatPass : public Pass {
SatHelper basecase(design, module, enable_undef);
SatHelper inductstep(design, module, enable_undef);
- bool basecase_setup_init = true;
basecase.sets = sets;
basecase.set_assumes = set_assumes;
@@ -1403,7 +1403,7 @@ struct SatPass : public Pass {
for (int timestep = 1; timestep <= seq_len; timestep++)
if (!tempinduct_inductonly)
- basecase.setup(timestep);
+ basecase.setup(timestep, timestep == 1);
inductstep.sets = sets;
inductstep.set_assumes = set_assumes;
@@ -1436,15 +1436,10 @@ struct SatPass : public Pass {
if (!tempinduct_inductonly)
{
- basecase.setup(seq_len + inductlen);
+ basecase.setup(seq_len + inductlen, seq_len + inductlen == 1);
int property = basecase.setup_proof(seq_len + inductlen);
basecase.generate_model();
- if (basecase_setup_init) {
- basecase.setup_init();
- basecase_setup_init = false;
- }
-
if (inductlen > 1)
basecase.force_unique_state(seq_len + 1, seq_len + inductlen);
@@ -1452,6 +1447,7 @@ struct SatPass : public Pass {
{
log("\n[base case %d] Solving problem with %d variables and %d clauses..\n",
inductlen, basecase.ez->numCnfVariables(), basecase.ez->numCnfClauses());
+ log_flush();
if (basecase.solve(basecase.ez->NOT(property))) {
log("SAT temporal induction proof finished - model found for base case: FAIL!\n");
@@ -1522,6 +1518,7 @@ struct SatPass : public Pass {
log("\n[induction step %d] Solving problem with %d variables and %d clauses..\n",
inductlen, inductstep.ez->numCnfVariables(), inductstep.ez->numCnfClauses());
+ log_flush();
if (!inductstep.solve(inductstep.ez->NOT(property))) {
if (inductstep.gotTimeout)
@@ -1599,14 +1596,13 @@ struct SatPass : public Pass {
} else {
std::vector<int> prove_bits;
for (int timestep = 1; timestep <= seq_len; timestep++) {
- sathelper.setup(timestep);
+ sathelper.setup(timestep, timestep == 1);
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
if (timestep > prove_skip)
prove_bits.push_back(sathelper.setup_proof(timestep));
}
if (sathelper.prove.size() || sathelper.prove_x.size() || sathelper.prove_asserts)
sathelper.ez->assume(sathelper.ez->NOT(sathelper.ez->expression(ezSAT::OpAnd, prove_bits)));
- sathelper.setup_init();
}
sathelper.generate_model();
@@ -1628,6 +1624,7 @@ struct SatPass : public Pass {
rerun_solver:
log("\nSolving problem with %d variables and %d clauses..\n",
sathelper.ez->numCnfVariables(), sathelper.ez->numCnfClauses());
+ log_flush();
if (sathelper.solve())
{
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 8112516c..b5024fa9 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -7,6 +7,9 @@ OBJS += passes/techmap/libparse.o
ifeq ($(ENABLE_ABC),1)
OBJS += passes/techmap/abc.o
+ifneq ($(ABCEXTERNAL),)
+passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
+endif
endif
ifneq ($(SMALL),1)
@@ -23,6 +26,11 @@ OBJS += passes/techmap/tribuf.o
OBJS += passes/techmap/lut2mux.o
OBJS += passes/techmap/nlutmap.o
OBJS += passes/techmap/dffsr2dff.o
+OBJS += passes/techmap/shregmap.o
+OBJS += passes/techmap/deminout.o
+OBJS += passes/techmap/insbuf.o
+OBJS += passes/techmap/attrmvcp.o
+OBJS += passes/techmap/attrmap.o
endif
GENFILES += passes/techmap/techmap.inc
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 7da26602..cc79296c 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -29,15 +29,17 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
-#define ABC_COMMAND_LIB "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}"
-#define ABC_COMMAND_CTR "strash; scorr; ifraig; retime {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_COMMAND_LUT "strash; scorr; ifraig; retime; strash; dch -f; if"
-#define ABC_COMMAND_DFL "strash; scorr; ifraig; retime; strash; dch -f; map"
-
-#define ABC_FAST_COMMAND_LIB "retime {D}; map {D}"
-#define ABC_FAST_COMMAND_CTR "retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "retime; if"
-#define ABC_FAST_COMMAND_DFL "retime; map"
+#define ABC_COMMAND_LIB "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}"
+#define ABC_COMMAND_CTR "strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_COMMAND_LUT "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs"
+#define ABC_COMMAND_SOP "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; cover {I} {P}"
+#define ABC_COMMAND_DFL "strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map"
+
+#define ABC_FAST_COMMAND_LIB "retime -o {D}; map {D}"
+#define ABC_FAST_COMMAND_CTR "retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "retime -o; if"
+#define ABC_FAST_COMMAND_SOP "retime -o; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_DFL "retime -o; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@@ -593,7 +595,8 @@ struct abc_output_filter
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells, bool show_tempdir)
+ bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode,
+ const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode)
{
module = current_module;
map_autoidx = autoidx++;
@@ -616,7 +619,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (!cleanup)
tempdir_name[0] = tempdir_name[4] = '_';
tempdir_name = make_temp_dir(tempdir_name);
- log_header("Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
+ log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n",
module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
@@ -642,16 +645,30 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
abc_script += script_file[i];
} else
abc_script += stringf("source %s", script_file.c_str());
- } else if (!lut_costs.empty())
+ } else if (!lut_costs.empty()) {
+ bool all_luts_cost_same = true;
+ for (int this_cost : lut_costs)
+ if (this_cost != lut_costs.front())
+ all_luts_cost_same = false;
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
- else if (!liberty_file.empty())
+ if (all_luts_cost_same && !fast_mode)
+ abc_script += "; lutpack";
+ } else if (!liberty_file.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
+ else if (sop_mode)
+ abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
+ for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3);
+
+ for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+ abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
+
abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str());
abc_script = add_echos_to_abc_cmd(abc_script);
@@ -828,7 +845,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (count_output > 0)
{
- log_header("Executing ABC.\n");
+ log_header(design, "Executing ABC.\n");
buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt");
@@ -892,13 +909,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
- bool builtin_lib = liberty_file.empty() && script_file.empty() && lut_costs.empty();
+ bool builtin_lib = liberty_file.empty();
RTLIL::Design *mapped_design = new RTLIL::Design;
- parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_");
+ parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
ifs.close();
- log_header("Re-integrating ABC results.\n");
+ log_header(design, "Re-integrating ABC results.\n");
RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
if (mapped_mod == NULL)
log_error("ABC output file does not contain a module `netlist'.\n");
@@ -910,10 +927,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
}
std::map<std::string, int> cell_stats;
- if (builtin_lib)
+ for (auto c : mapped_mod->cells())
{
- for (auto &it : mapped_mod->cells_) {
- RTLIL::Cell *c = it.second;
+ if (builtin_lib)
+ {
cell_stats[RTLIL::unescape_id(c->type)]++;
if (c->type == "\\ZERO" || c->type == "\\ONE") {
RTLIL::SigSig conn;
@@ -1052,60 +1069,57 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, cell);
continue;
}
- log_abort();
}
- }
- else
- {
- for (auto &it : mapped_mod->cells_)
- {
- RTLIL::Cell *c = it.second;
- cell_stats[RTLIL::unescape_id(c->type)]++;
- if (c->type == "\\_const0_" || c->type == "\\_const1_") {
- RTLIL::SigSig conn;
- conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
- conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
- module->connect(conn);
- continue;
- }
- if (c->type == "\\_dff_") {
- log_assert(clk_sig.size() == 1);
- RTLIL::Cell *cell;
- if (en_sig.size() == 0) {
- cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
- } else {
- log_assert(en_sig.size() == 1);
- cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
- cell->setPort("\\E", en_sig);
- }
- if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
- cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
- cell->setPort("\\C", clk_sig);
- design->select(module, cell);
- continue;
- }
- if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
- SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
- SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
- module->connect(my_y, my_a);
- continue;
+
+ cell_stats[RTLIL::unescape_id(c->type)]++;
+
+ if (c->type == "\\_const0_" || c->type == "\\_const1_") {
+ RTLIL::SigSig conn;
+ conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]);
+ conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1);
+ module->connect(conn);
+ continue;
+ }
+
+ if (c->type == "\\_dff_") {
+ log_assert(clk_sig.size() == 1);
+ RTLIL::Cell *cell;
+ if (en_sig.size() == 0) {
+ cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_");
+ } else {
+ log_assert(en_sig.size() == 1);
+ cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N'));
+ cell->setPort("\\E", en_sig);
}
- RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
- cell->parameters = c->parameters;
- for (auto &conn : c->connections()) {
- RTLIL::SigSpec newsig;
- for (auto &c : conn.second.chunks()) {
- if (c.width == 0)
- continue;
- log_assert(c.width == 1);
- newsig.append(module->wires_[remap_name(c.wire->name)]);
- }
- cell->setPort(conn.first, newsig);
- }
+ cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
+ cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
+ cell->setPort("\\C", clk_sig);
design->select(module, cell);
+ continue;
+ }
+
+ if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
+ SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
+ SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
+ module->connect(my_y, my_a);
+ continue;
+ }
+
+ RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type);
+ if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
+ cell->parameters = c->parameters;
+ for (auto &conn : c->connections()) {
+ RTLIL::SigSpec newsig;
+ for (auto &c : conn.second.chunks()) {
+ if (c.width == 0)
+ continue;
+ log_assert(c.width == 1);
+ newsig.append(module->wires_[remap_name(c.wire->name)]);
+ }
+ cell->setPort(conn.first, newsig);
}
+ design->select(module, cell);
}
for (auto conn : mapped_mod->connections()) {
@@ -1167,7 +1181,11 @@ struct AbcPass : public Pass {
log("library to a target architecture.\n");
log("\n");
log(" -exe <command>\n");
- log(" use the specified command name instead of \"yosys-abc\" to execute ABC.\n");
+#ifdef ABCEXTERNAL
+ log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
+#else
+ log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+#endif
log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n");
log("\n");
log(" -script <file>\n");
@@ -1186,9 +1204,15 @@ struct AbcPass : public Pass {
log(" for -liberty with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
- log(" for -lut:\n");
+ log(" for -lut/-luts (only one LUT size):\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack").c_str());
+ log("\n");
+ log(" for -lut/-luts (different LUT sizes):\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
log("\n");
+ log(" for -sop:\n");
+ log("%s\n", fold_abc_cmd(ABC_COMMAND_SOP).c_str());
+ log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str());
log("\n");
@@ -1202,9 +1226,12 @@ struct AbcPass : public Pass {
log(" for -liberty with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
- log(" for -lut:\n");
+ log(" for -lut/-luts:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
log("\n");
+ log(" for -sop:\n");
+ log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_SOP).c_str());
+ log("\n");
log(" otherwise:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str());
log("\n");
@@ -1227,6 +1254,14 @@ struct AbcPass : public Pass {
log(" set delay target. the string {D} in the default scripts above is\n");
log(" replaced by this option when used, and an empty string otherwise.\n");
log("\n");
+ log(" -I <num>\n");
+ log(" maximum number of SOP inputs.\n");
+ log(" (replaces {I} in the default scripts above)\n");
+ log("\n");
+ log(" -P <num>\n");
+ log(" maximum number of SOP products.\n");
+ log(" (replaces {P} in the default scripts above)\n");
+ log("\n");
log(" -lut <width>\n");
log(" generate netlist using luts of (max) the specified width.\n");
log("\n");
@@ -1240,6 +1275,9 @@ struct AbcPass : public Pass {
log(" generate netlist using luts. Use the specified costs for luts with 1,\n");
log(" 2, 3, .. inputs.\n");
log("\n");
+ log(" -sop\n");
+ log(" map to sum-of-product cells and inverters\n");
+ log("\n");
// log(" -mux4, -mux8, -mux16\n");
// log(" try to extract 4-input, 8-input, and/or 16-input muxes\n");
// log(" (ignored when used with -liberty or -lut)\n");
@@ -1286,13 +1324,18 @@ struct AbcPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing ABC pass (technology mapping using ABC).\n");
+ log_header(design, "Executing ABC pass (technology mapping using ABC).\n");
log_push();
+#ifdef ABCEXTERNAL
+ std::string exe_file = ABCEXTERNAL;
+#else
std::string exe_file = proc_self_dirname() + "yosys-abc";
- std::string script_file, liberty_file, constr_file, clk_str, delay_target;
+#endif
+ std::string script_file, liberty_file, constr_file, clk_str;
+ std::string delay_target, sop_inputs, sop_products;
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
- bool show_tempdir = false;
+ bool show_tempdir = false, sop_mode = false;
vector<int> lut_costs;
markgroups = false;
@@ -1302,9 +1345,11 @@ struct AbcPass : public Pass {
enabled_gates.clear();
#ifdef _WIN32
+#ifndef ABCEXTERNAL
if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
exe_file = proc_self_dirname() + "..\\yosys-abc";
#endif
+#endif
size_t argidx;
char pwd [PATH_MAX];
@@ -1340,6 +1385,14 @@ struct AbcPass : public Pass {
delay_target = "-D " + args[++argidx];
continue;
}
+ if (arg == "-I" && argidx+1 < args.size()) {
+ sop_inputs = "-I " + args[++argidx];
+ continue;
+ }
+ if (arg == "-P" && argidx+1 < args.size()) {
+ sop_products = "-P " + args[++argidx];
+ continue;
+ }
if (arg == "-lut" && argidx+1 < args.size()) {
string arg = args[++argidx];
size_t pos = arg.find_first_of(':');
@@ -1374,6 +1427,10 @@ struct AbcPass : public Pass {
}
continue;
}
+ if (arg == "-sop") {
+ sop_mode = true;
+ continue;
+ }
if (arg == "-mux4") {
map_mux4 = true;
continue;
@@ -1447,7 +1504,8 @@ struct AbcPass : public Pass {
if (mod->processes.size() > 0)
log("Skipping module %s as it contains processes.\n", log_id(mod));
else if (!dff_mode || !clk_str.empty())
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells(), show_tempdir);
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+ delay_target, sop_inputs, sop_products, fast_mode, mod->selected_cells(), show_tempdir, sop_mode);
else
{
assign_map.set(mod);
@@ -1580,7 +1638,7 @@ struct AbcPass : public Pass {
assigned_cells_reverse[cell] = key;
}
- log_header("Summary of detected clock domains:\n");
+ log_header(design, "Summary of detected clock domains:\n");
for (auto &it : assigned_cells)
log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
@@ -1591,8 +1649,8 @@ struct AbcPass : public Pass {
clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs,
- !clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second, show_tempdir);
+ abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ keepff, delay_target, sop_inputs, sop_products, fast_mode, it.second, show_tempdir, sop_mode);
assign_map.set(mod);
}
}
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index db1c731e..b9ac7ade 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -41,7 +41,7 @@ struct AigmapPass : public Pass {
{
bool nand_mode = false;
- log_header("Executing AIGMAP pass (map logic to AIG).\n");
+ log_header(design, "Executing AIGMAP pass (map logic to AIG).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index 3c7ff4b9..9f6dd02d 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -544,7 +544,7 @@ struct AlumaccPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing ALUMACC pass (create $alu and $macc cells).\n");
+ log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
new file mode 100644
index 00000000..f715b63e
--- /dev/null
+++ b/passes/techmap/attrmap.cc
@@ -0,0 +1,250 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+Const make_value(string &value)
+{
+ if (GetSize(value) >= 2 && value.front() == '"' && value.back() == '"')
+ return Const(value.substr(1, GetSize(value)-2));
+
+ SigSpec sig;
+ SigSpec::parse(sig, nullptr, value);
+ return sig.as_const();
+}
+
+bool match_name(string &name, IdString &id, bool ignore_case=false)
+{
+ string str1 = RTLIL::escape_id(name);
+ string str2 = id.str();
+
+ if (ignore_case)
+ return !strcasecmp(str1.c_str(), str2.c_str());
+
+ return str1 == str2;
+}
+
+bool match_value(string &value, Const &val, bool ignore_case=false)
+{
+ if (ignore_case && ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) && GetSize(value) && value.front() == '"' && value.back() == '"') {
+ string str1 = value.substr(1, GetSize(value)-2);
+ string str2 = val.decode_string();
+ return !strcasecmp(str1.c_str(), str2.c_str());
+ }
+
+ return make_value(value) == val;
+}
+
+struct AttrmapAction {
+ virtual ~AttrmapAction() { }
+ virtual bool apply(IdString &id, Const &val) = 0;
+};
+
+struct AttrmapTocase : AttrmapAction {
+ string name;
+ virtual bool apply(IdString &id, Const&) {
+ if (match_name(name, id, true))
+ id = RTLIL::escape_id(name);
+ return true;
+ }
+};
+
+struct AttrmapRename : AttrmapAction {
+ string old_name, new_name;
+ virtual bool apply(IdString &id, Const&) {
+ if (match_name(old_name, id))
+ id = RTLIL::escape_id(new_name);
+ return true;
+ }
+};
+
+struct AttrmapMap : AttrmapAction {
+ bool imap;
+ string old_name, new_name;
+ string old_value, new_value;
+ virtual bool apply(IdString &id, Const &val) {
+ if (match_name(old_name, id) && match_value(old_value, val, true)) {
+ id = RTLIL::escape_id(new_name);
+ val = make_value(new_value);
+ }
+ return true;
+ }
+};
+
+struct AttrmapRemove : AttrmapAction {
+ string name, value;
+ virtual bool apply(IdString &id, Const &val) {
+ return !(match_name(name, id) && match_value(value, val));
+ }
+};
+
+void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actions, dict<RTLIL::IdString, RTLIL::Const> &attributes)
+{
+ dict<RTLIL::IdString, RTLIL::Const> new_attributes;
+
+ for (auto attr : attributes)
+ {
+ auto new_attr = attr;
+ for (auto &action : actions)
+ if (!action->apply(new_attr.first, new_attr.second))
+ goto delete_this_attr;
+
+ if (new_attr != attr)
+ log("Changed attribute on %s: %s=%s -> %s=%s\n", objname.c_str(),
+ log_id(attr.first), log_const(attr.second), log_id(new_attr.first), log_const(new_attr.second));
+
+ new_attributes[new_attr.first] = new_attr.second;
+
+ if (0)
+ delete_this_attr:
+ log("Removed attribute on %s: %s=%s\n", objname.c_str(), log_id(attr.first), log_const(attr.second));
+ }
+
+ attributes.swap(new_attributes);
+}
+
+struct AttrmapPass : public Pass {
+ AttrmapPass() : Pass("attrmap", "renaming attributes") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" attrmap [options] [selection]\n");
+ log("\n");
+ log("This command renames attributes and/or mapps key/value pairs to\n");
+ log("other key/value pairs.\n");
+ log("\n");
+ log(" -tocase <name>\n");
+ log(" Match attribute names case-insensitively and set it to the specified\n");
+ log(" name.\n");
+ log("\n");
+ log(" -rename <old_name> <new_name>\n");
+ log(" Rename attributes as specified\n");
+ log("\n");
+ log(" -map <old_name>=<old_value> <new_name>=<new_value>\n");
+ log(" Map key/value pairs as indicated.\n");
+ log("\n");
+ log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n");
+ log(" Like -map, but use case-insensitive match for <old_value> when\n");
+ log(" it is a string value.\n");
+ log("\n");
+ log(" -remove <name>=<value>\n");
+ log(" Remove attributes matching this pattern.\n");
+ log("\n");
+ log(" -modattr\n");
+ log(" Operate on module attributes instead of attributes on wires and cells.\n");
+ log("\n");
+ log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n");
+ log("\n");
+ log(" attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n");
+ log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n");
+
+ bool modattr_mode = false;
+ vector<std::unique_ptr<AttrmapAction>> actions;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-tocase" && argidx+1 < args.size()) {
+ auto action = new AttrmapTocase;
+ action->name = args[++argidx];
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if (arg == "-rename" && argidx+2 < args.size()) {
+ auto action = new AttrmapRename;
+ action->old_name = args[++argidx];
+ action->new_name = args[++argidx];
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) {
+ string arg1 = args[++argidx];
+ string arg2 = args[++argidx];
+ string val1, val2;
+ size_t p = arg1.find("=");
+ if (p != string::npos) {
+ val1 = arg1.substr(p+1);
+ arg1 = arg1.substr(0, p);
+ }
+ p = arg2.find("=");
+ if (p != string::npos) {
+ val2 = arg2.substr(p+1);
+ arg2 = arg2.substr(0, p);
+ }
+ auto action = new AttrmapMap;
+ action->imap = (arg == "-map");
+ action->old_name = arg1;
+ action->new_name = arg2;
+ action->old_value = val1;
+ action->new_value = val2;
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if (arg == "-remove" && argidx+1 < args.size()) {
+ string arg1 = args[++argidx], val1;
+ size_t p = arg1.find("=");
+ if (p != string::npos) {
+ val1 = arg1.substr(p+1);
+ arg1 = arg1.substr(0, p);
+ }
+ auto action = new AttrmapRemove;
+ action->name = arg1;
+ action->value = val1;
+ actions.push_back(std::unique_ptr<AttrmapAction>(action));
+ continue;
+ }
+ if (arg == "-modattr") {
+ modattr_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (modattr_mode)
+ {
+ for (auto module : design->selected_whole_modules())
+ attrmap_apply(stringf("%s", log_id(module)), actions, module->attributes);
+ }
+ else
+ {
+ for (auto module : design->selected_modules())
+ {
+ for (auto wire : module->selected_wires())
+ attrmap_apply(stringf("%s.%s", log_id(module), log_id(wire)), actions, wire->attributes);
+
+ for (auto cell : module->selected_cells())
+ attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->attributes);
+ }
+ }
+ }
+} AttrmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
new file mode 100644
index 00000000..50eaf61d
--- /dev/null
+++ b/passes/techmap/attrmvcp.cc
@@ -0,0 +1,139 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct AttrmvcpPass : public Pass {
+ AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" attrmvcp [options] [selection]\n");
+ log("\n");
+ log("Move or copy attributes on wires to the cells driving them.\n");
+ log("\n");
+ log(" -copy\n");
+ log(" By default, attributes are moved. This will only add\n");
+ log(" the attribute to the cell, without removing it from\n");
+ log(" the wire.\n");
+ log("\n");
+ log(" -purge\n");
+ log(" If no selected cell consumes the attribute, then it is\n");
+ log(" left on the wire by default. This option will cause the\n");
+ log(" attribute to be removed from the wire, even if no selected\n");
+ log(" cell takes it.\n");
+ log("\n");
+ log(" -driven\n");
+ log(" By default, attriburtes are moved to the cell driving the\n");
+ log(" wire. With this option set it will be moved to the cell\n");
+ log(" driven by the wire instead.\n");
+ log("\n");
+ log(" -attr <attrname>\n");
+ log(" Move or copy this attribute. This option can be used\n");
+ log(" multiple times.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n");
+
+ bool copy_mode = false;
+ bool driven_mode = false;
+ bool purge_mode = false;
+ pool<IdString> attrnames;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-copy") {
+ copy_mode = true;
+ continue;
+ }
+ if (arg == "-driven") {
+ driven_mode = true;
+ continue;
+ }
+ if (arg == "-purge") {
+ purge_mode = true;
+ continue;
+ }
+ if (arg == "-attr" && argidx+1 < args.size()) {
+ attrnames.insert(RTLIL::escape_id(args[++argidx]));
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ dict<SigBit, pool<Cell*>> net2cells;
+ SigMap sigmap(module);
+
+ for (auto cell : module->selected_cells())
+ for (auto &conn : cell->connections())
+ if (driven_mode) {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ net2cells[bit].insert(cell);
+ } else {
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ net2cells[bit].insert(cell);
+ }
+
+ for (auto wire : module->selected_wires())
+ {
+ dict<IdString, Const> new_attributes;
+
+ for (auto attr : wire->attributes)
+ {
+ bool did_something = false;
+
+ if (!attrnames.count(attr.first)) {
+ new_attributes[attr.first] = attr.second;
+ continue;
+ }
+
+ for (auto bit : sigmap(wire))
+ if (net2cells.count(bit))
+ for (auto cell : net2cells.at(bit)) {
+ log("Moving attribute %s=%s from %s.%s to %s.%s.\n", log_id(attr.first), log_const(attr.second),
+ log_id(module), log_id(wire), log_id(module), log_id(cell));
+ cell->attributes[attr.first] = attr.second;
+ did_something = true;
+ }
+
+ if (!purge_mode && !did_something)
+ new_attributes[attr.first] = attr.second;
+ }
+
+ if (!copy_mode)
+ wire->attributes.swap(new_attributes);
+ }
+ }
+ }
+} AttrmvcpPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
new file mode 100644
index 00000000..ed4e4576
--- /dev/null
+++ b/passes/techmap/deminout.cc
@@ -0,0 +1,116 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct DeminoutPass : public Pass {
+ DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" deminout [options] [selection]\n");
+ log("\n");
+ log("\"Demote\" inout ports to input or output ports, if possible.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-bits") {
+ // flag_bits = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ bool keep_running = true;
+
+ while (keep_running)
+ {
+ keep_running = false;
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ pool<SigBit> bits_written, bits_used, bits_inout;
+ dict<SigBit, int> bits_numports;
+
+ for (auto wire : module->wires())
+ if (wire->port_id)
+ for (auto bit : sigmap(wire))
+ bits_numports[bit]++;
+
+ for (auto cell : module->cells())
+ for (auto &conn : cell->connections())
+ {
+ bool cellport_out = cell->output(conn.first) || !cell->known();
+ bool cellport_in = cell->input(conn.first) || !cell->known();
+
+ if (cellport_out && cellport_in)
+ for (auto bit : sigmap(conn.second))
+ bits_inout.insert(bit);
+
+ if (cellport_out)
+ for (auto bit : sigmap(conn.second))
+ bits_written.insert(bit);
+
+ if (cellport_in)
+ for (auto bit : sigmap(conn.second))
+ bits_used.insert(bit);
+ }
+
+ for (auto wire : module->selected_wires())
+ if (wire->port_input && wire->port_output)
+ {
+ bool new_input = false;
+ bool new_output = false;
+
+ for (auto bit : sigmap(wire))
+ {
+ if (bits_numports[bit] > 1 || bits_inout.count(bit))
+ new_input = true, new_output = true;
+
+ if (bits_written.count(bit))
+ new_output = true;
+ else if (bits_used.count(bit))
+ new_input = true;
+ }
+
+ if (new_input != new_output) {
+ log("Demoting inout port %s.%s to %s.\n", log_id(module), log_id(wire), new_input ? "input" : "output");
+ wire->port_input = new_input;
+ wire->port_output = new_output;
+ keep_running = true;
+ }
+ }
+ }
+ }
+ }
+} DeminoutPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 51bfaade..1b8920bb 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -285,7 +285,7 @@ struct Dff2dffePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
+ log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
bool unmap_mode = false;
dict<IdString, IdString> direct_dict;
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index e0273f43..d737b342 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -41,7 +41,7 @@ struct DffinitPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFFINIT pass (set INIT param on FF cells).\n");
+ log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n");
dict<IdString, dict<IdString, IdString>> ff_types;
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 4d7a1a70..c8104fb7 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -108,6 +108,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
+ bool best_cell_noninv = false;
double best_cell_area = 0;
if (ast->id != "library")
@@ -155,6 +156,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
int num_pins = 0;
bool found_output = false;
+ bool found_noninv_output = false;
for (auto pin : cell->children)
{
if (pin->id != "pin" || pin->args.size() != 1)
@@ -175,10 +177,14 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
value.erase(pos, 1);
if (value == ff->args[0]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
+ if (cell_next_pol)
+ found_noninv_output = true;
found_output = true;
} else
if (value == ff->args[1]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
+ if (!cell_next_pol)
+ found_noninv_output = true;
found_output = true;
}
}
@@ -187,7 +193,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
this_cell_ports[pin->args[0]] = 0;
}
- if (!found_output || (best_cell != NULL && num_pins > best_cell_pins))
+ if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
continue;
if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
@@ -196,12 +202,14 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool
best_cell = cell;
best_cell_pins = num_pins;
best_cell_area = area;
+ best_cell_noninv = found_noninv_output;
best_cell_ports.swap(this_cell_ports);
continue_cell_loop:;
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
+ best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
if (prepare_mode) {
cell_mappings[cell_type].cell_name = cell_type;
cell_mappings[cell_type].ports["C"] = 'C';
@@ -221,6 +229,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
LibertyAst *best_cell = NULL;
std::map<std::string, char> best_cell_ports;
int best_cell_pins = 0;
+ bool best_cell_noninv = false;
double best_cell_area = 0;
if (ast->id != "library")
@@ -260,6 +269,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
int num_pins = 0;
bool found_output = false;
+ bool found_noninv_output = false;
for (auto pin : cell->children)
{
if (pin->id != "pin" || pin->args.size() != 1)
@@ -280,10 +290,14 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
value.erase(pos, 1);
if (value == ff->args[0]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
+ if (cell_next_pol)
+ found_noninv_output = true;
found_output = true;
} else
if (value == ff->args[1]) {
this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
+ if (!cell_next_pol)
+ found_noninv_output = true;
found_output = true;
}
}
@@ -292,7 +306,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
this_cell_ports[pin->args[0]] = 0;
}
- if (!found_output || (best_cell != NULL && num_pins > best_cell_pins))
+ if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
continue;
if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
@@ -301,12 +315,14 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
best_cell = cell;
best_cell_pins = num_pins;
best_cell_area = area;
+ best_cell_noninv = found_noninv_output;
best_cell_ports.swap(this_cell_ports);
continue_cell_loop:;
}
if (best_cell != NULL) {
- log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str());
+ log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
+ best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
if (prepare_mode) {
cell_mappings[cell_type].cell_name = cell_type;
cell_mappings[cell_type].ports["C"] = 'C';
@@ -531,7 +547,7 @@ struct DfflibmapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
+ log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
std::string liberty_file;
bool prepare_mode = false;
diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc
index 8dcbb4ed..0d4d5362 100644
--- a/passes/techmap/dffsr2dff.cc
+++ b/passes/techmap/dffsr2dff.cc
@@ -188,7 +188,7 @@ struct Dffsr2dffPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
+ log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index fc73177c..71e29c60 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -442,7 +442,7 @@ struct ExtractPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing EXTRACT pass (map subcircuits to cells).\n");
+ log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n");
log_push();
SubCircuitSolver solver;
@@ -627,7 +627,7 @@ struct ExtractPass : public Pass {
std::map<std::string, RTLIL::Module*> needle_map, haystack_map;
std::vector<RTLIL::Module*> needle_list;
- log_header("Creating graphs for SubCircuit library.\n");
+ log_header(design, "Creating graphs for SubCircuit library.\n");
if (!mine_mode)
for (auto &mod_it : map->modules_) {
@@ -654,7 +654,7 @@ struct ExtractPass : public Pass {
if (!mine_mode)
{
std::vector<SubCircuit::Solver::Result> results;
- log_header("Running solver from SubCircuit library.\n");
+ log_header(design, "Running solver from SubCircuit library.\n");
std::sort(needle_list.begin(), needle_list.end(), compareSortNeedleList);
@@ -667,7 +667,7 @@ struct ExtractPass : public Pass {
if (results.size() > 0)
{
- log_header("Substitute SubCircuits with cells.\n");
+ log_header(design, "Substitute SubCircuits with cells.\n");
for (int i = 0; i < int(results.size()); i++) {
auto &result = results[i];
@@ -688,7 +688,7 @@ struct ExtractPass : public Pass {
{
std::vector<SubCircuit::Solver::MineResult> results;
- log_header("Running miner from SubCircuit library.\n");
+ log_header(design, "Running miner from SubCircuit library.\n");
solver.mine(results, mine_cells_min, mine_cells_max, mine_min_freq, mine_limit_mod);
map = new RTLIL::Design;
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index a0bd2f9a..82cecac2 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -76,7 +76,7 @@ struct HilomapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing HILOMAP pass (mapping to constant drivers).\n");
+ log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n");
hicell_celltype = std::string();
hicell_portname = std::string();
diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc
new file mode 100644
index 00000000..aa81468d
--- /dev/null
+++ b/passes/techmap/insbuf.cc
@@ -0,0 +1,94 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct InsbufPass : public Pass {
+ InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" insbuf [options] [selection]\n");
+ log("\n");
+ log("Insert buffer cells into the design for directly connected wires.\n");
+ log("\n");
+ log(" -buf <celltype> <in-portname> <out-portname>\n");
+ log(" Use the given cell type instead of $_BUF_. (Notice that the next\n");
+ log(" call to \"clean\" will remove all $_BUF_ in the design.)\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n");
+
+ std::string celltype = "$_BUF_", in_portname = "\\A", out_portname = "\\Y";
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ std::string arg = args[argidx];
+ if (arg == "-buf" && argidx+3 < args.size()) {
+ celltype = args[++argidx];
+ in_portname = args[++argidx];
+ out_portname = args[++argidx];
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ std::vector<RTLIL::SigSig> new_connections;
+
+ for (auto &conn : module->connections())
+ {
+ RTLIL::SigSig new_conn;
+
+ for (int i = 0; i < GetSize(conn.first); i++)
+ {
+ SigBit lhs = conn.first[i];
+ SigBit rhs = conn.second[i];
+
+ if (lhs.wire && !design->selected(module, lhs.wire)) {
+ new_conn.first.append(lhs);
+ new_conn.second.append(rhs);
+ continue;
+ }
+
+ Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
+ cell->setPort(RTLIL::escape_id(in_portname), rhs);
+ cell->setPort(RTLIL::escape_id(out_portname), lhs);
+ log("Added %s.%s: %s -> %s\n", log_id(module), log_id(cell), log_signal(rhs), log_signal(lhs));
+ }
+
+ if (GetSize(new_conn.first))
+ new_connections.push_back(new_conn);
+ }
+
+ module->new_connections(new_connections);
+ }
+ }
+} InsbufPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 9dab40ca..4acbf7c0 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -17,9 +17,8 @@
*
*/
-#include "kernel/register.h"
-#include "kernel/rtlil.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -48,12 +47,23 @@ struct IopadmapPass : public Pass {
log(" Map module input ports to the given cell type with the\n");
log(" given output port name. if a 2nd portname is given, the\n");
log(" signal is passed through the pad call, using the 2nd\n");
- log(" portname as input.\n");
+ log(" portname as the port facing the module port.\n");
log("\n");
log(" -outpad <celltype> <portname>[:<portname>]\n");
log(" -inoutpad <celltype> <portname>[:<portname>]\n");
log(" Similar to -inpad, but for output and inout ports.\n");
log("\n");
+ log(" -toutpad <celltype> <portname>:<portname>[:<portname>]\n");
+ log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n");
+ log(" over the other -outpad cell. The first portname is the enable input\n");
+ log(" of the tristate driver.\n");
+ log("\n");
+ log(" -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n");
+ log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n");
+ log(" over the other -inoutpad cell. The first portname is the enable input\n");
+ log(" of the tristate driver and the 2nd portname is the internal output\n");
+ log(" buffering the external signal.\n");
+ log("\n");
log(" -widthparam <param_name>\n");
log(" Use the specified parameter name to set the port width.\n");
log("\n");
@@ -65,14 +75,18 @@ struct IopadmapPass : public Pass {
log(" are wider. (the default behavior is to create word-wide\n");
log(" buffers using -widthparam to set the word size on the cell.)\n");
log("\n");
+ log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
+ log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n");
std::string inpad_celltype, inpad_portname, inpad_portname2;
std::string outpad_celltype, outpad_portname, outpad_portname2;
std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2;
+ std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3;
+ std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4;
std::string widthparam, nameparam;
bool flag_bits = false;
@@ -98,6 +112,21 @@ struct IopadmapPass : public Pass {
split_portname_pair(inoutpad_portname, inoutpad_portname2);
continue;
}
+ if (arg == "-toutpad" && argidx+2 < args.size()) {
+ toutpad_celltype = args[++argidx];
+ toutpad_portname = args[++argidx];
+ split_portname_pair(toutpad_portname, toutpad_portname2);
+ split_portname_pair(toutpad_portname2, toutpad_portname3);
+ continue;
+ }
+ if (arg == "-tinoutpad" && argidx+2 < args.size()) {
+ tinoutpad_celltype = args[++argidx];
+ tinoutpad_portname = args[++argidx];
+ split_portname_pair(tinoutpad_portname, tinoutpad_portname2);
+ split_portname_pair(tinoutpad_portname2, tinoutpad_portname3);
+ split_portname_pair(tinoutpad_portname3, tinoutpad_portname4);
+ continue;
+ }
if (arg == "-widthparam" && argidx+1 < args.size()) {
widthparam = args[++argidx];
continue;
@@ -116,12 +145,132 @@ struct IopadmapPass : public Pass {
for (auto module : design->selected_modules())
{
+ dict<IdString, pool<int>> skip_wires;
+
+ if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
+
+ for (auto cell : module->cells())
+ if (cell->type == "$_TBUF_") {
+ SigBit bit = sigmap(cell->getPort("\\Y").as_bit());
+ tbuf_bits[bit].first = cell->name;
+ }
+
+ for (auto cell : module->cells())
+ for (auto port : cell->connections())
+ for (auto bit : sigmap(port.second))
+ if (tbuf_bits.count(bit))
+ tbuf_bits.at(bit).second.insert(cell->name);
+
+ for (auto wire : module->selected_wires())
+ {
+ if (!wire->port_output)
+ continue;
+
+ for (int i = 0; i < GetSize(wire); i++)
+ {
+ SigBit wire_bit(wire, i);
+ SigBit mapped_wire_bit = sigmap(wire_bit);
+
+ if (tbuf_bits.count(mapped_wire_bit) == 0)
+ continue;
+
+ auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit);
+ Cell *tbuf_cell = module->cell(tbuf_cache.first);
+
+ if (tbuf_cell == nullptr)
+ continue;
+
+ SigBit en_sig = tbuf_cell->getPort("\\E").as_bit();
+ SigBit data_sig = tbuf_cell->getPort("\\A").as_bit();
+
+ if (wire->port_input && !tinoutpad_celltype.empty())
+ {
+ log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, tinoutpad_celltype.c_str());
+
+ Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(tinoutpad_celltype));
+ Wire *owire = module->addWire(NEW_ID);
+
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname), en_sig);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname2), owire);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname3), data_sig);
+ cell->setPort(RTLIL::escape_id(tinoutpad_portname4), wire_bit);
+ cell->attributes["\\keep"] = RTLIL::Const(1);
+
+ for (auto cn : tbuf_cache.second) {
+ auto c = module->cell(cn);
+ if (c == nullptr)
+ continue;
+ for (auto port : c->connections()) {
+ SigSpec sig = port.second;
+ bool newsig = false;
+ for (auto &bit : sig)
+ if (sigmap(bit) == mapped_wire_bit) {
+ bit = owire;
+ newsig = true;
+ }
+ if (newsig)
+ c->setPort(port.first, sig);
+ }
+ }
+
+
+ module->remove(tbuf_cell);
+ skip_wires[wire->name].insert(i);
+ continue;
+ }
+
+ if (!wire->port_input && !toutpad_celltype.empty())
+ {
+ log("Mapping port %s.%s[%d] using %s.\n", log_id(module), log_id(wire), i, toutpad_celltype.c_str());
+
+ Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(toutpad_celltype));
+
+ cell->setPort(RTLIL::escape_id(toutpad_portname), en_sig);
+ cell->setPort(RTLIL::escape_id(toutpad_portname2), data_sig);
+ cell->setPort(RTLIL::escape_id(toutpad_portname3), wire_bit);
+ cell->attributes["\\keep"] = RTLIL::Const(1);
+
+ for (auto cn : tbuf_cache.second) {
+ auto c = module->cell(cn);
+ if (c == nullptr)
+ continue;
+ for (auto port : c->connections()) {
+ SigSpec sig = port.second;
+ bool newsig = false;
+ for (auto &bit : sig)
+ if (sigmap(bit) == mapped_wire_bit) {
+ bit = data_sig;
+ newsig = true;
+ }
+ if (newsig)
+ c->setPort(port.first, sig);
+ }
+ }
+
+ module->remove(tbuf_cell);
+ skip_wires[wire->name].insert(i);
+ continue;
+ }
+ }
+ }
+ }
+
for (auto wire : module->selected_wires())
{
if (!wire->port_id)
continue;
std::string celltype, portname, portname2;
+ pool<int> skip_bit_indices;
+
+ if (skip_wires.count(wire->name)) {
+ if (!flag_bits)
+ continue;
+ skip_bit_indices = skip_wires.at(wire->name);
+ }
if (wire->port_input && !wire->port_output) {
if (inpad_celltype.empty()) {
@@ -163,12 +312,21 @@ struct IopadmapPass : public Pass {
if (!portname2.empty()) {
new_wire = module->addWire(NEW_ID, wire);
module->swap_names(new_wire, wire);
+ wire->attributes.clear();
}
if (flag_bits)
{
for (int i = 0; i < wire->width; i++)
{
+ if (skip_bit_indices.count(i)) {
+ if (wire->port_output)
+ module->connect(SigSpec(new_wire, i), SigSpec(wire, i));
+ else
+ module->connect(SigSpec(wire, i), SigSpec(new_wire, i));
+ continue;
+ }
+
RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype));
cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i));
if (!portname2.empty())
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index fe55e499..2bb0bd8b 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -67,7 +67,7 @@ struct Lut2muxPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing LUT2MUX pass (mapping to constant drivers).\n");
+ log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index d5b8fe80..32569d07 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -379,7 +379,7 @@ struct MaccmapPass : public Pass {
{
bool unmap_mode = false;
- log_header("Executing MACCMAP pass (map $macc cells).\n");
+ log_header(design, "Executing MACCMAP pass (map $macc cells).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 514c3365..1dc64958 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -581,7 +581,7 @@ struct MuxcoverPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing MUXCOVER pass (mapping to wider MUXes).\n");
+ log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n");
bool use_mux4 = false;
bool use_mux8 = false;
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index 7ece4005..6fcdf82b 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -26,6 +26,7 @@ PRIVATE_NAMESPACE_BEGIN
struct NlutmapConfig
{
vector<int> luts;
+ bool assert_mode = false;
};
struct NlutmapWorker
@@ -64,7 +65,7 @@ struct NlutmapWorker
{
vector<int> available_luts = config.luts;
- while (!available_luts.empty())
+ while (GetSize(available_luts) > 1)
{
int n_luts = available_luts.back();
int lut_size = GetSize(available_luts);
@@ -84,7 +85,7 @@ struct NlutmapWorker
if (cell->type != "$lut" || mapped_cells.count(cell))
continue;
- if (GetSize(cell->getPort("\\A")) == lut_size)
+ if (GetSize(cell->getPort("\\A")) == lut_size || lut_size == 2)
candidate_ratings[cell] = 0;
for (auto &conn : cell->connections())
@@ -116,6 +117,12 @@ struct NlutmapWorker
available_luts.back() += n_luts;
}
+ if (config.assert_mode) {
+ for (auto cell : module->cells())
+ if (cell->type == "$lut" && !mapped_cells.count(cell))
+ log_error("Insufficient number of LUTs to map all logic cells!\n");
+ }
+
run_abc(0);
}
};
@@ -135,6 +142,9 @@ struct NlutmapPass : public Pass {
log(" The number of LUTs with 1, 2, 3, ... inputs that are\n");
log(" available in the target architecture.\n");
log("\n");
+ log(" -assert\n");
+ log(" Create an error if not all logic can be mapped\n");
+ log("\n");
log("Excess logic that does not fit into the specified LUTs is mapped back\n");
log("to generic logic gates ($_AND_, etc.).\n");
log("\n");
@@ -143,7 +153,7 @@ struct NlutmapPass : public Pass {
{
NlutmapConfig config;
- log_header("Executing NLUTMAP pass (mapping to constant drivers).\n");
+ log_header(design, "Executing NLUTMAP pass (mapping to constant drivers).\n");
log_push();
size_t argidx;
@@ -156,6 +166,10 @@ struct NlutmapPass : public Pass {
config.luts.push_back(atoi(token.c_str()));
continue;
}
+ if (args[argidx] == "-assert") {
+ config.assert_mode = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index 3c12bfd0..c626dbcc 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -78,7 +78,7 @@ struct PmuxtreePass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing PMUXTREE pass.\n");
+ log_header(design, "Executing PMUXTREE pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
new file mode 100644
index 00000000..6936b499
--- /dev/null
+++ b/passes/techmap/shregmap.cc
@@ -0,0 +1,584 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ShregmapTech
+{
+ virtual ~ShregmapTech() { }
+ virtual bool analyze(vector<int> &taps) = 0;
+ virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
+};
+
+struct ShregmapOptions
+{
+ int minlen, maxlen;
+ int keep_before, keep_after;
+ bool zinit, init, params, ffe;
+ dict<IdString, pair<IdString, IdString>> ffcells;
+ ShregmapTech *tech;
+
+ ShregmapOptions()
+ {
+ minlen = 2;
+ maxlen = 0;
+ keep_before = 0;
+ keep_after = 0;
+ zinit = false;
+ init = false;
+ params = false;
+ ffe = false;
+ tech = nullptr;
+ }
+};
+
+struct ShregmapTechGreenpak4 : ShregmapTech
+{
+ bool analyze(vector<int> &taps)
+ {
+ if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
+ taps.clear();
+ return true;
+ }
+
+ if (GetSize(taps) > 2)
+ return false;
+
+ if (taps.back() > 16) return false;
+
+ return true;
+ }
+
+ bool fixup(Cell *cell, dict<int, SigBit> &taps)
+ {
+ auto D = cell->getPort("\\D");
+ auto C = cell->getPort("\\C");
+
+ auto newcell = cell->module->addCell(NEW_ID, "\\GP_SHREG");
+ newcell->setPort("\\nRST", State::S1);
+ newcell->setPort("\\CLK", C);
+ newcell->setPort("\\IN", D);
+
+ int i = 0;
+ for (auto tap : taps) {
+ newcell->setPort(i ? "\\OUTB" : "\\OUTA", tap.second);
+ newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap.first + 1);
+ i++;
+ }
+
+ cell->setParam("\\OUTA_INVERT", 0);
+ return false;
+ }
+};
+
+struct ShregmapWorker
+{
+ Module *module;
+ SigMap sigmap;
+
+ const ShregmapOptions &opts;
+ int dff_count, shreg_count;
+
+ pool<Cell*> remove_cells;
+ pool<SigBit> remove_init;
+
+ dict<SigBit, bool> sigbit_init;
+ dict<SigBit, Cell*> sigbit_chain_next;
+ dict<SigBit, Cell*> sigbit_chain_prev;
+ pool<SigBit> sigbit_with_non_chain_users;
+ pool<Cell*> chain_start_cells;
+
+ void make_sigbit_chain_next_prev()
+ {
+ for (auto wire : module->wires())
+ {
+ if (wire->port_output || wire->get_bool_attribute("\\keep")) {
+ for (auto bit : sigmap(wire))
+ sigbit_with_non_chain_users.insert(bit);
+ }
+
+ if (wire->attributes.count("\\init")) {
+ SigSpec initsig = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 && !opts.zinit)
+ sigbit_init[initsig[i]] = false;
+ else if (initval[i] == State::S1)
+ sigbit_init[initsig[i]] = true;
+ }
+ }
+
+ for (auto cell : module->cells())
+ {
+ if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep"))
+ {
+ IdString d_port = opts.ffcells.at(cell->type).first;
+ IdString q_port = opts.ffcells.at(cell->type).second;
+
+ SigBit d_bit = sigmap(cell->getPort(d_port).as_bit());
+ SigBit q_bit = sigmap(cell->getPort(q_port).as_bit());
+
+ if (opts.init || sigbit_init.count(q_bit) == 0)
+ {
+ if (sigbit_chain_next.count(d_bit)) {
+ sigbit_with_non_chain_users.insert(d_bit);
+ } else
+ sigbit_chain_next[d_bit] = cell;
+
+ sigbit_chain_prev[q_bit] = cell;
+ continue;
+ }
+ }
+
+ for (auto conn : cell->connections())
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ sigbit_with_non_chain_users.insert(bit);
+ }
+ }
+
+ void find_chain_start_cells()
+ {
+ for (auto it : sigbit_chain_next)
+ {
+ if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first))
+ goto start_cell;
+
+ if (sigbit_chain_prev.count(it.first) != 0)
+ {
+ Cell *c1 = sigbit_chain_prev.at(it.first);
+ Cell *c2 = it.second;
+
+ if (c1->type != c2->type)
+ goto start_cell;
+
+ if (c1->parameters != c2->parameters)
+ goto start_cell;
+
+ IdString d_port = opts.ffcells.at(c1->type).first;
+ IdString q_port = opts.ffcells.at(c1->type).second;
+
+ auto c1_conn = c1->connections();
+ auto c2_conn = c1->connections();
+
+ c1_conn.erase(d_port);
+ c1_conn.erase(q_port);
+
+ c2_conn.erase(d_port);
+ c2_conn.erase(q_port);
+
+ if (c1_conn != c2_conn)
+ goto start_cell;
+
+ continue;
+ }
+
+ start_cell:
+ chain_start_cells.insert(it.second);
+ }
+ }
+
+ vector<Cell*> create_chain(Cell *start_cell)
+ {
+ vector<Cell*> chain;
+
+ Cell *c = start_cell;
+ while (c != nullptr)
+ {
+ chain.push_back(c);
+
+ IdString q_port = opts.ffcells.at(c->type).second;
+ SigBit q_bit = sigmap(c->getPort(q_port).as_bit());
+
+ if (sigbit_chain_next.count(q_bit) == 0)
+ break;
+
+ c = sigbit_chain_next.at(q_bit);
+ if (chain_start_cells.count(c) != 0)
+ break;
+ }
+
+ return chain;
+ }
+
+ void process_chain(vector<Cell*> &chain)
+ {
+ if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after)
+ return;
+
+ int cursor = opts.keep_before;
+ while (cursor < GetSize(chain) - opts.keep_after)
+ {
+ int depth = GetSize(chain) - opts.keep_after - cursor;
+
+ if (opts.maxlen > 0)
+ depth = std::min(opts.maxlen, depth);
+
+ Cell *first_cell = chain[cursor];
+ IdString q_port = opts.ffcells.at(first_cell->type).second;
+ dict<int, SigBit> taps_dict;
+
+ if (opts.tech)
+ {
+ vector<SigBit> qbits;
+ vector<int> taps;
+
+ for (int i = 0; i < depth; i++)
+ {
+ Cell *cell = chain[cursor+i];
+ auto qbit = sigmap(cell->getPort(q_port));
+ qbits.push_back(qbit);
+
+ if (sigbit_with_non_chain_users.count(qbit))
+ taps.push_back(i);
+ }
+
+ while (depth > 0)
+ {
+ if (taps.empty() || taps.back() < depth-1)
+ taps.push_back(depth-1);
+
+ if (opts.tech->analyze(taps))
+ break;
+
+ taps.pop_back();
+ depth--;
+ }
+
+ depth = 0;
+ for (auto tap : taps) {
+ taps_dict[tap] = qbits.at(tap);
+ log_assert(depth < tap+1);
+ depth = tap+1;
+ }
+ }
+
+ if (depth < 2) {
+ cursor++;
+ continue;
+ }
+
+ Cell *last_cell = chain[cursor+depth-1];
+
+ log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n",
+ log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth);
+
+ dff_count += depth;
+ shreg_count += 1;
+
+ string shreg_cell_type_str = "$__SHREG";
+ if (opts.params) {
+ shreg_cell_type_str += "_";
+ } else {
+ if (first_cell->type[1] != '_')
+ shreg_cell_type_str += "_";
+ shreg_cell_type_str += first_cell->type.substr(1);
+ }
+
+ if (opts.init) {
+ vector<State> initval;
+ for (int i = depth-1; i >= 0; i--) {
+ SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit());
+ if (sigbit_init.count(bit) == 0)
+ initval.push_back(State::Sx);
+ else if (sigbit_init.at(bit))
+ initval.push_back(State::S1);
+ else
+ initval.push_back(State::S0);
+ remove_init.insert(bit);
+ }
+ first_cell->setParam("\\INIT", initval);
+ }
+
+ if (opts.zinit)
+ for (int i = depth-1; i >= 0; i--) {
+ SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit());
+ remove_init.insert(bit);
+ }
+
+ if (opts.params)
+ {
+ int param_clkpol = -1;
+ int param_enpol = 2;
+
+ if (first_cell->type == "$_DFF_N_") param_clkpol = 0;
+ if (first_cell->type == "$_DFF_P_") param_clkpol = 1;
+
+ if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0;
+ if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1;
+ if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0;
+ if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1;
+
+ log_assert(param_clkpol >= 0);
+ first_cell->setParam("\\CLKPOL", param_clkpol);
+ if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol);
+ }
+
+ first_cell->type = shreg_cell_type_str;
+ first_cell->setPort(q_port, last_cell->getPort(q_port));
+ first_cell->setParam("\\DEPTH", depth);
+
+ if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict))
+ remove_cells.insert(first_cell);
+
+ for (int i = 1; i < depth; i++)
+ remove_cells.insert(chain[cursor+i]);
+ cursor += depth;
+ }
+ }
+
+ void cleanup()
+ {
+ for (auto cell : remove_cells)
+ module->remove(cell);
+
+ for (auto wire : module->wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec initsig = sigmap(wire);
+ Const &initval = wire->attributes.at("\\init");
+
+ for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+ if (remove_init.count(initsig[i]))
+ initval[i] = State::Sx;
+
+ if (SigSpec(initval).is_fully_undef())
+ wire->attributes.erase("\\init");
+ }
+
+ remove_cells.clear();
+ sigbit_chain_next.clear();
+ sigbit_chain_prev.clear();
+ chain_start_cells.clear();
+ }
+
+ ShregmapWorker(Module *module, const ShregmapOptions &opts) :
+ module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
+ {
+ make_sigbit_chain_next_prev();
+ find_chain_start_cells();
+
+ for (auto c : chain_start_cells) {
+ vector<Cell*> chain = create_chain(c);
+ process_chain(chain);
+ }
+
+ cleanup();
+ }
+};
+
+struct ShregmapPass : public Pass {
+ ShregmapPass() : Pass("shregmap", "map shift registers") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" shregmap [options] [selection]\n");
+ log("\n");
+ log("This pass converts chains of $_DFF_[NP]_ gates to target specific shift register\n");
+ log("primitives. The generated shift register will be of type $__SHREG_DFF_[NP]_ and\n");
+ log("will use the same interface as the original $_DFF_*_ cells. The cell parameter\n");
+ log("'DEPTH' will contain the depth of the shift register. Use a target-specific\n");
+ log("'techmap' map file to convert those cells to the actual target cells.\n");
+ log("\n");
+ log(" -minlen N\n");
+ log(" minimum length of shift register (default = 2)\n");
+ log(" (this is the length after -keep_before and -keep_after)\n");
+ log("\n");
+ log(" -maxlen N\n");
+ log(" maximum length of shift register (default = no limit)\n");
+ log(" larger chains will be mapped to multiple shift register instances\n");
+ log("\n");
+ log(" -keep_before N\n");
+ log(" number of DFFs to keep before the shift register (default = 0)\n");
+ log("\n");
+ log(" -keep_after N\n");
+ log(" number of DFFs to keep after the shift register (default = 0)\n");
+ log("\n");
+ log(" -clkpol pos|neg|any\n");
+ log(" limit match to only positive or negative edge clocks. (default = any)\n");
+ log("\n");
+ log(" -enpol pos|neg|none|any_or_none|any\n");
+ log(" limit match to FFs with the specified enable polarity. (default = none)\n");
+ log("\n");
+ log(" -match <cell_type>[:<d_port_name>:<q_port_name>]\n");
+ log(" match the specified cells instead of $_DFF_N_ and $_DFF_P_. If\n");
+ log(" ':<d_port_name>:<q_port_name>' is omitted then 'D' and 'Q' is used\n");
+ log(" by default. E.g. the option '-clkpol pos' is just an alias for\n");
+ log(" '-match $_DFF_P_', which is an alias for '-match $_DFF_P_:D:Q'.\n");
+ log("\n");
+ log(" -params\n");
+ log(" instead of encoding the clock and enable polarity in the cell name by\n");
+ log(" deriving from the original cell name, simply name all generated cells\n");
+ log(" $__SHREG_ and use CLKPOL and ENPOL parameters. An ENPOL value of 2 is\n");
+ log(" used to denote cells without enable input. The ENPOL parameter is\n");
+ log(" omitted when '-enpol none' (or no -enpol option) is passed.\n");
+ log("\n");
+ log(" -zinit\n");
+ log(" assume the shift register is automatically zero-initialized, so it\n");
+ log(" becomes legal to merge zero initialized FFs into the shift register.\n");
+ log("\n");
+ log(" -init\n");
+ log(" map initialized registers to the shift reg, add an INIT parameter to\n");
+ log(" generated cells with the initialization value. (first bit to shift out\n");
+ log(" in LSB position)\n");
+ log("\n");
+ log(" -tech greenpak4\n");
+ log(" map to greenpak4 shift registers.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ ShregmapOptions opts;
+ string clkpol, enpol;
+
+ log_header(design, "Executing SHREGMAP pass (map shift registers).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-clkpol" && argidx+1 < args.size()) {
+ clkpol = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-enpol" && argidx+1 < args.size()) {
+ enpol = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-match" && argidx+1 < args.size()) {
+ vector<string> match_args = split_tokens(args[++argidx], ":");
+ if (GetSize(match_args) < 2)
+ match_args.push_back("D");
+ if (GetSize(match_args) < 3)
+ match_args.push_back("Q");
+ IdString id_cell_type(RTLIL::escape_id(match_args[0]));
+ IdString id_d_port_name(RTLIL::escape_id(match_args[1]));
+ IdString id_q_port_name(RTLIL::escape_id(match_args[2]));
+ opts.ffcells[id_cell_type] = make_pair(id_d_port_name, id_q_port_name);
+ continue;
+ }
+ if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
+ opts.minlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-maxlen" && argidx+1 < args.size()) {
+ opts.maxlen = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-keep_before" && argidx+1 < args.size()) {
+ opts.keep_before = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-keep_after" && argidx+1 < args.size()) {
+ opts.keep_after = atoi(args[++argidx].c_str());
+ continue;
+ }
+ if (args[argidx] == "-tech" && argidx+1 < args.size() && opts.tech == nullptr) {
+ string tech = args[++argidx];
+ if (tech == "greenpak4") {
+ clkpol = "pos";
+ opts.zinit = true;
+ opts.tech = new ShregmapTechGreenpak4;
+ } else {
+ argidx--;
+ break;
+ }
+ continue;
+ }
+ if (args[argidx] == "-zinit") {
+ opts.zinit = true;
+ continue;
+ }
+ if (args[argidx] == "-init") {
+ opts.init = true;
+ continue;
+ }
+ if (args[argidx] == "-params") {
+ opts.params = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (opts.zinit && opts.init)
+ log_cmd_error("Options -zinit and -init are exclusive!\n");
+
+ if (opts.ffcells.empty())
+ {
+ bool clk_pos = clkpol == "" || clkpol == "pos" || clkpol == "any";
+ bool clk_neg = clkpol == "" || clkpol == "neg" || clkpol == "any";
+
+ bool en_none = enpol == "" || enpol == "none" || enpol == "any_or_none";
+ bool en_pos = enpol == "pos" || enpol == "any" || enpol == "any_or_none";
+ bool en_neg = enpol == "neg" || enpol == "any" || enpol == "any_or_none";
+
+ if (clk_pos && en_none)
+ opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ if (clk_neg && en_none)
+ opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+
+ if (clk_pos && en_pos)
+ opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ if (clk_pos && en_neg)
+ opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+
+ if (clk_neg && en_pos)
+ opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+ if (clk_neg && en_neg)
+ opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q"));
+
+ if (en_pos || en_neg)
+ opts.ffe = true;
+ }
+ else
+ {
+ if (!clkpol.empty())
+ log_cmd_error("Options -clkpol and -match are exclusive!\n");
+ if (!enpol.empty())
+ log_cmd_error("Options -enpol and -match are exclusive!\n");
+ if (opts.params)
+ log_cmd_error("Options -params and -match are exclusive!\n");
+ }
+
+ int dff_count = 0;
+ int shreg_count = 0;
+
+ for (auto module : design->selected_modules()) {
+ ShregmapWorker worker(module, opts);
+ dff_count += worker.dff_count;
+ shreg_count += worker.shreg_count;
+ }
+
+ log("Converted %d dff cells into %d shift registers.\n", dff_count, shreg_count);
+
+ if (opts.tech != nullptr) {
+ delete opts.tech;
+ opts.tech = nullptr;
+ }
+ }
+} ShregmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index f6ac3964..0fb64734 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -321,6 +321,36 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(cell->getPort("\\Y"), lut_data);
}
+void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ SigSpec ctrl = cell->getPort("\\A");
+ SigSpec table = cell->getParam("\\TABLE");
+
+ int width = cell->getParam("\\WIDTH").as_int();
+ int depth = cell->getParam("\\DEPTH").as_int();
+ table.extend_u0(2 * width * depth);
+
+ SigSpec products;
+
+ for (int i = 0; i < depth; i++) {
+ SigSpec in, pat;
+ for (int j = 0; j < width; j++) {
+ if (table[2*i*width + 2*j + 0] == State::S1) {
+ in.append(ctrl[j]);
+ pat.append(State::S0);
+ }
+ if (table[2*i*width + 2*j + 1] == State::S1) {
+ in.append(ctrl[j]);
+ pat.append(State::S1);
+ }
+ }
+
+ products.append(GetSize(in) > 0 ? module->Eq(NEW_ID, in, pat) : State::S1);
+ }
+
+ module->connect(cell->getPort("\\Y"), module->ReduceOr(NEW_ID, products));
+}
+
void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
{
int offset = cell->parameters.at("\\OFFSET").as_int();
@@ -498,6 +528,7 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL
mappers["$mux"] = simplemap_mux;
mappers["$tribuf"] = simplemap_tribuf;
mappers["$lut"] = simplemap_lut;
+ mappers["$sop"] = simplemap_sop;
mappers["$slice"] = simplemap_slice;
mappers["$concat"] = simplemap_concat;
mappers["$sr"] = simplemap_sr;
@@ -543,7 +574,7 @@ struct SimplemapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
+ log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
extra_args(args, 1, design);
std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 5334ebfa..b2cc492b 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -234,8 +234,10 @@ struct TechmapWorker
tpl_written_bits.insert(bit);
SigMap port_signal_map;
+ SigSig port_signal_assign;
- for (auto &it : cell->connections()) {
+ for (auto &it : cell->connections())
+ {
RTLIL::IdString portname = it.first;
if (positional_ports.count(portname) > 0)
portname = positional_ports.at(portname);
@@ -244,16 +246,22 @@ struct TechmapWorker
log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str());
continue;
}
+
RTLIL::Wire *w = tpl->wires_.at(portname);
- RTLIL::SigSig c;
+ RTLIL::SigSig c, extra_connect;
+
if (w->port_output && !w->port_input) {
c.first = it.second;
c.second = RTLIL::SigSpec(w);
apply_prefix(cell->name.str(), c.second, module);
+ extra_connect.first = c.second;
+ extra_connect.second = c.first;
} else if (!w->port_output && w->port_input) {
c.first = RTLIL::SigSpec(w);
c.second = it.second;
apply_prefix(cell->name.str(), c.first, module);
+ extra_connect.first = c.first;
+ extra_connect.second = c.second;
} else {
SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second;
apply_prefix(cell->name.str(), sig_tpl_pf, module);
@@ -266,28 +274,48 @@ struct TechmapWorker
c.second.append(sig_mod[i]);
}
}
+ extra_connect.first = sig_tpl_pf;
+ extra_connect.second = sig_mod;
}
+
if (c.second.size() > c.first.size())
c.second.remove(c.first.size(), c.second.size() - c.first.size());
+
if (c.second.size() < c.first.size())
c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size()));
+
log_assert(c.first.size() == c.second.size());
- if (flatten_mode) {
+
+ if (flatten_mode)
+ {
// more conservative approach:
// connect internal and external wires
+
if (sigmaps.count(module) == 0)
sigmaps[module].set(module);
+
if (sigmaps.at(module)(c.first).has_const())
log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n",
log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second));
+
module->connect(c);
- } else {
+ }
+ else
+ {
// approach that yields nicer outputs:
// replace internal wires that are connected to external wires
+
if (w->port_output)
port_signal_map.add(c.second, c.first);
else
port_signal_map.add(c.first, c.second);
+
+ for (auto &attr : w->attributes) {
+ if (attr.first == "\\src")
+ continue;
+ module->connect(extra_connect);
+ break;
+ }
}
}
@@ -611,7 +639,7 @@ struct TechmapWorker
if (techmap_cache.count(key) > 0) {
tpl = techmap_cache[key];
} else {
- if (cell->parameters.size() != 0) {
+ if (parameters.size() != 0) {
derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name);
log_continue = true;
@@ -779,7 +807,7 @@ struct TechmapWorker
if (recursive_mode) {
if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
+ log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
}
while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
@@ -790,7 +818,7 @@ struct TechmapWorker
continue;
if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
+ log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
}
@@ -833,7 +861,7 @@ struct TechmapWorker
}
if (log_continue) {
- log_header("Continuing TECHMAP pass.\n");
+ log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
}
@@ -976,7 +1004,7 @@ struct TechmapPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing TECHMAP pass (map to technology primitives).\n");
+ log_header(design, "Executing TECHMAP pass (map to technology primitives).\n");
log_push();
TechmapWorker worker;
@@ -1108,7 +1136,7 @@ struct FlattenPass : public Pass {
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
- log_header("Executing FLATTEN pass (flatten design).\n");
+ log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
extra_args(args, 1, design);
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index d0564b4e..03629082 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -160,7 +160,7 @@ struct TribufPass : public Pass {
{
TribufConfig config;
- log_header("Executing TRIBUF pass.\n");
+ log_header(design, "Executing TRIBUF pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc
index bb516fca..cb31056f 100644
--- a/passes/tests/test_autotb.cc
+++ b/passes/tests/test_autotb.cc
@@ -71,16 +71,21 @@ static std::string idy(std::string str1, std::string str2 = std::string(), std::
return id(str1);
}
-static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
+static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int seed)
{
+ f << stringf("`ifndef outfile\n");
+ f << stringf("\t`define outfile \"/dev/stdout\"\n");
+ f << stringf("`endif\n");
+
f << stringf("module testbench;\n\n");
- f << stringf("integer i;\n\n");
+ f << stringf("integer i;\n");
+ f << stringf("integer file;\n\n");
f << stringf("reg [31:0] xorshift128_x = 123456789;\n");
f << stringf("reg [31:0] xorshift128_y = 362436069;\n");
f << stringf("reg [31:0] xorshift128_z = 521288629;\n");
- f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", int(time(NULL)));
+ f << stringf("reg [31:0] xorshift128_w = %u; // <-- seed value\n", seed ? seed : int(time(NULL)));
f << stringf("reg [31:0] xorshift128_t;\n\n");
f << stringf("task xorshift128;\n");
f << stringf("begin\n");
@@ -150,6 +155,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it)
f << stringf("\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
@@ -157,6 +163,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
delay_counter = 0;
for (auto it = signal_in.begin(); it != signal_in.end(); ++it)
f << stringf("\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
for (auto it = signal_clk.begin(); it != signal_clk.end(); ++it) {
f << stringf("\t#100; %s <= 1;\n", it->first.c_str());
f << stringf("\t#100; %s <= 0;\n", it->first.c_str());
@@ -167,6 +174,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
continue;
f << stringf("\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
}
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
f << stringf("end\n");
f << stringf("endtask\n\n");
@@ -179,6 +187,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("\txorshift128;\n");
f << stringf("\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
}
+ f << stringf("\t#%d;\n", ((2*delay_counter+99)/100)*100);
f << stringf("end\n");
f << stringf("endtask\n\n");
@@ -206,61 +215,70 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter)
f << stringf("task %s;\n", idy(mod->name.str(), "print_status").c_str());
f << stringf("begin\n");
- f << stringf("\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {");
+ f << stringf("\t$fdisplay(file, \"#OUT# %%b %%b %%b %%t %%d\", {");
if (signal_in.size())
for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
f << stringf("%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
int len = it->second;
+ header2 += ", \"";
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
+ header2 += "\"";
header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
+ header1.back()[0] = shorthand;
+ shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
}
else {
f << stringf(" 1'bx");
- header2 += "#";
+ header2 += ", \"#\"";
}
f << stringf(" }, {");
- header2 += " ";
+ header2 += ", \" \"";
if (signal_clk.size()) {
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
f << stringf("%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
int len = it->second;
+ header2 += ", \"";
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
+ header2 += "\"";
header1.push_back(" " + it->first);
- header1.back()[0] = shorthand++;
+ header1.back()[0] = shorthand;
+ shorthand = shorthand == 'Z' ? 'A' : shorthand+1;
}
} else {
f << stringf(" 1'bx");
- header2 += "#";
+ header2 += ", \"#\"";
}
f << stringf(" }, {");
- header2 += " ";
+ header2 += ", \" \"";
if (signal_out.size()) {
for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
f << stringf("%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
int len = it->second;
+ header2 += ", \"";
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len-