From 4f096fe65b77435daba019248273e547fa18d167 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Fri, 23 Sep 2016 07:09:40 +0200 Subject: Squashed commit of the following: commit 0c697b9eacacfebd69c9603c2cb79ec70311197d Author: Clifford Wolf Date: Tue Sep 20 09:29:56 2016 +0200 Added autotest.sh -I commit e788ad48855cf02ba426abef83077b7f4ec80fa3 Author: Clifford Wolf Date: Mon Sep 19 20:43:43 2016 +0200 Cosmetic fix in test_autotb.cc commit 2e244c2d8e8e57f185b4165267682536843c8616 Author: Clifford Wolf Date: Mon Sep 19 20:43:28 2016 +0200 Added yosys-smtbmc --noinfo and --dummy commit 5e155aa1214a586e0db50c27e9b487915032f08e Author: Clifford Wolf Date: Mon Sep 19 10:20:20 2016 +0200 Avoid creating very long strings in test_autotb commit aaa99c35bdcde8bec9d44ca23814f323a4e09c75 Author: Clifford Wolf Date: Mon Sep 19 01:30:07 2016 +0200 Added $past, $stable, $rose, $fell SVA functions commit d009cdd6eef5a24a11584a543bab8543f3940f6c Author: Clifford Wolf Date: Sun Sep 18 20:48:09 2016 +0200 Improved handling of SMT2 logics in yosys-smtbmc commit 13a03b84d402d4a9891e6513a44551572d3e92db Author: Clifford Wolf 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 Date: Sun Sep 18 00:50:02 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 7bc88e81010d5e641a55da9fb99724a90a2a4efa Author: Clifford Wolf Date: Sun Sep 18 00:48:36 2016 +0200 yosys-smtbmc: added -i support smtc files commit d8ad889594cb5746d3d0b1f7590eeaf63d13c64a Author: Clifford Wolf Date: Wed Sep 14 20:46:54 2016 +0200 Bugfix in techmap parameter handling commit d39db41df87113792c383fc2f127a3d42ae6dd0e Author: Clifford Wolf Date: Tue Sep 13 13:23:06 2016 +0200 Work-around for boolector bug commit d01e34136ecfecc3f155d3fe7c74e07346ecae4e Merge: 6f416c1 2c031cd Author: Clifford Wolf 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 Date: Tue Sep 13 13:13:27 2016 +0300 Fix for modules with big interfaces. commit 6f416c19537fcaab27b26d66c3144b468cec136a Author: Clifford Wolf Date: Sun Sep 11 18:08:56 2016 +0200 Added missing :produce-models setting to smtio.py commit 5199aafca0579aceb3b4a2ad1af610bcb4ccfcd1 Author: Clifford Wolf Date: Sat Sep 10 16:24:08 2016 +0200 Minor improvements to smtio.py vcd writer commit b582f11074c1877888341cf6d3fdceb490e88a3e Author: Clifford Wolf Date: Sat Sep 10 15:14:41 2016 +0200 fixed write_smt2 for (non-combinatorial) loops through hierarchical cells commit 3ceba145d54f725c90436c7322a67320d4308ce8 Author: Clifford Wolf Date: Thu Sep 8 18:08:15 2016 +0200 smt2 mem init bugfix commit 2c0d818296eda10f763287784b749a712bfeda98 Merge: 14bfd3c 9e72046 Author: Clifford Wolf Date: Thu Sep 8 11:17:05 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 14bfd3c5c159626a2b3b8dec3a446e0f7c4c7e0c Author: Clifford Wolf Date: Thu Sep 8 11:16:12 2016 +0200 yosys-smtbmc meminit support commit 9e72046906bdb9a15054c6c54b0003bfdc3baf6e Merge: 209a3d9 df4ab16 Author: Clifford Wolf Date: Thu Sep 8 10:06:40 2016 +0200 Merge pull request #225 from Kmanfi/test Typo fix. commit df4ab169a7ae84f9380e658e3ac5958a3d3e57d3 Author: Kaj Tuomi Date: Thu Sep 8 10:57:16 2016 +0300 Typo fix. commit 209a3d9ffcb5f7efbe60b0e0d45755329532535e Author: Clifford Wolf Date: Wed Sep 7 21:01:51 2016 +0200 Bugfix in "yosys-smtbmc --unroll" commit 6770d6e0f878b4e172bb04f1d0df5fa72f05e167 Author: Clifford Wolf Date: Wed Sep 7 20:57:56 2016 +0200 Added "yosys-smtbmc --unroll" commit ceff7ecd91e152dfac1d80188e592667cbec0392 Author: Clifford Wolf Date: Wed Sep 7 13:43:57 2016 +0200 Install celledges.h commit cb7dbf4070a7ca3658b7e473cb54f2eafb6c9ae3 Author: Clifford Wolf Date: Wed Sep 7 12:42:16 2016 +0200 Improvements in assertpmux commit e2570ffb872382f190b98d89b2eb7995a5d46758 Author: Clifford Wolf Date: Wed Sep 7 11:08:54 2016 +0200 Updated ABC to hg 8e08604f8ad3 commit ab18e9df7c55581a9713a332af425011793106a7 Author: Clifford Wolf Date: Wed Sep 7 00:28:01 2016 +0200 Added assertpmux commit f3f5a0204542da3b49e88bcf0b461b6476d45d63 Author: Clifford Wolf Date: Tue Sep 6 17:43:24 2016 +0200 Added "tee +INT -INT" commit fc5281b3f7656dd5e245f4ab7d81f39a14693f6b Author: Clifford Wolf Date: Tue Sep 6 17:35:25 2016 +0200 Run log_flush() before solving in sat command commit d55a93b39ff331aea16d627de92b1cbee2be68db Author: Clifford Wolf Date: Tue Sep 6 17:35:06 2016 +0200 Bugfix in parsing of BLIF latch init values commit 97583ab7295499b1b78ac7035e6e0b37d7b87734 Author: Clifford Wolf 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 Date: Mon Sep 5 19:58:18 2016 -0700 Fix spelling and grammar in README commit 97b449fe55384d6637db8a0850ed33a4c864bbc3 Author: Clifford Wolf Date: Tue Sep 6 01:40:31 2016 +0200 yosys-smtbmc: flush stdout after each log msg commit 372d672c2a73314aa4a796357ae09f1570527500 Author: Clifford Wolf Date: Sun Sep 4 16:32:47 2016 +0200 Minor bugfix in write_smt2 commit 19a3b3732cc0ab25858b99ce29a172abcfe1fd43 Author: Clifford Wolf Date: Sat Sep 3 18:49:53 2016 +0200 Minor README updates commit fa5565b606bf58de1e1150c937afe014fcd928b6 Author: Clifford Wolf Date: Sat Sep 3 14:26:00 2016 +0200 Added boolector support to yosys-smtbmc commit d2eba7631ff8bfb897db72f787ca365003176ca1 Merge: 2ee9bf1 068d5bc Author: Clifford Wolf Date: Fri Sep 2 13:55:51 2016 +0200 Merge branch 'smtbmc-kmanfi' commit 068d5bc02ffea9ba627bbf7151fdb36500eae0f2 Author: Clifford Wolf Date: Fri Sep 2 13:54:24 2016 +0200 Made examples/smtbmc/demo1.v more interesting commit 948aac9e1eaed04aa8de08e62cfb078d6337e9c9 Author: Clifford Wolf Date: Fri Sep 2 13:46:56 2016 +0200 Don't re-create hex_dict for each value commit d88cd0ae7f8761637722d5d2c6cc1c8bac762ce3 Author: Kaj Tuomi Date: Fri Sep 2 13:09:09 2016 +0300 More PEP 8 fixes. commit c4ba1965fd4300cb7de48cde996bb068d951967d Author: Kaj Tuomi 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 Date: Fri Sep 2 12:50:23 2016 +0300 Use dict lookup instead of many ifs. commit 279298c0b85250fd0c4e3637d10f9cf24e832259 Author: Kaj Tuomi Date: Fri Sep 2 11:12:30 2016 +0300 Fix: Unresolved reference. commit 74dd36ad5555ceae0ce153e67bf26d594e9f09da Author: Kaj Tuomi Date: Fri Sep 2 11:02:19 2016 +0300 Some syntax fixes. Generator and comma separated list modifications. commit 2ee9bf10d029396ba03b1d3023f15ff585e26bcb Author: Clifford Wolf Date: Tue Aug 30 23:57:24 2016 +0200 Added "prep -nomem" commit aa25a4cec66bfde84f9142b21679e82ba90ee910 Author: Clifford Wolf Date: Tue Aug 30 19:27:42 2016 +0200 Added $anyconst support to yosys-smtbmc commit 6f41e5277d1d41db7a620c73cf1b65558b55f236 Author: Clifford Wolf Date: Tue Aug 30 19:09:56 2016 +0200 Removed $aconst cell type commit a8124c137e2bfa3605dacadfe469ea22934b4cb3 Author: Clifford Wolf Date: Tue Aug 30 14:49:47 2016 +0200 Fixed memory bug in write_smt2 commit b04a40d9fe6725dbe1b97a63931b0c0710e3149d Author: Clifford Wolf 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 Date: Tue Aug 30 11:26:10 2016 +0200 Added $anyconst support to smt2 back-end commit 4ea7054b56c568e15ffe9ee3560fd458fabcdf00 Author: Clifford Wolf 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 Date: Mon Aug 29 22:41:45 2016 +0200 Added "yosys-smtbmc --dump-all" commit b226893461af46f2183be8ca9dfab62b49133c71 Author: Clifford Wolf Date: Mon Aug 29 14:53:32 2016 +0200 More yosys-smtbmc bugfixes commit a2e2fc5980e3465011d7373be34e2d018240ede4 Author: Clifford Wolf Date: Mon Aug 29 13:53:12 2016 +0200 Various fixes and improvements in yosys-smtbmc commit eae390ae17839bf0273b32149f46a2560a23d934 Author: Clifford Wolf Date: Sun Aug 28 21:35:33 2016 +0200 Removed $predict again commit 66582964bc11aadf3d0783a346706d801451a13f Author: Clifford Wolf Date: Sun Aug 28 12:34:36 2016 +0200 Improved "show" help message commit f56dba8e2053d12fbd8e1e9b7dc83f3e4e340f3d Author: Clifford Wolf 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 Date: Sat Aug 27 17:06:22 2016 +0200 Fixed handling of transparent bram rd ports on ROMs commit adcda6817e0df097bf70f8c200edcf15341f3188 Author: Clifford Wolf Date: Sat Aug 27 14:30:36 2016 +0200 Added smtc "final" statement commit 7500b403de9eeafcc3de2a8eba051a03d5f5f10e Merge: 1276c87 3356d39 Author: Clifford Wolf 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 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 Date: Fri Aug 26 23:35:27 2016 +0200 Added read_verilog -norestrict -assume-asserts commit ee620c6a24a62725f6f41b43728fe7ce4112e130 Author: Russell L Friesenhahn 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 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 Date: Fri Aug 26 17:33:02 2016 +0200 Various fixes and improvements in smt2 back-end commit 4be4969bae5d99af572ca99859dc4a550c24d4cf Author: Clifford Wolf Date: Thu Aug 25 11:44:25 2016 +0200 Improved verilog parser errors commit ad56ad44c3bdd3d075a32879785a04e3e30491eb Author: Clifford Wolf Date: Wed Aug 24 23:18:29 2016 +0200 More yosys-smtbmc smtc features commit ee3e7a0e45e764c2655391b0e444e4379c97fe3c Author: Clifford Wolf Date: Wed Aug 24 22:09:50 2016 +0200 yosys-smtbmc --smtc -g commit cd18235f30221ea2a5d51ab8b1d2639f51f1e99d Author: Clifford Wolf Date: Wed Aug 24 15:30:08 2016 +0200 Added SV "restrict" keyword commit 6523023645bd2227cac68f46364dff3867d9641a Author: Clifford Wolf Date: Mon Aug 22 17:45:01 2016 +0200 Minor yosys-smtbmc bugfix commit 583ceee6eb69fb8093f7d184d737ea93e2744c5b Author: Clifford Wolf Date: Mon Aug 22 17:27:43 2016 +0200 Added "yosys-smtbmc --constr" commit 2bd30e20261240057752f124506c8b38af95afc4 Author: Clifford Wolf Date: Mon Aug 22 16:48:46 2016 +0200 Added "yosys-smtbmc --dump-constr" commit f8a77abfac6da12e2e11c43b4e6aa6e613ac0d4b Author: Clifford Wolf Date: Mon Aug 22 15:05:57 2016 +0200 Added glob support to all front-ends commit 450f6f59b494af14014f0cbe93df4ceca0eecd76 Author: Clifford Wolf 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 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 Date: Sun Aug 21 15:56:22 2016 +0200 yosys-smtbmc: improved --dump-vlogtb handling of memories commit cdd0b85e47d6c1718ec5c0d2d80c87af3e3bbc83 Author: Clifford Wolf Date: Sun Aug 21 13:45:46 2016 +0200 Added another mem2reg test case commit 82a4a0230feedd994546ad57a1f4ae79b8f80136 Author: Clifford Wolf Date: Sun Aug 21 13:23:58 2016 +0200 Another bugfix in mem2reg code commit dbdd8927e78622885bc85c429e783b89b2d3022d Author: Clifford Wolf Date: Sun Aug 21 13:18:09 2016 +0200 Minor improvements to AstNode::dumpAst() and AstNode::dumpVlog() commit a93fcec93fdd5da581ece4a593369978db9dd42c Author: Clifford Wolf Date: Sat Aug 20 18:44:27 2016 +0200 Added examples/smtbmc/demo2.v commit f7578b0239720562571d88d5a0406488075a2a31 Author: Clifford Wolf Date: Sat Aug 20 18:43:39 2016 +0200 Added "yosys-smtbmc --dump-vlogtb" commit ed785194def450e68f217a3ae1764b5c5a679298 Author: Clifford Wolf Date: Sat Aug 20 18:42:32 2016 +0200 Added support for memories to smtio.py commit c325bae792a953037c115ad6763081c7ad15f01c Author: Clifford Wolf 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 Date: Sat Aug 20 16:32:50 2016 +0200 Added "yosys-smtbmc -g" commit a889acb897b742f8d17ebccb0fb0d0a8e622fb70 Author: Clifford Wolf Date: Sat Aug 20 16:07:59 2016 +0200 Added smtbmc longopt support commit fe9315b7a19bcb6dcde1a1ce49dd23f999bda7eb Author: Clifford Wolf Date: Sat Aug 20 13:47:46 2016 +0200 Fixed finish_addr handling in $readmemh/$readmemb commit 75bf7416f0dcf7b5bf3e095779f78039c75c316c Author: Clifford Wolf Date: Sat Aug 20 13:06:06 2016 +0200 Bugfix in partial mem write handling in verilog back-end commit d77a914683207ab9e4be20d8a10573acd8af777a Author: Clifford Wolf Date: Sat Aug 20 12:52:50 2016 +0200 Added "wreduce -memx" commit 15ef6084533809894dd0b5200a65497047c2ccf8 Author: Clifford Wolf Date: Fri Aug 19 19:48:26 2016 +0200 Added memory_memx pass, "memory -memx", and "prep -memx" commit f6629b9c29838879cec6a94d6cb47afc6fbd2db4 Author: Clifford Wolf 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 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 Date: Thu Aug 18 13:43:12 2016 +0200 Bugfix in test_autotb commit de8ee412c30e92efe3a3e1434c0f4b495f8cdbbe Author: Clifford Wolf Date: Thu Aug 18 11:17:45 2016 +0200 Improved smtbmc vcd generation performance commit dfcd30ea869f43af520aef033aa1311457112904 Author: Clifford Wolf 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 Date: Tue Aug 16 22:44:38 2016 +0200 Fixed default build config commit 1419f3983ef28cf8c9ec8837010bef498f085b63 Merge: 5767e4b 5299b17 Author: Clifford Wolf 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 Date: Tue Aug 16 14:41:37 2016 -0400 Add MSYS2-compatible build. commit 5767e4bc4db8d70bd02945769b6784618f7d003a Author: Clifford Wolf 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 Date: Tue Aug 16 09:08:26 2016 +0200 Updated ABC to hg rev a86455b00da5 commit 00f29d5e5cdd08a14aa02119f46f8ee10cd1368d Author: Clifford Wolf Date: Tue Aug 16 09:07:13 2016 +0200 Fixed use-after-free dict<> usage pattern in hierarchy.cc commit b4d544f0d90d50059d95520d863924bffa3122ac Author: Clifford Wolf Date: Tue Aug 16 00:56:42 2016 +0200 Updated ABC to hg rev 760ba358e790 commit 4561586eedb32fc5525cae87fded69860f609686 Author: Clifford Wolf Date: Tue Aug 16 00:52:10 2016 +0200 ABC mxe cross-build fix commit 321e15b0bfe84bf3b34b3a24d90ff55fe90de7cd Author: Clifford Wolf Date: Tue Aug 16 00:36:24 2016 +0200 Minor fixes in show command commit 5d90a5b9058d0e47643026b3439644cf974566a4 Author: Clifford Wolf Date: Mon Aug 15 09:33:06 2016 +0200 Added greenpak4_dffinv commit f0a8713fea9fea016e5a83fefd9e00a32f4a88d2 Author: Clifford Wolf Date: Mon Aug 15 08:26:20 2016 +0200 Fixed upto handling in verilog back-end commit 1058660ac882d97bd41737627c6246948edcab90 Merge: 6ac67ea 0b0ba96 Author: Clifford Wolf 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 Date: Sun Aug 14 00:30:45 2016 -0700 greenpak4: Changed name of inverted output ports for consistency commit 3b9756c6a3ae1d1f5b6e530d4b50e07710b44987 Author: Andrew Zonenberg Date: Sun Aug 14 00:11:44 2016 -0700 greenpak4: Added GP_DFFxI cells commit 2b062c48cb4405f4a1bb6bd49edaf687bbc2cc4e Author: Andrew Zonenberg 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 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 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 Date: Wed Aug 10 19:32:11 2016 +0200 Only allow posedge/negedge with 1 bit wide signals commit 73b7232ec89d9e3611ee5dbbc0cf663a33b09c8f Author: Clifford Wolf Date: Wed Aug 10 13:44:08 2016 +0200 Fixed some compiler warnings in attrmap command commit b0aab4e3046f1a598314e2563fa84b3a8ddc7fa5 Author: Clifford Wolf Date: Tue Aug 9 19:56:55 2016 +0200 Added "attrmap" command commit 39da8eddaefc078c6f7aba9958c40daec69f33d4 Author: Clifford Wolf Date: Tue Aug 9 19:56:10 2016 +0200 Added log_const() API commit 3c6d31fd061fb591a95b08ecfd1d2e50690dfc48 Author: Clifford Wolf Date: Tue Aug 9 11:18:48 2016 +0200 Added "attrmvcp" pass commit f7730d43bb4d5b44ec76e1080f4baf2f6b26807f Author: Yury Gribov Date: Sun Aug 7 21:34:33 2016 +0100 Use /proc/self/exe on Cygwin as well. commit 9d15529214f164701ac4f53d0f3a5d4943b8f8dd Author: Clifford Wolf 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 Date: Sat Aug 6 13:32:29 2016 +0200 Added "test_autotb -seed" (and "autotest.sh -S") commit 90c17aad56b0bf4b3ace5dea8c2d8555b52d4bfb Author: Clifford Wolf Date: Sat Aug 6 13:24:59 2016 +0200 preserve wire attributes in iopadmap commit 7f755dec75824e27dd79173a76d5819bf7fdbd27 Author: Clifford Wolf Date: Sat Aug 6 13:16:23 2016 +0200 Fixed bug in parsing real constants commit 5d6765a9d20ab2a88c02d06cb58fca2bfaf39c8d Author: Clifford Wolf Date: Tue Aug 2 10:37:19 2016 +0200 Added "insbuf" command commit 21e1bac0846e01fb58ae1fd42215b92f245ae18d Merge: 5fe13a1 da56a5b Author: Clifford Wolf Date: Sat Jul 30 12:50:39 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 5fe13a16eaaee4ac53523b5325cb9d92b5a1150d Author: Clifford Wolf Date: Sat Jul 30 12:46:06 2016 +0200 Added "write_verilog -defparam" commit 7fa61cba1bd9c29a6a9516a75003db576f673b4c Author: Clifford Wolf Date: Sat Jul 30 12:38:40 2016 +0200 Added "write_verilog -nodec -nostr" commit da56a5bbc60e58c305227105b68654264738c241 Author: Clifford Wolf Date: Wed Jul 27 16:11:37 2016 +0200 Added $initstate support to smtbmc flow commit 8d88fcb27011a6f8f47a8615c30ab658fafab0f2 Author: Clifford Wolf Date: Wed Jul 27 15:52:20 2016 +0200 Added SatGen support for $anyconst commit 9540be1d45cce45d0008a4160bc4aa70ff0dfe1d Author: Clifford Wolf Date: Wed Jul 27 15:44:11 2016 +0200 Removed $predict support from SatGen commit 40563129872f5a2287f54cb0dbd79534b493a5d6 Author: Clifford Wolf Date: Wed Jul 27 15:41:22 2016 +0200 Added $anyconst and $aconst commit a7b07696238dbfd8e4fb5fd41d597200abef4909 Author: Clifford Wolf Date: Wed Jul 27 15:40:17 2016 +0200 Added "read_verilog -dump_rtlil" commit 8537c4d2061db1ee11defc357781c6c534be5b3d Author: Clifford Wolf Date: Mon Jul 25 16:39:25 2016 +0200 Renamed AbstractCellEdgesDatabase::add_cell() to add_edges_from_cell() commit 5b944ef11b8964a00d833ad29c96ad46da06f7a3 Author: Clifford Wolf Date: Mon Jul 25 16:37:58 2016 +0200 Fixed a verilog parser memory leak commit 7a67add95d3d2f3293f84e38b891024d6444d2a4 Author: Clifford Wolf Date: Mon Jul 25 12:48:03 2016 +0200 Fixed parsing of empty positional cell ports commit b1c432af5613b0e5817ccc35bb081737dfcb6867 Author: Clifford Wolf Date: Sun Jul 24 17:21:53 2016 +0200 Improvements in CellEdgesDatabase commit f162b858f22e66dd553973c1275fc7994fc615f1 Author: Clifford Wolf Date: Sun Jul 24 13:59:57 2016 +0200 Added CellEdgesDatabase API commit 54966679df103781f0c8d72079aedd84a9dc0ec6 Author: Clifford Wolf Date: Sun Jul 24 12:18:39 2016 +0200 Moved SatHelper::setup_init() code to SatHelper::setup() commit 34e833103b77b06972ead21a9373c5541cb5ee7d Author: Clifford Wolf Date: Sat Jul 23 17:01:03 2016 +0200 Added $initstate support to "sat" command commit 9aae1d1e8ff1afa15459e5463397d1557ba8a361 Author: Clifford Wolf Date: Sat Jul 23 11:56:53 2016 +0200 No tristate warning message for "read_verilog -lib" commit 89deb412c68505a0c66e92a93a334e08370f0e6b Author: Clifford Wolf Date: Fri Jul 22 10:28:45 2016 +0200 Added satgen initstate support commit 7fef5ff10436a51a91f57157f687345795f60e40 Author: Clifford Wolf Date: Thu Jul 21 14:37:28 2016 +0200 Using $initstate in "initial assume" and "initial assert" commit 5c166e76e52cdaf6ea97952c17d3d79185a59f96 Author: Clifford Wolf Date: Thu Jul 21 14:23:22 2016 +0200 Added $initstate cell type and vlog function commit d7763634b68a735443c61aa32918ee0cdd6e9250 Author: Clifford Wolf 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 Date: Wed Jul 13 16:56:17 2016 +0200 Added basic support for $expect cells commit b3155af5f65333d272da339222e1e1962fb088b7 Author: Clifford Wolf Date: Wed Jul 13 09:49:05 2016 +0200 Added examples/smtbmc commit 2afc72cae31720d7eacb0423a0dc87d4eccb1aa1 Merge: 9e5c947 546233f Author: Clifford Wolf 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 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 Date: Tue Jul 12 16:12:37 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit e92998a79cec635270a350117eddb52c6232f388 Author: Clifford Wolf Date: Tue Jul 12 09:46:15 2016 +0200 Minor bugfix in FSM reset state detection commit 546233f0e154cca0bacb4960faf54ba8d206c1fd Author: whitequark Date: Tue Jul 12 06:32:04 2016 +0000 write_json: also write module attributes. commit 52a738a54435d9e54ac7cb523551ae866cc76770 Author: Andrew Zonenberg Date: Mon Jul 11 22:45:55 2016 -0700 Added GP_DAC cell commit baae472b83b3dac1293bb95ff0a87d9180a67479 Author: Andrew Zonenberg Date: Mon Jul 11 22:45:42 2016 -0700 Removed VOUT port of GP_BANDGAP commit 8619d33114edc58d89247ac3471d4115e1689a82 Author: Andrew Zonenberg Date: Mon Jul 11 22:42:25 2016 -0700 Removed splitnets in prep for new gp4par parser commit c71785d65e9775093b24ce684ed4fbe93bedb04d Author: Clifford Wolf Date: Mon Jul 11 12:49:33 2016 +0200 Yosys-smtbmc: Support for hierarchical VCD dumping commit 0153ad85d906105f5b4b520f6d62dbf646b2c285 Author: Clifford Wolf 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 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 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 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 Date: Sun Jul 10 18:11:25 2016 +0200 Support for hierarchical designs in smt2 back-end commit c0645839fe499fbc37199744cab5c624e5840dba Author: whitequark Date: Sun Jul 10 14:41:34 2016 +0000 greenpak4: add GP_COUNT{8,14}_ADV cells. commit b5a9fba0db5a8f29cffa22aa61f9d9cb7f69009a Author: Clifford Wolf 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 Date: Sat Jul 9 13:23:06 2016 +0200 Added printing of some warning messages to fsm_detect commit d3f0d7242732d8fb8885600c00c80c1aff8b5253 Author: Clifford Wolf 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 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 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 Date: Fri Jul 8 11:56:53 2016 +0200 Merge branch 'eddiehung-vtr' commit 27b5347a871d209ec4cba094e1203cc896c9c4b3 Author: Clifford Wolf Date: Fri Jul 8 11:49:55 2016 +0200 Restored blif "-true - .." behavior, use "-true + .." for eddiehung-vtr behavior commit 72149aba2e8fece72450a81142a44d123154fd12 Author: Clifford Wolf Date: Fri Jul 8 11:41:26 2016 +0200 In BLIF, a .names without entries already always outputs 0 commit 6bda61292513cbe7ffd69b4e3462b849757d2337 Author: Clifford Wolf Date: Fri Jul 8 11:35:15 2016 +0200 Undo eddiehung-vtr Makefile changes commit f6b7cf23d65c8e86cbfb742f30167dcc89825cbd Merge: e420412 7c62318 Author: Clifford Wolf 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 Date: Sat Jul 2 13:32:20 2016 +0200 Fixed autotest.sh handling of `timescale commit 080f95f9332d9caae95095ab9935f78d3b60f204 Merge: df5ebfa 6ed6b3c Author: Clifford Wolf Date: Fri Jul 1 12:24:31 2016 +0200 Merge branch 'assert-limit' commit 6ed6b3cb6d1f1735201861d30cd70736b76e5221 Author: Clifford Wolf Date: Fri Jul 1 12:24:13 2016 +0200 Replaced "select -assert-limit" with -assert-max and -assert-min commit 9a742f4069d6413bcf46b84c3b3f0e5cfc47f647 Author: eshellko 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 Date: Thu Jun 30 09:58:13 2016 +0200 Improved ice40_ffinit error reporting commit 7cddab0788cadc220ffa098c4ac037362ad6948e Merge: 541083c 545bcb3 Author: Clifford Wolf 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 Date: Mon Jun 20 20:16:37 2016 +0200 Allow defining input ports as "input logic" in SystemVerilog commit 541083cf329addb57117618de41697dd010d07cf Author: Clifford Wolf Date: Sun Jun 19 22:19:19 2016 +0200 Bugfix in "abc -script" handling commit 9bca8ccd40d70b6f6ad218cb9b1ae7dd4d3e8e68 Merge: ca91bcc a8200a7 Author: Clifford Wolf Date: Sun Jun 19 15:48:40 2016 +0200 Merge branch 'sv_packages' of https://github.com/rubund/yosys commit ca91bccb6b03a0b098f80bf14b55a1444eef73c0 Author: Clifford Wolf Date: Sun Jun 19 13:08:16 2016 +0200 Added "deminout" commit a8200a773fb8cf2ce2d8793716b62e01c97dd731 Author: Ruben Undheim 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 Date: Sat Jun 18 12:33:13 2016 +0200 Added "read_blif -sop" commit 5ffad4e0737bfb7e86129f3c74e7ee917ef782cc Author: Clifford Wolf Date: Sat Jun 18 12:28:49 2016 +0200 Added $sop support to BLIF back-end commit 178ff3e7f6f9766f0b1a3e8dcc96e030aea59b15 Author: Ruben Undheim Date: Sat Jun 18 10:24:21 2016 +0200 Added support for SystemVerilog packages with localparam definitions commit 3380281e15ca61cec8beda70938fb7b6f4c121d6 Author: Clifford Wolf Date: Fri Jun 17 20:15:35 2016 +0200 Added "dc2" to default ABC scripts commit 7a4ee5da747382df323d41f60e974ef92bdc1e82 Author: Clifford Wolf Date: Fri Jun 17 20:15:11 2016 +0200 Fixed init issue in mem2reg_test2 test case commit f498204ae462e2307f93c3ba8e6ba3b793b94d1f Author: Clifford Wolf Date: Fri Jun 17 19:39:35 2016 +0200 Added "abc -I -P " commit ebece2b8d5123aeb372df3ce226927bf3e6d09d6 Author: Clifford Wolf Date: Fri Jun 17 17:47:30 2016 +0200 Added $sop SAT model commit 95757efb25dc51a73b384b475b0fc87d0e11d10e Author: Clifford Wolf Date: Fri Jun 17 16:31:16 2016 +0200 Improved support for $sop cells commit 52bb1b968d4bfbbbd84eca88f0e80c486cc1a16e Author: Clifford Wolf Date: Fri Jun 17 13:46:01 2016 +0200 Added $sop cell type and "abc -sop" commit c3365034e9db8b6450db578daefd860276d5071f Author: Clifford Wolf Date: Fri Jun 17 11:16:31 2016 +0200 Updated ABC to hg rev b5df6e2b76f0 commit 99edf249669158b8c8bef0c7c3b926a2bbb7a621 Author: Clifford Wolf Date: Thu Jun 9 11:47:41 2016 +0200 Added "nlutmap -assert" commit 52b0b4e31e98816bc15b957c89bca76619231143 Author: Clifford Wolf Date: Wed Jun 8 12:14:32 2016 +0200 Do not run "wreduce" in "prep -ifx" commit 2032e6d8e46c0b715e73423cb34f4a624617df6e Author: Clifford Wolf Date: Mon Jun 6 17:15:50 2016 +0200 Added "proc_mux -ifx" commit dcf576641b4a9b476d51fbe1b0cdfb57d02a76e6 Author: Clifford Wolf Date: Fri Jun 3 11:38:31 2016 +0200 Added "setundef -init" commit d2695e2bfa0c1bc8cbcb5cd8396b12a7f83959af Author: Clifford Wolf Date: Thu Jun 2 14:37:07 2016 +0200 Fix all undef-muxes in dlatch input cone commit adfc80727c19021f911833305f5d322af6b8a0aa Author: Clifford Wolf Date: Wed Jun 1 13:25:06 2016 +0200 Avoid creating undef-muxes when inferring latches in proc_dlatch commit 11f7b8a2a1dd6e5c47e8081e4485127331fd80be Author: Clifford Wolf 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 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 Date: Fri May 27 17:25:33 2016 +0200 Fixed access-after-delete bug in mem2reg code commit e9ceec26ffe773d36b5316c79149913777d6581f Author: Clifford Wolf Date: Fri May 27 16:37:36 2016 +0200 fixed typos in error messages commit 611f121cb9fb8a451e891356a6260f4b299afc7d Author: Clifford Wolf 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 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 Date: Sun May 22 16:37:47 2016 +0200 Made the expansion order of hierarchy deterministic commit 8e9e793126a2772eed4b041bc60415943c71d5ee Author: Clifford Wolf Date: Fri May 20 17:13:11 2016 +0200 Some fixes in tests/asicworld/*_tb.v commit 1e227caf720bc5870ea9244e6b5657cf9c9717ab Author: Clifford Wolf 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 Date: Fri May 20 16:48:50 2016 +0200 Merge branch 'master' of https://github.com/Kmanfi/yosys commit f3983a094052e875e05823a6063c1775d1f84b39 Author: Clifford Wolf Date: Fri May 20 16:43:13 2016 +0200 Also escape "=" in spice output commit 060bf4819a3742ba2ad8142c9a7e665555c22ac7 Author: Clifford Wolf Date: Fri May 20 16:21:35 2016 +0200 Small improvements in Verilog front-end docs commit 8c3bc2ac0da4457f90775608e9701e0a7ba1e4cf Author: Kaj Tuomi Date: Thu May 19 11:53:29 2016 +0300 Close opened dump file. commit f6221ade950411ed10e6f260971cff78b30b8666 Author: Kaj Tuomi Date: Thu May 19 11:34:38 2016 +0300 Fix for Modelsim transcript line warp issue #164 commit ffcdc53a18197e40571b9c604fff07408cc12346 Author: Clifford Wolf Date: Sun May 15 00:05:30 2016 +0200 Don't sign-extend memory bram initialization data commit 864eeadcd9244505c7c026e2044799ff5bcf4782 Author: Clifford Wolf Date: Sat May 14 11:43:20 2016 +0200 Added missing "#define HASHLIB_H" commit d05115ceda2969badb83b3b2f0cefcd447c29451 Author: Clifford Wolf Date: Sat May 14 11:35:39 2016 +0200 Minor presentation fixes commit 407cdea0bc3a3d2a258b30a3e19d0861c3c4ba6f Author: Clifford Wolf Date: Wed May 11 09:31:53 2016 +0200 Updated min GCC requirement to GCC 4.8 commit b8b39472bb1b991ab96dede1b188868d9d98246b Author: Clifford Wolf Date: Mon May 9 12:43:49 2016 +0200 Added manual download link to README commit 570014800aa34d71868d04f9ef83e4a13b847773 Author: Clifford Wolf Date: Sun May 8 10:50:39 2016 +0200 Include in yosys.h commit fa76d51941ce5e4076317195bd1b603bccb74f02 Merge: f103bfb 47eace0 Author: Clifford Wolf 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 Date: Sat May 7 21:29:26 2016 -0700 Added GP_DELAY cell commit 41bbad4e4c25bc1b0227348ec0329187c8688c4b Author: Andrew Zonenberg Date: Sat May 7 21:14:42 2016 -0700 Fixed typo in port name commit b5171541cd9da6a4e2b5aaaaf3bca76e059c7e3f Author: Andrew Zonenberg Date: Sat May 7 21:14:18 2016 -0700 Fixed extra semicolon commit 85ee88b0ee13eb49bb255d7e66a62fce823c028a Author: Andrew Zonenberg Date: Sat May 7 21:14:00 2016 -0700 Fixed typo in parameter name commit a0c19aae55d878576c7481a6a4a5d10ba98c5224 Author: Andrew Zonenberg Date: Sat May 7 21:13:47 2016 -0700 Added simulation timescale declaration commit f103bfb9baddcd5ff16e610bc314c3de9eb3d526 Author: Clifford Wolf Date: Sat May 7 10:53:18 2016 +0200 Fixes for MXE build commit c3f6e0ea851b90b11671015f2bb472c857f0e2d9 Author: Clifford Wolf Date: Sat May 7 09:33:16 2016 +0200 Added support for "keep" attribute to shregmap commit 6fe3d5a1cf938081110db0470def2b2687dd665f Author: Clifford Wolf Date: Fri May 6 23:02:37 2016 +0200 Added synth_ice40 support for latches via logic loops commit d10dfccabb6bf4b1ba3f334b899f57093b8a0ddc Author: Clifford Wolf Date: Fri May 6 15:05:53 2016 +0200 Added "write_blif -noalias" commit 126da0ad3dfb7b75aaaadc97c7d40b495da9d164 Author: Clifford Wolf Date: Fri May 6 14:32:32 2016 +0200 Fixed ice40_opt lut unmapping, added "ice40_opt -unlut" commit aadca148da35963888e362d6eb5a3982b1903c10 Author: Clifford Wolf Date: Fri May 6 13:59:30 2016 +0200 Fixed preservation of important attributes in techmap commit ec1938737bcfb625d4e62afaefd30d67acb588bf Merge: 9647dc3 2096a05 Author: Clifford Wolf 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 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 Date: Wed May 4 17:04:50 2016 -0700 Changed port names in greenpak shregmap commit dee1c27a19f91fb44df67b2ab9834ee8140772c4 Author: Andrew Zonenberg Date: Wed May 4 17:03:45 2016 -0700 Renamed module parameter commit a613f171aeb8703b6849a87b73899389fb9912d8 Author: Andrew Zonenberg 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 Date: Wed May 4 22:48:02 2016 +0200 Added tristate buffer support to iopadmap commit 86add2907276ab7c9ec2c2861901a7a7adedf0fa Merge: 7a74ae4 deb1ecc Author: Clifford Wolf 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 Date: Wed May 4 08:06:18 2016 -0700 Fixed incorrect signal naming in GP_IOBUF commit 2db8dd6d354b8d29382054668ae34e7852b413a2 Merge: dcee325 7a74ae4 Author: Andrew Zonenberg Date: Wed May 4 07:23:27 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 7a74ae4c5403ce68a8245c45359d49f80d6e863a Merge: 658f936 12000b9 Author: Clifford Wolf Date: Wed May 4 10:48:42 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit 658f93663b12d3199f636cad8bf75aa1ee58108b Author: Clifford Wolf Date: Wed May 4 10:48:23 2016 +0200 Fixed iopadmap attribute handling commit dcee3256d59907c474542e0dfd24df7c047e6f50 Author: Andrew Zonenberg Date: Tue May 3 22:53:29 2016 -0700 Added tri-state I/O extraction for GreenPak commit 66095153fd6110dbe84552175d4919f4f5fd75fc Author: Andrew Zonenberg Date: Tue May 3 22:03:04 2016 -0700 Added GreenPak I/O buffer cells commit 9fc9d5f1fb1eea47118c00ecad1352ec84fd3047 Author: Andrew Zonenberg Date: Mon May 2 20:29:39 2016 -0700 Added comment to clarify GP_ABUF cell commit 79460208c928e62c608d71c0d6d484293835e8dc Author: Andrew Zonenberg Date: Mon May 2 20:27:41 2016 -0700 Added GP_ABUF cell commit 12000b90de0bade5fca641c49f3375316220ed39 Merge: 06d35ea 3a85e40 Author: Clifford Wolf 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 Date: Sun May 1 10:07:21 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 06d35ea9425dbfeff8bcd0d842a31d22843b937b Author: Clifford Wolf 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 Date: Fri Apr 29 00:57:37 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit e01464e2ac2bf3bd2752e10b48d2fc3ffc4fdf9e Author: Clifford Wolf Date: Thu Apr 28 23:17:30 2016 +0200 Added "qwp -v" commit 134e093e4e86080e1e4066f32128d268a36aeee5 Author: Andrew Zonenberg Date: Wed Apr 27 23:07:21 2016 -0700 Added GP_PGA cell commit 0d2923cccd00ed14537f3239b0059a76673798a4 Author: Clifford Wolf Date: Tue Apr 26 19:49:05 2016 +0200 Connections between inputs and inouts are driven by the input commit 958fb29c76a13838a922ff8553178d2c31c1ddef Author: Clifford Wolf Date: Mon Apr 25 16:37:11 2016 +0200 Fixed test_autotb for modules with many cell ports commit 93e107e455b506731d9114e0dc2644f78797cf0f Author: Clifford Wolf Date: Mon Apr 25 10:43:04 2016 +0200 Fixed proc_mux performance bug commit d086224a39fcd488062d7f75cc936cce5435069c Merge: b1d6f05 d57c851 Author: Clifford Wolf 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 Date: Sun Apr 24 22:11:56 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 349d7172023e9ee38b8e25e3bd04e2dfd0af1e62 Author: Andrew Zonenberg Date: Sun Apr 24 17:01:21 2016 -0700 Removed VIN_BUF_EN commit b1d6f05fa2156017f50383d01d49342c8ec5e209 Author: Clifford Wolf Date: Sun Apr 24 19:29:56 2016 +0200 Fixed performance bug in proc_dlatch commit 9aa4b3309c35d842e2b1a04172745a5e34a3c445 Author: Clifford Wolf Date: Sun Apr 24 17:12:34 2016 +0200 Added "yosys -D ALL" commit 6e215f374dcd92e2c1bff8ad6114f3d3dc9b06f5 Author: Andrew Zonenberg Date: Sat Apr 23 22:53:49 2016 -0700 Renamed VOUT to OUT on GP_ACMP cell commit 512486dcf37f779e6271e299eb186ab2559eb344 Author: Andrew Zonenberg Date: Sat Apr 23 22:33:36 2016 -0700 Added GP_ACMP cell commit 09ffebb9959510cacdc04c926800223235f50313 Author: Clifford Wolf Date: Sun Apr 24 00:48:33 2016 +0200 Added "prep -flatten" and "synth -flatten" commit 77aa2031e7e93b3d91b7594ad21d84e946b7cb04 Author: Clifford Wolf Date: Sun Apr 24 00:48:06 2016 +0200 Converted "prep" to ScriptPass commit 096c25d29d7e66003123dc4700ae72b0a4c10ca2 Author: Clifford Wolf Date: Sat Apr 23 23:10:13 2016 +0200 Improvements in greenpak4 shreg mapping commit c9c5192cd63dc4c08441e94c8d53428503ccc4af Author: Clifford Wolf Date: Sat Apr 23 23:09:45 2016 +0200 Run clean after splitnets in synth_greenpak4 commit 7f16784f3c0151c9b7f2861965d73ce7c960ebb5 Merge: 421b0d7 e13c661 Author: Andrew Zonenberg Date: Sat Apr 23 12:22:08 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit e13c66122ef4bc9cc8da77cda1d6bf594104acdb Author: Clifford Wolf Date: Sat Apr 23 20:20:21 2016 +0200 Added "shregmap -zinit" for greenpak4 tech commit 421b0d715c43fbcbfc1465518d444c9ca97cbabb Merge: 2849fd4 34195f2 Author: Andrew Zonenberg Date: Sat Apr 23 10:18:15 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 34195f281fc4829f58c3dfc9c7944691044186e0 Merge: f85cfa5 0cbe70e Author: Clifford Wolf Date: Sat Apr 23 10:33:32 2016 +0200 Merge https://github.com/azonenberg/yosys commit f85cfa56667e32ff9e165f9d957d05bde25342c0 Author: Clifford Wolf Date: Sat Apr 23 10:31:19 2016 +0200 Added "shregmap" to synth_greenpak4 commit a24021ea20bb70d0368c6b3e549a87fa5c4ab8ae Author: Clifford Wolf Date: Sat Apr 23 10:27:33 2016 +0200 Converted synth_greenpak4 to ScriptPass commit 2849fd486eaa1a77316cc6ffc86ec885b8a0d9fb Author: Andrew Zonenberg Date: Fri Apr 22 23:01:39 2016 -0700 Fixed typo in help text commit 0cbe70eaa40056a9d41070652282694cd7285b1a Author: Andrew Zonenberg Date: Fri Apr 22 19:08:19 2016 -0700 Fixed typo commit ab11f2aa701f4ff7a8df98d2a4158ea1f661a205 Merge: d90c1e9 7311be4 Author: Andrew Zonenberg Date: Fri Apr 22 19:07:55 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 7311be4028a9caad5a0fac1a3433220b4233ef84 Author: Clifford Wolf Date: Fri Apr 22 19:42:08 2016 +0200 Added "shregmap -tech greenpak4" commit 779e2cc819463fa5bc4ebfee397eb06368eb10b0 Author: Clifford Wolf 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 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 Date: Fri Apr 22 12:13:06 2016 +0200 More flexible handling of initialization values commit 0bc95f1e049afc35bb5ea30663b0a5725dfbf584 Author: Clifford Wolf Date: Thu Apr 21 23:28:37 2016 +0200 Added "yosys -D" feature commit 1565d1af69f552b790aa43fd6be194ee59ab76f3 Author: Clifford Wolf Date: Thu Apr 21 19:47:25 2016 +0200 Fixed performance bug in "share" pass commit 5a09fa45535ffceae90359be727d2ff6e0ac2c58 Author: Clifford Wolf 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 Date: Thu Apr 21 13:02:56 2016 +0200 Improvements in opt_expr commit 1761d08dd239bcf1765ebf807fc22514edac387f Author: Clifford Wolf Date: Thu Apr 21 12:06:07 2016 +0200 Bugfix and improvements in memory_share commit d90c1e952256dc00d070863835e061d73e4bc6b3 Author: Andrew Zonenberg Date: Wed Apr 20 20:48:19 2016 -0700 Added GP_VREF cell commit bf64974d43600b2e8ad63a1762489a152c002a41 Merge: f1fa757 8c9ac5d Author: Clifford Wolf 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 Date: Mon Apr 18 19:22:52 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit f1fa757d0e7de4fce01dd4c2b2ec8f1aed0fb1a6 Author: Clifford Wolf Date: Mon Apr 18 11:58:21 2016 +0200 Added "shregmap -params" commit 525651c8f6fc5a4f00f3c7b5208d6882f75ac736 Author: Clifford Wolf Date: Mon Apr 18 11:44:10 2016 +0200 Added "shregmap -zinit" and "shregmap -init" commit b2c36f6136d0fa3a6203197d78092bc1bb31e998 Merge: be57071 ce7c980 Author: Andrew Zonenberg Date: Sun Apr 17 08:15:34 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit ce7c980ec755c481182de9bd078e190bd8d9ff51 Author: Clifford Wolf Date: Sun Apr 17 15:37:22 2016 +0200 Improvements in "shregmap" commit be570712d82eafb28850d4400f2220991c3864a4 Merge: d0aaf8d de647a3 Author: Andrew Zonenberg Date: Sat Apr 16 15:14:32 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit de647a390c654bcdb04255c89d5d970cb0c1ed24 Author: Clifford Wolf Date: Sat Apr 16 23:20:49 2016 +0200 Added "shregmap" pass commit fbdb8e7b3ed94993228181f949506355989ef54b Author: Clifford Wolf Date: Sat Apr 16 23:20:34 2016 +0200 Fixed copy&paste error in log message in lut2mux commit a07f893a5fd018e426e1aa6de7ad986ea8acd468 Author: Clifford Wolf Date: Sat Apr 16 23:20:11 2016 +0200 Minor hashlib bugfix commit d0aaf8d2621fd75b968700ec4cb8dd6acf568737 Author: Andrew Zonenberg Date: Wed Apr 13 23:13:51 2016 -0700 Added GP_SHREG cell commit cdefa60367cf15b2e0a7fb35e4a42fe8358755b5 Author: Andrew Zonenberg Date: Wed Apr 13 23:13:39 2016 -0700 Refactoring: alphabetized cells_sim commit f1679936fe3f40d7fab3438a00dad2fed5a5f00e Author: Andrew Zonenberg Date: Sat Apr 9 01:18:02 2016 -0700 Fixed missing semicolon commit c1b8d3b580601ad9ba61b247fa967efdfe19fcda Merge: 58d8715 3d9ff91 Author: Andrew Zonenberg Date: Sat Apr 9 01:17:24 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 58d87156815871c47c0ea356ba50b738537adfab Author: Andrew Zonenberg Date: Sat Apr 9 01:17:13 2016 -0700 Added GP_RCOSC cell commit 3d9ff912c208d330fea12c0149fbe352e9ea7c0a Merge: ace4622 01a5f71 Author: Clifford Wolf 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 Date: Wed Apr 6 23:42:22 2016 -0700 Fixed assertion failure for non-inferrable counters in some cases commit 48c10d90f4b8c813782d4c5a304b2e1e24d140d8 Author: Andrew Zonenberg Date: Wed Apr 6 23:10:34 2016 -0700 Added second divider to GP_RINGOSC commit 1df559c7062b62a8b72b70d40d65da99667a2183 Author: Andrew Zonenberg Date: Wed Apr 6 22:40:25 2016 -0700 Added GP_RINGOSC primitive commit f6a0f2cf73e8dde315493f113235bbfa27920391 Merge: c2b909c ace4622 Author: Andrew Zonenberg Date: Wed Apr 6 22:31:22 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit ace462237f1223a41f6d29d1fe29652fcf435882 Author: Clifford Wolf Date: Tue Apr 5 13:25:23 2016 +0200 Hashlib indenting fix commit 38245b6733d9ec28ae1d37fb5ffba62b0aec791c Author: Clifford Wolf Date: Tue Apr 5 13:25:05 2016 +0200 Added msan origins tracking commit 6041f780c31525c1fc4d34b95317d7946466957b Author: Clifford Wolf Date: Tue Apr 5 12:51:04 2016 +0200 Prefer noninverting FFs in dfflibmap commit eaac5bfbc7faa7144a85590a94d14094899d197f Author: Clifford Wolf Date: Tue Apr 5 08:26:10 2016 +0200 Improved formatting of "sat" output tables commit 3920bf58d01ad9b34a7afba5bfa2f19ffff53240 Author: Clifford Wolf Date: Tue Apr 5 08:18:21 2016 +0200 Fixed some typos commit c2b909c051edf189d6e1f807bb367c3c543dc058 Author: Andrew Zonenberg Date: Mon Apr 4 21:46:07 2016 -0700 Added GP_POR commit c01ff05fabe948acfbbb259e92b3bd0009bd068e Author: Andrew Zonenberg Date: Mon Apr 4 16:56:43 2016 -0700 Added GP_BANDGAP cell commit e4e6becba9259a125bfd2788d453f5ac33272d2f Merge: 27e0d29 71f9f40 Author: Clifford Wolf 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 Date: Sun Apr 3 14:26:56 2016 +0200 Fix a few typos in the manual commit f9d7091c3b04fd9aa067ed1c087a29faac55d640 Author: Wladimir J. van der Laan Date: Sun Apr 3 14:26:46 2016 +0200 Add instructions for building manual on Ubuntu commit 27e0d29863bcf80520993574415f79b32312c5fb Merge: 7a4dd27 34667de Author: Clifford Wolf 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 Date: Fri Apr 1 23:41:03 2016 -0700 Removed more debug prints commit 87e7cd9fbd6e603da262e68f7ec68eb0d7233c2c Author: Andrew Zonenberg Date: Fri Apr 1 23:39:32 2016 -0700 Removed forgotten debug code commit 2386885f228ebecccf4987ac81bde11df56dae38 Author: Andrew Zonenberg Date: Fri Apr 1 21:18:29 2016 -0700 Added GreenPak inverter support commit b0a28c793cebcd1a7317b63b215151ce9ace3a42 Merge: 6dbcf50 7a4dd27 Author: Andrew Zonenberg Date: Fri Apr 1 18:09:08 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 6dbcf50fa1ea8591d8d944234627e6918612060b Author: Andrew Zonenberg 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 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 Date: Fri Apr 1 00:03:00 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 736a998a75e12ca83b45b74a79e78fae8ab12d16 Author: Andrew Zonenberg 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 Date: Thu Mar 31 22:51:22 2016 -0700 Fixed incorrect port name in cells_map.v commit 25533190818b0fe207be9a4626a9a273a08ae219 Author: Clifford Wolf Date: Thu Mar 31 11:16:34 2016 +0200 Added ScriptPass helper class for script-like passes commit 6cafd08ac1090f405168187632fab4308129c599 Author: Clifford Wolf Date: Thu Mar 31 09:58:55 2016 +0200 Improved opt_merge support for $pmux cells commit 6f1b6dc322bf6cceeadef7c666b8ff333ec6f2bf Author: Clifford Wolf Date: Thu Mar 31 09:57:44 2016 +0200 Added log_dump() support for dict<> and pool<> containers commit e5dd5c0bcccd4e79921e6a28b550a5960a93ee07 Author: Clifford Wolf Date: Thu Mar 31 09:57:23 2016 +0200 Preserve empty $pmux default cases commit e2f6d61c004776f2f573f3c5b70ad352ce6b4e1a Author: Clifford Wolf Date: Thu Mar 31 09:56:56 2016 +0200 Typo fixes in opt_expr and opt_merge commit c04a3d276320aa9aca4e3a678df3135b35473055 Author: Andrew Zonenberg Date: Wed Mar 30 23:58:45 2016 -0700 Fixed typo (wasn't written in 2012) commit ec93680bd583b670e03ed98b4b1081eab8d0f3f6 Author: Clifford Wolf Date: Thu Mar 31 08:52:49 2016 +0200 Renamed opt_share to opt_merge commit 1d0f0d668ade740c928c66c400476924abf62384 Author: Clifford Wolf Date: Thu Mar 31 08:43:28 2016 +0200 Renamed opt_const to opt_expr commit d31c968d76e99d5c7288d0eb844e041bb36aa77d Author: Clifford Wolf Date: Thu Mar 31 08:00:59 2016 +0200 Fixed typo in greenpak4_counters.cc commit cecd0cf788a7fcefe6e88c32557fd844482a1c9c Merge: 0db5328 984561c Author: Clifford Wolf 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 Date: Wed Mar 30 22:52:01 2016 -0700 Renamed counters pass to greenpak4_counters commit 1ae33344f4f18f4fbb899e4635659bf1cd8f0448 Author: Andrew Zonenberg 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 Date: Wed Mar 30 22:03:50 2016 -0700 Reduced log verbosity commit ad19e0c64ab69ab059efc258ae616f4fb5b8847d Author: Andrew Zonenberg 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 Date: Wed Mar 30 20:38:18 2016 -0700 Merge https://github.com/cliffordwolf/yosys commit 94a6923e7dd363c5b11116e9bd85aa012fed512a Author: Andrew Zonenberg Date: Wed Mar 30 20:30:25 2016 -0700 Updated tech lib for greenpak4 counter with some clarifications commit dd7204c0bdb65956fdf27925da3ccfe6f592d012 Author: Andrew Zonenberg Date: Wed Mar 30 20:30:03 2016 -0700 Fixed typo in log message commit 0db53284fd610cac1e956a87c7eec7df3d8564c5 Author: Clifford Wolf Date: Wed Mar 30 13:52:26 2016 +0200 We have 2016 for a while now commit 48dbc75beddd6db92f09125b49761859be33693d Author: Clifford Wolf Date: Wed Mar 30 13:24:49 2016 +0200 Added .vhd file extension support commit 489caf32c54ee250338eca72c5f0098106d17788 Author: Andrew Zonenberg 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 Date: Wed Mar 30 10:02:18 2016 +0200 Merge branch 'master' of github.com:cliffordwolf/yosys commit a47f69536a1ac93657d334f57dac2a800ab34f3f Author: Clifford Wolf Date: Wed Mar 30 10:02:03 2016 +0200 Added support for installed plugins commit 3ea60266488fe7e0b040c379a11d523c11ec9460 Author: Andrew Zonenberg Date: Tue Mar 29 20:02:59 2016 -0700 Added splitnets to synth_greenpak4 commit 19c20235b55648c150df294320b9f2515d2f3c5b Author: Clifford Wolf Date: Tue Mar 29 15:12:14 2016 +0200 Added more cell help messages commit 8c8b2e72b1b34f6219c87e7bd5b39620947cd787 Author: Clifford Wolf 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 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 Date: Mon Mar 28 23:16:43 2016 -0700 Added keep constraint to GP_SYSRESET cell commit ea9cc0309245c8d1af5d34b836238f197d34e332 Author: Andrew Zonenberg Date: Mon Mar 28 22:49:46 2016 -0700 Added GP_SYSRESET block commit 95784437ac237be981d0cf573386ba22f28f9624 Merge: 2ec832d 963c0d2 Author: Clifford Wolf 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 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 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 Date: Sat Mar 26 23:29:02 2016 -0700 Added GP_COUNT8/GP_COUNT14 cells commit 31a7567affb7425af1aa27d6dcda4666859ce62f Author: Andrew Zonenberg Date: Sat Mar 26 14:13:52 2016 -0700 Changed GP_LFOSC parameter configuration commit 44fd3cd149786bc3aaf180af8ec83f790d9cebbe Author: Andrew Zonenberg Date: Sat Mar 26 13:42:53 2016 -0700 Added GP_LFOSC cell commit af15b92c861f11d1f4b5016fed0cb8cb45af9175 Author: Andrew Zonenberg Date: Sat Mar 26 13:42:41 2016 -0700 Renamed GP4_V* cells to GP_V* for consistency commit 73870c1edfb72a402d69394b5dc6b0a7dd5bb596 Author: Sebastian Kuzminsky Date: Sat Mar 26 11:15:35 2016 -0600 fix a cut-n-paste error in the -h help commit 963c0d2525c9d7af9a2c7640b554923f3a4f647e Author: Sergey Kvachonok 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 Date: Fri Mar 25 09:16:45 2016 +0100 Merge pull request #136 from ravenexp/master Minor Makefile adjustments commit e14055edf06f4551f220b3875a95d8c25b8b7aae Author: Sergey Kvachonok 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 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 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 Date: Thu Mar 24 12:16:32 2016 +0100 Do not set "nosync" on task outputs, fixes #134 commit 9717495401e58a3d0a41113b541442227daa7cc3 Author: Clifford Wolf Date: Wed Mar 23 08:56:08 2016 +0100 Fixed handling of inverters (aka 1-input luts) in nlutmap commit b4bf787f1091c79d6fed6ac1ec91ebadbceb8023 Author: Clifford Wolf Date: Wed Mar 23 08:46:10 2016 +0100 Added GP_DFFS, GP_DFFR, and GP_DFFSR commit 456c10f16e5b535fc5aa95eacfabbe018fef2348 Author: Clifford Wolf Date: Wed Mar 23 08:12:54 2016 +0100 Added GP_DFF INIT parameter commit 4f2ea221dcdc632cdbb22f91403d076b61ec69ca Author: Clifford Wolf Date: Tue Mar 22 14:46:10 2016 +0100 Added ast.h to exported headers commit 043fa0fad039287ee1b6a6fec3d925b9c7304af8 Author: Clifford Wolf Date: Mon Mar 21 16:33:34 2016 +0100 Cleanup abstract modules at end of "hierarchy -top" commit 2c7e107d7a55a47fe6f6943e4541014649b57567 Author: Clifford Wolf Date: Mon Mar 21 16:30:55 2016 +0100 Support for abstract modules in chparam commit 4f0d4899ce2c93f1f4eef685b03d9f06d4433429 Author: Clifford Wolf Date: Mon Mar 21 16:19:51 2016 +0100 Added support for $stop system task commit ca8f8e30f20fd48127003486f1701ac17fd35aa6 Author: Clifford Wolf Date: Mon Mar 21 09:44:52 2016 +0100 Improvements in synth_greenpak4, added -part option commit bb9374b67c583761f4bdc72dbd19a79940d51082 Author: Clifford Wolf Date: Sat Mar 19 20:02:40 2016 +0100 Improvements in ABCEXTERNAL handling commit b471a32ec3c563bcb02b84a15217beca18b409ab Merge: e5d42eb 2656b2c Author: Clifford Wolf 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 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 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 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 Date: Fri Mar 18 12:15:00 2016 +0100 Fixed localparam signdness, fixes #127 commit b6d08f39baf508951ef36bedbd583f2b9fb48d1b Author: Clifford Wolf Date: Fri Mar 18 10:53:29 2016 +0100 Set "nosync" attribute on internal task/function wires commit 33c10350b22a8cc943cf3c294ee86969c5ce97f4 Author: Clifford Wolf Date: Tue Mar 15 12:22:31 2016 +0100 Fixed Verilog parser fix and more similar improvements commit 81d4e9e7c1c311f837dadb1634c83b4e70929669 Author: Andrew Becker 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 Date: Mon Mar 14 13:03:28 2016 +0100 Bugfix in write_verilog for RTLIL processes commit dac807fb33a3619dea955ce4b16342e6e0008111 Author: Clifford Wolf Date: Fri Mar 11 11:30:01 2016 +0100 Cleanups and improvements in examples/cmos/ commit 3265795154200786adbb399c6615915a6641f958 Merge: 35a6ad4 b34385e Author: Clifford Wolf Date: Fri Mar 11 11:10:44 2016 +0100 Merge commit 'b34385ec924b6067c1f82bdbae923f8062518956' commit 35a6ad4cc162d0f6aeec5bab1fd52d6ca041d868 Author: Clifford Wolf Date: Thu Mar 10 11:14:51 2016 +0100 Fixed typos in verilog_defaults help message commit d117893007baa506b702967ac6ee9f70af3c236a Author: Clifford Wolf Date: Tue Mar 8 21:30:45 2016 +0100 Added "write_edif -nogndvcc" commit dcd4fb998435b13193a9816e54d4c6b9284d119b Author: Clifford Wolf Date: Tue Mar 8 16:54:15 2016 +0100 Added examples/cxx-api/evaldemo.cc commit e7ed653771ab3483f988f4adfca5c635c10c3480 Merge: c4aaed0 b0ac32b Author: Clifford Wolf Date: Mon Mar 7 11:17:44 2016 +0100 Merge branch 'master' of github.com:cliffordwolf/yosys commit c4aaed099f948f8212898faecfc0f09027347928 Author: Clifford Wolf Date: Mon Mar 7 11:14:11 2016 +0100 Using "mfs" and "lutpack" in ABC lut mapping commit b34385ec924b6067c1f82bdbae923f8062518956 Author: Uros Platise Date: Sat Mar 5 08:34:05 2016 +0100 Completed ngspice digital example with verilog tb commit b0ac32bc03b340b26e0d3bb778af1c915722abdf Author: Clifford Wolf Date: Wed Mar 2 12:07:57 2016 +0100 Added digital (xspice) example code to examples/cmos/ commit 5547fae4cf2e254d2f35f76f5c0b07abec2376dd Author: Clifford Wolf 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 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 Date: Sun Feb 28 15:14:01 2016 -0700 user-facing spelling fixes "speciefied" -> "specified" "unkown" -> "unknown" commit 7c623182393aa2e8445336a99f0cfd4bc7c7e88f Author: eddiehung Date: Sun May 3 12:53:09 2015 +0100 Fix for all zero mask commit 079c1205fec6d194114b3d031d78a23cb8e0e7f9 Author: eddiehung Date: Sun May 3 10:37:20 2015 +0100 Escape '<' and '>' some more commit 872e13321c4c39997d3b14408224ef1c2fcc0821 Author: eddiehung Date: Tue Apr 28 08:56:00 2015 +0100 For vtr, escape angle brackets as well commit 058deb777e72458fa018e21eaf0322ca75b86fd7 Author: eddiehung Date: Tue Apr 28 08:55:26 2015 +0100 blifwriter: write out .names for true/false/undef type == '-' --- CodingReadme | 4 +- Makefile | 108 +- README | 61 +- backends/blif/blif.cc | 105 +- backends/btor/btor.cc | 2 +- backends/btor/verilog2btor.sh | 2 +- backends/edif/edif.cc | 55 +- backends/ilang/ilang_backend.cc | 2 +- backends/intersynth/intersynth.cc | 4 +- backends/json/json.cc | 16 +- backends/smt2/smt2.cc | 483 ++- backends/smt2/smtbmc.py | 622 +++- backends/smt2/smtio.py | 545 +++- backends/smv/smv.cc | 2 +- backends/spice/spice.cc | 67 +- backends/verilog/verilog_backend.cc | 170 +- examples/cmos/.gitignore | 4 + examples/cmos/README | 13 + examples/cmos/cmos_cells_digital.sp | 31 + examples/cmos/counter_digital.ys | 16 + examples/cmos/counter_tb.gtkw | 5 + examples/cmos/counter_tb.v | 33 + examples/cmos/testbench.sp | 2 +- examples/cmos/testbench_digital.sh | 15 + examples/cmos/testbench_digital.sp | 26 + examples/cxx-api/evaldemo.cc | 55 + examples/smtbmc/.gitignore | 22 + examples/smtbmc/Makefile | 59 + examples/smtbmc/demo1.v | 19 + examples/smtbmc/demo2.v | 29 + examples/smtbmc/demo3.smtc | 5 + examples/smtbmc/demo3.v | 18 + examples/smtbmc/demo4.smtc | 11 + examples/smtbmc/demo4.v | 13 + examples/smtbmc/demo5.v | 18 + examples/smtbmc/demo6.v | 14 + examples/smtbmc/demo7.v | 18 + frontends/ast/ast.cc | 71 +- frontends/ast/ast.h | 18 +- frontends/ast/genrtlil.cc | 105 +- frontends/ast/simplify.cc | 412 ++- frontends/blif/blifparse.cc | 125 +- frontends/blif/blifparse.h | 2 +- frontends/ilang/ilang_frontend.cc | 2 +- frontends/liberty/liberty.cc | 80 +- frontends/verific/verific.cc | 2 +- frontends/verilog/verilog_frontend.cc | 43 +- frontends/verilog/verilog_frontend.h | 9 + frontends/verilog/verilog_lexer.l | 9 + frontends/verilog/verilog_parser.y | 131 +- frontends/vhdl2verilog/vhdl2verilog.cc | 4 +- kernel/celledges.cc | 209 ++ kernel/celledges.h | 63 + kernel/celltypes.h | 42 +- kernel/driver.cc | 38 +- kernel/hashlib.h | 7 +- kernel/log.cc | 51 +- kernel/log.h | 48 +- kernel/register.cc | 77 +- kernel/register.h | 17 + kernel/rtlil.cc | 51 +- kernel/rtlil.h | 5 + kernel/satgen.h | 131 + kernel/yosys.cc | 45 +- kernel/yosys.h | 4 +- manual/APPNOTE_012_Verilog_to_BTOR.tex | 4 +- manual/CHAPTER_CellLib.tex | 6 +- manual/CHAPTER_Optimize.tex | 26 +- manual/CHAPTER_Overview.tex | 6 +- manual/CHAPTER_Prog/stubnets.cc | 2 +- manual/PRESENTATION_ExSyn.tex | 10 +- manual/PRESENTATION_Prog.tex | 4 +- manual/PRESENTATION_Prog/my_cmd.cc | 2 +- manual/command-reference-manual.tex | 6 +- manual/manual.tex | 6 +- passes/cmds/check.cc | 2 +- passes/cmds/connwrappers.cc | 2 +- passes/cmds/cover.cc | 2 +- passes/cmds/plugin.cc | 8 +- passes/cmds/qwp.cc | 32 +- passes/cmds/scc.cc | 8 +- passes/cmds/select.cc | 42 +- passes/cmds/setattr.cc | 6 + passes/cmds/setundef.cc | 94 +- passes/cmds/show.cc | 18 +- passes/cmds/splice.cc | 2 +- passes/cmds/splitnets.cc | 2 +- passes/cmds/stat.cc | 2 +- passes/cmds/tee.cc | 10 + passes/cmds/torder.cc | 2 +- passes/equiv/equiv_induct.cc | 2 +- passes/equiv/equiv_make.cc | 2 +- passes/equiv/equiv_mark.cc | 2 +- passes/equiv/equiv_miter.cc | 2 +- passes/equiv/equiv_purge.cc | 2 +- passes/equiv/equiv_remove.cc | 2 +- passes/equiv/equiv_simple.cc | 2 +- passes/equiv/equiv_status.cc | 2 +- passes/equiv/equiv_struct.cc | 2 +- passes/fsm/fsm.cc | 2 +- passes/fsm/fsm_detect.cc | 139 +- passes/fsm/fsm_expand.cc | 2 +- passes/fsm/fsm_export.cc | 2 +- passes/fsm/fsm_extract.cc | 9 +- passes/fsm/fsm_info.cc | 2 +- passes/fsm/fsm_map.cc | 2 +- passes/fsm/fsm_opt.cc | 2 +- passes/fsm/fsm_recode.cc | 2 +- passes/hierarchy/hierarchy.cc | 20 +- passes/hierarchy/singleton.cc | 2 +- passes/hierarchy/submod.cc | 6 +- passes/memory/Makefile.inc | 1 + passes/memory/memory.cc | 15 +- passes/memory/memory_bram.cc | 7 +- passes/memory/memory_collect.cc | 18 +- passes/memory/memory_dff.cc | 2 +- passes/memory/memory_map.cc | 2 +- passes/memory/memory_memx.cc | 92 + passes/memory/memory_share.cc | 51 +- passes/memory/memory_unpack.cc | 2 +- passes/opt/Makefile.inc | 4 +- passes/opt/opt.cc | 52 +- passes/opt/opt_clean.cc | 5 +- passes/opt/opt_const.cc | 1163 ------- passes/opt/opt_expr.cc | 1283 ++++++++ passes/opt/opt_merge.cc | 383 +++ passes/opt/opt_muxtree.cc | 4 +- passes/opt/opt_reduce.cc | 2 +- passes/opt/opt_rmdff.cc | 123 +- passes/opt/opt_share.cc | 341 -- passes/opt/share.cc | 55 +- passes/opt/wreduce.cc | 31 +- passes/proc/proc.cc | 16 +- passes/proc/proc_arst.cc | 2 +- passes/proc/proc_clean.cc | 2 +- passes/proc/proc_dff.cc | 2 +- passes/proc/proc_dlatch.cc | 147 +- passes/proc/proc_init.cc | 31 +- passes/proc/proc_mux.cc | 53 +- passes/proc/proc_rmdead.cc | 6 +- passes/sat/Makefile.inc | 1 + passes/sat/assertpmux.cc | 240 ++ passes/sat/eval.cc | 2 +- passes/sat/expose.cc | 2 +- passes/sat/freduce.cc | 2 +- passes/sat/miter.cc | 12 +- passes/sat/sat.cc | 217 +- passes/techmap/Makefile.inc | 8 + passes/techmap/abc.cc | 216 +- passes/techmap/aigmap.cc | 2 +- passes/techmap/alumacc.cc | 2 +- passes/techmap/attrmap.cc | 250 ++ passes/techmap/attrmvcp.cc | 139 + passes/techmap/deminout.cc | 116 + passes/techmap/dff2dffe.cc | 2 +- passes/techmap/dffinit.cc | 2 +- passes/techmap/dfflibmap.cc | 26 +- passes/techmap/dffsr2dff.cc | 2 +- passes/techmap/extract.cc | 10 +- passes/techmap/hilomap.cc | 2 +- passes/techmap/insbuf.cc | 94 + passes/techmap/iopadmap.cc | 168 +- passes/techmap/lut2mux.cc | 2 +- passes/techmap/maccmap.cc | 2 +- passes/techmap/muxcover.cc | 2 +- passes/techmap/nlutmap.cc | 20 +- passes/techmap/pmuxtree.cc | 2 +- passes/techmap/shregmap.cc | 584 ++++ passes/techmap/simplemap.cc | 33 +- passes/techmap/techmap.cc | 48 +- passes/techmap/tribuf.cc | 2 +- passes/tests/test_autotb.cc | 63 +- passes/tests/test_cell.cc | 171 +- techlibs/common/prep.cc | 170 +- techlibs/common/simlib.v | 136 +- techlibs/common/synth.cc | 177 +- techlibs/common/techmap.v | 6 +- techlibs/greenpak4/Makefile.inc | 2 + techlibs/greenpak4/cells_map.v | 74 +- techlibs/greenpak4/cells_sim.v | 425 ++- techlibs/greenpak4/gp_dff.lib | 26 +- techlibs/greenpak4/greenpak4_counters.cc | 442 +++ techlibs/greenpak4/greenpak4_dffinv.cc | 197 ++ techlibs/greenpak4/synth_greenpak4.cc | 192 +- techlibs/ice40/Makefile.inc | 1 + techlibs/ice40/ice40_ffinit.cc | 38 +- techlibs/ice40/ice40_ffssr.cc | 9 +- techlibs/ice40/ice40_opt.cc | 38 +- techlibs/ice40/latches_map.v | 11 + techlibs/ice40/synth_ice40.cc | 210 +- techlibs/xilinx/Makefile.inc | 1 + techlibs/xilinx/cells_xtra.sh | 145 + techlibs/xilinx/cells_xtra.v | 3293 ++++++++++++++++++++ techlibs/xilinx/synth_xilinx.cc | 4 +- tests/asicworld/code_hdl_models_arbiter_tb.v | 28 +- tests/asicworld/code_verilog_tutorial_counter_tb.v | 36 +- .../code_verilog_tutorial_first_counter_tb.v | 15 +- .../asicworld/code_verilog_tutorial_fsm_full_tb.v | 12 +- tests/simple/constmuldivmod.v | 27 + tests/simple/mem2reg.v | 41 +- tests/simple/memory.v | 64 + tests/tools/autotest.sh | 59 +- tests/tools/cmp_tbdata.c | 4 +- 203 files changed, 13967 insertions(+), 3242 deletions(-) create mode 100644 examples/cmos/.gitignore create mode 100644 examples/cmos/README create mode 100644 examples/cmos/cmos_cells_digital.sp create mode 100644 examples/cmos/counter_digital.ys create mode 100644 examples/cmos/counter_tb.gtkw create mode 100644 examples/cmos/counter_tb.v create mode 100644 examples/cmos/testbench_digital.sh create mode 100644 examples/cmos/testbench_digital.sp create mode 100644 examples/cxx-api/evaldemo.cc create mode 100644 examples/smtbmc/.gitignore create mode 100644 examples/smtbmc/Makefile create mode 100644 examples/smtbmc/demo1.v create mode 100644 examples/smtbmc/demo2.v create mode 100644 examples/smtbmc/demo3.smtc create mode 100644 examples/smtbmc/demo3.v create mode 100644 examples/smtbmc/demo4.smtc create mode 100644 examples/smtbmc/demo4.v create mode 100644 examples/smtbmc/demo5.v create mode 100644 examples/smtbmc/demo6.v create mode 100644 examples/smtbmc/demo7.v create mode 100644 kernel/celledges.cc create mode 100644 kernel/celledges.h create mode 100644 passes/memory/memory_memx.cc delete mode 100644 passes/opt/opt_const.cc create mode 100644 passes/opt/opt_expr.cc create mode 100644 passes/opt/opt_merge.cc delete mode 100644 passes/opt/opt_share.cc create mode 100644 passes/sat/assertpmux.cc create mode 100644 passes/techmap/attrmap.cc create mode 100644 passes/techmap/attrmvcp.cc create mode 100644 passes/techmap/deminout.cc create mode 100644 passes/techmap/insbuf.cc create mode 100644 passes/techmap/shregmap.cc create mode 100644 techlibs/greenpak4/greenpak4_counters.cc create mode 100644 techlibs/greenpak4/greenpak4_dffinv.cc create mode 100644 techlibs/ice40/latches_map.v create mode 100644 techlibs/xilinx/cells_xtra.sh create mode 100644 techlibs/xilinx/cells_xtra.v create mode 100644 tests/simple/constmuldivmod.v 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 = 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 | + | Copyright (C) 2012 - 2016 Clifford Wolf | | | | 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 ":" 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 ();" and within an always block: "assert();". 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> 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 cstr_buf; + pool 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 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 , then 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 , then \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 args, RTLIL::Design *design) { - log_header("Executing EDIF backend.\n"); + log_header(design, "Executing EDIF backend.\n"); std::string top_module_name; std::map> 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 args, RTLIL::Design *design) { - log_header("Executing INTERSYNTH backend.\n"); + log_header(design, "Executing INTERSYNTH backend.\n"); log_push(); std::vector 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 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 ¶meters) + void write_parameters(const dict ¶meters, bool for_module=false) { bool first = true; for (auto ¶m : 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\", , , ]\n"); - log(" - the ANDed value of the speciefied nodes\n"); + log(" - the ANDed value of the specified nodes\n"); log("\n"); log(" [ \"nand\", , , ]\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\", ]\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 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 decls, trans; + std::vector decls, trans, hier; std::map bit_driver; - std::set exported_cells; + std::set exported_cells, hiercells, hiercells_queue; pool recursive_cells, registers; std::map> fcache; std::map memarrays; std::map bvsizes; + dict 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 + 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 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 assert_list, assume_list; + vector 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 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 '_s' sort represents a module state. Additional '_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 '_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 '_i' function evaluates to 'true' when the given state conforms\n"); - log("to the initial state.\n"); + log("to the initial state. Furthermore the '_is' function should be asserted\n"); + log("to be true for initial states in addition to '_i', and should be\n"); + log("asserted to be false for non-initial states.\n"); + log("\n"); + log("For hierarchical designs, the '_h' function must be asserted for each\n"); + log("state to establish the design hierarchy. The '_h ' function\n"); + log("evaluates to the state corresponding to the given cell within .\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. '_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 '_n' functions for all registers.\n"); - log("\n"); log(" -wires\n"); - log(" also create '_n' functions for all public wires.\n"); + log(" create '_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 \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 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 sorted_modules; + + // extract module dependencies + std::map> module_deps; + for (auto &mod_it : design->modules_) { + module_deps[mod_it.second] = std::set(); + 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] - -t , -t : - default: skip_steps=0, num_steps=20 + -t + -t : + -t :: + default: skip_steps=0, step_size=1, num_steps=20 - -u - assume asserts in skipped steps in BMC - - -S - proof time steps at once - - -c - 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 name of the top module + + --smtc + 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 + assume asserts in skipped steps in BMC. + no assumptions are created for skipped steps + before . + + --dump-vcd + write trace to this VCD file + (hint: use 'write_smt2 -wires' for maximum + coverage of signals in generated VCD file) + + --dump-vlogtb + write trace as Verilog test bench + + --dump-smtc + 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 - set SMT solver: z3, cvc4, yices, mathsat + set SMT solver: z3, cvc4, yices, mathsat, boolector, dummy default: z3 + --logic + use the specified SMT2 logic (e.g. QF_AUFBV) + + --dummy + 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 + --dump-smt2 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 &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 &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 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 auto_name_map; std::set reg_wires, reg_ct; @@ -146,6 +141,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_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 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 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(); } - // 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 ¤t_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 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 <, 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 -#include - -#if defined(__APPLE__) -# include -#else -# include -#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 current_scope; const dict *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 &rules); void mem2reg_as_needed_pass1(dict> &mem2reg_places, dict &mem2reg_flags, dict &proc_flags, uint32_t &status_flags); - bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block); + bool mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); bool mem2reg_check(pool &mem2reg_set); + void mem2reg_remove(pool &mem2reg_set, vector &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 current_scope; extern const dict *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 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 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()) + 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 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 &mem2reg_set) return true; } +void AstNode::mem2reg_remove(pool &mem2reg_set, vector &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 &mem2reg_set, AstNode *mod, AstNode *block) +bool AstNode::mem2reg_as_needed_pass2(pool &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 &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 &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 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 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 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> 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(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 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 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 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 *al) %token 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 *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 range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list @@ -133,6 +136,9 @@ static void free_attr(std::map *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 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 + * + * 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 + * + * 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> 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> 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 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 binary_ops = { @@ -116,6 +116,8 @@ struct CellTypes setup_type("$assert", {A, EN}, pool(), true); setup_type("$assume", {A, EN}, pool(), true); + setup_type("$initstate", pool(), {Y}, true); + setup_type("$anyconst", pool(), {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 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 [:]\n"); + printf(" dump the design when printing the specified log header to a file.\n"); + printf(" yosys_dump_.il is used as filename if none is specified.\n"); + printf(" Use 'ALL' as 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 #include @@ -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 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 log_files; std::vector log_streams; +std::map> 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 log_files; extern std::vector log_streams; +extern std::map> 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 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 +static inline void log_dump_val_worker(dict &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 +static inline void log_dump_val_worker(pool &v) { + log("{"); + bool first = true; + for (auto &it : v) { + log(first ? " " : ", "); + log_dump_val_worker(it); + first = false; + } + log(" }"); +} + template 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 &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 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 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::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 modules_; + std::vector verilog_packages; std::vector selection_stack; dict 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 asserts_a, asserts_en; std::map assumes_a, assumes_en; std::map> imported_signals; + std::map, 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 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 table_raw = cell->getParam("\\TABLE").bits; + while (GetSize(table_raw) < 2*width*depth) + table_raw.push_back(State::S0); + + vector> 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 products, undef_products; + std::vector 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 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 masked_a = ez->vec_or(cmp_a, cmp_ua); + std::vector 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 products; + + for (int i = 0; i < depth; i++) + { + std::vector 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 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 d = importDefSigSpec(cell->getPort("\\Y"), timestep-1); + std::vector q = importDefSigSpec(cell->getPort("\\Y"), timestep); + + std::vector qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1); + std::vector 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 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 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 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 # include # include +# include #else # include # include # include # include +# include #endif #include @@ -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 |\n"); + log(" | Copyright (C) 2012 - 2016 Clifford Wolf |\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 glob_filename(const std::string &filename_pattern) +{ + std::vector 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 [:]\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 #include #include +#include #include #include @@ -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 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,13 +421,17 @@ 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} 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", , , ] - - the ANDed value of the speciefied nodes + - the ANDed value of the specified nodes [ "nand", , , ] - - the inverted ANDed value of the speciefied nodes + - the inverted ANDed value of the specified nodes [ "true", ] - 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 loaded_plugin_aliases; #ifdef YOSYS_ENABLE_PLUGINS void load_plugin(std::string filename, std::vector 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) 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 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 \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 ] {-read | }\n"); - log(" select [ -assert-none | -assert-any ] {-read | }\n"); + log(" select [ ] {-read | }\n"); log(" select [ -list | -write | -count | -clear ]\n"); log(" select -module \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 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 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 ffbits; + pool initwires; + + pool fftypes; + fftypes.insert("$dff"); + fftypes.insert("$dffe"); + fftypes.insert("$dffsr"); + fftypes.insert("$adff"); + + std::vector 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 \n"); - log(" Generate a graphics file in the specified format.\n"); - log(" Usually 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 strings such as 'svg' or 'ps'\n"); + log(" to generate files in other formats (this calls the 'dot' command).\n"); log("\n"); log(" -lib \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 .\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 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> 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 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 args, RTLIL::Design *design) { std::vector 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> 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 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 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 &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 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 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 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 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 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 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 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 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 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 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 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 &used, RTLIL::Module *mod, int indent) +void hierarchy_worker(RTLIL::Design *design, std::set> &used, RTLIL::Module *mod, int indent) { if (used.count(mod) > 0) return; @@ -287,7 +287,7 @@ void hierarchy_worker(RTLIL::Design *design, std::set &used, RTL void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) { - std::set used; + std::set> used; hierarchy_worker(design, used, top, 0); std::vector 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 &cache, RTLIL::Module *mod) int find_top_mod_score(Design *design, Module *module, dict &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 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 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 used_modules; + std::set> 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 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 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 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 ] [selection]\n"); + log(" memory [-nomap] [-nordff] [-memx] [-bram ] [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 (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 clkdom(clksig, clkpol); if (!clken) clkdom = pair(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 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 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 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 + * + * 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 +#include +#include + +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 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 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> sig_to_mux; - std::map>, RTLIL::SigBit> conditions_logic_cache; + std::map>, SigBit>, SigBit> conditions_logic_cache; // ----------------------------------------------------------------- @@ -109,10 +109,12 @@ struct MemoryShareWorker return false; } - RTLIL::SigBit conditions_to_logic(std::set> &conditions, int &created_conditions) + RTLIL::SigBit conditions_to_logic(std::set> &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 &rd_ports, std::vector &wr_ports) @@ -140,15 +145,14 @@ struct MemoryShareWorker std::map> muxtree_upstream_map; std::set non_feedback_nets; - for (auto wire_it : module->wires_) - if (wire_it.second->port_output) { - std::vector bits = RTLIL::SigSpec(wire_it.second); + for (auto wire : module->wires()) + if (wire->port_output) { + std::vector 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 state; std::set> 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::vector>> 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 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 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 \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 \n"); @@ -66,12 +66,12 @@ struct OptPass : public Pass { virtual void execute(std::vector 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 ®s, 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_const.cc deleted file mode 100644 index 0fcacf0a..00000000 --- a/passes/opt/opt_const.cc +++ /dev/null @@ -1,1163 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * 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/sigtools.h" -#include "kernel/celltypes.h" -#include "kernel/utils.h" -#include "kernel/log.h" -#include -#include -#include - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -bool did_something; - -void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) -{ - CellTypes ct(design); - SigMap sigmap(module); - SigPool driven_signals; - SigPool used_signals; - SigPool all_signals; - - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) { - if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) - driven_signals.add(sigmap(conn.second)); - if (!ct.cell_known(cell->type) || ct.cell_input(cell->type, conn.first)) - used_signals.add(sigmap(conn.second)); - } - - for (auto wire : module->wires()) { - if (wire->port_input) - driven_signals.add(sigmap(wire)); - if (wire->port_output) - used_signals.add(sigmap(wire)); - all_signals.add(sigmap(wire)); - } - - all_signals.del(driven_signals); - RTLIL::SigSpec undriven_signals = all_signals.export_all(); - - for (auto &c : undriven_signals.chunks()) - { - RTLIL::SigSpec sig = c; - - if (c.wire->name[0] == '$') - sig = used_signals.extract(sig); - if (sig.size() == 0) - continue; - - log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); - module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); - did_something = true; - } -} - -void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) -{ - RTLIL::SigSpec Y = cell->getPort(out_port); - out_val.extend_u0(Y.size(), false); - - log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", - cell->type.c_str(), cell->name.c_str(), info.c_str(), - module->name.c_str(), log_signal(Y), log_signal(out_val)); - // log_cell(cell); - assign_map.add(Y, out_val); - module->connect(Y, out_val); - module->remove(cell); - did_something = true; -} - -bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap) -{ - std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A"; - - bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool(); - - RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A")); - RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name)); - RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); - - sig_a.extend_u0(sig_y.size(), a_signed); - sig_b.extend_u0(sig_y.size(), b_signed); - - std::vector bits_a = sig_a, bits_b = sig_b, bits_y = sig_y; - - enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N }; - std::map, std::set> grouped_bits[GRP_N]; - - for (int i = 0; i < GetSize(bits_y); i++) - { - int group_idx = GRP_DYN; - RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; - - if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) - bit_a = bit_b = RTLIL::State::S1; - - if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) - bit_a = bit_b = RTLIL::State::S0; - - if (bit_a.wire == NULL && bit_b.wire == NULL) - group_idx = GRP_CONST_AB; - else if (bit_a.wire == NULL) - group_idx = GRP_CONST_A; - else if (bit_b.wire == NULL && commutative) - group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); - else if (bit_b.wire == NULL) - group_idx = GRP_CONST_B; - - grouped_bits[group_idx][std::pair(bit_a, bit_b)].insert(bits_y[i]); - } - - for (int i = 0; i < GRP_N; i++) - if (GetSize(grouped_bits[i]) == GetSize(bits_y)) - return false; - - log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", - log_id(cell->type), log_id(cell), log_id(module)); - - for (int i = 0; i < GRP_N; i++) - { - if (grouped_bits[i].empty()) - continue; - - RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); - RTLIL::SigSpec new_a, new_b; - RTLIL::SigSig new_conn; - - for (auto &it : grouped_bits[i]) { - for (auto &bit : it.second) { - new_conn.first.append_bit(bit); - new_conn.second.append_bit(RTLIL::SigBit(new_y, new_a.size())); - } - new_a.append_bit(it.first.first); - new_b.append_bit(it.first.second); - } - - RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); - - c->setPort("\\A", new_a); - c->parameters["\\A_WIDTH"] = new_a.size(); - c->parameters["\\A_SIGNED"] = false; - - if (b_name == "\\B") { - c->setPort("\\B", new_b); - c->parameters["\\B_WIDTH"] = new_b.size(); - c->parameters["\\B_SIGNED"] = false; - } - - c->setPort("\\Y", new_y); - c->parameters["\\Y_WIDTH"] = new_y->width; - c->check(); - - module->connect(new_conn); - - log(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); - if (b_name == "\\B") - log(", B=%s", log_signal(new_b)); - log("\n"); - } - - cover_list("opt.opt_const.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); - - module->remove(cell); - did_something = true; - return true; -} - -void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap &assign_map, const dict &invert_map) -{ - SigSpec sig = assign_map(cell->getPort(port)); - if (invert_map.count(sig)) { - log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", - log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), - log_signal(sig), log_signal(invert_map.at(sig))); - cell->setPort(port, (invert_map.at(sig))); - cell->setParam(param, !cell->getParam(param).as_bool()); - } -} - -void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdString port, const SigMap &assign_map, const dict &invert_map) -{ - log_assert(GetSize(type1) == GetSize(type2)); - string cell_type = cell->type.str(); - - if (GetSize(type1) != GetSize(cell_type)) - return; - - for (int i = 0; i < GetSize(type1); i++) { - log_assert((type1[i] == '?') == (type2[i] == '?')); - if (type1[i] == '?') { - if (cell_type[i] != '0' && cell_type[i] != '1' && cell_type[i] != 'N' && cell_type[i] != 'P') - return; - type1[i] = cell_type[i]; - type2[i] = cell_type[i]; - } - } - - if (cell->type.in(type1, type2)) { - SigSpec sig = assign_map(cell->getPort(port)); - if (invert_map.count(sig)) { - log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", - log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), - log_signal(sig), log_signal(invert_map.at(sig))); - cell->setPort(port, (invert_map.at(sig))); - cell->type = cell->type == type1 ? type2 : type1; - } - } -} - -bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative) -{ - bool all_bits_one = true; - bool last_bit_one = true; - - if (GetSize(value.bits) < 1) - return false; - - if (GetSize(value.bits) == 1) { - if (value.bits[0] != State::S1) - return false; - if (is_signed) - is_negative = true; - return true; - } - - for (int i = 0; i < GetSize(value.bits); i++) { - if (value.bits[i] != State::S1) - all_bits_one = false; - if (value.bits[i] != (i ? State::S0 : State::S1)) - last_bit_one = false; - } - - if (all_bits_one && is_signed) { - is_negative = true; - return true; - } - - return last_bit_one; -} - -void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv) -{ - if (!design->selected(module)) - return; - - CellTypes ct_combinational; - ct_combinational.setup_internals(); - ct_combinational.setup_stdcells(); - - SigMap assign_map(module); - dict invert_map; - - TopoSort> cells; - dict> cell_to_inbit; - dict> outbit_to_cell; - - for (auto cell : module->cells()) - if (design->selected(module, cell) && cell->type[0] == '$') { - if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && - cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1) - invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A")); - if ((cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == SigSpec(State::S1) && cell->getPort("\\B") == SigSpec(State::S0)) - invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\S")); - if (ct_combinational.cell_known(cell->type)) - for (auto &conn : cell->connections()) { - RTLIL::SigSpec sig = assign_map(conn.second); - sig.remove_const(); - if (ct_combinational.cell_input(cell->type, conn.first)) - cell_to_inbit[cell].insert(sig.begin(), sig.end()); - if (ct_combinational.cell_output(cell->type, conn.first)) - for (auto &bit : sig) - outbit_to_cell[bit].insert(cell); - } - cells.node(cell); - } - - for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); - - cells.sort(); - - 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_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_)) - - if (clkinv) - { - if (cell->type.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr")) - handle_polarity_inv(cell, "\\CLK", "\\CLK_POLARITY", assign_map, invert_map); - - if (cell->type.in("$sr", "$dffsr", "$dlatchsr")) { - handle_polarity_inv(cell, "\\SET", "\\SET_POLARITY", assign_map, invert_map); - handle_polarity_inv(cell, "\\CLR", "\\CLR_POLARITY", assign_map, invert_map); - } - - if (cell->type.in("$dffe", "$dlatch", "$dlatchsr")) - handle_polarity_inv(cell, "\\EN", "\\EN_POLARITY", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map, invert_map); - - handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map); - } - - if (do_fine) - { - if (cell->type == "$not" || cell->type == "$pos" || - cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor") - if (group_cell_inputs(module, cell, true, assign_map)) - goto next_cell; - - if (cell->type == "$reduce_and") - { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - - RTLIL::State new_a = RTLIL::State::S1; - for (auto &bit : sig_a.to_sigbit_vector()) - if (bit == RTLIL::State::Sx) { - if (new_a == RTLIL::State::S1) - new_a = RTLIL::State::Sx; - } else if (bit == RTLIL::State::S0) { - new_a = RTLIL::State::S0; - break; - } else if (bit.wire != NULL) { - new_a = RTLIL::State::Sm; - } - - if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { - cover("opt.opt_const.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); - cell->parameters.at("\\A_WIDTH") = 1; - did_something = true; - } - } - - if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") - { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - - RTLIL::State new_a = RTLIL::State::S0; - for (auto &bit : sig_a.to_sigbit_vector()) - if (bit == RTLIL::State::Sx) { - if (new_a == RTLIL::State::S0) - new_a = RTLIL::State::Sx; - } else if (bit == RTLIL::State::S1) { - new_a = RTLIL::State::S1; - break; - } else if (bit.wire != NULL) { - new_a = RTLIL::State::Sm; - } - - 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()); - 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); - cell->parameters.at("\\A_WIDTH") = 1; - did_something = true; - } - } - - if (cell->type == "$logic_and" || cell->type == "$logic_or") - { - RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); - - RTLIL::State new_b = RTLIL::State::S0; - for (auto &bit : sig_b.to_sigbit_vector()) - if (bit == RTLIL::State::Sx) { - if (new_b == RTLIL::State::S0) - new_b = RTLIL::State::Sx; - } else if (bit == RTLIL::State::S1) { - new_b = RTLIL::State::S1; - break; - } else if (bit.wire != NULL) { - new_b = RTLIL::State::Sm; - } - - 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()); - 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); - cell->parameters.at("\\B_WIDTH") = 1; - did_something = true; - } - } - } - - 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" || - cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" || - cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow") - { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec(); - - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") - sig_a = RTLIL::SigSpec(); - - for (auto &bit : sig_a.to_sigbit_vector()) - if (bit == RTLIL::State::Sx) - goto found_the_x_bit; - - for (auto &bit : sig_b.to_sigbit_vector()) - if (bit == RTLIL::State::Sx) - goto found_the_x_bit; - - if (0) { - found_the_x_bit: - cover_list("opt.opt_const.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") - replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx); - else - replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size())); - goto next_cell; - } - } - - 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()); - 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()); - 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")); - cell->setPort("\\B", tmp); - cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S")))); - did_something = true; - goto next_cell; - } - - if (cell->type == "$_NOT_") { - RTLIL::SigSpec input = cell->getPort("\\A"); - assign_map.apply(input); - if (input.match("1")) ACTION_DO_Y(0); - if (input.match("0")) ACTION_DO_Y(1); - if (input.match("*")) ACTION_DO_Y(x); - } - - if (cell->type == "$_AND_") { - RTLIL::SigSpec input; - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); - assign_map.apply(input); - if (input.match(" 0")) ACTION_DO_Y(0); - if (input.match("0 ")) ACTION_DO_Y(0); - if (input.match("11")) ACTION_DO_Y(1); - if (input.match("**")) ACTION_DO_Y(x); - if (input.match("1*")) ACTION_DO_Y(x); - if (input.match("*1")) ACTION_DO_Y(x); - if (consume_x) { - if (input.match(" *")) ACTION_DO_Y(0); - if (input.match("* ")) ACTION_DO_Y(0); - } - if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("1 ")) ACTION_DO("\\Y", input.extract(0, 1)); - } - - if (cell->type == "$_OR_") { - RTLIL::SigSpec input; - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); - assign_map.apply(input); - if (input.match(" 1")) ACTION_DO_Y(1); - if (input.match("1 ")) ACTION_DO_Y(1); - if (input.match("00")) ACTION_DO_Y(0); - if (input.match("**")) ACTION_DO_Y(x); - if (input.match("0*")) ACTION_DO_Y(x); - if (input.match("*0")) ACTION_DO_Y(x); - if (consume_x) { - if (input.match(" *")) ACTION_DO_Y(1); - if (input.match("* ")) ACTION_DO_Y(1); - } - if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1)); - } - - if (cell->type == "$_XOR_") { - RTLIL::SigSpec input; - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); - assign_map.apply(input); - if (input.match("00")) ACTION_DO_Y(0); - if (input.match("01")) ACTION_DO_Y(1); - if (input.match("10")) ACTION_DO_Y(1); - if (input.match("11")) ACTION_DO_Y(0); - if (input.match(" *")) ACTION_DO_Y(x); - if (input.match("* ")) ACTION_DO_Y(x); - if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1)); - } - - if (cell->type == "$_MUX_") { - RTLIL::SigSpec input; - input.append(cell->getPort("\\S")); - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); - assign_map.apply(input); - if (input.extract(2, 1) == input.extract(1, 1)) - ACTION_DO("\\Y", input.extract(2, 1)); - if (input.match(" 0")) ACTION_DO("\\Y", input.extract(2, 1)); - 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"); - cell->type = "$_NOT_"; - cell->setPort("\\A", input.extract(0, 1)); - cell->unsetPort("\\B"); - cell->unsetPort("\\S"); - goto next_cell; - } - if (input.match("11 ")) ACTION_DO_Y(1); - if (input.match("00 ")) ACTION_DO_Y(0); - if (input.match("** ")) ACTION_DO_Y(x); - if (input.match("01*")) ACTION_DO_Y(x); - if (input.match("10*")) ACTION_DO_Y(x); - if (mux_undef) { - if (input.match("* ")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match(" * ")) ACTION_DO("\\Y", input.extract(2, 1)); - if (input.match(" *")) ACTION_DO("\\Y", input.extract(2, 1)); - } - } - - if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex") - { - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec b = cell->getPort("\\B"); - - if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) { - int width = max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int()); - a.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()); - b.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()); - } - - RTLIL::SigSpec new_a, new_b; - - 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()); - 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); - goto next_cell; - } - if (a[i] == b[i]) - continue; - new_a.append(a[i]); - new_b.append(b[i]); - } - - if (new_a.size() == 0) { - cover_list("opt.opt_const.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); - goto next_cell; - } - - 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()); - cell->setPort("\\A", new_a); - cell->setPort("\\B", new_b); - cell->parameters["\\A_WIDTH"] = new_a.size(); - cell->parameters["\\B_WIDTH"] = new_b.size(); - } - } - - if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 && - cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1) - { - RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); - 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()); - cell->setPort("\\A", b); - cell->setPort("\\B", a); - std::swap(a, b); - } - - if (b.is_fully_const()) { - if (b.as_bool() == (cell->type == "$eq")) { - RTLIL::SigSpec input = b; - ACTION_DO("\\Y", cell->getPort("\\A")); - } else { - cover_list("opt.opt_const.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"); - cell->parameters.erase("\\B_SIGNED"); - cell->unsetPort("\\B"); - did_something = true; - } - goto next_cell; - } - } - - 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()); - 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"; - if (assign_map(cell->getPort("\\A")).is_fully_zero()) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->setParam("\\A_SIGNED", cell->getParam("\\B_SIGNED")); - cell->setParam("\\A_WIDTH", cell->getParam("\\B_WIDTH")); - } - cell->unsetPort("\\B"); - cell->unsetParam("\\B_SIGNED"); - cell->unsetParam("\\B_WIDTH"); - did_something = true; - goto next_cell; - } - - if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const()) - { - bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool(); - int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool()); - - if (cell->type.in("$shl", "$sshl")) - shift_bits *= -1; - - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int()); - - if (GetSize(sig_a) < GetSize(sig_y)) - sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool()); - - for (int i = 0; i < GetSize(sig_y); i++) { - int idx = i + shift_bits; - if (0 <= idx && idx < GetSize(sig_a)) - sig_y[i] = sig_a[idx]; - else if (GetSize(sig_a) <= idx && sign_ext) - sig_y[i] = sig_a[GetSize(sig_a)-1]; - } - - cover_list("opt.opt_const.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)); - - module->connect(cell->getPort("\\Y"), sig_y); - module->remove(cell); - - did_something = true; - goto next_cell; - } - - if (!keepdc) - { - bool identity_wrt_a = false; - bool identity_wrt_b = false; - bool arith_inverse = false; - - if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor") - { - RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); - - if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false) - identity_wrt_b = true; - - if (b.is_fully_const() && b.as_bool() == false) - identity_wrt_a = true; - } - - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") - { - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); - - if (b.is_fully_const() && b.as_bool() == false) - identity_wrt_a = true; - } - - if (cell->type == "$mul") - { - RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); - - if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam("\\A_SIGNED").as_bool(), arith_inverse)) - identity_wrt_b = true; - else - if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam("\\B_SIGNED").as_bool(), arith_inverse)) - identity_wrt_a = true; - } - - if (cell->type == "$div") - { - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); - - if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1) - identity_wrt_a = true; - } - - 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()); - 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()); - - 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'); - - if (!identity_wrt_a) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH"); - cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED"); - } - - cell->type = arith_inverse ? "$neg" : "$pos"; - cell->unsetPort("\\B"); - cell->parameters.erase("\\B_WIDTH"); - cell->parameters.erase("\\B_SIGNED"); - cell->check(); - - did_something = true; - goto next_cell; - } - } - - 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()); - 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()); - 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"); - cell->unsetPort("\\S"); - if (cell->type == "$mux") { - Const width = cell->parameters["\\WIDTH"]; - cell->parameters["\\A_WIDTH"] = width; - cell->parameters["\\Y_WIDTH"] = width; - cell->parameters["\\A_SIGNED"] = 0; - cell->parameters.erase("\\WIDTH"); - cell->type = "$not"; - } else - cell->type = "$_NOT_"; - did_something = true; - goto next_cell; - } - - 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()); - 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"); - if (cell->type == "$mux") { - Const width = cell->parameters["\\WIDTH"]; - cell->parameters["\\A_WIDTH"] = width; - cell->parameters["\\B_WIDTH"] = width; - cell->parameters["\\Y_WIDTH"] = width; - cell->parameters["\\A_SIGNED"] = 0; - cell->parameters["\\B_SIGNED"] = 0; - cell->parameters.erase("\\WIDTH"); - cell->type = "$and"; - } else - cell->type = "$_AND_"; - did_something = true; - goto next_cell; - } - - 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()); - 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"); - if (cell->type == "$mux") { - Const width = cell->parameters["\\WIDTH"]; - cell->parameters["\\A_WIDTH"] = width; - cell->parameters["\\B_WIDTH"] = width; - cell->parameters["\\Y_WIDTH"] = width; - cell->parameters["\\A_SIGNED"] = 0; - cell->parameters["\\B_SIGNED"] = 0; - cell->parameters.erase("\\WIDTH"); - cell->type = "$or"; - } else - cell->type = "$_OR_"; - did_something = true; - goto next_cell; - } - - if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) { - RTLIL::SigSpec new_a, new_b, new_s; - 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()); - replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A")); - goto next_cell; - } - for (int i = 0; i < cell->getPort("\\S").size(); i++) { - RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width); - RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1); - if (old_b.is_fully_undef() || old_s.is_fully_undef()) - continue; - new_b.append(old_b); - new_s.append(old_s); - } - new_a = cell->getPort("\\A"); - if (new_a.is_fully_undef() && new_s.size() > 0) { - new_a = new_b.extract((new_s.size()-1)*width, width); - new_b = new_b.extract(0, (new_s.size()-1)*width); - 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()); - 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()); - 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()); - 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); - cell->setPort("\\B", new_b); - cell->setPort("\\S", new_s); - if (new_s.size() > 1) { - cell->type = "$pmux"; - cell->parameters["\\S_WIDTH"] = new_s.size(); - } else { - cell->type = "$mux"; - cell->parameters.erase("\\S_WIDTH"); - } - did_something = true; - } - } - -#define FOLD_1ARG_CELL(_t) \ - if (cell->type == "$" #_t) { \ - RTLIL::SigSpec a = cell->getPort("\\A"); \ - assign_map.apply(a); \ - if (a.is_fully_const()) { \ - RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \ - 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); \ - replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \ - goto next_cell; \ - } \ - } -#define FOLD_2ARG_CELL(_t) \ - if (cell->type == "$" #_t) { \ - RTLIL::SigSpec a = cell->getPort("\\A"); \ - RTLIL::SigSpec b = cell->getPort("\\B"); \ - assign_map.apply(a), assign_map.apply(b); \ - if (a.is_fully_const() && b.is_fully_const()) { \ - RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \ - cell->parameters["\\A_SIGNED"].as_bool(), \ - cell->parameters["\\B_SIGNED"].as_bool(), \ - cell->parameters["\\Y_WIDTH"].as_int())); \ - cover("opt.opt_const.const.$" #_t); \ - replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \ - goto next_cell; \ - } \ - } - - FOLD_1ARG_CELL(not) - FOLD_2ARG_CELL(and) - FOLD_2ARG_CELL(or) - FOLD_2ARG_CELL(xor) - FOLD_2ARG_CELL(xnor) - - FOLD_1ARG_CELL(reduce_and) - FOLD_1ARG_CELL(reduce_or) - FOLD_1ARG_CELL(reduce_xor) - FOLD_1ARG_CELL(reduce_xnor) - FOLD_1ARG_CELL(reduce_bool) - - FOLD_1ARG_CELL(logic_not) - FOLD_2ARG_CELL(logic_and) - FOLD_2ARG_CELL(logic_or) - - FOLD_2ARG_CELL(shl) - FOLD_2ARG_CELL(shr) - FOLD_2ARG_CELL(sshl) - FOLD_2ARG_CELL(sshr) - FOLD_2ARG_CELL(shift) - FOLD_2ARG_CELL(shiftx) - - FOLD_2ARG_CELL(lt) - FOLD_2ARG_CELL(le) - FOLD_2ARG_CELL(eq) - FOLD_2ARG_CELL(ne) - FOLD_2ARG_CELL(gt) - FOLD_2ARG_CELL(ge) - - FOLD_2ARG_CELL(add) - FOLD_2ARG_CELL(sub) - FOLD_2ARG_CELL(mul) - FOLD_2ARG_CELL(div) - FOLD_2ARG_CELL(mod) - FOLD_2ARG_CELL(pow) - - FOLD_1ARG_CELL(pos) - FOLD_1ARG_CELL(neg) - - // be very conservative with optimizing $mux cells as we do not want to break mux trees - if (cell->type == "$mux") { - RTLIL::SigSpec input = assign_map(cell->getPort("\\S")); - RTLIL::SigSpec inA = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec inB = assign_map(cell->getPort("\\B")); - if (input.is_fully_const()) - ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A")); - else if (inA == inB) - ACTION_DO("\\Y", cell->getPort("\\A")); - } - - if (!keepdc && cell->type == "$mul") - { - bool a_signed = cell->parameters["\\A_SIGNED"].as_bool(); - bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); - bool swapped_ab = false; - - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); - RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y")); - - if (sig_b.is_fully_const() && sig_b.size() <= 32) - std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true; - - if (sig_a.is_fully_def() && sig_a.size() <= 32) - { - int a_val = sig_a.as_int(); - - if (a_val == 0) - { - cover("opt.opt_const.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()); - - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - module->remove(cell); - - did_something = true; - goto next_cell; - } - - for (int i = 1; i < (a_signed ? sig_a.size()-1 : sig_a.size()); i++) - if (a_val == (1 << i)) - { - if (swapped_ab) - cover("opt.opt_const.mul_shift.swapped"); - else - cover("opt.opt_const.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); - - if (!swapped_ab) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH"); - cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED"); - } - - std::vector new_b = RTLIL::SigSpec(i, 6); - - while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) - new_b.pop_back(); - - cell->type = "$shl"; - cell->parameters["\\B_WIDTH"] = GetSize(new_b); - cell->parameters["\\B_SIGNED"] = false; - cell->setPort("\\B", new_b); - cell->check(); - - did_something = true; - goto next_cell; - } - } - } - - next_cell:; -#undef ACTION_DO -#undef ACTION_DO_Y -#undef FOLD_1ARG_CELL -#undef FOLD_2ARG_CELL - } -} - -struct OptConstPass : public Pass { - OptConstPass() : Pass("opt_const", "perform const folding") { } - virtual void help() - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" opt_const [options] [selection]\n"); - log("\n"); - log("This pass performs const folding on internal cell types with constant inputs.\n"); - log("\n"); - log(" -mux_undef\n"); - log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n"); - log("\n"); - log(" -mux_bool\n"); - log(" replace $mux cells with inverters or buffers when possible\n"); - log("\n"); - log(" -undriven\n"); - log(" replace undriven nets with undef (x) constants\n"); - log("\n"); - log(" -clkinv\n"); - log(" optimize clock inverters by changing FF types\n"); - log("\n"); - log(" -fine\n"); - log(" perform fine-grain optimizations\n"); - log("\n"); - log(" -full\n"); - log(" alias for -mux_undef -mux_bool -undriven -fine\n"); - log("\n"); - log(" -keepdc\n"); - log(" some optimizations change the behavior of the circuit with respect to\n"); - log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n"); - log(" all result bits to be set to x. this behavior changes when 'a+0' is\n"); - log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n"); - log("\n"); - } - virtual void execute(std::vector args, RTLIL::Design *design) - { - bool mux_undef = false; - bool mux_bool = false; - bool undriven = false; - bool clkinv = false; - bool do_fine = false; - bool keepdc = false; - - log_header("Executing OPT_CONST pass (perform const folding).\n"); - log_push(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-mux_undef") { - mux_undef = true; - continue; - } - if (args[argidx] == "-mux_bool") { - mux_bool = true; - continue; - } - if (args[argidx] == "-undriven") { - undriven = true; - continue; - } - if (args[argidx] == "-clkinv") { - clkinv = true; - continue; - } - if (args[argidx] == "-fine") { - do_fine = true; - continue; - } - if (args[argidx] == "-full") { - mux_undef = true; - mux_bool = true; - undriven = true; - do_fine = true; - continue; - } - if (args[argidx] == "-keepdc") { - keepdc = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - for (auto module : design->selected_modules()) - { - if (undriven) - replace_undriven(design, module); - - do { - do { - did_something = false; - replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv); - if (did_something) - design->scratchpad_set_bool("opt.did_something", true); - } while (did_something); - replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); - } while (did_something); - } - - log_pop(); - } -} OptConstPass; - -PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc new file mode 100644 index 00000000..b62eae28 --- /dev/null +++ b/passes/opt/opt_expr.cc @@ -0,0 +1,1283 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/utils.h" +#include "kernel/log.h" +#include +#include +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool did_something; + +void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) +{ + CellTypes ct(design); + SigMap sigmap(module); + SigPool driven_signals; + SigPool used_signals; + SigPool all_signals; + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) { + if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) + driven_signals.add(sigmap(conn.second)); + if (!ct.cell_known(cell->type) || ct.cell_input(cell->type, conn.first)) + used_signals.add(sigmap(conn.second)); + } + + for (auto wire : module->wires()) { + if (wire->port_input) + driven_signals.add(sigmap(wire)); + if (wire->port_output) + used_signals.add(sigmap(wire)); + all_signals.add(sigmap(wire)); + } + + all_signals.del(driven_signals); + RTLIL::SigSpec undriven_signals = all_signals.export_all(); + + for (auto &c : undriven_signals.chunks()) + { + RTLIL::SigSpec sig = c; + + if (c.wire->name[0] == '$') + sig = used_signals.extract(sig); + if (sig.size() == 0) + continue; + + log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); + module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); + did_something = true; + } +} + +void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) +{ + RTLIL::SigSpec Y = cell->getPort(out_port); + out_val.extend_u0(Y.size(), false); + + log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", + cell->type.c_str(), cell->name.c_str(), info.c_str(), + module->name.c_str(), log_signal(Y), log_signal(out_val)); + // log_cell(cell); + assign_map.add(Y, out_val); + module->connect(Y, out_val); + module->remove(cell); + did_something = true; +} + +bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap) +{ + std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A"; + + bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); + bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool(); + + RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A")); + RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name)); + RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); + + sig_a.extend_u0(sig_y.size(), a_signed); + sig_b.extend_u0(sig_y.size(), b_signed); + + std::vector bits_a = sig_a, bits_b = sig_b, bits_y = sig_y; + + enum { GRP_DYN, GRP_CONST_A, GRP_CONST_B, GRP_CONST_AB, GRP_N }; + std::map, std::set> grouped_bits[GRP_N]; + + for (int i = 0; i < GetSize(bits_y); i++) + { + int group_idx = GRP_DYN; + RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; + + if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) + bit_a = bit_b = RTLIL::State::S1; + + if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) + bit_a = bit_b = RTLIL::State::S0; + + if (bit_a.wire == NULL && bit_b.wire == NULL) + group_idx = GRP_CONST_AB; + else if (bit_a.wire == NULL) + group_idx = GRP_CONST_A; + else if (bit_b.wire == NULL && commutative) + group_idx = GRP_CONST_A, std::swap(bit_a, bit_b); + else if (bit_b.wire == NULL) + group_idx = GRP_CONST_B; + + grouped_bits[group_idx][std::pair(bit_a, bit_b)].insert(bits_y[i]); + } + + for (int i = 0; i < GRP_N; i++) + if (GetSize(grouped_bits[i]) == GetSize(bits_y)) + return false; + + log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", + log_id(cell->type), log_id(cell), log_id(module)); + + for (int i = 0; i < GRP_N; i++) + { + if (grouped_bits[i].empty()) + continue; + + RTLIL::Wire *new_y = module->addWire(NEW_ID, GetSize(grouped_bits[i])); + RTLIL::SigSpec new_a, new_b; + RTLIL::SigSig new_conn; + + for (auto &it : grouped_bits[i]) { + for (auto &bit : it.second) { + new_conn.first.append_bit(bit); + new_conn.second.append_bit(RTLIL::SigBit(new_y, new_a.size())); + } + new_a.append_bit(it.first.first); + new_b.append_bit(it.first.second); + } + + RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); + + c->setPort("\\A", new_a); + c->parameters["\\A_WIDTH"] = new_a.size(); + c->parameters["\\A_SIGNED"] = false; + + if (b_name == "\\B") { + c->setPort("\\B", new_b); + c->parameters["\\B_WIDTH"] = new_b.size(); + c->parameters["\\B_SIGNED"] = false; + } + + c->setPort("\\Y", new_y); + c->parameters["\\Y_WIDTH"] = new_y->width; + c->check(); + + module->connect(new_conn); + + log(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); + if (b_name == "\\B") + log(", B=%s", log_signal(new_b)); + log("\n"); + } + + cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); + + module->remove(cell); + did_something = true; + return true; +} + +void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap &assign_map, const dict &invert_map) +{ + SigSpec sig = assign_map(cell->getPort(port)); + if (invert_map.count(sig)) { + log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", + log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), + log_signal(sig), log_signal(invert_map.at(sig))); + cell->setPort(port, (invert_map.at(sig))); + cell->setParam(param, !cell->getParam(param).as_bool()); + } +} + +void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdString port, const SigMap &assign_map, const dict &invert_map) +{ + log_assert(GetSize(type1) == GetSize(type2)); + string cell_type = cell->type.str(); + + if (GetSize(type1) != GetSize(cell_type)) + return; + + for (int i = 0; i < GetSize(type1); i++) { + log_assert((type1[i] == '?') == (type2[i] == '?')); + if (type1[i] == '?') { + if (cell_type[i] != '0' && cell_type[i] != '1' && cell_type[i] != 'N' && cell_type[i] != 'P') + return; + type1[i] = cell_type[i]; + type2[i] = cell_type[i]; + } + } + + if (cell->type.in(type1, type2)) { + SigSpec sig = assign_map(cell->getPort(port)); + if (invert_map.count(sig)) { + log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", + log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), + log_signal(sig), log_signal(invert_map.at(sig))); + cell->setPort(port, (invert_map.at(sig))); + cell->type = cell->type == type1 ? type2 : type1; + } + } +} + +bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative) +{ + bool all_bits_one = true; + bool last_bit_one = true; + + if (GetSize(value.bits) < 1) + return false; + + if (GetSize(value.bits) == 1) { + if (value.bits[0] != State::S1) + return false; + if (is_signed) + is_negative = true; + return true; + } + + for (int i = 0; i < GetSize(value.bits); i++) { + if (value.bits[i] != State::S1) + all_bits_one = false; + if (value.bits[i] != (i ? State::S0 : State::S1)) + last_bit_one = false; + } + + if (all_bits_one && is_signed) { + is_negative = true; + return true; + } + + return last_bit_one; +} + +void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool clkinv) +{ + if (!design->selected(module)) + return; + + CellTypes ct_combinational; + ct_combinational.setup_internals(); + ct_combinational.setup_stdcells(); + + SigMap assign_map(module); + dict invert_map; + + TopoSort> cells; + dict> cell_to_inbit; + dict> outbit_to_cell; + + for (auto cell : module->cells()) + if (design->selected(module, cell) && cell->type[0] == '$') { + if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && + cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1) + invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A")); + if ((cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == SigSpec(State::S1) && cell->getPort("\\B") == SigSpec(State::S0)) + invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\S")); + if (ct_combinational.cell_known(cell->type)) + for (auto &conn : cell->connections()) { + RTLIL::SigSpec sig = assign_map(conn.second); + sig.remove_const(); + if (ct_combinational.cell_input(cell->type, conn.first)) + cell_to_inbit[cell].insert(sig.begin(), sig.end()); + if (ct_combinational.cell_output(cell->type, conn.first)) + for (auto &bit : sig) + outbit_to_cell[bit].insert(cell); + } + cells.node(cell); + } + + for (auto &it_right : cell_to_inbit) + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); + + cells.sort(); + + for (auto cell : cells.sorted) + { +#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) + { + if (cell->type.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr")) + handle_polarity_inv(cell, "\\CLK", "\\CLK_POLARITY", assign_map, invert_map); + + if (cell->type.in("$sr", "$dffsr", "$dlatchsr")) { + handle_polarity_inv(cell, "\\SET", "\\SET_POLARITY", assign_map, invert_map); + handle_polarity_inv(cell, "\\CLR", "\\CLR_POLARITY", assign_map, invert_map); + } + + if (cell->type.in("$dffe", "$dlatch", "$dlatchsr")) + handle_polarity_inv(cell, "\\EN", "\\EN_POLARITY", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map, invert_map); + + handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map, invert_map); + 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 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 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" || + cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor") + if (group_cell_inputs(module, cell, true, assign_map)) + goto next_cell; + + if (cell->type == "$reduce_and") + { + RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + + RTLIL::State new_a = RTLIL::State::S1; + for (auto &bit : sig_a.to_sigbit_vector()) + if (bit == RTLIL::State::Sx) { + if (new_a == RTLIL::State::S1) + new_a = RTLIL::State::Sx; + } else if (bit == RTLIL::State::S0) { + new_a = RTLIL::State::S0; + break; + } else if (bit.wire != NULL) { + new_a = RTLIL::State::Sm; + } + + if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { + 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); + cell->parameters.at("\\A_WIDTH") = 1; + did_something = true; + } + } + + if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") + { + RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + + RTLIL::State new_a = RTLIL::State::S0; + for (auto &bit : sig_a.to_sigbit_vector()) + if (bit == RTLIL::State::Sx) { + if (new_a == RTLIL::State::S0) + new_a = RTLIL::State::Sx; + } else if (bit == RTLIL::State::S1) { + new_a = RTLIL::State::S1; + break; + } else if (bit.wire != NULL) { + new_a = RTLIL::State::Sm; + } + + if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { + 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); + cell->parameters.at("\\A_WIDTH") = 1; + did_something = true; + } + } + + if (cell->type == "$logic_and" || cell->type == "$logic_or") + { + RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); + + RTLIL::State new_b = RTLIL::State::S0; + for (auto &bit : sig_b.to_sigbit_vector()) + if (bit == RTLIL::State::Sx) { + if (new_b == RTLIL::State::S0) + new_b = RTLIL::State::Sx; + } else if (bit == RTLIL::State::S1) { + new_b = RTLIL::State::S1; + break; + } else if (bit.wire != NULL) { + new_b = RTLIL::State::Sm; + } + + if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { + 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); + cell->parameters.at("\\B_WIDTH") = 1; + did_something = true; + } + } + } + + 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" || + cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" || + cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow") + { + RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec(); + + if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") + sig_a = RTLIL::SigSpec(); + + for (auto &bit : sig_a.to_sigbit_vector()) + if (bit == RTLIL::State::Sx) + goto found_the_x_bit; + + for (auto &bit : sig_b.to_sigbit_vector()) + if (bit == RTLIL::State::Sx) + goto found_the_x_bit; + + if (0) { + found_the_x_bit: + 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") + replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx); + else + replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size())); + goto next_cell; + } + } + + 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_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_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")); + cell->setPort("\\B", tmp); + cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S")))); + did_something = true; + goto next_cell; + } + + if (cell->type == "$_NOT_") { + RTLIL::SigSpec input = cell->getPort("\\A"); + assign_map.apply(input); + if (input.match("1")) ACTION_DO_Y(0); + if (input.match("0")) ACTION_DO_Y(1); + if (input.match("*")) ACTION_DO_Y(x); + } + + if (cell->type == "$_AND_") { + RTLIL::SigSpec input; + input.append(cell->getPort("\\B")); + input.append(cell->getPort("\\A")); + assign_map.apply(input); + if (input.match(" 0")) ACTION_DO_Y(0); + if (input.match("0 ")) ACTION_DO_Y(0); + if (input.match("11")) ACTION_DO_Y(1); + if (input.match("**")) ACTION_DO_Y(x); + if (input.match("1*")) ACTION_DO_Y(x); + if (input.match("*1")) ACTION_DO_Y(x); + if (consume_x) { + if (input.match(" *")) ACTION_DO_Y(0); + if (input.match("* ")) ACTION_DO_Y(0); + } + if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); + if (input.match("1 ")) ACTION_DO("\\Y", input.extract(0, 1)); + } + + if (cell->type == "$_OR_") { + RTLIL::SigSpec input; + input.append(cell->getPort("\\B")); + input.append(cell->getPort("\\A")); + assign_map.apply(input); + if (input.match(" 1")) ACTION_DO_Y(1); + if (input.match("1 ")) ACTION_DO_Y(1); + if (input.match("00")) ACTION_DO_Y(0); + if (input.match("**")) ACTION_DO_Y(x); + if (input.match("0*")) ACTION_DO_Y(x); + if (input.match("*0")) ACTION_DO_Y(x); + if (consume_x) { + if (input.match(" *")) ACTION_DO_Y(1); + if (input.match("* ")) ACTION_DO_Y(1); + } + if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1)); + if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1)); + } + + if (cell->type == "$_XOR_") { + RTLIL::SigSpec input; + input.append(cell->getPort("\\B")); + input.append(cell->getPort("\\A")); + assign_map.apply(input); + if (input.match("00")) ACTION_DO_Y(0); + if (input.match("01")) ACTION_DO_Y(1); + if (input.match("10")) ACTION_DO_Y(1); + if (input.match("11")) ACTION_DO_Y(0); + if (input.match(" *")) ACTION_DO_Y(x); + if (input.match("* ")) ACTION_DO_Y(x); + if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1)); + if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1)); + } + + if (cell->type == "$_MUX_") { + RTLIL::SigSpec input; + input.append(cell->getPort("\\S")); + input.append(cell->getPort("\\B")); + input.append(cell->getPort("\\A")); + assign_map.apply(input); + if (input.extract(2, 1) == input.extract(1, 1)) + ACTION_DO("\\Y", input.extract(2, 1)); + if (input.match(" 0")) ACTION_DO("\\Y", input.extract(2, 1)); + 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_expr.mux_to_inv"); + cell->type = "$_NOT_"; + cell->setPort("\\A", input.extract(0, 1)); + cell->unsetPort("\\B"); + cell->unsetPort("\\S"); + goto next_cell; + } + if (input.match("11 ")) ACTION_DO_Y(1); + if (input.match("00 ")) ACTION_DO_Y(0); + if (input.match("** ")) ACTION_DO_Y(x); + if (input.match("01*")) ACTION_DO_Y(x); + if (input.match("10*")) ACTION_DO_Y(x); + if (mux_undef) { + if (input.match("* ")) ACTION_DO("\\Y", input.extract(1, 1)); + if (input.match(" * ")) ACTION_DO("\\Y", input.extract(2, 1)); + if (input.match(" *")) ACTION_DO("\\Y", input.extract(2, 1)); + } + } + + if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex") + { + RTLIL::SigSpec a = cell->getPort("\\A"); + RTLIL::SigSpec b = cell->getPort("\\B"); + + if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) { + int width = max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int()); + a.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()); + b.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()); + } + + RTLIL::SigSpec new_a, new_b; + + 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_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); + goto next_cell; + } + if (a[i] == b[i]) + continue; + new_a.append(a[i]); + new_b.append(b[i]); + } + + if (new_a.size() == 0) { + 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); + goto next_cell; + } + + if (new_a.size() < a.size() || new_b.size() < b.size()) { + 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(); + cell->parameters["\\B_WIDTH"] = new_b.size(); + } + } + + if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 && + cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1) + { + RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + + if (a.is_fully_const() && !b.is_fully_const()) { + cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str()); + cell->setPort("\\A", b); + cell->setPort("\\B", a); + std::swap(a, b); + } + + if (b.is_fully_const()) { + if (b.as_bool() == (cell->type == "$eq")) { + RTLIL::SigSpec input = b; + ACTION_DO("\\Y", cell->getPort("\\A")); + } else { + 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"); + cell->parameters.erase("\\B_SIGNED"); + cell->unsetPort("\\B"); + did_something = true; + } + goto next_cell; + } + } + + 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_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"; + if (assign_map(cell->getPort("\\A")).is_fully_zero()) { + cell->setPort("\\A", cell->getPort("\\B")); + cell->setParam("\\A_SIGNED", cell->getParam("\\B_SIGNED")); + cell->setParam("\\A_WIDTH", cell->getParam("\\B_WIDTH")); + } + cell->unsetPort("\\B"); + cell->unsetParam("\\B_SIGNED"); + cell->unsetParam("\\B_WIDTH"); + did_something = true; + goto next_cell; + } + + if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const()) + { + bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool(); + int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool()); + + if (cell->type.in("$shl", "$sshl")) + shift_bits *= -1; + + RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int()); + + if (GetSize(sig_a) < GetSize(sig_y)) + sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool()); + + for (int i = 0; i < GetSize(sig_y); i++) { + int idx = i + shift_bits; + if (0 <= idx && idx < GetSize(sig_a)) + sig_y[i] = sig_a[idx]; + else if (GetSize(sig_a) <= idx && sign_ext) + sig_y[i] = sig_a[GetSize(sig_a)-1]; + } + + 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)); + + module->connect(cell->getPort("\\Y"), sig_y); + module->remove(cell); + + did_something = true; + goto next_cell; + } + + if (!keepdc) + { + bool identity_wrt_a = false; + bool identity_wrt_b = false; + bool arith_inverse = false; + + if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor") + { + RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + + if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false) + identity_wrt_b = true; + + if (b.is_fully_const() && b.as_bool() == false) + identity_wrt_a = true; + } + + if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") + { + RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + + if (b.is_fully_const() && b.as_bool() == false) + identity_wrt_a = true; + } + + if (cell->type == "$mul") + { + RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + + if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam("\\A_SIGNED").as_bool(), arith_inverse)) + identity_wrt_b = true; + else + if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam("\\B_SIGNED").as_bool(), arith_inverse)) + identity_wrt_a = true; + } + + if (cell->type == "$div") + { + RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + + if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1) + identity_wrt_a = true; + } + + if (identity_wrt_a || identity_wrt_b) + { + if (identity_wrt_a) + 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_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'); + + if (!identity_wrt_a) { + cell->setPort("\\A", cell->getPort("\\B")); + cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH"); + cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED"); + } + + cell->type = arith_inverse ? "$neg" : "$pos"; + cell->unsetPort("\\B"); + cell->parameters.erase("\\B_WIDTH"); + cell->parameters.erase("\\B_SIGNED"); + cell->check(); + + did_something = true; + goto next_cell; + } + } + + 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_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_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"); + cell->unsetPort("\\S"); + if (cell->type == "$mux") { + Const width = cell->parameters["\\WIDTH"]; + cell->parameters["\\A_WIDTH"] = width; + cell->parameters["\\Y_WIDTH"] = width; + cell->parameters["\\A_SIGNED"] = 0; + cell->parameters.erase("\\WIDTH"); + cell->type = "$not"; + } else + cell->type = "$_NOT_"; + did_something = true; + goto next_cell; + } + + if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { + 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"); + if (cell->type == "$mux") { + Const width = cell->parameters["\\WIDTH"]; + cell->parameters["\\A_WIDTH"] = width; + cell->parameters["\\B_WIDTH"] = width; + cell->parameters["\\Y_WIDTH"] = width; + cell->parameters["\\A_SIGNED"] = 0; + cell->parameters["\\B_SIGNED"] = 0; + cell->parameters.erase("\\WIDTH"); + cell->type = "$and"; + } else + cell->type = "$_AND_"; + did_something = true; + goto next_cell; + } + + if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { + 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"); + if (cell->type == "$mux") { + Const width = cell->parameters["\\WIDTH"]; + cell->parameters["\\A_WIDTH"] = width; + cell->parameters["\\B_WIDTH"] = width; + cell->parameters["\\Y_WIDTH"] = width; + cell->parameters["\\A_SIGNED"] = 0; + cell->parameters["\\B_SIGNED"] = 0; + cell->parameters.erase("\\WIDTH"); + cell->type = "$or"; + } else + cell->type = "$_OR_"; + did_something = true; + goto next_cell; + } + + if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) { + RTLIL::SigSpec new_a, new_b, new_s; + 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_expr.mux_undef", "$mux", "$pmux", cell->type.str()); + replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A")); + goto next_cell; + } + for (int i = 0; i < cell->getPort("\\S").size(); i++) { + RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width); + RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1); + if (old_b.is_fully_undef() || old_s.is_fully_undef()) + continue; + new_b.append(old_b); + new_s.append(old_s); + } + new_a = cell->getPort("\\A"); + if (new_a.is_fully_undef() && new_s.size() > 0) { + new_a = new_b.extract((new_s.size()-1)*width, width); + new_b = new_b.extract(0, (new_s.size()-1)*width); + new_s = new_s.extract(0, new_s.size()-1); + } + if (new_s.size() == 0) { + 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_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_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); + cell->setPort("\\B", new_b); + cell->setPort("\\S", new_s); + if (new_s.size() > 1) { + cell->type = "$pmux"; + cell->parameters["\\S_WIDTH"] = new_s.size(); + } else { + cell->type = "$mux"; + cell->parameters.erase("\\S_WIDTH"); + } + did_something = true; + } + } + +#define FOLD_1ARG_CELL(_t) \ + if (cell->type == "$" #_t) { \ + RTLIL::SigSpec a = cell->getPort("\\A"); \ + assign_map.apply(a); \ + if (a.is_fully_const()) { \ + RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \ + 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_expr.const.$" #_t); \ + replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \ + goto next_cell; \ + } \ + } +#define FOLD_2ARG_CELL(_t) \ + if (cell->type == "$" #_t) { \ + RTLIL::SigSpec a = cell->getPort("\\A"); \ + RTLIL::SigSpec b = cell->getPort("\\B"); \ + assign_map.apply(a), assign_map.apply(b); \ + if (a.is_fully_const() && b.is_fully_const()) { \ + RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \ + cell->parameters["\\A_SIGNED"].as_bool(), \ + cell->parameters["\\B_SIGNED"].as_bool(), \ + cell->parameters["\\Y_WIDTH"].as_int())); \ + 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; \ + } \ + } + + FOLD_1ARG_CELL(not) + FOLD_2ARG_CELL(and) + FOLD_2ARG_CELL(or) + FOLD_2ARG_CELL(xor) + FOLD_2ARG_CELL(xnor) + + FOLD_1ARG_CELL(reduce_and) + FOLD_1ARG_CELL(reduce_or) + FOLD_1ARG_CELL(reduce_xor) + FOLD_1ARG_CELL(reduce_xnor) + FOLD_1ARG_CELL(reduce_bool) + + FOLD_1ARG_CELL(logic_not) + FOLD_2ARG_CELL(logic_and) + FOLD_2ARG_CELL(logic_or) + + FOLD_2ARG_CELL(shl) + FOLD_2ARG_CELL(shr) + FOLD_2ARG_CELL(sshl) + FOLD_2ARG_CELL(sshr) + FOLD_2ARG_CELL(shift) + FOLD_2ARG_CELL(shiftx) + + FOLD_2ARG_CELL(lt) + FOLD_2ARG_CELL(le) + FOLD_2ARG_CELL(eq) + FOLD_2ARG_CELL(ne) + FOLD_2ARG_CELL(gt) + FOLD_2ARG_CELL(ge) + + FOLD_2ARG_CELL(add) + FOLD_2ARG_CELL(sub) + FOLD_2ARG_CELL(mul) + FOLD_2ARG_CELL(div) + FOLD_2ARG_CELL(mod) + FOLD_2ARG_CELL(pow) + + FOLD_1ARG_CELL(pos) + FOLD_1ARG_CELL(neg) + + // be very conservative with optimizing $mux cells as we do not want to break mux trees + if (cell->type == "$mux") { + RTLIL::SigSpec input = assign_map(cell->getPort("\\S")); + RTLIL::SigSpec inA = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec inB = assign_map(cell->getPort("\\B")); + if (input.is_fully_const()) + ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A")); + else if (inA == inB) + ACTION_DO("\\Y", cell->getPort("\\A")); + } + + if (!keepdc && cell->type == "$mul") + { + bool a_signed = cell->parameters["\\A_SIGNED"].as_bool(); + bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); + bool swapped_ab = false; + + RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y")); + + if (sig_b.is_fully_const() && sig_b.size() <= 32) + std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true; + + if (sig_a.is_fully_def() && sig_a.size() <= 32) + { + int a_val = sig_a.as_int(); + + if (a_val == 0) + { + 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()); + + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + module->remove(cell); + + did_something = true; + goto next_cell; + } + + for (int i = 1; i < (a_signed ? sig_a.size()-1 : sig_a.size()); i++) + if (a_val == (1 << i)) + { + if (swapped_ab) + cover("opt.opt_expr.mul_shift.swapped"); + else + 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); + + if (!swapped_ab) { + cell->setPort("\\A", cell->getPort("\\B")); + cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH"); + cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED"); + } + + std::vector new_b = RTLIL::SigSpec(i, 6); + + while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) + new_b.pop_back(); + + cell->type = "$shl"; + cell->parameters["\\B_WIDTH"] = GetSize(new_b); + cell->parameters["\\B_SIGNED"] = false; + cell->setPort("\\B", new_b); + cell->check(); + + did_something = true; + goto next_cell; + } + } + } + + 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 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 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 +#undef FOLD_1ARG_CELL +#undef FOLD_2ARG_CELL + } +} + +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_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"); + log("\n"); + log(" -mux_bool\n"); + log(" replace $mux cells with inverters or buffers when possible\n"); + log("\n"); + log(" -undriven\n"); + log(" replace undriven nets with undef (x) constants\n"); + log("\n"); + log(" -clkinv\n"); + log(" optimize clock inverters by changing FF types\n"); + log("\n"); + log(" -fine\n"); + log(" perform fine-grain optimizations\n"); + log("\n"); + log(" -full\n"); + log(" alias for -mux_undef -mux_bool -undriven -fine\n"); + log("\n"); + log(" -keepdc\n"); + log(" some optimizations change the behavior of the circuit with respect to\n"); + log(" don't-care bits. for example in 'a+0' a single x-bit in 'a' will cause\n"); + log(" all result bits to be set to x. this behavior changes when 'a+0' is\n"); + log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + bool mux_undef = false; + bool mux_bool = false; + bool undriven = false; + bool clkinv = false; + bool do_fine = false; + bool keepdc = false; + + log_header(design, "Executing OPT_EXPR pass (perform const folding).\n"); + log_push(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-mux_undef") { + mux_undef = true; + continue; + } + if (args[argidx] == "-mux_bool") { + mux_bool = true; + continue; + } + if (args[argidx] == "-undriven") { + undriven = true; + continue; + } + if (args[argidx] == "-clkinv") { + clkinv = true; + continue; + } + if (args[argidx] == "-fine") { + do_fine = true; + continue; + } + if (args[argidx] == "-full") { + mux_undef = true; + mux_bool = true; + undriven = true; + do_fine = true; + continue; + } + if (args[argidx] == "-keepdc") { + keepdc = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + if (undriven) + replace_undriven(design, module); + + do { + do { + did_something = false; + replace_const_cells(design, module, false, mux_undef, mux_bool, do_fine, keepdc, clkinv); + if (did_something) + design->scratchpad_set_bool("opt.did_something", true); + } while (did_something); + replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); + } while (did_something); + } + + log_pop(); + } +} OptExprPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc new file mode 100644 index 00000000..97989d27 --- /dev/null +++ b/passes/opt/opt_merge.cc @@ -0,0 +1,383 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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/sigtools.h" +#include "kernel/log.h" +#include "kernel/celltypes.h" +#include "libs/sha1/sha1.h" +#include +#include +#include + +#define USE_CELL_HASH_CACHE + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct OptMergeWorker +{ + RTLIL::Design *design; + RTLIL::Module *module; + SigMap assign_map; + SigMap dff_init_map; + bool mode_share_all; + + CellTypes ct; + int total_count; +#ifdef USE_CELL_HASH_CACHE + dict cell_hash_cache; +#endif + + static void sort_pmux_conn(dict &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> sb_pairs; + for (int i = 0; i < s_width; i++) + sb_pairs.push_back(pair(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) + { + if (v == 0) + return "0"; + std::string str = ""; + while (v > 0) { + str += 'a' + (v & 15); + v = v >> 4; + } + return str; + } + + std::string hash_cell_parameters_and_connections(const RTLIL::Cell *cell) + { + if (cell_hash_cache.count(cell) > 0) + return cell_hash_cache[cell]; + + std::string hash_string = cell->type.str() + "\n"; + + for (auto &it : cell->parameters) + hash_string += "P " + it.first.str() + "=" + it.second.as_string() + "\n"; + + const dict *conn = &cell->connections(); + dict alt_conn; + + if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" || + cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") { + alt_conn = *conn; + if (assign_map(alt_conn.at("\\A")) < assign_map(alt_conn.at("\\B"))) { + alt_conn["\\A"] = conn->at("\\B"); + alt_conn["\\B"] = conn->at("\\A"); + } + conn = &alt_conn; + } else + if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") { + alt_conn = *conn; + assign_map.apply(alt_conn.at("\\A")); + alt_conn.at("\\A").sort(); + conn = &alt_conn; + } else + if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") { + alt_conn = *conn; + 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 hash_conn_strings; + + for (auto &it : *conn) { + if (cell->output(it.first)) + continue; + RTLIL::SigSpec sig = it.second; + assign_map.apply(sig); + string s = "C " + it.first.str() + "="; + for (auto &chunk : sig.chunks()) { + if (chunk.wire) + s += "{" + chunk.wire->name.str() + " " + + int_to_hash_string(chunk.offset) + " " + + int_to_hash_string(chunk.width) + "}"; + else + s += RTLIL::Const(chunk.data).as_string(); + } + 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]; + } +#endif + + bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2, bool <) + { +#ifdef USE_CELL_HASH_CACHE + std::string hash1 = hash_cell_parameters_and_connections(cell1); + std::string hash2 = hash_cell_parameters_and_connections(cell2); + + if (hash1 != hash2) { + lt = hash1 < hash2; + return true; + } +#endif + + if (cell1->parameters != cell2->parameters) { + std::map p1(cell1->parameters.begin(), cell1->parameters.end()); + std::map p2(cell2->parameters.begin(), cell2->parameters.end()); + lt = p1 < p2; + return true; + } + + dict conn1 = cell1->connections(); + dict conn2 = cell2->connections(); + + for (auto &it : conn1) { + if (cell1->output(it.first)) + it.second = RTLIL::SigSpec(); + else + assign_map.apply(it.second); + } + + for (auto &it : conn2) { + if (cell2->output(it.first)) + it.second = RTLIL::SigSpec(); + else + assign_map.apply(it.second); + } + + if (cell1->type == "$and" || cell1->type == "$or" || cell1->type == "$xor" || cell1->type == "$xnor" || cell1->type == "$add" || cell1->type == "$mul" || + cell1->type == "$logic_and" || cell1->type == "$logic_or" || cell1->type == "$_AND_" || cell1->type == "$_OR_" || cell1->type == "$_XOR_") { + if (conn1.at("\\A") < conn1.at("\\B")) { + RTLIL::SigSpec tmp = conn1["\\A"]; + conn1["\\A"] = conn1["\\B"]; + conn1["\\B"] = tmp; + } + if (conn2.at("\\A") < conn2.at("\\B")) { + RTLIL::SigSpec tmp = conn2["\\A"]; + conn2["\\A"] = conn2["\\B"]; + conn2["\\B"] = tmp; + } + } else + if (cell1->type == "$reduce_xor" || cell1->type == "$reduce_xnor") { + conn1["\\A"].sort(); + conn2["\\A"].sort(); + } else + 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) { + std::map c1(conn1.begin(), conn1.end()); + std::map c2(conn2.begin(), conn2.end()); + lt = c1 < c2; + return true; + } + + if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) { + std::vector q1 = dff_init_map(cell1->getPort("\\Q")).to_sigbit_vector(); + std::vector q2 = dff_init_map(cell2->getPort("\\Q")).to_sigbit_vector(); + for (size_t i = 0; i < q1.size(); i++) + if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) { + lt = q1.at(i) < q2.at(i); + return true; + } + } + + return false; + } + + bool compare_cells(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) + { + if (cell1->type != cell2->type) + return cell1->type < cell2->type; + + if ((!mode_share_all && !ct.cell_known(cell1->type)) || !cell1->known()) + return cell1 < cell2; + + if (cell1->has_keep_attr() || cell2->has_keep_attr()) + return cell1 < cell2; + + bool lt; + if (compare_cell_parameters_and_connections(cell1, cell2, lt)) + return lt; + + return false; + } + + struct CompareCells { + OptMergeWorker *that; + CompareCells(OptMergeWorker *that) : that(that) {} + bool operator()(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) const { + return that->compare_cells(cell1, cell2); + } + }; + + 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; + ct.setup_internals(); + ct.setup_internals_mem(); + ct.setup_stdcells(); + ct.setup_stdcells_mem(); + + if (mode_nomux) { + ct.cell_types.erase("$mux"); + ct.cell_types.erase("$pmux"); + } + + log("Finding identical cells in module `%s'.\n", module->name.c_str()); + assign_map.set(module); + + dff_init_map.set(module); + for (auto &it : module->wires_) + if (it.second->attributes.count("\\init") != 0) + dff_init_map.add(it.second, it.second->attributes.at("\\init")); + + bool did_something = true; + while (did_something) + { +#ifdef USE_CELL_HASH_CACHE + cell_hash_cache.clear(); +#endif + std::vector cells; + cells.reserve(module->cells_.size()); + for (auto &it : module->cells_) { + if (!design->selected(module, it.second)) + continue; + if (ct.cell_known(it.second->type) || (mode_share_all && it.second->known())) + cells.push_back(it.second); + } + + did_something = false; + std::map sharemap(CompareCells(this)); + for (auto cell : cells) + { + if (sharemap.count(cell) > 0) { + did_something = true; + log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); + for (auto &it : cell->connections()) { + if (cell->output(it.first)) { + RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); + log(" Redirecting output %s: %s = %s\n", it.first.c_str(), + log_signal(it.second), log_signal(other_sig)); + module->connect(RTLIL::SigSig(it.second, other_sig)); + assign_map.add(it.second, other_sig); + } + } + log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); +#ifdef USE_CELL_HASH_CACHE + cell_hash_cache.erase(cell); +#endif + module->remove(cell); + total_count++; + } else { + sharemap[cell] = cell; + } + } + } + } +}; + +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_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"); + log("\n"); + log(" -nomux\n"); + log(" Do not merge MUX cells.\n"); + log("\n"); + log(" -share_all\n"); + log(" Operate on all cell types, not just built-in types.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n"); + + bool mode_nomux = false; + bool mode_share_all = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-nomux") { + mode_nomux = true; + continue; + } + if (arg == "-share_all") { + mode_share_all = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + int total_count = 0; + for (auto module : design->selected_modules()) { + OptMergeWorker worker(design, module, mode_nomux, mode_share_all); + total_count += worker.total_count; + } + + if (total_count) + design->scratchpad_set_bool("opt.did_something", true); + log("Removed a total of %d cells.\n", total_count); + } +} 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 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 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 driven_bits; + dict 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 dff_list; std::vector 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/opt_share.cc b/passes/opt/opt_share.cc deleted file mode 100644 index 46752e43..00000000 --- a/passes/opt/opt_share.cc +++ /dev/null @@ -1,341 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * 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/sigtools.h" -#include "kernel/log.h" -#include "kernel/celltypes.h" -#include "libs/sha1/sha1.h" -#include -#include -#include - -#define USE_CELL_HASH_CACHE - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct OptShareWorker -{ - RTLIL::Design *design; - RTLIL::Module *module; - SigMap assign_map; - SigMap dff_init_map; - bool mode_share_all; - - CellTypes ct; - int total_count; -#ifdef USE_CELL_HASH_CACHE - dict cell_hash_cache; -#endif - -#ifdef USE_CELL_HASH_CACHE - std::string int_to_hash_string(unsigned int v) - { - if (v == 0) - return "0"; - std::string str = ""; - while (v > 0) { - str += 'a' + (v & 15); - v = v >> 4; - } - return str; - } - - std::string hash_cell_parameters_and_connections(const RTLIL::Cell *cell) - { - if (cell_hash_cache.count(cell) > 0) - return cell_hash_cache[cell]; - - std::string hash_string = cell->type.str() + "\n"; - - for (auto &it : cell->parameters) - hash_string += "P " + it.first.str() + "=" + it.second.as_string() + "\n"; - - const dict *conn = &cell->connections(); - dict alt_conn; - - if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" || - cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") { - alt_conn = *conn; - if (assign_map(alt_conn.at("\\A")) < assign_map(alt_conn.at("\\B"))) { - alt_conn["\\A"] = conn->at("\\B"); - alt_conn["\\B"] = conn->at("\\A"); - } - conn = &alt_conn; - } else - if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") { - alt_conn = *conn; - assign_map.apply(alt_conn.at("\\A")); - alt_conn.at("\\A").sort(); - conn = &alt_conn; - } else - if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") { - alt_conn = *conn; - assign_map.apply(alt_conn.at("\\A")); - alt_conn.at("\\A").sort_and_unify(); - conn = &alt_conn; - } - - 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() + "="; - for (auto &chunk : sig.chunks()) { - if (chunk.wire) - hash_string += "{" + 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(); - } - hash_string += "\n"; - } - - cell_hash_cache[cell] = sha1(hash_string); - return cell_hash_cache[cell]; - } -#endif - - bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2, bool <) - { -#ifdef USE_CELL_HASH_CACHE - std::string hash1 = hash_cell_parameters_and_connections(cell1); - std::string hash2 = hash_cell_parameters_and_connections(cell2); - - if (hash1 != hash2) { - lt = hash1 < hash2; - return true; - } -#endif - - if (cell1->parameters != cell2->parameters) { - std::map p1(cell1->parameters.begin(), cell1->parameters.end()); - std::map p2(cell2->parameters.begin(), cell2->parameters.end()); - lt = p1 < p2; - return true; - } - - dict conn1 = cell1->connections(); - dict conn2 = cell2->connections(); - - for (auto &it : conn1) { - if (cell1->output(it.first)) - it.second = RTLIL::SigSpec(); - else - assign_map.apply(it.second); - } - - for (auto &it : conn2) { - if (cell2->output(it.first)) - it.second = RTLIL::SigSpec(); - else - assign_map.apply(it.second); - } - - if (cell1->type == "$and" || cell1->type == "$or" || cell1->type == "$xor" || cell1->type == "$xnor" || cell1->type == "$add" || cell1->type == "$mul" || - cell1->type == "$logic_and" || cell1->type == "$logic_or" || cell1->type == "$_AND_" || cell1->type == "$_OR_" || cell1->type == "$_XOR_") { - if (conn1.at("\\A") < conn1.at("\\B")) { - RTLIL::SigSpec tmp = conn1["\\A"]; - conn1["\\A"] = conn1["\\B"]; - conn1["\\B"] = tmp; - } - if (conn2.at("\\A") < conn2.at("\\B")) { - RTLIL::SigSpec tmp = conn2["\\A"]; - conn2["\\A"] = conn2["\\B"]; - conn2["\\B"] = tmp; - } - } else - if (cell1->type == "$reduce_xor" || cell1->type == "$reduce_xnor") { - conn1["\\A"].sort(); - conn2["\\A"].sort(); - } else - if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") { - conn1["\\A"].sort_and_unify(); - conn2["\\A"].sort_and_unify(); - } - - if (conn1 != conn2) { - std::map c1(conn1.begin(), conn1.end()); - std::map c2(conn2.begin(), conn2.end()); - lt = c1 < c2; - return true; - } - - if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) { - std::vector q1 = dff_init_map(cell1->getPort("\\Q")).to_sigbit_vector(); - std::vector q2 = dff_init_map(cell2->getPort("\\Q")).to_sigbit_vector(); - for (size_t i = 0; i < q1.size(); i++) - if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) { - lt = q1.at(i) < q2.at(i); - return true; - } - } - - return false; - } - - bool compare_cells(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) - { - if (cell1->type != cell2->type) - return cell1->type < cell2->type; - - if ((!mode_share_all && !ct.cell_known(cell1->type)) || !cell1->known()) - return cell1 < cell2; - - if (cell1->has_keep_attr() || cell2->has_keep_attr()) - return cell1 < cell2; - - bool lt; - if (compare_cell_parameters_and_connections(cell1, cell2, lt)) - return lt; - - return false; - } - - struct CompareCells { - OptShareWorker *that; - CompareCells(OptShareWorker *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) : - design(design), module(module), assign_map(module), mode_share_all(mode_share_all) - { - total_count = 0; - ct.setup_internals(); - ct.setup_internals_mem(); - ct.setup_stdcells(); - ct.setup_stdcells_mem(); - - if (mode_nomux) { - ct.cell_types.erase("$mux"); - ct.cell_types.erase("$pmux"); - } - - log("Finding identical cells in module `%s'.\n", module->name.c_str()); - assign_map.set(module); - - dff_init_map.set(module); - for (auto &it : module->wires_) - if (it.second->attributes.count("\\init") != 0) - dff_init_map.add(it.second, it.second->attributes.at("\\init")); - - bool did_something = true; - while (did_something) - { -#ifdef USE_CELL_HASH_CACHE - cell_hash_cache.clear(); -#endif - std::vector cells; - cells.reserve(module->cells_.size()); - for (auto &it : module->cells_) { - if (!design->selected(module, it.second)) - continue; - if (ct.cell_known(it.second->type) || (mode_share_all && it.second->known())) - cells.push_back(it.second); - } - - did_something = false; - std::map sharemap(CompareCells(this)); - for (auto cell : cells) - { - if (sharemap.count(cell) > 0) { - did_something = true; - log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); - for (auto &it : cell->connections()) { - if (cell->output(it.first)) { - RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); - log(" Redirecting output %s: %s = %s\n", it.first.c_str(), - log_signal(it.second), log_signal(other_sig)); - module->connect(RTLIL::SigSig(it.second, other_sig)); - assign_map.add(it.second, other_sig); - } - } - log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); -#ifdef USE_CELL_HASH_CACHE - cell_hash_cache.erase(cell); -#endif - module->remove(cell); - total_count++; - } else { - sharemap[cell] = cell; - } - } - } - } -}; - -struct OptSharePass : public Pass { - OptSharePass() : Pass("opt_share", "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("\n"); - log("This pass identifies cells with identical type and input signals. Such cells\n"); - log("are then merged to one cell.\n"); - log("\n"); - log(" -nomux\n"); - log(" Do not merge MUX cells.\n"); - log("\n"); - log(" -share_all\n"); - log(" Operate on all cell types, not just built-in types.\n"); - log("\n"); - } - virtual void execute(std::vector args, RTLIL::Design *design) - { - log_header("Executing OPT_SHARE pass (detect identical cells).\n"); - - bool mode_nomux = false; - bool mode_share_all = false; - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-nomux") { - mode_nomux = true; - continue; - } - if (arg == "-share_all") { - mode_share_all = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - int total_count = 0; - for (auto module : design->selected_modules()) { - OptShareWorker worker(design, module, mode_nomux, mode_share_all); - total_count += worker.total_count; - } - - if (total_count) - design->scratchpad_set_bool("opt.did_something", true); - log("Removed a total of %d cells.\n", total_count); - } -} OptSharePass; - -PRIVATE_NAMESPACE_END 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 & /* patterns */) + void optimize_activation_patterns(pool &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> 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 &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 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 [!]\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 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 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 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 generated_dlatches; + dict> mux_srcbits; dict> mux_drivers; dict 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, i); + + pool 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 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 haystack_bits = sigmap(haystack).to_sigbit_pool(); + pool needle_bits = sigmap(needle).to_sigbit_pool(); + + pool cells_queue, cells_visited; + pool 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 visited, queue; + dict> upstream_cell2net; + dict> 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 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 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 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 &compare, RTLIL::SwitchRule *sw) +RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector &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 &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 &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 &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 &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 &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 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 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 + * + * 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_muxusers; + + dict sigbit_actsignals; + dict sigspec_actsignals; + dict, 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 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 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 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 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 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 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 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 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 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 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 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 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 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 lut_costs, bool dff_mode, std::string clk_str, - bool keepff, std::string delay_target, bool fast_mode, const std::vector &cells, bool show_tempdir) + bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, bool fast_mode, + const std::vector &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 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 \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-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 \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 \n"); + log(" maximum number of SOP inputs.\n"); + log(" (replaces {I} in the default scripts above)\n"); + log("\n"); + log(" -P \n"); + log(" maximum number of SOP products.\n"); + log(" (replaces {P} in the default scripts above)\n"); + log("\n"); log(" -lut \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 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 lut_costs; markgroups = false; @@ -1302,8 +1345,10 @@ 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; @@ -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 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 + * + * 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> &actions, dict &attributes) +{ + dict 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 \n"); + log(" Match attribute names case-insensitively and set it to the specified\n"); + log(" name.\n"); + log("\n"); + log(" -rename \n"); + log(" Rename attributes as specified\n"); + log("\n"); + log(" -map = =\n"); + log(" Map key/value pairs as indicated.\n"); + log("\n"); + log(" -imap = =\n"); + log(" Like -map, but use case-insensitive match for when\n"); + log(" it is a string value.\n"); + log("\n"); + log(" -remove =\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 args, RTLIL::Design *design) + { + log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n"); + + bool modattr_mode = false; + vector> 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(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(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(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(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 + * + * 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 \n"); + log(" Move or copy this attribute. This option can be used\n"); + log(" multiple times.\n"); + log("\n"); + } + virtual void execute(std::vector 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 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> 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 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 + * + * 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 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 bits_written, bits_used, bits_inout; + dict 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 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 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 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> 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 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 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 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 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 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 needle_map, haystack_map; std::vector 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 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 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 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 + * + * 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 \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 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 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 [:]\n"); log(" -inoutpad [:]\n"); log(" Similar to -inpad, but for output and inout ports.\n"); log("\n"); + log(" -toutpad :[:]\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 ::[:]\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 \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 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> skip_wires; + + if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) + { + SigMap sigmap(module); + dict>> 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 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 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 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 luts; + bool assert_mode = false; }; struct NlutmapWorker @@ -64,7 +65,7 @@ struct NlutmapWorker { vector 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 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 + * + * 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 &taps) = 0; + virtual bool fixup(Cell *cell, dict &taps) = 0; +}; + +struct ShregmapOptions +{ + int minlen, maxlen; + int keep_before, keep_after; + bool zinit, init, params, ffe; + dict> 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 &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 &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 remove_cells; + pool remove_init; + + dict sigbit_init; + dict sigbit_chain_next; + dict sigbit_chain_prev; + pool sigbit_with_non_chain_users; + pool 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 create_chain(Cell *start_cell) + { + vector 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 &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 taps_dict; + + if (opts.tech) + { + vector qbits; + vector 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 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 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 [::]\n"); + log(" match the specified cells instead of $_DFF_N_ and $_DFF_P_. If\n"); + log(" '::' 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 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 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 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 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(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 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 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--; 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(" }, $time, i);\n"); f << stringf("end\n"); @@ -268,17 +286,17 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("task %s;\n", idy(mod->name.str(), "print_header").c_str()); f << stringf("begin\n"); - f << stringf("\t$display(\"#OUT#\");\n"); + f << stringf("\t$fdisplay(file, \"#OUT#\");\n"); for (auto &hdr : header1) - f << stringf("\t$display(\"#OUT# %s\");\n", hdr.c_str()); - f << stringf("\t$display(\"#OUT#\");\n"); - f << stringf("\t$display(\"#OUT# %s\");\n", header2.c_str()); + f << stringf("\t$fdisplay(file, \"#OUT# %s\");\n", hdr.c_str()); + f << stringf("\t$fdisplay(file, \"#OUT#\");\n"); + f << stringf("\t$fdisplay(file, {\"#OUT# \"%s});\n", header2.c_str()); f << stringf("end\n"); f << stringf("endtask\n\n"); f << stringf("task %s;\n", idy(mod->name.str(), "test").c_str()); f << stringf("begin\n"); - f << stringf("\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str()); + f << stringf("\t$fdisplay(file, \"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name.str()).c_str()); f << stringf("\t%s;\n", idy(mod->name.str(), "reset").c_str()); f << stringf("\tfor (i=0; i<%d; i=i+1) begin\n", num_iter); f << stringf("\t\tif (i %% 20 == 0) %s;\n", idy(mod->name.str(), "print_header").c_str()); @@ -293,9 +311,11 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter) f << stringf("initial begin\n"); f << stringf("\t// $dumpfile(\"testbench.vcd\");\n"); f << stringf("\t// $dumpvars(0, testbench);\n"); + f << stringf("\tfile = $fopen(`outfile);\n"); for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) if (!it->second->get_bool_attribute("\\gentb_skip")) f << stringf("\t%s;\n", idy(it->first.str(), "test").c_str()); + f << stringf("\t$fclose(file);\n"); f << stringf("\t$finish;\n"); f << stringf("end\n\n"); @@ -332,8 +352,9 @@ struct TestAutotbBackend : public Backend { virtual void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) { int num_iter = 1000; + int seed = 0; - log_header("Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n"); + log_header(design, "Executing TEST_AUTOTB backend (auto-generate pseudo-random test benches).\n"); int argidx; for (argidx = 1; argidx < GetSize(args); argidx++) @@ -342,11 +363,15 @@ struct TestAutotbBackend : public Backend { num_iter = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-seed" && argidx+1 < GetSize(args)) { + seed = atoi(args[++argidx].c_str()); + continue; + } break; } extra_args(f, filename, args, argidx); - autotest(*f, design, num_iter); + autotest(*f, design, num_iter, seed); } } TestAutotbBackend; diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index a8fcac9b..049c2053 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -21,6 +21,7 @@ #include "kernel/yosys.h" #include "kernel/satgen.h" #include "kernel/consteval.h" +#include "kernel/celledges.h" #include "kernel/macc.h" #include @@ -42,6 +43,32 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, RTLIL::Cell *cell = module->addCell("\\UUT", cell_type); RTLIL::Wire *wire; + if (cell_type == "$mux" || cell_type == "$pmux") + { + int width = 1 + xorshift32(8); + int swidth = cell_type == "$mux" ? 1 : 1 + xorshift32(8); + + wire = module->addWire("\\A"); + wire->width = width; + wire->port_input = true; + cell->setPort("\\A", wire); + + wire = module->addWire("\\B"); + wire->width = width * swidth; + wire->port_input = true; + cell->setPort("\\B", wire); + + wire = module->addWire("\\S"); + wire->width = swidth; + wire->port_input = true; + cell->setPort("\\S", wire); + + wire = module->addWire("\\Y"); + wire->width = width; + wire->port_output = true; + cell->setPort("\\Y", wire); + } + if (cell_type == "$fa") { int width = 1 + xorshift32(8); @@ -164,6 +191,41 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->setParam("\\LUT", config.as_const()); } + if (cell_type == "$sop") + { + int width = 1 + xorshift32(8); + int depth = 1 + xorshift32(8); + + wire = module->addWire("\\A"); + wire->width = width; + wire->port_input = true; + cell->setPort("\\A", wire); + + wire = module->addWire("\\Y"); + wire->port_output = true; + cell->setPort("\\Y", wire); + + RTLIL::SigSpec config; + for (int i = 0; i < width*depth; i++) + switch (xorshift32(3)) { + case 0: + config.append(RTLIL::S1); + config.append(RTLIL::S0); + break; + case 1: + config.append(RTLIL::S0); + config.append(RTLIL::S1); + break; + case 2: + config.append(RTLIL::S0); + config.append(RTLIL::S0); + break; + } + + cell->setParam("\\DEPTH", depth); + cell->setParam("\\TABLE", config.as_const()); + } + if (cell_type_flags.find('A') != std::string::npos) { wire = module->addWire("\\A"); wire->width = 1 + xorshift32(8); @@ -270,6 +332,91 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->check(); } +static void run_edges_test(RTLIL::Design *design, bool verbose) +{ + Module *module = *design->modules().begin(); + Cell *cell = *module->cells().begin(); + + ezSatPtr ezptr; + ezSAT &ez = *ezptr.get(); + + SigMap sigmap(module); + SatGen satgen(&ez, &sigmap); + + FwdCellEdgesDatabase edges_db(sigmap); + if (!edges_db.add_edges_from_cell(cell)) + log_error("Creating edge database failed for this cell!\n"); + + dict> satgen_db; + + satgen.setContext(&sigmap, "X:"); + satgen.importCell(cell); + + satgen.setContext(&sigmap, "Y:"); + satgen.importCell(cell); + + vector> input_db, output_db; + + for (auto &conn : cell->connections()) + { + SigSpec bits = sigmap(conn.second); + + satgen.setContext(&sigmap, "X:"); + std::vector xbits = satgen.importSigSpec(bits); + + satgen.setContext(&sigmap, "Y:"); + std::vector ybits = satgen.importSigSpec(bits); + + for (int i = 0; i < GetSize(bits); i++) + if (cell->input(conn.first)) + input_db.emplace_back(bits[i], xbits[i], ybits[i]); + else + output_db.emplace_back(bits[i], xbits[i], ybits[i]); + } + + if (verbose) + log("\nSAT solving for all edges:\n"); + + for (int i = 0; i < GetSize(input_db); i++) + { + SigBit inbit = std::get<0>(input_db[i]); + + if (verbose) + log(" Testing input signal %s:\n", log_signal(inbit)); + + vector xinbits, yinbits; + for (int k = 0; k < GetSize(input_db); k++) + if (k != i) { + xinbits.push_back(std::get<1>(input_db[k])); + yinbits.push_back(std::get<2>(input_db[k])); + } + + int xyinbit_ok = ez.vec_eq(xinbits, yinbits); + + for (int k = 0; k < GetSize(output_db); k++) + { + SigBit outbit = std::get<0>(output_db[k]); + int xoutbit = std::get<1>(output_db[k]); + int youtbit = std::get<2>(output_db[k]); + + bool is_edge = ez.solve(xyinbit_ok, ez.XOR(xoutbit, youtbit)); + + if (is_edge) + satgen_db[inbit].insert(outbit); + + if (verbose) { + bool is_ref_edge = edges_db.db.count(inbit) && edges_db.db.at(inbit).count(outbit); + log(" %c %s %s\n", is_edge ? 'x' : 'o', log_signal(outbit), is_edge == is_ref_edge ? "OK" : "ERROR"); + } + } + } + + if (satgen_db == edges_db.db) + log("PASS.\n"); + else + log_error("SAT-based edge table does not match the database!\n"); +} + static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std::string uut_name, std::ofstream &vlog_file) { log("Eval testing:%c", verbose ? '\n' : ' '); @@ -534,7 +681,7 @@ struct TestCellPass : public Pass { log(" pass this option to techmap.\n"); log("\n"); log(" -simlib\n"); - log(" use \"techmap -map +/simlib.v -max_iter 2 -autoproc\"\n"); + log(" use \"techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc\"\n"); log("\n"); log(" -aigmap\n"); log(" instead of calling \"techmap\", call \"aigmap\"\n"); @@ -555,6 +702,9 @@ struct TestCellPass : public Pass { log(" -noeval\n"); log(" do not check const-eval models\n"); log("\n"); + log(" -edges\n"); + log(" test cell edges db creator against sat-based implementation\n"); + log("\n"); log(" -v\n"); log(" print additional debug information to the console\n"); log("\n"); @@ -574,6 +724,7 @@ struct TestCellPass : public Pass { bool constmode = false; bool nosat = false; bool noeval = false; + bool edges = false; int argidx; for (argidx = 1; argidx < GetSize(args); argidx++) @@ -604,7 +755,7 @@ struct TestCellPass : public Pass { continue; } if (args[argidx] == "-simlib") { - techmap_cmd = "techmap -map +/simlib.v -max_iter 2 -autoproc"; + techmap_cmd = "techmap -D SIMLIB_NOCHECKS -map +/simlib.v -max_iter 2 -autoproc"; continue; } if (args[argidx] == "-aigmap") { @@ -627,6 +778,10 @@ struct TestCellPass : public Pass { noeval = true; continue; } + if (args[argidx] == "-edges") { + edges = true; + continue; + } if (args[argidx] == "-v") { verbose = true; continue; @@ -690,13 +845,18 @@ struct TestCellPass : public Pass { cell_types["$logic_and"] = "ABSY"; cell_types["$logic_or"] = "ABSY"; - // cell_types["$mux"] = "A"; - // cell_types["$pmux"] = "A"; + if (edges) { + cell_types["$mux"] = "*"; + cell_types["$pmux"] = "*"; + } + // cell_types["$slice"] = "A"; // cell_types["$concat"] = "A"; // cell_types["$assert"] = "A"; + // cell_types["$assume"] = "A"; cell_types["$lut"] = "*"; + cell_types["$sop"] = "*"; cell_types["$alu"] = "ABSY"; cell_types["$lcu"] = "*"; cell_types["$macc"] = "*"; @@ -763,6 +923,9 @@ struct TestCellPass : public Pass { create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv); if (!write_prefix.empty()) { Pass::call(design, stringf("write_ilang %s_%s_%05d.il", write_prefix.c_str(), cell_type.c_str()+1, i)); + } else if (edges) { + Pass::call(design, "dump gold"); + run_edges_test(design, verbose); } else { Pass::call(design, stringf("copy gold gate; cd gate; %s; cd ..; opt -fast gate", techmap_cmd.c_str())); if (!nosat) diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index 8bae920d..fac6c4ba 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -25,22 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct PrepPass : public ScriptPass { - if (!run_from.empty() && run_from == run_to) { - active = (label == run_from); - } else { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - } - return active; -} + PrepPass() : ScriptPass("prep", "generic synthesis script") { } -struct PrepPass : public Pass { - PrepPass() : Pass("prep", "generic synthesis script") { } - virtual void help() + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -53,6 +42,24 @@ struct PrepPass : public Pass { log(" -top \n"); log(" use the specified module as top module (default='top')\n"); log("\n"); + log(" -auto-top\n"); + log(" automatically determine the top of the design hierarchy\n"); + log("\n"); + log(" -flatten\n"); + log(" flatten the design before synthesis. this will pass '-auto-top' to\n"); + log(" 'hierarchy' if no top module is specified.\n"); + log("\n"); + log(" -ifx\n"); + log(" passed to 'proc'. uses verilog simulation behavior for verilog if/case\n"); + log(" undef handling. this also prevents 'wreduce' from being run.\n"); + log("\n"); + log(" -memx\n"); + log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n"); + log(" using the 'memory_memx' pass. This option implies -nordff.\n"); + log("\n"); + log(" -nomem\n"); + log(" do not run any of the memory_* passes\n"); + log("\n"); log(" -nordff\n"); log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n"); log("\n"); @@ -63,31 +70,28 @@ struct PrepPass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); - log(" begin:\n"); - log(" hierarchy -check [-top ]\n"); - log("\n"); - log(" prep:\n"); - log(" proc\n"); - log(" opt_const\n"); - log(" opt_clean\n"); - log(" check\n"); - log(" opt -keepdc\n"); - log(" wreduce\n"); - log(" memory_dff [-nordff]\n"); - log(" opt_clean\n"); - log(" memory_collect\n"); - log(" opt -keepdc -fast\n"); - log("\n"); - log(" check:\n"); - log(" stat\n"); - log(" check\n"); - log("\n"); } - virtual void execute(std::vector args, RTLIL::Design *design) + + string top_module, fsm_opts, memory_opts; + bool autotop, flatten, ifxmode, memxmode, nomemmode; + + virtual void clear_flags() YS_OVERRIDE + { + top_module.clear(); + memory_opts.clear(); + + autotop = false; + flatten = false; + ifxmode = false; + memxmode = false; + nomemmode = false; + } + + virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_module, memory_opts; - std::string run_from, run_to; + string run_from, run_to; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -107,6 +111,27 @@ struct PrepPass : public Pass { } continue; } + if (args[argidx] == "-auto-top") { + autotop = true; + continue; + } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } + if (args[argidx] == "-ifx") { + ifxmode = true; + continue; + } + if (args[argidx] == "-memx") { + memxmode = true; + memory_opts += " -nordff"; + continue; + } + if (args[argidx] == "-nomem") { + nomemmode = true; + continue; + } if (args[argidx] == "-nordff") { memory_opts += " -nordff"; continue; @@ -118,40 +143,65 @@ struct PrepPass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); - - log_header("Executing PREP pass.\n"); + log_header(design, "Executing PREP pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + + if (check_label("begin")) { - if (top_module.empty()) - Pass::call(design, stringf("hierarchy -check")); - else - Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); + if (help_mode) { + run("hierarchy -check [-top | -auto-top]"); + } else { + if (top_module.empty()) { + if (flatten || autotop) + run("hierarchy -check -auto-top"); + else + run("hierarchy -check"); + } else + run(stringf("hierarchy -check -top %s", top_module.c_str())); + } } - if (check_label(active, run_from, run_to, "coarse")) + if (check_label("coarse")) { - Pass::call(design, "proc"); - Pass::call(design, "opt_const"); - Pass::call(design, "opt_clean"); - Pass::call(design, "check"); - Pass::call(design, "opt -keepdc"); - Pass::call(design, "wreduce"); - Pass::call(design, "memory_dff" + memory_opts); - Pass::call(design, "opt_clean"); - Pass::call(design, "memory_collect"); - Pass::call(design, "opt -keepdc -fast"); + if (help_mode) + run("proc [-ifx]"); + else + run(ifxmode ? "proc -ifx" : "proc"); + if (help_mode || flatten) + run("flatten", "(if -flatten)"); + run("opt_expr -keepdc"); + run("opt_clean"); + run("check"); + run("opt -keepdc"); + if (!ifxmode) { + if (help_mode) + run("wreduce [-memx]"); + else + run(memxmode ? "wreduce -memx" : "wreduce"); + } + if (!nomemmode) { + run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts)); + if (help_mode || memxmode) + run("memory_memx", "(if -memx)"); + run("opt_clean"); + run("memory_collect"); + } + run("opt -keepdc -fast"); } - if (check_label(active, run_from, run_to, "check")) + if (check_label("check")) { - Pass::call(design, "stat"); - Pass::call(design, "check"); + run("stat"); + run("check"); } - - log_pop(); } } PrepPass; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index a2dc466d..922a47ca 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -33,6 +33,12 @@ // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $not (A, Y) +//- +//- A bit-wise inverter. This corresponds to the Verilog unary prefix '~' operator. +//- module \$not (A, Y); parameter A_SIGNED = 0; @@ -55,6 +61,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $pos (A, Y) +//- +//- A buffer. This corresponds to the Verilog unary prefix '+' operator. +//- module \$pos (A, Y); parameter A_SIGNED = 0; @@ -76,6 +88,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $neg (A, Y) +//- +//- An arithmetic inverter. This corresponds to the Verilog unary prefix '-' operator. +//- module \$neg (A, Y); parameter A_SIGNED = 0; @@ -97,6 +115,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $and (A, B, Y) +//- +//- A bit-wise AND. This corresponds to the Verilog '&' operator. +//- module \$and (A, B, Y); parameter A_SIGNED = 0; @@ -121,6 +145,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $or (A, B, Y) +//- +//- A bit-wise OR. This corresponds to the Verilog '|' operator. +//- module \$or (A, B, Y); parameter A_SIGNED = 0; @@ -145,6 +175,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $xor (A, B, Y) +//- +//- A bit-wise XOR. This corresponds to the Verilog '^' operator. +//- module \$xor (A, B, Y); parameter A_SIGNED = 0; @@ -169,6 +205,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $xnor (A, B, Y) +//- +//- A bit-wise XNOR. This corresponds to the Verilog '~^' operator. +//- module \$xnor (A, B, Y); parameter A_SIGNED = 0; @@ -193,6 +235,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_and (A, B, Y) +//- +//- An AND reduction. This corresponds to the Verilog unary prefix '&' operator. +//- module \$reduce_and (A, Y); parameter A_SIGNED = 0; @@ -214,6 +262,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_or (A, B, Y) +//- +//- An OR reduction. This corresponds to the Verilog unary prefix '|' operator. +//- module \$reduce_or (A, Y); parameter A_SIGNED = 0; @@ -235,6 +289,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_xor (A, B, Y) +//- +//- A XOR reduction. This corresponds to the Verilog unary prefix '^' operator. +//- module \$reduce_xor (A, Y); parameter A_SIGNED = 0; @@ -256,6 +316,12 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_xnor (A, B, Y) +//- +//- A XNOR reduction. This corresponds to the Verilog unary prefix '~^' operator. +//- module \$reduce_xnor (A, Y); parameter A_SIGNED = 0; @@ -277,6 +343,13 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $reduce_bool (A, B, Y) +//- +//- An OR reduction. This cell type is used instead of $reduce_or when a signal is +//- implicitly converted to a boolean signal, e.g. for operands of '&&' and '||'. +//- module \$reduce_bool (A, Y); parameter A_SIGNED = 0; @@ -1156,6 +1229,34 @@ endmodule `endif // -------------------------------------------------------- +module \$sop (A, Y); + +parameter WIDTH = 0; +parameter DEPTH = 0; +parameter TABLE = 0; + +input [WIDTH-1:0] A; +output reg Y; + +integer i, j; +reg match; + +always @* begin + Y = 0; + for (i = 0; i < DEPTH; i=i+1) begin + match = 1; + for (j = 0; j < WIDTH; j=j+1) begin + if (TABLE[2*WIDTH*i + 2*j + 0] && A[j]) match = 0; + if (TABLE[2*WIDTH*i + 2*j + 1] && !A[j]) match = 0; + end + if (match) Y = 1; + end +end + +endmodule + +// -------------------------------------------------------- + module \$tribuf (A, EN, Y); parameter WIDTH = 0; @@ -1204,6 +1305,35 @@ endmodule // -------------------------------------------------------- +module \$initstate (Y); + +output reg Y = 1; +reg [3:0] cnt = 1; +reg trig = 0; + +initial trig <= 1; + +always @(cnt, trig) begin + Y <= |cnt; + cnt <= cnt + |cnt; +end + +endmodule + +// -------------------------------------------------------- + +module \$anyconst (Y); + +parameter WIDTH = 0; + +output [WIDTH-1:0] Y; + +assign Y = 'bx; + +endmodule + +// -------------------------------------------------------- + module \$equiv (A, B, Y); input A, B; @@ -1239,7 +1369,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate - for (i = 0; i < WIDTH; i = i+1) begin:bit + for (i = 0; i < WIDTH; i = i+1) begin:bitslices always @(posedge pos_set[i], posedge pos_clr[i]) if (pos_clr[i]) Q[i] <= 0; @@ -1308,7 +1438,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate - for (i = 0; i < WIDTH; i = i+1) begin:bit + for (i = 0; i < WIDTH; i = i+1) begin:bitslices always @(posedge pos_set[i], posedge pos_clr[i], posedge pos_clk) if (pos_clr[i]) Q[i] <= 0; @@ -1384,7 +1514,7 @@ wire [WIDTH-1:0] pos_clr = CLR_POLARITY ? CLR : ~CLR; genvar i; generate - for (i = 0; i < WIDTH; i = i+1) begin:bit + for (i = 0; i < WIDTH; i = i+1) begin:bitslices always @* if (pos_clr[i]) Q[i] = 0; diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 83d00f32..11ebe533 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -25,22 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthPass : public ScriptPass { - if (!run_from.empty() && run_from == run_to) { - active = (label == run_from); - } else { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - } - return active; -} + SynthPass() : ScriptPass("synth", "generic synthesis script") { } -struct SynthPass : public Pass { - SynthPass() : Pass("synth", "generic synthesis script") { } - virtual void help() + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -52,6 +41,13 @@ struct SynthPass : public Pass { log(" -top \n"); log(" use the specified module as top module (default='top')\n"); log("\n"); + log(" -auto-top\n"); + log(" automatically determine the top of the design hierarchy\n"); + log("\n"); + log(" -flatten\n"); + log(" flatten the design before synthesis. this will pass '-auto-top' to\n"); + log(" 'hierarchy' if no top module is specified.\n"); + log("\n"); log(" -encfile \n"); log(" passed to 'fsm_recode' via 'fsm'\n"); log("\n"); @@ -75,49 +71,30 @@ struct SynthPass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); - log("\n"); - log(" begin:\n"); - log(" hierarchy -check [-top ]\n"); - log("\n"); - log(" coarse:\n"); - log(" proc\n"); - log(" opt_const\n"); - log(" opt_clean\n"); - log(" check\n"); - log(" opt\n"); - log(" wreduce\n"); - log(" alumacc\n"); - log(" share\n"); - log(" opt\n"); - log(" fsm\n"); - log(" opt -fast\n"); - log(" memory -nomap\n"); - log(" opt_clean\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -full\n"); - log(" memory_map\n"); - log(" opt -full\n"); - log(" techmap\n"); - log(" opt -fast\n"); - #ifdef YOSYS_ENABLE_ABC - log(" abc -fast\n"); - log(" opt -fast\n"); - #endif - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check\n"); + help_script(); log("\n"); } - virtual void execute(std::vector args, RTLIL::Design *design) + + string top_module, fsm_opts, memory_opts; + bool autotop, flatten, noalumacc, nofsm, noabc; + + virtual void clear_flags() YS_OVERRIDE + { + top_module.clear(); + fsm_opts.clear(); + memory_opts.clear(); + + autotop = false; + flatten = false; + noalumacc = false; + nofsm = false; + noabc = false; + } + + virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_module, fsm_opts, memory_opts; - std::string run_from, run_to; - bool noalumacc = false; - bool nofsm = false; - bool noabc = false; + string run_from, run_to; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -141,6 +118,14 @@ struct SynthPass : public Pass { } continue; } + if (args[argidx] == "-auto-top") { + autotop = true; + continue; + } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } if (args[argidx] == "-nofsm") { nofsm = true; continue; @@ -164,62 +149,74 @@ struct SynthPass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); - - log_header("Executing SYNTH pass.\n"); + log_header(design, "Executing SYNTH pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) { - if (top_module.empty()) - Pass::call(design, stringf("hierarchy -check")); - else - Pass::call(design, stringf("hierarchy -check -top %s", top_module.c_str())); + if (help_mode) { + run("hierarchy -check [-top | -auto-top]"); + } else { + if (top_module.empty()) { + if (flatten || autotop) + run("hierarchy -check -auto-top"); + else + run("hierarchy -check"); + } else + run(stringf("hierarchy -check -top %s", top_module.c_str())); + } } - if (check_label(active, run_from, run_to, "coarse")) + if (check_label("coarse")) { - Pass::call(design, "proc"); - Pass::call(design, "opt_const"); - Pass::call(design, "opt_clean"); - Pass::call(design, "check"); - Pass::call(design, "opt"); - Pass::call(design, "wreduce"); + run("proc"); + if (help_mode || flatten) + run("flatten", "(if -flatten)"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); if (!noalumacc) - Pass::call(design, "alumacc"); - Pass::call(design, "share"); - Pass::call(design, "opt"); + run("alumacc"); + run("share"); + run("opt"); if (!nofsm) - Pass::call(design, "fsm" + fsm_opts); - Pass::call(design, "opt -fast"); - Pass::call(design, "memory -nomap" + memory_opts); - Pass::call(design, "opt_clean"); + run("fsm" + fsm_opts); + run("opt -fast"); + run("memory -nomap" + memory_opts); + run("opt_clean"); } - if (check_label(active, run_from, run_to, "fine")) + if (check_label("fine")) { - Pass::call(design, "opt -fast -full"); - Pass::call(design, "memory_map"); - Pass::call(design, "opt -full"); - Pass::call(design, "techmap"); - Pass::call(design, "opt -fast"); + run("opt -fast -full"); + run("memory_map"); + run("opt -full"); + run("techmap"); + run("opt -fast"); if (!noabc) { #ifdef YOSYS_ENABLE_ABC - Pass::call(design, "abc -fast"); - Pass::call(design, "opt -fast"); + run("abc -fast"); + run("opt -fast"); #endif } } - if (check_label(active, run_from, run_to, "check")) + if (check_label("check")) { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check"); + run("hierarchy -check"); + run("stat"); + run("check"); } - - log_pop(); } } SynthPass; diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index ae08c3d1..90c4ed7e 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -93,7 +93,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y); localparam BB_WIDTH = `MIN($clog2(shift_left ? Y_WIDTH : A_SIGNED ? WIDTH : A_WIDTH) + 1, B_WIDTH); wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; - wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; + wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; reg [WIDTH-1:0] buffer; @@ -136,7 +136,7 @@ module _90_shift_shiftx (A, B, Y); localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx; wire [1023:0] _TECHMAP_DO_00_ = "proc;;"; - wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_const -mux_undef -mux_bool -fine;;;"; + wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;"; integer i; reg [WIDTH-1:0] buffer; @@ -452,7 +452,7 @@ endmodule `ifndef NOLUT (* techmap_simplemap *) -(* techmap_celltype = "$lut" *) +(* techmap_celltype = "$lut $sop" *) module _90_lut; endmodule `endif diff --git a/techlibs/greenpak4/Makefile.inc b/techlibs/greenpak4/Makefile.inc index 5808e7bd..1c9871e2 100644 --- a/techlibs/greenpak4/Makefile.inc +++ b/techlibs/greenpak4/Makefile.inc @@ -1,5 +1,7 @@ OBJS += techlibs/greenpak4/synth_greenpak4.o +OBJS += techlibs/greenpak4/greenpak4_counters.o +OBJS += techlibs/greenpak4/greenpak4_dffinv.o $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_map.v)) $(eval $(call add_share_file,share/greenpak4,techlibs/greenpak4/cells_sim.v)) diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v index 667d853d..111a77a1 100644 --- a/techlibs/greenpak4/cells_map.v +++ b/techlibs/greenpak4/cells_map.v @@ -1,20 +1,61 @@ -module \$_DFF_P_ (input D, C, output Q); - GP_DFF _TECHMAP_REPLACE_ ( +module GP_DFFS(input D, CLK, nSET, output reg Q); + parameter [0:0] INIT = 1'bx; + GP_DFFSR #( + .INIT(INIT), + .SRMODE(1'b1), + ) _TECHMAP_REPLACE_ ( .D(D), - .Q(Q), - .CLK(C), - .nRSTZ(1'b1), - .nSETZ(1'b1) + .CLK(CLK), + .nSR(nSET), + .Q(Q) ); endmodule -module \$_DFFSR_PNN_ (input C, S, R, D, output Q); - GP_DFF _TECHMAP_REPLACE_ ( +module GP_DFFR(input D, CLK, nRST, output reg Q); + parameter [0:0] INIT = 1'bx; + GP_DFFSR #( + .INIT(INIT), + .SRMODE(1'b0), + ) _TECHMAP_REPLACE_ ( .D(D), - .Q(Q), - .CLK(C), - .nRSTZ(R), - .nSETZ(S) + .CLK(CLK), + .nSR(nRST), + .Q(Q) + ); +endmodule + +module GP_DFFSI(input D, CLK, nSET, output reg nQ); + parameter [0:0] INIT = 1'bx; + GP_DFFSRI #( + .INIT(INIT), + .SRMODE(1'b1), + ) _TECHMAP_REPLACE_ ( + .D(D), + .CLK(CLK), + .nSR(nSET), + .nQ(nQ) + ); +endmodule + +module GP_DFFRI(input D, CLK, nRST, output reg nQ); + parameter [0:0] INIT = 1'bx; + GP_DFFSRI #( + .INIT(INIT), + .SRMODE(1'b0), + ) _TECHMAP_REPLACE_ ( + .D(D), + .CLK(CLK), + .nSR(nRST), + .nQ(nQ) + ); +endmodule + +module GP_OBUFT(input IN, input OE, output OUT); + GP_IOBUF _TECHMAP_REPLACE_ ( + .IN(IN), + .OE(OE), + .IO(OUT), + .OUT() ); endmodule @@ -27,8 +68,13 @@ module \$lut (A, Y); generate if (WIDTH == 1) begin - GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(1'b0)); + if(LUT == 2'b01) begin + GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) ); + end + else begin + GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(1'b0)); + end end else if (WIDTH == 2) begin GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), diff --git a/techlibs/greenpak4/cells_sim.v b/techlibs/greenpak4/cells_sim.v index d9ddaacc..6ae9ae79 100644 --- a/techlibs/greenpak4/cells_sim.v +++ b/techlibs/greenpak4/cells_sim.v @@ -1,13 +1,4 @@ -module GP_DFF(input D, CLK, nRSTZ, nSETZ, output reg Q); - always @(posedge CLK, negedge nRSTZ, negedge nSETZ) begin - if (!nRSTZ) - Q <= 1'b0; - else if (!nSETZ) - Q <= 1'b1; - else - Q <= D; - end -endmodule +`timescale 1ns/1ps module GP_2LUT(input IN0, IN1, output OUT); parameter [3:0] INIT = 0; @@ -23,3 +14,417 @@ module GP_4LUT(input IN0, IN1, IN2, IN3, output OUT); parameter [15:0] INIT = 0; assign OUT = INIT[{IN3, IN2, IN1, IN0}]; endmodule + +module GP_ABUF(input wire IN, output wire OUT); + + assign OUT = IN; + + //cannot simulate mixed signal IP + +endmodule + +module GP_ACMP(input wire PWREN, input wire VIN, input wire VREF, output reg OUT); + + parameter BANDWIDTH = "HIGH"; + parameter VIN_ATTEN = 1; + parameter VIN_ISRC_EN = 0; + parameter HYSTERESIS = 0; + + initial OUT = 0; + + //cannot simulate mixed signal IP + +endmodule + +module GP_BANDGAP(output reg OK); + parameter AUTO_PWRDN = 1; + parameter CHOPPER_EN = 1; + parameter OUT_DELAY = 100; + + //cannot simulate mixed signal IP + +endmodule + +module GP_COUNT8(input CLK, input wire RST, output reg OUT); + + parameter RESET_MODE = "RISING"; + + parameter COUNT_TO = 8'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + + reg[7:0] count = COUNT_TO; + + //Combinatorially output whenever we wrap low + always @(*) begin + OUT <= (count == 8'h0); + end + + //POR or SYSRST reset value is COUNT_TO. Datasheet is unclear but conversations w/ Silego confirm. + //Runtime reset value is clearly 0 except in count/FSM cells where it's configurable but we leave at 0 for now. + //Datasheet seems to indicate that reset is asynchronous, but for now we model as sync due to Yosys issues... + always @(posedge CLK) begin + + count <= count - 1'd1; + + if(count == 0) + count <= COUNT_TO; + + /* + if((RESET_MODE == "RISING") && RST) + count <= 0; + if((RESET_MODE == "FALLING") && !RST) + count <= 0; + if((RESET_MODE == "BOTH") && RST) + count <= 0; + */ + end + +endmodule + +module GP_COUNT14(input CLK, input wire RST, output reg OUT); + + parameter RESET_MODE = "RISING"; + + parameter COUNT_TO = 14'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + +endmodule + +module GP_COUNT8_ADV(input CLK, input RST, output reg OUT, + input UP, input KEEP); + + parameter RESET_MODE = "RISING"; + parameter RESET_VALUE = "ZERO"; + + parameter COUNT_TO = 8'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + +endmodule + +module GP_COUNT14_ADV(input CLK, input RST, output reg OUT, + input UP, input KEEP); + + parameter RESET_MODE = "RISING"; + parameter RESET_VALUE = "ZERO"; + + parameter COUNT_TO = 14'h1; + parameter CLKIN_DIVIDE = 1; + + //more complex hard IP blocks are not supported for simulation yet + +endmodule + +module GP_DAC(input[7:0] DIN, input wire VREF, output reg VOUT); + + initial VOUT = 0; + + //analog hard IP is not supported for simulation + +endmodule + +module GP_DELAY(input IN, output reg OUT); + + parameter DELAY_STEPS = 1; + + //TODO: additional delay/glitch filter mode + + initial OUT = 0; + + generate + + //TODO: These delays are PTV dependent! For now, hard code 3v3 timing + //Change simulation-mode delay depending on global Vdd range (how to specify this?) + always @(*) begin + case(DELAY_STEPS) + 1: #166 OUT = IN; + 2: #318 OUT = IN; + 2: #471 OUT = IN; + 3: #622 OUT = IN; + default: begin + $display("ERROR: GP_DELAY must have DELAY_STEPS in range [1,4]"); + $finish; + end + endcase + end + + endgenerate + +endmodule + +module GP_DFF(input D, CLK, output reg Q); + parameter [0:0] INIT = 1'bx; + initial Q = INIT; + always @(posedge CLK) begin + Q <= D; + end +endmodule + +module GP_DFFI(input D, CLK, output reg nQ); + parameter [0:0] INIT = 1'bx; + initial nQ = INIT; + always @(posedge CLK) begin + nQ <= ~D; + end +endmodule + +module GP_DFFR(input D, CLK, nRST, output reg Q); + parameter [0:0] INIT = 1'bx; + initial Q = INIT; + always @(posedge CLK, negedge nRST) begin + if (!nRST) + Q <= 1'b0; + else + Q <= D; + end +endmodule + +module GP_DFFRI(input D, CLK, nRST, output reg nQ); + parameter [0:0] INIT = 1'bx; + initial nQ = INIT; + always @(posedge CLK, negedge nRST) begin + if (!nRST) + nQ <= 1'b1; + else + nQ <= ~D; + end +endmodule + +module GP_DFFS(input D, CLK, nSET, output reg Q); + parameter [0:0] INIT = 1'bx; + initial Q = INIT; + always @(posedge CLK, negedge nSET) begin + if (!nSET) + Q <= 1'b1; + else + Q <= D; + end +endmodule + +module GP_DFFSI(input D, CLK, nSET, output reg nQ); + parameter [0:0] INIT = 1'bx; + initial nQ = INIT; + always @(posedge CLK, negedge nSET) begin + if (!nSET) + nQ <= 1'b0; + else + nQ <= ~D; + end +endmodule + +module GP_DFFSR(input D, CLK, nSR, output reg Q); + parameter [0:0] INIT = 1'bx; + parameter [0:0] SRMODE = 1'bx; + initial Q = INIT; + always @(posedge CLK, negedge nSR) begin + if (!nSR) + Q <= SRMODE; + else + Q <= D; + end +endmodule + +module GP_DFFSRI(input D, CLK, nSR, output reg nQ); + parameter [0:0] INIT = 1'bx; + parameter [0:0] SRMODE = 1'bx; + initial nQ = INIT; + always @(posedge CLK, negedge nSR) begin + if (!nSR) + nQ <= ~SRMODE; + else + nQ <= ~D; + end +endmodule + +module GP_IBUF(input IN, output OUT); + assign OUT = IN; +endmodule + +module GP_IOBUF(input IN, input OE, output OUT, inout IO); + assign OUT = IO; + assign IO = OE ? IN : 1'bz; +endmodule + +module GP_INV(input IN, output OUT); + assign OUT = ~IN; +endmodule + +module GP_LFOSC(input PWRDN, output reg CLKOUT); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter OUT_DIV = 1; + + initial CLKOUT = 0; + + //auto powerdown not implemented for simulation + //output dividers not implemented for simulation + + always begin + if(PWRDN) + CLKOUT = 0; + else begin + //half period of 1730 Hz + #289017; + CLKOUT = ~CLKOUT; + end + end + +endmodule + +module GP_OBUF(input IN, output OUT); + assign OUT = IN; +endmodule + +module GP_OBUFT(input IN, input OE, output OUT); + assign OUT = OE ? IN : 1'bz; +endmodule + +module GP_PGA(input wire VIN_P, input wire VIN_N, input wire VIN_SEL, output reg VOUT); + + parameter GAIN = 1; + parameter INPUT_MODE = "SINGLE"; + + initial VOUT = 0; + + //cannot simulate mixed signal IP + +endmodule + +module GP_POR(output reg RST_DONE); + parameter POR_TIME = 500; + + initial begin + RST_DONE = 0; + + if(POR_TIME == 4) + #4000; + else if(POR_TIME == 500) + #500000; + else begin + $display("ERROR: bad POR_TIME for GP_POR cell"); + $finish; + end + + RST_DONE = 1; + + end + +endmodule + +module GP_RCOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter HARDIP_DIV = 1; + parameter FABRIC_DIV = 1; + parameter OSC_FREQ = "25k"; + + initial CLKOUT_HARDIP = 0; + initial CLKOUT_FABRIC = 0; + + //output dividers not implemented for simulation + //auto powerdown not implemented for simulation + + always begin + if(PWRDN) begin + CLKOUT_HARDIP = 0; + CLKOUT_FABRIC = 0; + end + else begin + + if(OSC_FREQ == "25k") begin + //half period of 25 kHz + #20000; + end + + else begin + //half period of 2 MHz + #250; + end + + CLKOUT_HARDIP = ~CLKOUT_HARDIP; + CLKOUT_FABRIC = ~CLKOUT_FABRIC; + end + end + +endmodule + +module GP_RINGOSC(input PWRDN, output reg CLKOUT_HARDIP, output reg CLKOUT_FABRIC); + + parameter PWRDN_EN = 0; + parameter AUTO_PWRDN = 0; + parameter HARDIP_DIV = 1; + parameter FABRIC_DIV = 1; + + initial CLKOUT_HARDIP = 0; + initial CLKOUT_FABRIC = 0; + + //output dividers not implemented for simulation + //auto powerdown not implemented for simulation + + always begin + if(PWRDN) begin + CLKOUT_HARDIP = 0; + CLKOUT_FABRIC = 0; + end + else begin + //half period of 27 MHz + #18.518; + CLKOUT_HARDIP = ~CLKOUT_HARDIP; + CLKOUT_FABRIC = ~CLKOUT_FABRIC; + end + end + +endmodule + +module GP_SHREG(input nRST, input CLK, input IN, output OUTA, output OUTB); + + parameter OUTA_TAP = 1; + parameter OUTA_INVERT = 0; + parameter OUTB_TAP = 1; + + reg[15:0] shreg = 0; + + always @(posedge CLK, negedge nRST) begin + + if(!nRST) + shreg = 0; + + else + shreg <= {shreg[14:0], IN}; + + end + + assign OUTA = (OUTA_INVERT) ? ~shreg[OUTA_TAP - 1] : shreg[OUTA_TAP - 1]; + assign OUTB = shreg[OUTB_TAP - 1]; + +endmodule + +//keep constraint needed to prevent optimization since we have no outputs +(* keep *) +module GP_SYSRESET(input RST); + parameter RESET_MODE = "RISING"; + + //cannot simulate whole system reset + +endmodule + +module GP_VDD(output OUT); + assign OUT = 1; +endmodule + +module GP_VREF(input VIN, output reg VOUT); + parameter VIN_DIV = 1; + parameter VREF = 0; + //cannot simulate mixed signal IP +endmodule + +module GP_VSS(output OUT); + assign OUT = 0; +endmodule diff --git a/techlibs/greenpak4/gp_dff.lib b/techlibs/greenpak4/gp_dff.lib index 9e2e46cb..b4b8c102 100644 --- a/techlibs/greenpak4/gp_dff.lib +++ b/techlibs/greenpak4/gp_dff.lib @@ -1,26 +1,36 @@ library(gp_dff) { - cell(GP_DFF_NOSR) { + cell(GP_DFF) { area: 1; ff("IQ", "IQN") { clocked_on: CLK; - next_state: D; } + next_state: D; } pin(CLK) { direction: input; - clock: true; } + clock: true; } pin(D) { direction: input; } pin(Q) { direction: output; function: "IQ"; } } - cell(GP_DFF_SR) { + cell(GP_DFFS) { area: 1; ff("IQ", "IQN") { clocked_on: CLK; next_state: D; - preset: "nSETZ'"; - clear: "nRSTZ'"; } + preset: "nSET'"; } pin(CLK) { direction: input; clock: true; } pin(D) { direction: input; } pin(Q) { direction: output; function: "IQ"; } - pin(nRSTZ) { direction: input; } - pin(nSETZ) { direction: input; } + pin(nSET) { direction: input; } + } + cell(GP_DFFR) { + area: 1; + ff("IQ", "IQN") { clocked_on: CLK; + next_state: D; + clear: "nRST'"; } + pin(CLK) { direction: input; + clock: true; } + pin(D) { direction: input; } + pin(Q) { direction: output; + function: "IQ"; } + pin(nRST) { direction: input; } } } diff --git a/techlibs/greenpak4/greenpak4_counters.cc b/techlibs/greenpak4/greenpak4_counters.cc new file mode 100644 index 00000000..998bb73b --- /dev/null +++ b/techlibs/greenpak4/greenpak4_counters.cc @@ -0,0 +1,442 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2016 Clifford Wolf + * + * 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" +#include "kernel/modtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +//get the list of cells hooked up to at least one bit of a given net +pool get_other_cells(const RTLIL::SigSpec& port, ModIndex& index, Cell* src) +{ + pool rval; + for(auto b : port) + { + pool ports = index.query_ports(b); + for(auto x : ports) + { + if(x.cell == src) + continue; + rval.insert(x.cell); + } + } + return rval; +} + +//return true if there is a full-width bus connection from cell a port ap to cell b port bp +//if other_conns_allowed is false, then we require a strict point to point connection (no other links) +bool is_full_bus( + const RTLIL::SigSpec& sig, + ModIndex& index, + Cell* a, + RTLIL::IdString ap, + Cell* b, + RTLIL::IdString bp, + bool other_conns_allowed = false) +{ + for(auto s : sig) + { + pool ports = index.query_ports(s); + bool found_a = false; + bool found_b = false; + for(auto x : ports) + { + if( (x.cell == a) && (x.port == ap) ) + found_a = true; + else if( (x.cell == b) && (x.port == bp) ) + found_b = true; + else if(!other_conns_allowed) + return false; + } + + if( (!found_a) || (!found_b) ) + return false; + } + + return true; +} + +//return true if the signal connects to one port only (nothing on the other end) +bool is_unconnected(const RTLIL::SigSpec& port, ModIndex& index) +{ + for(auto b : port) + { + pool ports = index.query_ports(b); + if(ports.size() > 1) + return false; + } + + return true; +} + +struct CounterExtraction +{ + int width; //counter width + RTLIL::Wire* rwire; //the register output + bool has_reset; //true if we have a reset + RTLIL::SigSpec rst; //reset pin + int count_value; //value we count from + RTLIL::SigSpec clk; //clock signal + RTLIL::SigSpec outsig; //counter output signal + RTLIL::Cell* count_mux; //counter mux + RTLIL::Cell* count_reg; //counter register + RTLIL::Cell* underflow_inv; //inverter reduction for output-underflow detect +}; + +//attempt to extract a counter centered on the given cell +int greenpak4_counters_tryextract(ModIndex& index, Cell *cell, CounterExtraction& extract) +{ + SigMap& sigmap = index.sigmap; + + //GreenPak does not support counters larger than 14 bits so immediately skip anything bigger + int a_width = cell->getParam("\\A_WIDTH").as_int(); + extract.width = a_width; + if(a_width > 14) + return 1; + + //Second input must be a single bit + int b_width = cell->getParam("\\B_WIDTH").as_int(); + if(b_width != 1) + return 2; + + //Both inputs must be unsigned, so don't extract anything with a signed input + bool a_sign = cell->getParam("\\A_SIGNED").as_bool(); + bool b_sign = cell->getParam("\\B_SIGNED").as_bool(); + if(a_sign || b_sign) + return 3; + + //To be a counter, one input of the ALU must be a constant 1 + //TODO: can A or B be swapped in synthesized RTL or is B always the 1? + const RTLIL::SigSpec b_port = sigmap(cell->getPort("\\B")); + if(!b_port.is_fully_const() || (b_port.as_int() != 1) ) + return 4; + + //BI and CI must be constant 1 as well + const RTLIL::SigSpec bi_port = sigmap(cell->getPort("\\BI")); + if(!bi_port.is_fully_const() || (bi_port.as_int() != 1) ) + return 5; + const RTLIL::SigSpec ci_port = sigmap(cell->getPort("\\CI")); + if(!ci_port.is_fully_const() || (ci_port.as_int() != 1) ) + return 6; + + //CO and X must be unconnected (exactly one connection to each port) + if(!is_unconnected(sigmap(cell->getPort("\\CO")), index)) + return 7; + if(!is_unconnected(sigmap(cell->getPort("\\X")), index)) + return 8; + + //Y must have exactly one connection, and it has to be a $mux cell. + //We must have a direct bus connection from our Y to their A. + const RTLIL::SigSpec aluy = sigmap(cell->getPort("\\Y")); + pool y_loads = get_other_cells(aluy, index, cell); + if(y_loads.size() != 1) + return 9; + Cell* count_mux = *y_loads.begin(); + extract.count_mux = count_mux; + if(count_mux->type != "$mux") + return 10; + if(!is_full_bus(aluy, index, cell, "\\Y", count_mux, "\\A")) + return 11; + + //B connection of the mux is our underflow value + const RTLIL::SigSpec underflow = sigmap(count_mux->getPort("\\B")); + if(!underflow.is_fully_const()) + return 12; + extract.count_value = underflow.as_int(); + + //S connection of the mux must come from an inverter (need not be the only load) + const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort("\\S")); + extract.outsig = muxsel; + pool muxsel_conns = get_other_cells(muxsel, index, count_mux); + Cell* underflow_inv = NULL; + for(auto c : muxsel_conns) + { + if(c->type != "$logic_not") + continue; + if(!is_full_bus(muxsel, index, c, "\\Y", count_mux, "\\S", true)) + continue; + + underflow_inv = c; + break; + } + if(underflow_inv == NULL) + return 13; + extract.underflow_inv = underflow_inv; + + //Y connection of the mux must have exactly one load, the counter's internal register + const RTLIL::SigSpec muxy = sigmap(count_mux->getPort("\\Y")); + pool muxy_loads = get_other_cells(muxy, index, count_mux); + if(muxy_loads.size() != 1) + return 14; + Cell* count_reg = *muxy_loads.begin(); + extract.count_reg = count_reg; + if(count_reg->type == "$dff") + extract.has_reset = false; + else if(count_reg->type == "$adff") + { + extract.has_reset = true; + + //Verify ARST_VALUE is zero and ARST_POLARITY is 1 + //TODO: infer an inverter to make it 1 if necessary, so we can support negative level resets? + if(count_reg->getParam("\\ARST_POLARITY").as_int() != 1) + return 22; + if(count_reg->getParam("\\ARST_VALUE").as_int() != 0) + return 23; + + //Save the reset + extract.rst = sigmap(count_reg->getPort("\\ARST")); + } + //TODO: support synchronous reset + else + return 15; + if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D")) + return 16; + + //TODO: Verify count_reg CLK_POLARITY is 1 + + //Register output must have exactly two loads, the inverter and ALU + const RTLIL::SigSpec cnout = sigmap(count_reg->getPort("\\Q")); + pool cnout_loads = get_other_cells(cnout, index, count_reg); + if(cnout_loads.size() != 2) + return 17; + if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true)) + return 18; + if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true)) + return 19; + + //Look up the clock from the register + extract.clk = sigmap(count_reg->getPort("\\CLK")); + + //Register output net must have an INIT attribute equal to the count value + extract.rwire = cnout.as_wire(); + if(extract.rwire->attributes.find("\\init") == extract.rwire->attributes.end()) + return 20; + int rinit = extract.rwire->attributes["\\init"].as_int(); + if(rinit != extract.count_value) + return 21; + + return 0; +} + +void greenpak4_counters_worker( + ModIndex& index, + Cell *cell, + unsigned int& total_counters, + pool& cells_to_remove) +{ + SigMap& sigmap = index.sigmap; + + //Core of the counter must be an ALU + if (cell->type != "$alu") + return; + + //A input is the count value. Check if it has COUNT_EXTRACT set. + //If it's not a wire, don't even try + auto port = sigmap(cell->getPort("\\A")); + if(!port.is_wire()) + return; + RTLIL::Wire* a_wire = port.as_wire(); + bool force_extract = false; + bool never_extract = false; + string count_reg_src = a_wire->attributes["\\src"].decode_string().c_str(); + if(a_wire->attributes.find("\\COUNT_EXTRACT") != a_wire->attributes.end()) + { + pool sa = a_wire->get_strpool_attribute("\\COUNT_EXTRACT"); + string extract_value; + if(sa.size() >= 1) + { + extract_value = *sa.begin(); + log(" Signal %s declared at %s has COUNT_EXTRACT = %s\n", + log_id(a_wire), + count_reg_src.c_str(), + extract_value.c_str()); + + if(extract_value == "FORCE") + force_extract = true; + else if(extract_value == "NO") + never_extract = true; + else if(extract_value == "AUTO") + {} //default + else + log_error(" Illegal COUNT_EXTRACT value %s (must be one of FORCE, NO, AUTO)\n", + extract_value.c_str()); + } + } + + //If we're explicitly told not to extract, don't infer a counter + if(never_extract) + return; + + //Attempt to extract a counter + CounterExtraction extract; + int reason = greenpak4_counters_tryextract(index, cell, extract); + + //Nonzero code - we could not find a matchable counter. + //Do nothing, unless extraction was forced in which case give an error + if(reason != 0) + { + static const char* reasons[24]= + { + "no problem", //0 + "counter is larger than 14 bits", //1 + "counter does not count by one", //2 + "counter uses signed math", //3 + "counter does not count by one", //4 + "ALU is not a subtractor", //5 + "ALU is not a subtractor", //6 + "ALU ports used outside counter", //7 + "ALU ports used outside counter", //8 + "ALU output used outside counter", //9 + "ALU output is not a mux", //10 + "ALU output is not full bus", //11 + "Underflow value is not constant", //12 + "No underflow detector found", //13 + "Mux output is used outside counter", //14 + "Counter reg is not DFF/ADFF", //15 + "Counter input is not full bus", //16 + "Count register is used outside counter", //17 + "Register output is not full bus", //18 + "Register output is not full bus", //19 + "No init value found", //20 + "Underflow value is not equal to init value", //21 + "Reset polarity is not positive", //22 + "Reset is not to zero" //23 + }; + + if(force_extract) + { + log_error( + "Counter extraction is set to FORCE on register %s, but a counter could not be inferred (%s)\n", + log_id(a_wire), + reasons[reason]); + } + return; + } + + //Figure out the final cell type based on the counter size + string celltype = "\\GP_COUNT8"; + if(extract.width > 8) + celltype = "\\GP_COUNT14"; + + //Log it + total_counters ++; + string reset_type = "non-resettable"; + if(extract.has_reset) + { + //TODO: support other kind of reset + reset_type = "async resettable"; + } + log(" Found %d-bit %s down counter (from %d) for register %s declared at %s\n", + extract.width, + reset_type.c_str(), + extract.count_value, + log_id(extract.rwire->name), + count_reg_src.c_str()); + + //Wipe all of the old connections to the ALU + cell->unsetPort("\\A"); + cell->unsetPort("\\B"); + cell->unsetPort("\\BI"); + cell->unsetPort("\\CI"); + cell->unsetPort("\\CO"); + cell->unsetPort("\\X"); + cell->unsetPort("\\Y"); + cell->unsetParam("\\A_SIGNED"); + cell->unsetParam("\\A_WIDTH"); + cell->unsetParam("\\B_SIGNED"); + cell->unsetParam("\\B_WIDTH"); + cell->unsetParam("\\Y_WIDTH"); + + //Change the cell type + cell->type = celltype; + + //Hook up resets + if(extract.has_reset) + { + //TODO: support other kinds of reset + cell->setParam("\\RESET_MODE", RTLIL::Const("LEVEL")); + cell->setPort("\\RST", extract.rst); + } + else + { + cell->setParam("\\RESET_MODE", RTLIL::Const("RISING")); + cell->setPort("\\RST", RTLIL::SigSpec(false)); + } + + //Hook up other stuff + cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1)); + cell->setParam("\\COUNT_TO", RTLIL::Const(extract.count_value)); + + cell->setPort("\\CLK", extract.clk); + cell->setPort("\\OUT", extract.outsig); + + //Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires) + cells_to_remove.insert(extract.count_mux); + cells_to_remove.insert(extract.count_reg); + cells_to_remove.insert(extract.underflow_inv); +} + +struct Greenpak4CountersPass : public Pass { + Greenpak4CountersPass() : Pass("greenpak4_counters", "Extract GreenPak4 counter cells") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" greenpak4_counters [options] [selection]\n"); + log("\n"); + log("This pass converts non-resettable or async resettable down counters to GreenPak4\n"); + log("counter cells (All other GreenPak4 counter modes must be instantiated manually.)\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + log_header(design, "Executing GREENPAK4_COUNTERS pass (mapping counters to hard IP blocks).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-v") { + // continue; + // } + break; + } + extra_args(args, argidx, design); + + //Extract all of the counters we could find + unsigned int total_counters = 0; + for (auto module : design->selected_modules()) + { + pool cells_to_remove; + + ModIndex index(module); + for (auto cell : module->selected_cells()) + greenpak4_counters_worker(index, cell, total_counters, cells_to_remove); + + for(auto cell : cells_to_remove) + module->remove(cell); + } + + if(total_counters) + log("Extracted %u counters\n", total_counters); + } +} Greenpak4CountersPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/greenpak4/greenpak4_dffinv.cc b/techlibs/greenpak4/greenpak4_dffinv.cc new file mode 100644 index 00000000..ff63958e --- /dev/null +++ b/techlibs/greenpak4/greenpak4_dffinv.cc @@ -0,0 +1,197 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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 + +void invert_gp_dff(Cell *cell, bool invert_input) +{ + string cell_type = cell->type.str(); + bool cell_type_i = cell_type.find('I') != string::npos; + bool cell_type_r = cell_type.find('R') != string::npos; + bool cell_type_s = cell_type.find('S') != string::npos; + + if (!invert_input) + { + Const initval = cell->getParam("\\INIT"); + if (GetSize(initval) >= 1) { + if (initval.bits[0] == State::S0) + initval.bits[0] = State::S1; + else if (initval.bits[0] == State::S1) + initval.bits[0] = State::S0; + cell->setParam("\\INIT", initval); + } + + if (cell_type_r && cell_type_s) + { + Const srmode = cell->getParam("\\SRMODE"); + if (GetSize(srmode) >= 1) { + if (srmode.bits[0] == State::S0) + srmode.bits[0] = State::S1; + else if (srmode.bits[0] == State::S1) + srmode.bits[0] = State::S0; + cell->setParam("\\SRMODE", srmode); + } + } + else + { + if (cell_type_r) { + cell->setPort("\\nSET", cell->getPort("\\nRST")); + cell->unsetPort("\\nRST"); + cell_type_r = false; + cell_type_s = true; + } else + if (cell_type_s) { + cell->setPort("\\nRST", cell->getPort("\\nSET")); + cell->unsetPort("\\nSET"); + cell_type_r = true; + cell_type_s = false; + } + } + } + + if (cell_type_i) { + cell->setPort("\\Q", cell->getPort("\\nQ")); + cell->unsetPort("\\nQ"); + cell_type_i = false; + } else { + cell->setPort("\\nQ", cell->getPort("\\Q")); + cell->unsetPort("\\Q"); + cell_type_i = true; + } + + cell->type = stringf("\\GP_DFF%s%s%s", cell_type_s ? "S" : "", cell_type_r ? "R" : "", cell_type_i ? "I" : ""); + + log("Merged %s inverter into cell %s.%s: %s -> %s\n", invert_input ? "input" : "output", + log_id(cell->module), log_id(cell), cell_type.c_str()+1, log_id(cell->type)); +} + +struct Greenpak4DffInvPass : public Pass { + Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFFs") { } + virtual void help() + { + log("\n"); + log(" greenpak4_dffinv [options] [selection]\n"); + log("\n"); + log("Merge GP_INV cells with GP_DFF* cells.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + log_header(design, "Executing GREENPAK4_DFFINV pass (merge synchronous set/reset into FF cells).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + pool gp_dff_types; + gp_dff_types.insert("\\GP_DFF"); + gp_dff_types.insert("\\GP_DFFI"); + gp_dff_types.insert("\\GP_DFFR"); + gp_dff_types.insert("\\GP_DFFRI"); + gp_dff_types.insert("\\GP_DFFS"); + gp_dff_types.insert("\\GP_DFFSI"); + gp_dff_types.insert("\\GP_DFFSR"); + gp_dff_types.insert("\\GP_DFFSRI"); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + dict sig_use_cnt; + dict inv_in2out, inv_out2in; + dict inv_in2cell; + pool dff_cells; + + for (auto wire : module->wires()) + { + if (!wire->port_output) + continue; + + for (auto bit : sigmap(wire)) + sig_use_cnt[bit]++; + } + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) + if (cell->input(conn.first) || !cell->known()) + for (auto bit : sigmap(conn.second)) + sig_use_cnt[bit]++; + + for (auto cell : module->selected_cells()) + { + if (gp_dff_types.count(cell->type)) { + dff_cells.insert(cell); + continue; + } + + if (cell->type == "\\GP_INV") { + SigBit in_bit = sigmap(cell->getPort("\\IN")); + SigBit out_bit = sigmap(cell->getPort("\\OUT")); + inv_in2out[in_bit] = out_bit; + inv_out2in[out_bit] = in_bit; + inv_in2cell[in_bit] = cell; + continue; + } + } + + for (auto cell : dff_cells) + { + SigBit d_bit = sigmap(cell->getPort("\\D")); + SigBit q_bit = sigmap(cell->hasPort("\\Q") ? cell->getPort("\\Q") : cell->getPort("\\nQ")); + + while (inv_out2in.count(d_bit)) + { + sig_use_cnt[d_bit]--; + invert_gp_dff(cell, true); + d_bit = inv_out2in.at(d_bit); + cell->setPort("\\D", d_bit); + sig_use_cnt[d_bit]++; + } + + while (inv_in2out.count(q_bit) && sig_use_cnt[q_bit] == 1) + { + SigBit new_q_bit = inv_in2out.at(q_bit); + module->remove(inv_in2cell.at(q_bit)); + sig_use_cnt.erase(q_bit); + inv_in2out.erase(q_bit); + inv_out2in.erase(new_q_bit); + inv_in2cell.erase(q_bit); + + invert_gp_dff(cell, false); + if (cell->hasPort("\\Q")) + cell->setPort("\\Q", new_q_bit); + else + cell->setPort("\\nQ", new_q_bit); + } + } + } + } +} Greenpak4DffInvPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index 15b53d62..10e2a149 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc @@ -25,18 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthGreenPAK4Pass : public ScriptPass { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - return active; -} - -struct SynthGreenPAK4Pass : public Pass { - SynthGreenPAK4Pass() : Pass("synth_greenpak4", "synthesis for GreenPAK4 FPGAs") { } - virtual void help() + SynthGreenPAK4Pass() : ScriptPass("synth_greenpak4", "synthesis for GreenPAK4 FPGAs") { } + + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -47,12 +40,12 @@ struct SynthGreenPAK4Pass : public Pass { log(" -top \n"); log(" use the specified module as top module (default='top')\n"); log("\n"); - log(" -blif \n"); - log(" write the design to the specified BLIF file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); + log(" -part \n"); + log(" synthesize for the specified part. Valid values are SLG46140V,\n"); + log(" SLG46620V, and SLG46621V (default).\n"); log("\n"); - log(" -edif \n"); - log(" write the design to the specified edif file. writing of an output file\n"); + log(" -json \n"); + log(" write the design to the specified JSON file. writing of an output file\n"); log(" is omitted if this parameter is not specified.\n"); log("\n"); log(" -run :\n"); @@ -68,55 +61,26 @@ struct SynthGreenPAK4Pass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/greenpak4/cells_sim.v\n"); - log(" hierarchy -check -top \n"); - log("\n"); - log(" flatten: (unless -noflatten)\n"); - log(" proc\n"); - log(" flatten\n"); - log(" tribuf -logic\n"); - log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -mux_undef -undriven -fine\n"); - log(" memory_map\n"); - log(" opt -undriven -fine\n"); - log(" techmap\n"); - log(" dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib\n"); - log(" opt -fast\n"); - log(" abc -dff (only if -retime)\n"); - log("\n"); - log(" map_luts:\n"); - log(" nlutmap -luts 0,8,16,2\n"); - log(" clean\n"); - log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/greenpak4/cells_map.v\n"); - log(" clean\n"); - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); - log("\n"); - log(" blif:\n"); - log(" write_blif -gates -attr -param \n"); - log("\n"); - log(" edif:\n"); - log(" write_edif \n"); - log("\n"); } - virtual void execute(std::vector args, RTLIL::Design *design) + + string top_opt, part, json_file; + bool flatten, retime; + + virtual void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + part = "SLG46621V"; + json_file = ""; + flatten = true; + retime = false; + } + + virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string run_from, run_to; - std::string blif_file, edif_file; - bool flatten = true; - bool retime = false; + string run_from, run_to; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -125,12 +89,12 @@ struct SynthGreenPAK4Pass : public Pass { top_opt = "-top " + args[++argidx]; continue; } - if (args[argidx] == "-blif" && argidx+1 < args.size()) { - blif_file = args[++argidx]; + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; continue; } - if (args[argidx] == "-edif" && argidx+1 < args.size()) { - edif_file = args[++argidx]; + if (args[argidx] == "-part" && argidx+1 < args.size()) { + part = args[++argidx]; continue; } if (args[argidx] == "-run" && argidx+1 < args.size()) { @@ -141,10 +105,6 @@ struct SynthGreenPAK4Pass : public Pass { run_to = args[argidx].substr(pos+1); continue; } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -160,70 +120,86 @@ struct SynthGreenPAK4Pass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); + if (part != "SLG46140V" && part != "SLG46620V" && part != "SLG46621V") + log_cmd_error("Invalid part name: '%s'\n", part.c_str()); - log_header("Executing SYNTH_GREENPAK4 pass.\n"); + log_header(design, "Executing SYNTH_GREENPAK4 pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) - { - Pass::call(design, "read_verilog -lib +/greenpak4/cells_sim.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); - } + run_script(design, run_from, run_to); + + log_pop(); + } - if (flatten && check_label(active, run_from, run_to, "flatten")) + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); - Pass::call(design, "tribuf -logic"); + run("read_verilog -lib +/greenpak4/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); } - if (check_label(active, run_from, run_to, "coarse")) + if (flatten && check_label("flatten", "(unless -noflatten)")) { - Pass::call(design, "synth -run coarse"); + run("proc"); + run("flatten"); + run("tribuf -logic"); } - if (check_label(active, run_from, run_to, "fine")) + if (check_label("coarse")) { - Pass::call(design, "opt -fast -mux_undef -undriven -fine"); - Pass::call(design, "memory_map"); - Pass::call(design, "opt -undriven -fine"); - Pass::call(design, "techmap"); - Pass::call(design, "dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); - Pass::call(design, "opt -fast"); - if (retime) - Pass::call(design, "abc -dff"); + run("synth -run coarse"); } - if (check_label(active, run_from, run_to, "map_luts")) + if (check_label("fine")) { - Pass::call(design, "nlutmap -luts 0,8,16,2"); - Pass::call(design, "clean"); + run("greenpak4_counters"); + run("clean"); + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + run("techmap"); + run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); + run("opt -fast"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); } - if (check_label(active, run_from, run_to, "map_cells")) + if (check_label("map_luts")) { - Pass::call(design, "techmap -map +/greenpak4/cells_map.v"); - Pass::call(design, "clean"); + if (help_mode || part == "SLG46140V") run("nlutmap -assert -luts 0,6,8,2", " (for -part SLG46140V)"); + if (help_mode || part == "SLG46620V") run("nlutmap -assert -luts 2,8,16,2", "(for -part SLG46620V)"); + if (help_mode || part == "SLG46621V") run("nlutmap -assert -luts 2,8,16,2", "(for -part SLG46621V)"); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) + if (check_label("map_cells")) { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + run("shregmap -tech greenpak4"); + run("dfflibmap -liberty +/greenpak4/gp_dff.lib"); + run("dffinit -ff GP_DFF Q INIT"); + run("dffinit -ff GP_DFFR Q INIT"); + run("dffinit -ff GP_DFFS Q INIT"); + run("dffinit -ff GP_DFFSR Q INIT"); + run("iopadmap -bits -inpad GP_IBUF OUT:IN -outpad GP_OBUF IN:OUT -inoutpad GP_OBUF OUT:IN -toutpad GP_OBUFT OE:IN:OUT -tinoutpad GP_IOBUF OE:OUT:IN:IO"); + run("attrmvcp -attr src -attr LOC t:GP_OBUF t:GP_OBUFT t:GP_IOBUF n:*"); + run("attrmvcp -attr src -attr LOC -driven t:GP_IBUF n:*"); + run("techmap -map +/greenpak4/cells_map.v"); + run("greenpak4_dffinv"); + run("clean"); } - if (check_label(active, run_from, run_to, "blif")) + if (check_label("check")) { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif -gates -attr -param %s", blif_file.c_str())); + run("hierarchy -check"); + run("stat"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "edif")) + if (check_label("json")) { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); } log_pop(); diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 83009d17..14761c6c 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -23,6 +23,7 @@ techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk $(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v)) diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc index 8c4b9a37..c914b20e 100644 --- a/techlibs/ice40/ice40_ffinit.cc +++ b/techlibs/ice40/ice40_ffinit.cc @@ -37,7 +37,7 @@ struct Ice40FfinitPass : public Pass { } virtual void execute(std::vector args, RTLIL::Design *design) { - log_header("Executing ICE40_FFINIT pass (implement FF init values).\n"); + log_header(design, "Executing ICE40_FFINIT pass (implement FF init values).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -57,6 +57,7 @@ struct Ice40FfinitPass : public Pass { SigMap sigmap(module); pool init_wires; dict initbits; + dict initbit_to_wire; pool handled_initbits; for (auto wire : module->selected_wires()) @@ -78,11 +79,14 @@ struct Ice40FfinitPass : public Pass { if (initbits.count(bit)) { if (initbits.at(bit) != val) - log_error("Conflicting init values for signal %s.\n", log_signal(bit)); + log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), + log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); continue; } initbits[bit] = val; + initbit_to_wire[bit] = SigBit(wire, i); } } @@ -97,17 +101,23 @@ struct Ice40FfinitPass : public Pass { if (!sb_dff_types.count(cell->type)) continue; - SigBit sig_d = sigmap(cell->getPort("\\D")); - SigBit sig_q = sigmap(cell->getPort("\\Q")); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); - if (!initbits.count(sig_q)) + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) continue; - State val = initbits.at(sig_q); - handled_initbits.insert(sig_q); + SigBit bit_d = sigmap(sig_d[0]); + SigBit bit_q = sigmap(sig_q[0]); + + if (!initbits.count(bit_q)) + continue; + + State val = initbits.at(bit_q); + handled_initbits.insert(bit_q); log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), - log_signal(sig_q), val != State::S0 ? '1' : '0'); + log_signal(bit_q), val != State::S0 ? '1' : '0'); if (val == State::S0) continue; @@ -127,14 +137,14 @@ struct Ice40FfinitPass : public Pass { cell->unsetPort("\\R"); } - Wire *new_sig_d = module->addWire(NEW_ID); - Wire *new_sig_q = module->addWire(NEW_ID); + Wire *new_bit_d = module->addWire(NEW_ID); + Wire *new_bit_q = module->addWire(NEW_ID); - module->addNotGate(NEW_ID, sig_d, new_sig_d); - module->addNotGate(NEW_ID, new_sig_q, sig_q); + module->addNotGate(NEW_ID, bit_d, new_bit_d); + module->addNotGate(NEW_ID, new_bit_q, bit_q); - cell->setPort("\\D", new_sig_d); - cell->setPort("\\Q", new_sig_q); + cell->setPort("\\D", new_bit_d); + cell->setPort("\\Q", new_bit_q); } for (auto wire : init_wires) diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc index 9ebc3c0d..9afbc0fc 100644 --- a/techlibs/ice40/ice40_ffssr.cc +++ b/techlibs/ice40/ice40_ffssr.cc @@ -35,7 +35,7 @@ struct Ice40FfssrPass : public Pass { } virtual void execute(std::vector args, RTLIL::Design *design) { - log_header("Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n"); + log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -81,7 +81,12 @@ struct Ice40FfssrPass : public Pass { for (auto cell : ff_cells) { - SigBit bit_d = sigmap(cell->getPort("\\D")); + SigSpec sig_d = cell->getPort("\\D"); + + if (GetSize(sig_d) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); if (sr_muxes.count(bit_d) == 0) continue; diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc index 677ac8d7..ae72f5d6 100644 --- a/techlibs/ice40/ice40_opt.cc +++ b/techlibs/ice40/ice40_opt.cc @@ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -static void run_ice40_opts(Module *module) +static void run_ice40_opts(Module *module, bool unlut_mode) { pool optimized_co; vector sb_lut_cells; @@ -84,6 +84,9 @@ static void run_ice40_opts(Module *module) inbits.append(cell->getPort("\\I3")); sigmap.apply(inbits); + if (unlut_mode) + goto remap_lut; + if (optimized_co.count(inbits[0])) goto remap_lut; if (optimized_co.count(inbits[1])) goto remap_lut; if (optimized_co.count(inbits[2])) goto remap_lut; @@ -101,7 +104,7 @@ static void run_ice40_opts(Module *module) cell->setParam("\\LUT", cell->getParam("\\LUT_INIT")); cell->unsetParam("\\LUT_INIT"); - cell->setPort("\\A", SigSpec({cell->getPort("\\I0"), cell->getPort("\\I1"), cell->getPort("\\I2"), cell->getPort("\\I3")})); + cell->setPort("\\A", SigSpec({cell->getPort("\\I3"), cell->getPort("\\I2"), cell->getPort("\\I1"), cell->getPort("\\I0")})); cell->setPort("\\Y", cell->getPort("\\O")); cell->unsetPort("\\I0"); cell->unsetPort("\\I1"); @@ -127,23 +130,32 @@ struct Ice40OptPass : public Pass { log("\n"); log(" do\n"); log(" \n"); - log(" opt_const -mux_undef -undriven [-full]\n"); - log(" opt_share\n"); + log(" opt_expr -mux_undef -undriven [-full]\n"); + log(" opt_merge\n"); log(" opt_rmdff\n"); log(" opt_clean\n"); log(" while \n"); log("\n"); + log("When called with the option -unlut, this command will transform all already\n"); + log("mapped SB_LUT4 cells back to logic.\n"); + log("\n"); } virtual void execute(std::vector args, RTLIL::Design *design) { - string opt_const_args = "-mux_undef -undriven"; - log_header("Executing ICE40_OPT pass (performing simple optimizations).\n"); + string opt_expr_args = "-mux_undef -undriven"; + bool unlut_mode = false; + + log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n"); log_push(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-full") { - opt_const_args += " -full"; + opt_expr_args += " -full"; + continue; + } + if (args[argidx] == "-unlut") { + unlut_mode = true; continue; } break; @@ -154,26 +166,26 @@ struct Ice40OptPass : public Pass { { design->scratchpad_unset("opt.did_something"); - log_header("Running ICE40 specific optimizations.\n"); + log_header(design, "Running ICE40 specific optimizations.\n"); for (auto module : design->selected_modules()) - run_ice40_opts(module); + run_ice40_opts(module, unlut_mode); - Pass::call(design, "opt_const " + opt_const_args); - Pass::call(design, "opt_share"); + Pass::call(design, "opt_expr " + opt_expr_args); + Pass::call(design, "opt_merge"); Pass::call(design, "opt_rmdff"); Pass::call(design, "opt_clean"); if (design->scratchpad_get_bool("opt.did_something") == false) break; - log_header("Rerunning OPT passes. (Removed registers in this run.)\n"); + log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n"); } design->optimize(); design->sort(); design->check(); - log_header("Finished OPT passes. (There is nothing left to do.)\n"); + log_header(design, "Finished OPT passes. (There is nothing left to do.)\n"); log_pop(); } } Ice40OptPass; diff --git a/techlibs/ice40/latches_map.v b/techlibs/ice40/latches_map.v new file mode 100644 index 00000000..c28f88cf --- /dev/null +++ b/techlibs/ice40/latches_map.v @@ -0,0 +1,11 @@ +module \$_DLATCH_N_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = !E ? D : Q; +endmodule + +module \$_DLATCH_P_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = E ? D : Q; +endmodule diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 92d53f4a..38a9cf9d 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -25,18 +25,11 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthIce40Pass : public ScriptPass { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - return active; -} + SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { } -struct SynthIce40Pass : public Pass { - SynthIce40Pass() : Pass("synth_ice40", "synthesis for iCE40 FPGAs") { } - virtual void help() + virtual void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -77,73 +70,29 @@ struct SynthIce40Pass : public Pass { log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/ice40/cells_sim.v\n"); - log(" hierarchy -check -top \n"); - log("\n"); - log(" flatten: (unless -noflatten)\n"); - log(" proc\n"); - log(" flatten\n"); - log(" tribuf -logic\n"); - log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); - log("\n"); - log(" bram: (skip if -nobram)\n"); - log(" memory_bram -rules +/ice40/brams.txt\n"); - log(" techmap -map +/ice40/brams_map.v\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -mux_undef -undriven -fine\n"); - log(" memory_map\n"); - log(" opt -undriven -fine\n"); - log(" techmap -map +/techmap.v [-map +/ice40/arith_map.v]\n"); - log(" abc -dff (only if -retime)\n"); - log(" ice40_opt\n"); - log("\n"); - log(" map_ffs:\n"); - log(" dffsr2dff\n"); - log(" dff2dffe -direct-match $_DFF_*\n"); - log(" techmap -map +/ice40/cells_map.v\n"); - log(" opt_const -mux_undef\n"); - log(" simplemap\n"); - log(" ice40_ffinit\n"); - log(" ice40_ffssr\n"); - log(" ice40_opt -full\n"); - log("\n"); - log(" map_luts:\n"); - log(" abc (only if -abc2)\n"); - log(" ice40_opt (only if -abc2)\n"); - log(" abc -lut 4\n"); - log(" clean\n"); - log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/ice40/cells_map.v\n"); - log(" clean\n"); - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); - log("\n"); - log(" blif:\n"); - log(" write_blif -gates -attr -param \n"); - log("\n"); - log(" edif:\n"); - log(" write_edif \n"); - log("\n"); } - virtual void execute(std::vector args, RTLIL::Design *design) + + string top_opt, blif_file, edif_file; + bool nocarry, nobram, flatten, retime, abc2; + + virtual void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + blif_file = ""; + edif_file = ""; + nocarry = false; + nobram = false; + flatten = true; + retime = false; + abc2 = false; + } + + virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string run_from, run_to; - std::string blif_file, edif_file; - bool nocarry = false; - bool nobram = false; - bool flatten = true; - bool retime = false; - bool abc2 = false; + string run_from, run_to; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -199,97 +148,102 @@ struct SynthIce40Pass : public Pass { if (!design->full_selection()) log_cmd_error("This comannd only operates on fully selected designs!\n"); - bool active = run_from.empty(); - - log_header("Executing SYNTH_ICE40 pass.\n"); + log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) + run_script(design, run_from, run_to); + + log_pop(); + } + + virtual void script() YS_OVERRIDE + { + if (check_label("begin")) { - Pass::call(design, "read_verilog -lib +/ice40/cells_sim.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); + run("read_verilog -lib +/ice40/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); } - if (flatten && check_label(active, run_from, run_to, "flatten")) + if (flatten && check_label("flatten", "(unless -noflatten)")) { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); - Pass::call(design, "tribuf -logic"); + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); } - if (check_label(active, run_from, run_to, "coarse")) + if (check_label("coarse")) { - Pass::call(design, "synth -run coarse"); + run("synth -run coarse"); } - if (!nobram && check_label(active, run_from, run_to, "bram")) + if (!nobram && check_label("bram", "(skip if -nobram)")) { - Pass::call(design, "memory_bram -rules +/ice40/brams.txt"); - Pass::call(design, "techmap -map +/ice40/brams_map.v"); + run("memory_bram -rules +/ice40/brams.txt"); + run("techmap -map +/ice40/brams_map.v"); } - if (check_label(active, run_from, run_to, "fine")) + if (check_label("fine")) { - Pass::call(design, "opt -fast -mux_undef -undriven -fine"); - Pass::call(design, "memory_map"); - Pass::call(design, "opt -undriven -fine"); + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); if (nocarry) - Pass::call(design, "techmap"); + run("techmap"); else - Pass::call(design, "techmap -map +/techmap.v -map +/ice40/arith_map.v"); - if (retime) - Pass::call(design, "abc -dff"); - Pass::call(design, "ice40_opt"); + run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); + run("ice40_opt"); } - if (check_label(active, run_from, run_to, "map_ffs")) + if (check_label("map_ffs")) { - Pass::call(design, "dffsr2dff"); - Pass::call(design, "dff2dffe -direct-match $_DFF_*"); - Pass::call(design, "techmap -map +/ice40/cells_map.v"); - Pass::call(design, "opt_const -mux_undef"); - Pass::call(design, "simplemap"); - Pass::call(design, "ice40_ffinit"); - Pass::call(design, "ice40_ffssr"); - Pass::call(design, "ice40_opt -full"); + run("dffsr2dff"); + run("dff2dffe -direct-match $_DFF_*"); + run("techmap -map +/ice40/cells_map.v"); + run("opt_expr -mux_undef"); + run("simplemap"); + run("ice40_ffinit"); + run("ice40_ffssr"); + run("ice40_opt -full"); } - if (check_label(active, run_from, run_to, "map_luts")) + if (check_label("map_luts")) { - if (abc2) { - Pass::call(design, "abc"); - Pass::call(design, "ice40_opt"); + if (abc2 || help_mode) { + run("abc", " (only if -abc2)"); + run("ice40_opt", "(only if -abc2)"); } - Pass::call(design, "abc -lut 4"); - Pass::call(design, "clean"); + run("techmap -map +/ice40/latches_map.v"); + run("abc -lut 4"); + run("clean"); } - if (check_label(active, run_from, run_to, "map_cells")) + if (check_label("map_cells")) { - Pass::call(design, "techmap -map +/ice40/cells_map.v"); - Pass::call(design, "clean"); + run("techmap -map +/ice40/cells_map.v"); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) + if (check_label("check")) { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + run("hierarchy -check"); + run("stat"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "blif")) + if (check_label("blif")) { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif -gates -attr -param %s", blif_file.c_str())); + if (!blif_file.empty() || help_mode) + run(stringf("write_blif -gates -attr -param %s", help_mode ? "" : blif_file.c_str())); } - if (check_label(active, run_from, run_to, "edif")) + if (check_label("edif")) { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + if (!edif_file.empty() || help_mode) + run(stringf("write_edif %s", help_mode ? "" : edif_file.c_str())); } - - log_pop(); } } SynthIce40Pass; diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index ccf88ec7..5f09ffb0 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -21,6 +21,7 @@ techlibs/xilinx/brams_init_16.vh: techlibs/xilinx/brams_init.mk $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v)) diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh new file mode 100644 index 00000000..c7ad1604 --- /dev/null +++ b/techlibs/xilinx/cells_xtra.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +set -e +libdir="/opt/Xilinx/Vivado/2015.4/data/verilog/src" + +function xtract_cell_decl() +{ + for dir in $libdir/xeclib $libdir/retarget; do + [ -f $dir/$1.v ] || continue + egrep '^\s*((end)?module|parameter|input|output|(end)?function|(end)?task)' $dir/$1.v | + sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d; + s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; + s/\s+$//; s/,$/;/; /input|output|parameter/ s/[^;]$/&;/; s/\s+/ /g; + s/^ ((end)?module)/\1/; s/^ / /; /module.*_bb/,/endmodule/ d;' + echo; return + done + echo "Can't find $1." + exit 1 +} + +{ + echo "// Created by cells_xtra.sh from Xilinx models" + echo + + # Design elements types listed in Xilinx UG953 + xtract_cell_decl BSCANE2 + # xtract_cell_decl BUFG + xtract_cell_decl BUFGCE + xtract_cell_decl BUFGCE_1 + xtract_cell_decl BUFGCTRL + xtract_cell_decl BUFGMUX + xtract_cell_decl BUFGMUX_1 + xtract_cell_decl BUFGMUX_CTRL + xtract_cell_decl BUFH + xtract_cell_decl BUFHCE + xtract_cell_decl BUFIO + xtract_cell_decl BUFMR + xtract_cell_decl BUFMRCE + xtract_cell_decl BUFR + xtract_cell_decl CAPTUREE2 + # xtract_cell_decl CARRY4 + xtract_cell_decl CFGLUT5 + xtract_cell_decl DCIRESET + xtract_cell_decl DNA_PORT + xtract_cell_decl DSP48E1 + xtract_cell_decl EFUSE_USR + # xtract_cell_decl FDCE + # xtract_cell_decl FDPE + # xtract_cell_decl FDRE + # xtract_cell_decl FDSE + xtract_cell_decl FIFO18E1 + xtract_cell_decl FIFO36E1 + xtract_cell_decl FRAME_ECCE2 + xtract_cell_decl GTHE2_CHANNEL + xtract_cell_decl GTHE2_COMMON + xtract_cell_decl GTPE2_CHANNEL + xtract_cell_decl GTPE2_COMMON + xtract_cell_decl GTXE2_CHANNEL + xtract_cell_decl GTXE2_COMMON + # xtract_cell_decl IBUF + xtract_cell_decl IBUF_IBUFDISABLE + xtract_cell_decl IBUF_INTERMDISABLE + xtract_cell_decl IBUFDS + xtract_cell_decl IBUFDS_DIFF_OUT + xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE + xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE + xtract_cell_decl IBUFDS_GTE2 + xtract_cell_decl IBUFDS_IBUFDISABLE + xtract_cell_decl IBUFDS_INTERMDISABLE + xtract_cell_decl ICAPE2 + xtract_cell_decl IDDR + xtract_cell_decl IDDR_2CLK + xtract_cell_decl IDELAYCTRL + xtract_cell_decl IDELAYE2 + xtract_cell_decl IN_FIFO + xtract_cell_decl IOBUF + xtract_cell_decl IOBUF_DCIEN + xtract_cell_decl IOBUF_INTERMDISABLE + xtract_cell_decl IOBUFDS + xtract_cell_decl IOBUFDS_DCIEN + xtract_cell_decl IOBUFDS_DIFF_OUT + xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN + xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE + xtract_cell_decl ISERDESE2 + xtract_cell_decl KEEPER + xtract_cell_decl LDCE + xtract_cell_decl LDPE + # xtract_cell_decl LUT1 + # xtract_cell_decl LUT2 + # xtract_cell_decl LUT3 + # xtract_cell_decl LUT4 + # xtract_cell_decl LUT5 + # xtract_cell_decl LUT6 + xtract_cell_decl LUT6_2 + xtract_cell_decl MMCME2_ADV + xtract_cell_decl MMCME2_BASE + # xtract_cell_decl MUXF7 + # xtract_cell_decl MUXF8 + # xtract_cell_decl OBUF + xtract_cell_decl OBUFDS + xtract_cell_decl OBUFT + xtract_cell_decl OBUFTDS + xtract_cell_decl ODDR + xtract_cell_decl ODELAYE2 + xtract_cell_decl OSERDESE2 + xtract_cell_decl OUT_FIFO + xtract_cell_decl PHASER_IN + xtract_cell_decl PHASER_IN_PHY + xtract_cell_decl PHASER_OUT + xtract_cell_decl PHASER_OUT_PHY + xtract_cell_decl PHASER_REF + xtract_cell_decl PHY_CONTROL + xtract_cell_decl PLLE2_ADV + xtract_cell_decl PLLE2_BASE + xtract_cell_decl PULLDOWN + xtract_cell_decl PULLUP + # xtract_cell_decl RAM128X1D + xtract_cell_decl RAM128X1S + xtract_cell_decl RAM256X1S + xtract_cell_decl RAM32M + xtract_cell_decl RAM32X1D + xtract_cell_decl RAM32X1S + xtract_cell_decl RAM32X1S_1 + xtract_cell_decl RAM32X2S + xtract_cell_decl RAM64M + # xtract_cell_decl RAM64X1D + xtract_cell_decl RAM64X1S + xtract_cell_decl RAM64X1S_1 + xtract_cell_decl RAM64X2S + # xtract_cell_decl RAMB18E1 + # xtract_cell_decl RAMB36E1 + xtract_cell_decl ROM128X1 + xtract_cell_decl ROM256X1 + xtract_cell_decl ROM32X1 + xtract_cell_decl ROM64X1 + xtract_cell_decl SRL16E + xtract_cell_decl SRLC32E + xtract_cell_decl STARTUPE2 + xtract_cell_decl USR_ACCESSE2 + xtract_cell_decl XADC +} > cells_xtra.new + +mv cells_xtra.new cells_xtra.v +exit 0 + diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v new file mode 100644 index 00000000..a2dd01ad --- /dev/null +++ b/techlibs/xilinx/cells_xtra.v @@ -0,0 +1,3293 @@ +// Created by cells_xtra.sh from Xilinx models + +module BSCANE2 (...); + parameter DISABLE_JTAG = "FALSE"; + parameter integer JTAG_CHAIN = 1; + output CAPTURE; + output DRCK; + output RESET; + output RUNTEST; + output SEL; + output SHIFT; + output TCK; + output TDI; + output TMS; + output UPDATE; + input TDO; +endmodule + +module BUFGCE (...); + parameter CE_TYPE = "SYNC"; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + output O; + input CE; + input I; +endmodule + +module BUFGCE_1 (...); + output O; + input CE, I; +endmodule + +module BUFGCTRL (...); + output O; + input CE0; + input CE1; + input I0; + input I1; + input IGNORE0; + input IGNORE1; + input S0; + input S1; + parameter integer INIT_OUT = 0; + parameter PRESELECT_I0 = "FALSE"; + parameter PRESELECT_I1 = "FALSE"; + parameter [0:0] IS_CE0_INVERTED = 1'b0; + parameter [0:0] IS_CE1_INVERTED = 1'b0; + parameter [0:0] IS_I0_INVERTED = 1'b0; + parameter [0:0] IS_I1_INVERTED = 1'b0; + parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; + parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; + parameter [0:0] IS_S0_INVERTED = 1'b0; + parameter [0:0] IS_S1_INVERTED = 1'b0; +endmodule + +module BUFGMUX (...); + parameter CLK_SEL_TYPE = "SYNC"; + output O; + input I0, I1, S; +endmodule + +module BUFGMUX_1 (...); + parameter CLK_SEL_TYPE = "SYNC"; + output O; + input I0, I1, S; +endmodule + +module BUFGMUX_CTRL (...); + output O; + input I0; + input I1; + input S; +endmodule + +module BUFH (...); + output O; + input I; +endmodule + +module BUFHCE (...); + parameter CE_TYPE = "SYNC"; + parameter integer INIT_OUT = 0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + output O; + input CE; + input I; +endmodule + +module BUFIO (...); + output O; + input I; +endmodule + +module BUFMR (...); + output O; + input I; +endmodule + +module BUFMRCE (...); + parameter CE_TYPE = "SYNC"; + parameter integer INIT_OUT = 0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + output O; + input CE; + input I; +endmodule + +module BUFR (...); + output O; + input CE; + input CLR; + input I; + parameter BUFR_DIVIDE = "BYPASS"; + parameter SIM_DEVICE = "7SERIES"; +endmodule + +module CAPTUREE2 (...); + parameter ONESHOT = "TRUE"; + input CAP; + input CLK; +endmodule + +module CFGLUT5 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output CDO; + output O5; + output O6; + input I4, I3, I2, I1, I0; + input CDI, CE, CLK; +endmodule + +module DCIRESET (...); + output LOCKED; + input RST; +endmodule + +module DNA_PORT (...); + parameter [56:0] SIM_DNA_VALUE = 57'h0; + output DOUT; + input CLK, DIN, READ, SHIFT; +endmodule + +module DSP48E1 (...); + parameter integer ACASCREG = 1; + parameter integer ADREG = 1; + parameter integer ALUMODEREG = 1; + parameter integer AREG = 1; + parameter AUTORESET_PATDET = "NO_RESET"; + parameter A_INPUT = "DIRECT"; + parameter integer BCASCREG = 1; + parameter integer BREG = 1; + parameter B_INPUT = "DIRECT"; + parameter integer CARRYINREG = 1; + parameter integer CARRYINSELREG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer INMODEREG = 1; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter integer PREG = 1; + parameter SEL_MASK = "MASK"; + parameter SEL_PATTERN = "PATTERN"; + parameter USE_DPORT = "FALSE"; + parameter USE_MULT = "MULTIPLY"; + parameter USE_PATTERN_DETECT = "NO_PATDET"; + parameter USE_SIMD = "ONE48"; + parameter [47:0] MASK = 48'h3FFFFFFFFFFF; + parameter [47:0] PATTERN = 48'h000000000000; + parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; + parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [4:0] IS_INMODE_INVERTED = 5'b0; + parameter [6:0] IS_OPMODE_INVERTED = 7'b0; + output [29:0] ACOUT; + output [17:0] BCOUT; + output CARRYCASCOUT; + output [3:0] CARRYOUT; + output MULTSIGNOUT; + output OVERFLOW; + output [47:0] P; + output PATTERNBDETECT; + output PATTERNDETECT; + output [47:0] PCOUT; + output UNDERFLOW; + input [29:0] A; + input [29:0] ACIN; + input [3:0] ALUMODE; + input [17:0] B; + input [17:0] BCIN; + input [47:0] C; + input CARRYCASCIN; + input CARRYIN; + input [2:0] CARRYINSEL; + input CEA1; + input CEA2; + input CEAD; + input CEALUMODE; + input CEB1; + input CEB2; + input CEC; + input CECARRYIN; + input CECTRL; + input CED; + input CEINMODE; + input CEM; + input CEP; + input CLK; + input [24:0] D; + input [4:0] INMODE; + input MULTSIGNIN; + input [6:0] OPMODE; + input [47:0] PCIN; + input RSTA; + input RSTALLCARRYIN; + input RSTALUMODE; + input RSTB; + input RSTC; + input RSTCTRL; + input RSTD; + input RSTINMODE; + input RSTM; + input RSTP; +endmodule + +module EFUSE_USR (...); + parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; + output [31:0] EFUSEUSR; +endmodule + +module FIFO18E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO18"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 36'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 36'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output [31:0] DO; + output [3:0] DOP; + output EMPTY; + output FULL; + output [11:0] RDCOUNT; + output RDERR; + output [11:0] WRCOUNT; + output WRERR; + input [31:0] DI; + input [3:0] DIP; + input RDCLK; + input RDEN; + input REGCE; + input RST; + input RSTREG; + input WRCLK; + input WREN; +endmodule + +module FIFO36E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_ECC_READ = "FALSE"; + parameter EN_ECC_WRITE = "FALSE"; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO36"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 72'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 72'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output DBITERR; + output [63:0] DO; + output [7:0] DOP; + output [7:0] ECCPARITY; + output EMPTY; + output FULL; + output [12:0] RDCOUNT; + output RDERR; + output SBITERR; + output [12:0] WRCOUNT; + output WRERR; + input [63:0] DI; + input [7:0] DIP; + input INJECTDBITERR; + input INJECTSBITERR; + input RDCLK; + input RDEN; + input REGCE; + input RST; + input RSTREG; + input WRCLK; + input WREN; +endmodule + +module FRAME_ECCE2 (...); + parameter FARSRC = "EFAR"; + parameter FRAME_RBT_IN_FILENAME = "NONE"; + output CRCERROR; + output ECCERROR; + output ECCERRORSINGLE; + output SYNDROMEVALID; + output [12:0] SYNDROME; + output [25:0] FAR; + output [4:0] SYNBIT; + output [6:0] SYNWORD; +endmodule + +module GTHE2_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [19:0] ADAPT_CFG0 = 20'h00C10; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter [0:0] A_RXOSCALRESET = 1'b0; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [41:0] CFOK_CFG = 42'h24800040E80; + parameter [5:0] CFOK_CFG2 = 6'b100000; + parameter [5:0] CFOK_CFG3 = 6'b100000; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 1; + parameter [28:0] CPLL_CFG = 29'h00BC07DC; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 5; + parameter [23:0] CPLL_INIT_CFG = 24'h00001E; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [23:0] DMONITOR_CFG = 24'h000A00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "TRUE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h000; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [79:0] ES_QUALIFIER = 80'h00000000000000000000; + parameter [79:0] ES_QUAL_MASK = 80'h00000000000000000000; + parameter [79:0] ES_SDATA_MASK = 80'h00000000000000000000; + parameter [8:0] ES_VERT_OFFSET = 9'b000000000; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [2:0] GEARBOX_MODE = 3'b000; + parameter [0:0] IS_CLKRSVD0_INVERTED = 1'b0; + parameter [0:0] IS_CLKRSVD1_INVERTED = 1'b0; + parameter [0:0] IS_CPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [0:0] IS_DMONITORCLK_INVERTED = 1'b0; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK_INVERTED = 1'b0; + parameter [0:0] IS_SIGVALIDCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXPHDLYTSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK_INVERTED = 1'b0; + parameter [0:0] LOOPBACK_CFG = 1'b0; + parameter [1:0] OUTREFCLK_SEL_INV = 2'b11; + parameter PCS_PCIE_EN = "FALSE"; + parameter [47:0] PCS_RSVD_ATTR = 48'h000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [31:0] PMA_RSV = 32'b00000000000000000000000010000000; + parameter [31:0] PMA_RSV2 = 32'b00011100000000000000000000001010; + parameter [1:0] PMA_RSV3 = 2'b00; + parameter [14:0] PMA_RSV4 = 15'b000000000001000; + parameter [3:0] PMA_RSV5 = 4'b0000; + parameter [0:0] RESET_POWERSAVE_DISABLE = 1'b0; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 61; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [82:0] RXCDR_CFG = 83'h0002007FE2000C208001A; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [5:0] RXCDR_LOCK_CFG = 6'b001001; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDLY_CFG = 16'h001F; + parameter [8:0] RXDLY_LCFG = 9'h030; + parameter [15:0] RXDLY_TAP_CFG = 16'h0000; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [13:0] RXLPM_HF_CFG = 14'b00001000000000; + parameter [17:0] RXLPM_LF_CFG = 18'b001001000000000000; + parameter [6:0] RXOOB_CFG = 7'b0000110; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter [4:0] RXOSCALRESET_TIMEOUT = 5'b00000; + parameter integer RXOUT_DIV = 2; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [23:0] RXPHDLY_CFG = 24'h084020; + parameter [23:0] RXPH_CFG = 24'hC00002; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] RXPI_CFG0 = 2'b00; + parameter [1:0] RXPI_CFG1 = 2'b00; + parameter [1:0] RXPI_CFG2 = 2'b00; + parameter [1:0] RXPI_CFG3 = 2'b00; + parameter [0:0] RXPI_CFG4 = 1'b0; + parameter [0:0] RXPI_CFG5 = 1'b0; + parameter [2:0] RXPI_CFG6 = 3'b100; + parameter [4:0] RXPMARESET_TIME = 5'b00011; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [23:0] RX_BIAS_CFG = 24'b000011000000000000010000; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter integer RX_CLK25_DIV = 7; + parameter [0:0] RX_CLKMUX_PD = 1'b1; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [3:0] RX_CM_TRIM = 4'b0100; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter [13:0] RX_DEBUG_CFG = 14'b00000000000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [3:0] RX_DFELPM_CFG0 = 4'b0110; + parameter [0:0] RX_DFELPM_CFG1 = 1'b0; + parameter [0:0] RX_DFELPM_KLKH_AGC_STUP_EN = 1'b1; + parameter [1:0] RX_DFE_AGC_CFG0 = 2'b00; + parameter [2:0] RX_DFE_AGC_CFG1 = 3'b010; + parameter [3:0] RX_DFE_AGC_CFG2 = 4'b0000; + parameter [0:0] RX_DFE_AGC_OVRDEN = 1'b1; + parameter [22:0] RX_DFE_GAIN_CFG = 23'h0020C0; + parameter [11:0] RX_DFE_H2_CFG = 12'b000000000000; + parameter [11:0] RX_DFE_H3_CFG = 12'b000001000000; + parameter [10:0] RX_DFE_H4_CFG = 11'b00011100000; + parameter [10:0] RX_DFE_H5_CFG = 11'b00011100000; + parameter [10:0] RX_DFE_H6_CFG = 11'b00000100000; + parameter [10:0] RX_DFE_H7_CFG = 11'b00000100000; + parameter [32:0] RX_DFE_KL_CFG = 33'b000000000000000000000001100010000; + parameter [1:0] RX_DFE_KL_LPM_KH_CFG0 = 2'b01; + parameter [2:0] RX_DFE_KL_LPM_KH_CFG1 = 3'b010; + parameter [3:0] RX_DFE_KL_LPM_KH_CFG2 = 4'b0010; + parameter [0:0] RX_DFE_KL_LPM_KH_OVRDEN = 1'b1; + parameter [1:0] RX_DFE_KL_LPM_KL_CFG0 = 2'b10; + parameter [2:0] RX_DFE_KL_LPM_KL_CFG1 = 3'b010; + parameter [3:0] RX_DFE_KL_LPM_KL_CFG2 = 4'b0010; + parameter [0:0] RX_DFE_KL_LPM_KL_OVRDEN = 1'b1; + parameter [15:0] RX_DFE_LPM_CFG = 16'h0080; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter [53:0] RX_DFE_ST_CFG = 54'h00E100000C003F; + parameter [16:0] RX_DFE_UT_CFG = 17'b00011100000000000; + parameter [16:0] RX_DFE_VP_CFG = 17'b00011101010100011; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter integer RX_INT_DATAWIDTH = 0; + parameter [12:0] RX_OS_CFG = 13'b0000010000000; + parameter integer RX_SIG_VALID_DLY = 10; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter [2:0] SIM_CPLLREFCLK_SEL = 3'b001; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X"; + parameter SIM_VERSION = "1.1"; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [31:0] TST_RSV = 32'h00000000; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h001F; + parameter [8:0] TXDLY_LCFG = 9'h030; + parameter [15:0] TXDLY_TAP_CFG = 16'h0000; + parameter TXGEARBOX_EN = "FALSE"; + parameter [0:0] TXOOB_CFG = 1'b0; + parameter integer TXOUT_DIV = 2; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [23:0] TXPHDLY_CFG = 24'h084020; + parameter [15:0] TXPH_CFG = 16'h0780; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b0; + parameter [2:0] TXPI_CFG5 = 3'b100; + parameter [0:0] TXPI_GREY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 7; + parameter [0:0] TX_CLKMUX_PD = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter integer TX_INT_DATAWIDTH = 0; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [0:0] TX_QPI_STATUS_EN = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h1832; + parameter [16:0] TX_RXDETECT_PRECHARGE_TIME = 17'h00000; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter TX_XCLK_SEL = "TXUSR"; + parameter [0:0] UCODEER_CLR = 1'b0; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output DRPRDY; + output EYESCANDATAERROR; + output GTHTXN; + output GTHTXP; + output GTREFCLKMONITOR; + output PHYSTATUS; + output RSOSINTDONE; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output RXDFESLIDETAPSTARTED; + output RXDFESLIDETAPSTROBEDONE; + output RXDFESLIDETAPSTROBESTARTED; + output RXDFESTADAPTDONE; + output RXDLYSRESETDONE; + output RXELECIDLE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPMARESETDONE; + output RXPRBSERR; + output RXQPISENN; + output RXQPISENP; + output RXRATEDONE; + output RXRESETDONE; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXGEARBOXREADY; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXQPISENN; + output TXQPISENP; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + output [14:0] DMONITOROUT; + output [15:0] DRPDO; + output [15:0] PCSRSVDOUT; + output [1:0] RXCLKCORCNT; + output [1:0] RXDATAVALID; + output [1:0] RXHEADERVALID; + output [1:0] RXSTARTOFSEQ; + output [1:0] TXBUFSTATUS; + output [2:0] RXBUFSTATUS; + output [2:0] RXSTATUS; + output [4:0] RXCHBONDO; + output [4:0] RXPHMONITOR; + output [4:0] RXPHSLIPMONITOR; + output [5:0] RXHEADER; + output [63:0] RXDATA; + output [6:0] RXMONITOROUT; + output [7:0] RXCHARISCOMMA; + output [7:0] RXCHARISK; + output [7:0] RXDISPERR; + output [7:0] RXNOTINTABLE; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input CPLLRESET; + input DMONFIFORESET; + input DMONITORCLK; + input DRPCLK; + input DRPEN; + input DRPWE; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTGREFCLK; + input GTHRXN; + input GTHRXP; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTRESETSEL; + input GTRXRESET; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input QPLLCLK; + input QPLLREFCLK; + input RESETOVRD; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input RXDDIEN; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input RXDFECM1EN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFESLIDETAPADAPTEN; + input RXDFESLIDETAPHOLD; + input RXDFESLIDETAPINITOVRDEN; + input RXDFESLIDETAPONLYADAPTEN; + input RXDFESLIDETAPOVRDEN; + input RXDFESLIDETAPSTROBE; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFETAP6HOLD; + input RXDFETAP6OVRDEN; + input RXDFETAP7HOLD; + input RXDFETAP7OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEVSEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input RXGEARBOXSLIP; + input RXLPMEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXMCOMMAALIGNEN; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input RXOSINTEN; + input RXOSINTHOLD; + input RXOSINTNTRLEN; + input RXOSINTOVRDEN; + input RXOSINTSTROBE; + input RXOSINTTESTOVRDEN; + input RXOSOVRDEN; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input RXQPIEN; + input RXRATEMODE; + input RXSLIDE; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input RXUSERRDY; + input RXUSRCLK2; + input RXUSRCLK; + input SETERRSTATUS; + input SIGVALIDCLK; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXINHIBIT; + input TXPCSRESET; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input TXPISOPD; + input TXPMARESET; + input TXPOLARITY; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input TXPRECURSORINV; + input TXQPIBIASEN; + input TXQPISTRONGPDOWN; + input TXQPIWEAKPUP; + input TXRATEMODE; + input TXSTARTSEQ; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input TXUSERRDY; + input TXUSRCLK2; + input TXUSRCLK; + input [13:0] RXADAPTSELTEST; + input [15:0] DRPDI; + input [15:0] GTRSVD; + input [15:0] PCSRSVDIN; + input [19:0] TSTIN; + input [1:0] RXELECIDLEMODE; + input [1:0] RXMONITORSEL; + input [1:0] RXPD; + input [1:0] RXSYSCLKSEL; + input [1:0] TXPD; + input [1:0] TXSYSCLKSEL; + input [2:0] CPLLREFCLKSEL; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXOUTCLKSEL; + input [2:0] RXPRBSSEL; + input [2:0] RXRATE; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input [2:0] TXPRBSSEL; + input [2:0] TXRATE; + input [3:0] RXOSINTCFG; + input [3:0] RXOSINTID0; + input [3:0] TXDIFFCTRL; + input [4:0] PCSRSVDIN2; + input [4:0] PMARSVDIN; + input [4:0] RXCHBONDI; + input [4:0] RXDFEAGCTRL; + input [4:0] RXDFESLIDETAP; + input [4:0] TXPIPPMSTEPSIZE; + input [4:0] TXPOSTCURSOR; + input [4:0] TXPRECURSOR; + input [5:0] RXDFESLIDETAPID; + input [63:0] TXDATA; + input [6:0] TXMAINCURSOR; + input [6:0] TXSEQUENCE; + input [7:0] TX8B10BBYPASS; + input [7:0] TXCHARDISPMODE; + input [7:0] TXCHARDISPVAL; + input [7:0] TXCHARISK; + input [8:0] DRPADDR; +endmodule + +module GTHE2_COMMON (...); + parameter [63:0] BIAS_CFG = 64'h0000040000001000; + parameter [31:0] COMMON_CFG = 32'h0000001C; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_QPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [26:0] QPLL_CFG = 27'h0480181; + parameter [3:0] QPLL_CLKOUT_CFG = 4'b0000; + parameter [5:0] QPLL_COARSE_FREQ_OVRD = 6'b010000; + parameter [0:0] QPLL_COARSE_FREQ_OVRD_EN = 1'b0; + parameter [9:0] QPLL_CP = 10'b0000011111; + parameter [0:0] QPLL_CP_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_DMONITOR_SEL = 1'b0; + parameter [9:0] QPLL_FBDIV = 10'b0000000000; + parameter [0:0] QPLL_FBDIV_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_FBDIV_RATIO = 1'b0; + parameter [23:0] QPLL_INIT_CFG = 24'h000006; + parameter [15:0] QPLL_LOCK_CFG = 16'h01E8; + parameter [3:0] QPLL_LPF = 4'b1111; + parameter integer QPLL_REFCLK_DIV = 2; + parameter [0:0] QPLL_RP_COMP = 1'b0; + parameter [1:0] QPLL_VTRL_RESET = 2'b00; + parameter [1:0] RCAL_CFG = 2'b00; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [2:0] SIM_QPLLREFCLK_SEL = 3'b001; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_VERSION = "1.1"; + output DRPRDY; + output QPLLFBCLKLOST; + output QPLLLOCK; + output QPLLOUTCLK; + output QPLLOUTREFCLK; + output QPLLREFCLKLOST; + output REFCLKOUTMONITOR; + output [15:0] DRPDO; + output [15:0] PMARSVDOUT; + output [7:0] QPLLDMONITOR; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input BGRCALOVRDENB; + input DRPCLK; + input DRPEN; + input DRPWE; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input QPLLLOCKDETCLK; + input QPLLLOCKEN; + input QPLLOUTRESET; + input QPLLPD; + input QPLLRESET; + input RCALENB; + input [15:0] DRPDI; + input [15:0] QPLLRSVD1; + input [2:0] QPLLREFCLKSEL; + input [4:0] BGRCALOVRD; + input [4:0] QPLLRSVD2; + input [7:0] DRPADDR; + input [7:0] PMARSVD; +endmodule + +module GTPE2_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [19:0] ADAPT_CFG0 = 20'b00000000000000000000; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [42:0] CFOK_CFG = 43'b1001001000000000000000001000000111010000000; + parameter [6:0] CFOK_CFG2 = 7'b0100000; + parameter [6:0] CFOK_CFG3 = 7'b0100000; + parameter [0:0] CFOK_CFG4 = 1'b0; + parameter [1:0] CFOK_CFG5 = 2'b00; + parameter [3:0] CFOK_CFG6 = 4'b0000; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter [0:0] CLK_COMMON_SWING = 1'b0; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 1; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [23:0] DMONITOR_CFG = 24'h000A00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h010; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [79:0] ES_QUALIFIER = 80'h00000000000000000000; + parameter [79:0] ES_QUAL_MASK = 80'h00000000000000000000; + parameter [79:0] ES_SDATA_MASK = 80'h00000000000000000000; + parameter [8:0] ES_VERT_OFFSET = 9'b000000000; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [2:0] GEARBOX_MODE = 3'b000; + parameter [0:0] IS_CLKRSVD0_INVERTED = 1'b0; + parameter [0:0] IS_CLKRSVD1_INVERTED = 1'b0; + parameter [0:0] IS_DMONITORCLK_INVERTED = 1'b0; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK_INVERTED = 1'b0; + parameter [0:0] IS_SIGVALIDCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXPHDLYTSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK_INVERTED = 1'b0; + parameter [0:0] LOOPBACK_CFG = 1'b0; + parameter [1:0] OUTREFCLK_SEL_INV = 2'b11; + parameter PCS_PCIE_EN = "FALSE"; + parameter [47:0] PCS_RSVD_ATTR = 48'h000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [0:0] PMA_LOOPBACK_CFG = 1'b0; + parameter [31:0] PMA_RSV = 32'h00000333; + parameter [31:0] PMA_RSV2 = 32'h00002050; + parameter [1:0] PMA_RSV3 = 2'b00; + parameter [3:0] PMA_RSV4 = 4'b0000; + parameter [0:0] PMA_RSV5 = 1'b0; + parameter [0:0] PMA_RSV6 = 1'b0; + parameter [0:0] PMA_RSV7 = 1'b0; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 61; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [82:0] RXCDR_CFG = 83'h0000107FE406001041010; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [5:0] RXCDR_LOCK_CFG = 6'b001001; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [15:0] RXDLY_CFG = 16'h0010; + parameter [8:0] RXDLY_LCFG = 9'h020; + parameter [15:0] RXDLY_TAP_CFG = 16'h0000; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [6:0] RXLPMRESET_TIME = 7'b0001111; + parameter [0:0] RXLPM_BIAS_STARTUP_DISABLE = 1'b0; + parameter [3:0] RXLPM_CFG = 4'b0110; + parameter [0:0] RXLPM_CFG1 = 1'b0; + parameter [0:0] RXLPM_CM_CFG = 1'b0; + parameter [8:0] RXLPM_GC_CFG = 9'b111100010; + parameter [2:0] RXLPM_GC_CFG2 = 3'b001; + parameter [13:0] RXLPM_HF_CFG = 14'b00001111110000; + parameter [4:0] RXLPM_HF_CFG2 = 5'b01010; + parameter [3:0] RXLPM_HF_CFG3 = 4'b0000; + parameter [0:0] RXLPM_HOLD_DURING_EIDLE = 1'b0; + parameter [0:0] RXLPM_INCM_CFG = 1'b0; + parameter [0:0] RXLPM_IPCM_CFG = 1'b0; + parameter [17:0] RXLPM_LF_CFG = 18'b000000001111110000; + parameter [4:0] RXLPM_LF_CFG2 = 5'b01010; + parameter [2:0] RXLPM_OSINT_CFG = 3'b100; + parameter [6:0] RXOOB_CFG = 7'b0000110; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter [4:0] RXOSCALRESET_TIMEOUT = 5'b00000; + parameter integer RXOUT_DIV = 2; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [23:0] RXPHDLY_CFG = 24'h084000; + parameter [23:0] RXPH_CFG = 24'hC00002; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [2:0] RXPI_CFG0 = 3'b000; + parameter [0:0] RXPI_CFG1 = 1'b0; + parameter [0:0] RXPI_CFG2 = 1'b0; + parameter [4:0] RXPMARESET_TIME = 5'b00011; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [15:0] RX_BIAS_CFG = 16'b0000111100110011; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter integer RX_CLK25_DIV = 7; + parameter [0:0] RX_CLKMUX_EN = 1'b1; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [3:0] RX_CM_TRIM = 4'b0100; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter [13:0] RX_DEBUG_CFG = 14'b00000000000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter [12:0] RX_OS_CFG = 13'b0001111110000; + parameter integer RX_SIG_VALID_DLY = 10; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SATA_PLL_CFG = "VCO_3000MHZ"; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X"; + parameter SIM_VERSION = "1.0"; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [31:0] TST_RSV = 32'h00000000; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h0010; + parameter [8:0] TXDLY_LCFG = 9'h020; + parameter [15:0] TXDLY_TAP_CFG = 16'h0000; + parameter TXGEARBOX_EN = "FALSE"; + parameter [0:0] TXOOB_CFG = 1'b0; + parameter integer TXOUT_DIV = 2; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [23:0] TXPHDLY_CFG = 24'h084000; + parameter [15:0] TXPH_CFG = 16'h0400; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b0; + parameter [2:0] TXPI_CFG5 = 3'b000; + parameter [0:0] TXPI_GREY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 7; + parameter [0:0] TX_CLKMUX_EN = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [0:0] TX_PREDRIVER_MODE = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h1832; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter TX_XCLK_SEL = "TXUSR"; + parameter [0:0] UCODEER_CLR = 1'b0; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + output DRPRDY; + output EYESCANDATAERROR; + output GTPTXN; + output GTPTXP; + output PHYSTATUS; + output PMARSVDOUT0; + output PMARSVDOUT1; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output RXDLYSRESETDONE; + output RXELECIDLE; + output RXHEADERVALID; + output RXOSINTDONE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPMARESETDONE; + output RXPRBSERR; + output RXRATEDONE; + output RXRESETDONE; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXGEARBOXREADY; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + output [14:0] DMONITOROUT; + output [15:0] DRPDO; + output [15:0] PCSRSVDOUT; + output [1:0] RXCLKCORCNT; + output [1:0] RXDATAVALID; + output [1:0] RXSTARTOFSEQ; + output [1:0] TXBUFSTATUS; + output [2:0] RXBUFSTATUS; + output [2:0] RXHEADER; + output [2:0] RXSTATUS; + output [31:0] RXDATA; + output [3:0] RXCHARISCOMMA; + output [3:0] RXCHARISK; + output [3:0] RXCHBONDO; + output [3:0] RXDISPERR; + output [3:0] RXNOTINTABLE; + output [4:0] RXPHMONITOR; + output [4:0] RXPHSLIPMONITOR; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input DMONFIFORESET; + input DMONITORCLK; + input DRPCLK; + input DRPEN; + input DRPWE; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTPRXN; + input GTPRXP; + input GTRESETSEL; + input GTRXRESET; + input GTTXRESET; + input PLL0CLK; + input PLL0REFCLK; + input PLL1CLK; + input PLL1REFCLK; + input PMARSVDIN0; + input PMARSVDIN1; + input PMARSVDIN2; + input PMARSVDIN3; + input PMARSVDIN4; + input RESETOVRD; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input RXDDIEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input RXGEARBOXSLIP; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFOVRDEN; + input RXLPMOSINTNTRLEN; + input RXLPMRESET; + input RXMCOMMAALIGNEN; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input RXOSINTEN; + input RXOSINTHOLD; + input RXOSINTNTRLEN; + input RXOSINTOVRDEN; + input RXOSINTPD; + input RXOSINTSTROBE; + input RXOSINTTESTOVRDEN; + input RXOSOVRDEN; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input RXRATEMODE; + input RXSLIDE; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input RXUSERRDY; + input RXUSRCLK2; + input RXUSRCLK; + input SETERRSTATUS; + input SIGVALIDCLK; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXINHIBIT; + input TXPCSRESET; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input TXPISOPD; + input TXPMARESET; + input TXPOLARITY; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input TXPRECURSORINV; + input TXRATEMODE; + input TXSTARTSEQ; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input TXUSERRDY; + input TXUSRCLK2; + input TXUSRCLK; + input [13:0] RXADAPTSELTEST; + input [15:0] DRPDI; + input [15:0] GTRSVD; + input [15:0] PCSRSVDIN; + input [19:0] TSTIN; + input [1:0] RXELECIDLEMODE; + input [1:0] RXPD; + input [1:0] RXSYSCLKSEL; + input [1:0] TXPD; + input [1:0] TXSYSCLKSEL; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXOUTCLKSEL; + input [2:0] RXPRBSSEL; + input [2:0] RXRATE; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input [2:0] TXPRBSSEL; + input [2:0] TXRATE; + input [31:0] TXDATA; + input [3:0] RXCHBONDI; + input [3:0] RXOSINTCFG; + input [3:0] RXOSINTID0; + input [3:0] TX8B10BBYPASS; + input [3:0] TXCHARDISPMODE; + input [3:0] TXCHARDISPVAL; + input [3:0] TXCHARISK; + input [3:0] TXDIFFCTRL; + input [4:0] TXPIPPMSTEPSIZE; + input [4:0] TXPOSTCURSOR; + input [4:0] TXPRECURSOR; + input [6:0] TXMAINCURSOR; + input [6:0] TXSEQUENCE; + input [8:0] DRPADDR; +endmodule + +module GTPE2_COMMON (...); + parameter [63:0] BIAS_CFG = 64'h0000000000000000; + parameter [31:0] COMMON_CFG = 32'h00000000; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK0_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK1_INVERTED = 1'b0; + parameter [0:0] IS_PLL0LOCKDETCLK_INVERTED = 1'b0; + parameter [0:0] IS_PLL1LOCKDETCLK_INVERTED = 1'b0; + parameter [26:0] PLL0_CFG = 27'h01F03DC; + parameter [0:0] PLL0_DMON_CFG = 1'b0; + parameter integer PLL0_FBDIV = 4; + parameter integer PLL0_FBDIV_45 = 5; + parameter [23:0] PLL0_INIT_CFG = 24'h00001E; + parameter [8:0] PLL0_LOCK_CFG = 9'h1E8; + parameter integer PLL0_REFCLK_DIV = 1; + parameter [26:0] PLL1_CFG = 27'h01F03DC; + parameter [0:0] PLL1_DMON_CFG = 1'b0; + parameter integer PLL1_FBDIV = 4; + parameter integer PLL1_FBDIV_45 = 5; + parameter [23:0] PLL1_INIT_CFG = 24'h00001E; + parameter [8:0] PLL1_LOCK_CFG = 9'h1E8; + parameter integer PLL1_REFCLK_DIV = 1; + parameter [7:0] PLL_CLKOUT_CFG = 8'b00000000; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [2:0] SIM_PLL0REFCLK_SEL = 3'b001; + parameter [2:0] SIM_PLL1REFCLK_SEL = 3'b001; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_VERSION = "1.0"; + output DRPRDY; + output PLL0FBCLKLOST; + output PLL0LOCK; + output PLL0OUTCLK; + output PLL0OUTREFCLK; + output PLL0REFCLKLOST; + output PLL1FBCLKLOST; + output PLL1LOCK; + output PLL1OUTCLK; + output PLL1OUTREFCLK; + output PLL1REFCLKLOST; + output REFCLKOUTMONITOR0; + output REFCLKOUTMONITOR1; + output [15:0] DRPDO; + output [15:0] PMARSVDOUT; + output [7:0] DMONITOROUT; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input BGRCALOVRDENB; + input DRPCLK; + input DRPEN; + input DRPWE; + input GTEASTREFCLK0; + input GTEASTREFCLK1; + input GTGREFCLK0; + input GTGREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTWESTREFCLK0; + input GTWESTREFCLK1; + input PLL0LOCKDETCLK; + input PLL0LOCKEN; + input PLL0PD; + input PLL0RESET; + input PLL1LOCKDETCLK; + input PLL1LOCKEN; + input PLL1PD; + input PLL1RESET; + input RCALENB; + input [15:0] DRPDI; + input [15:0] PLLRSVD1; + input [2:0] PLL0REFCLKSEL; + input [2:0] PLL1REFCLKSEL; + input [4:0] BGRCALOVRD; + input [4:0] PLLRSVD2; + input [7:0] DRPADDR; + input [7:0] PMARSVD; +endmodule + +module GTXE2_CHANNEL (...); + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 1; + parameter [23:0] CPLL_CFG = 24'hB007D8; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 5; + parameter [23:0] CPLL_INIT_CFG = 24'h00001E; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [23:0] DMONITOR_CFG = 24'h000A00; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h000; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [79:0] ES_QUALIFIER = 80'h00000000000000000000; + parameter [79:0] ES_QUAL_MASK = 80'h00000000000000000000; + parameter [79:0] ES_SDATA_MASK = 80'h00000000000000000000; + parameter [8:0] ES_VERT_OFFSET = 9'b000000000; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [2:0] GEARBOX_MODE = 3'b000; + parameter [0:0] IS_CPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_RXUSRCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXPHDLYTSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK2_INVERTED = 1'b0; + parameter [0:0] IS_TXUSRCLK_INVERTED = 1'b0; + parameter [1:0] OUTREFCLK_SEL_INV = 2'b11; + parameter PCS_PCIE_EN = "FALSE"; + parameter [47:0] PCS_RSVD_ATTR = 48'h000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [31:0] PMA_RSV = 32'h00000000; + parameter [15:0] PMA_RSV2 = 16'h2050; + parameter [1:0] PMA_RSV3 = 2'b00; + parameter [31:0] PMA_RSV4 = 32'h00000000; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 61; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [71:0] RXCDR_CFG = 72'h0B000023FF20400020; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [5:0] RXCDR_LOCK_CFG = 6'b010101; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDLY_CFG = 16'h001F; + parameter [8:0] RXDLY_LCFG = 9'h030; + parameter [15:0] RXDLY_TAP_CFG = 16'h0000; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [13:0] RXLPM_HF_CFG = 14'b00000011110000; + parameter [13:0] RXLPM_LF_CFG = 14'b00000011110000; + parameter [6:0] RXOOB_CFG = 7'b0000110; + parameter integer RXOUT_DIV = 2; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [23:0] RXPHDLY_CFG = 24'h084020; + parameter [23:0] RXPH_CFG = 24'h000000; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [4:0] RXPMARESET_TIME = 5'b00011; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [11:0] RX_BIAS_CFG = 12'b000000000000; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter integer RX_CLK25_DIV = 7; + parameter [0:0] RX_CLKMUX_PD = 1'b1; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [2:0] RX_CM_TRIM = 3'b100; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter [11:0] RX_DEBUG_CFG = 12'b000000000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [22:0] RX_DFE_GAIN_CFG = 23'h180E0F; + parameter [11:0] RX_DFE_H2_CFG = 12'b000111100000; + parameter [11:0] RX_DFE_H3_CFG = 12'b000111100000; + parameter [10:0] RX_DFE_H4_CFG = 11'b00011110000; + parameter [10:0] RX_DFE_H5_CFG = 11'b00011110000; + parameter [12:0] RX_DFE_KL_CFG = 13'b0001111110000; + parameter [31:0] RX_DFE_KL_CFG2 = 32'h3008E56A; + parameter [15:0] RX_DFE_LPM_CFG = 16'h0904; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter [16:0] RX_DFE_UT_CFG = 17'b00111111000000000; + parameter [16:0] RX_DFE_VP_CFG = 17'b00011111100000000; + parameter [12:0] RX_DFE_XYD_CFG = 13'b0000000010000; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter integer RX_INT_DATAWIDTH = 0; + parameter [12:0] RX_OS_CFG = 13'b0001111110000; + parameter integer RX_SIG_VALID_DLY = 10; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter [2:0] SIM_CPLLREFCLK_SEL = 3'b001; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "X"; + parameter SIM_VERSION = "4.0"; + parameter [4:0] TERM_RCAL_CFG = 5'b10000; + parameter [0:0] TERM_RCAL_OVRD = 1'b0; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [31:0] TST_RSV = 32'h00000000; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h001F; + parameter [8:0] TXDLY_LCFG = 9'h030; + parameter [15:0] TXDLY_TAP_CFG = 16'h0000; + parameter TXGEARBOX_EN = "FALSE"; + parameter integer TXOUT_DIV = 2; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [23:0] TXPHDLY_CFG = 24'h084020; + parameter [15:0] TXPH_CFG = 16'h0780; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter integer TX_CLK25_DIV = 7; + parameter [0:0] TX_CLKMUX_PD = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [4:0] TX_DEEMPH0 = 5'b00000; + parameter [4:0] TX_DEEMPH1 = 5'b00000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter integer TX_INT_DATAWIDTH = 0; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [0:0] TX_PREDRIVER_MODE = 1'b0; + parameter [0:0] TX_QPI_STATUS_EN = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h1832; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter TX_XCLK_SEL = "TXUSR"; + parameter [0:0] UCODEER_CLR = 1'b0; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output DRPRDY; + output EYESCANDATAERROR; + output GTREFCLKMONITOR; + output GTXTXN; + output GTXTXP; + output PHYSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output RXDATAVALID; + output RXDLYSRESETDONE; + output RXELECIDLE; + output RXHEADERVALID; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPRBSERR; + output RXQPISENN; + output RXQPISENP; + output RXRATEDONE; + output RXRESETDONE; + output RXSTARTOFSEQ; + output RXVALID; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXGEARBOXREADY; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXQPISENN; + output TXQPISENP; + output TXRATEDONE; + output TXRESETDONE; + output [15:0] DRPDO; + output [15:0] PCSRSVDOUT; + output [1:0] RXCLKCORCNT; + output [1:0] TXBUFSTATUS; + output [2:0] RXBUFSTATUS; + output [2:0] RXHEADER; + output [2:0] RXSTATUS; + output [4:0] RXCHBONDO; + output [4:0] RXPHMONITOR; + output [4:0] RXPHSLIPMONITOR; + output [63:0] RXDATA; + output [6:0] RXMONITOROUT; + output [7:0] DMONITOROUT; + output [7:0] RXCHARISCOMMA; + output [7:0] RXCHARISK; + output [7:0] RXDISPERR; + output [7:0] RXNOTINTABLE; + output [9:0] TSTOUT; + input CFGRESET; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input CPLLRESET; + input DRPCLK; + input DRPEN; + input DRPWE; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTRESETSEL; + input GTRXRESET; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input GTXRXN; + input GTXRXP; + input QPLLCLK; + input QPLLREFCLK; + input RESETOVRD; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input RXDDIEN; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input RXDFECM1EN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEVSEN; + input RXDFEXYDEN; + input RXDFEXYDHOLD; + input RXDFEXYDOVRDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input RXGEARBOXSLIP; + input RXLPMEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXMCOMMAALIGNEN; + input RXOOBRESET; + input RXOSHOLD; + input RXOSOVRDEN; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input RXQPIEN; + input RXSLIDE; + input RXUSERRDY; + input RXUSRCLK2; + input RXUSRCLK; + input SETERRSTATUS; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXINHIBIT; + input TXPCSRESET; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPISOPD; + input TXPMARESET; + input TXPOLARITY; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input TXPRECURSORINV; + input TXQPIBIASEN; + input TXQPISTRONGPDOWN; + input TXQPIWEAKPUP; + input TXSTARTSEQ; + input TXSWING; + input TXUSERRDY; + input TXUSRCLK2; + input TXUSRCLK; + input [15:0] DRPDI; + input [15:0] GTRSVD; + input [15:0] PCSRSVDIN; + input [19:0] TSTIN; + input [1:0] RXELECIDLEMODE; + input [1:0] RXMONITORSEL; + input [1:0] RXPD; + input [1:0] RXSYSCLKSEL; + input [1:0] TXPD; + input [1:0] TXSYSCLKSEL; + input [2:0] CPLLREFCLKSEL; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXOUTCLKSEL; + input [2:0] RXPRBSSEL; + input [2:0] RXRATE; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input [2:0] TXPRBSSEL; + input [2:0] TXRATE; + input [3:0] CLKRSVD; + input [3:0] TXDIFFCTRL; + input [4:0] PCSRSVDIN2; + input [4:0] PMARSVDIN2; + input [4:0] PMARSVDIN; + input [4:0] RXCHBONDI; + input [4:0] TXPOSTCURSOR; + input [4:0] TXPRECURSOR; + input [63:0] TXDATA; + input [6:0] TXMAINCURSOR; + input [6:0] TXSEQUENCE; + input [7:0] TX8B10BBYPASS; + input [7:0] TXCHARDISPMODE; + input [7:0] TXCHARDISPVAL; + input [7:0] TXCHARISK; + input [8:0] DRPADDR; +endmodule + +module GTXE2_COMMON (...); + parameter [63:0] BIAS_CFG = 64'h0000040000001000; + parameter [31:0] COMMON_CFG = 32'h00000000; + parameter [0:0] IS_DRPCLK_INVERTED = 1'b0; + parameter [0:0] IS_GTGREFCLK_INVERTED = 1'b0; + parameter [0:0] IS_QPLLLOCKDETCLK_INVERTED = 1'b0; + parameter [26:0] QPLL_CFG = 27'h0680181; + parameter [3:0] QPLL_CLKOUT_CFG = 4'b0000; + parameter [5:0] QPLL_COARSE_FREQ_OVRD = 6'b010000; + parameter [0:0] QPLL_COARSE_FREQ_OVRD_EN = 1'b0; + parameter [9:0] QPLL_CP = 10'b0000011111; + parameter [0:0] QPLL_CP_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_DMONITOR_SEL = 1'b0; + parameter [9:0] QPLL_FBDIV = 10'b0000000000; + parameter [0:0] QPLL_FBDIV_MONITOR_EN = 1'b0; + parameter [0:0] QPLL_FBDIV_RATIO = 1'b0; + parameter [23:0] QPLL_INIT_CFG = 24'h000006; + parameter [15:0] QPLL_LOCK_CFG = 16'h21E8; + parameter [3:0] QPLL_LPF = 4'b1111; + parameter integer QPLL_REFCLK_DIV = 2; + parameter [2:0] SIM_QPLLREFCLK_SEL = 3'b001; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_VERSION = "4.0"; + output DRPRDY; + output QPLLFBCLKLOST; + output QPLLLOCK; + output QPLLOUTCLK; + output QPLLOUTREFCLK; + output QPLLREFCLKLOST; + output REFCLKOUTMONITOR; + output [15:0] DRPDO; + output [7:0] QPLLDMONITOR; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input DRPCLK; + input DRPEN; + input DRPWE; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input QPLLLOCKDETCLK; + input QPLLLOCKEN; + input QPLLOUTRESET; + input QPLLPD; + input QPLLRESET; + input RCALENB; + input [15:0] DRPDI; + input [15:0] QPLLRSVD1; + input [2:0] QPLLREFCLKSEL; + input [4:0] BGRCALOVRD; + input [4:0] QPLLRSVD2; + input [7:0] DRPADDR; + input [7:0] PMARSVD; +endmodule + +module IBUF_IBUFDISABLE (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IBUFDISABLE; +endmodule + +module IBUF_INTERMDISABLE (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IFD_DELAY_VALUE = "AUTO"; + parameter IOSTANDARD = "DEFAULT"; + output O; + input I, IB; +endmodule + +module IBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O, OB; + input I, IB; +endmodule + +module IBUFDS_DIFF_OUT_IBUFDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input I; + input IB; + input IBUFDISABLE; +endmodule + +module IBUFDS_DIFF_OUT_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input I; + input IB; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDS_GTE2 (...); + parameter CLKCM_CFG = "TRUE"; + parameter CLKRCV_TRST = "TRUE"; + parameter CLKSWING_CFG = "TRUE"; + output O; + output ODIV2; + input CEB; + input I; + input IB; +endmodule + +module IBUFDS_IBUFDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IB; + input IBUFDISABLE; +endmodule + +module IBUFDS_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IB; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module ICAPE2 (...); + parameter [31:0] DEVICE_ID = 32'h04244093; + parameter ICAP_WIDTH = "X32"; + parameter SIM_CFG_FILE_NAME = "NONE"; + output [31:0] O; + input CLK; + input CSIB; + input RDWRB; + input [31:0] I; +endmodule + +module IDDR (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q1; + output Q2; + input C; + input CE; + input D; + input R; + input S; +endmodule + +module IDDR_2CLK (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_CB_INVERTED = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + output Q1; + output Q2; + input C; + input CB; + input CE; + input D; + input R; + input S; +endmodule + +module IDELAYCTRL (...); + parameter SIM_DEVICE = "7SERIES"; + output RDY; + input REFCLK; + input RST; +endmodule + +module IDELAYE2 (...); + parameter CINVCTRL_SEL = "FALSE"; + parameter DELAY_SRC = "IDATAIN"; + parameter HIGH_PERFORMANCE_MODE = "FALSE"; + parameter IDELAY_TYPE = "FIXED"; + parameter integer IDELAY_VALUE = 0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_DATAIN_INVERTED = 1'b0; + parameter [0:0] IS_IDATAIN_INVERTED = 1'b0; + parameter PIPE_SEL = "FALSE"; + parameter real REFCLK_FREQUENCY = 200.0; + parameter SIGNAL_PATTERN = "DATA"; + parameter integer SIM_DELAY_D = 0; + output [4:0] CNTVALUEOUT; + output DATAOUT; + input C; + input CE; + input CINVCTRL; + input [4:0] CNTVALUEIN; + input DATAIN; + input IDATAIN; + input INC; + input LD; + input LDPIPEEN; + input REGRST; +endmodule + +module IN_FIFO (...); + parameter integer ALMOST_EMPTY_VALUE = 1; + parameter integer ALMOST_FULL_VALUE = 1; + parameter ARRAY_MODE = "ARRAY_MODE_4_X_8"; + parameter SYNCHRONOUS_MODE = "FALSE"; + output ALMOSTEMPTY; + output ALMOSTFULL; + output EMPTY; + output FULL; + output [7:0] Q0; + output [7:0] Q1; + output [7:0] Q2; + output [7:0] Q3; + output [7:0] Q4; + output [7:0] Q5; + output [7:0] Q6; + output [7:0] Q7; + output [7:0] Q8; + output [7:0] Q9; + input RDCLK; + input RDEN; + input RESET; + input WRCLK; + input WREN; + input [3:0] D0; + input [3:0] D1; + input [3:0] D2; + input [3:0] D3; + input [3:0] D4; + input [3:0] D7; + input [3:0] D8; + input [3:0] D9; + input [7:0] D5; + input [7:0] D6; +endmodule + +module IOBUF (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + input I, T; +endmodule + +module IOBUF_DCIEN (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input T; +endmodule + +module IOBUF_INTERMDISABLE (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input T; +endmodule + +module IOBUFDS (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + input I, T; +endmodule + +module IOBUFDS_DCIEN (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input T; +endmodule + +module IOBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + input I; + input TM; + input TS; +endmodule + +module IOBUFDS_DIFF_OUT_DCIEN (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input TM; + input TS; +endmodule + +module IOBUFDS_DIFF_OUT_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input TM; + input TS; +endmodule + +module ISERDESE2 (...); + parameter DATA_RATE = "DDR"; + parameter integer DATA_WIDTH = 4; + parameter DYN_CLKDIV_INV_EN = "FALSE"; + parameter DYN_CLK_INV_EN = "FALSE"; + parameter [0:0] INIT_Q1 = 1'b0; + parameter [0:0] INIT_Q2 = 1'b0; + parameter [0:0] INIT_Q3 = 1'b0; + parameter [0:0] INIT_Q4 = 1'b0; + parameter INTERFACE_TYPE = "MEMORY"; + parameter IOBDELAY = "NONE"; + parameter [0:0] IS_CLKB_INVERTED = 1'b0; + parameter [0:0] IS_CLKDIVP_INVERTED = 1'b0; + parameter [0:0] IS_CLKDIV_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_OCLKB_INVERTED = 1'b0; + parameter [0:0] IS_OCLK_INVERTED = 1'b0; + parameter integer NUM_CE = 2; + parameter OFB_USED = "FALSE"; + parameter SERDES_MODE = "MASTER"; + parameter [0:0] SRVAL_Q1 = 1'b0; + parameter [0:0] SRVAL_Q2 = 1'b0; + parameter [0:0] SRVAL_Q3 = 1'b0; + parameter [0:0] SRVAL_Q4 = 1'b0; + output O; + output Q1; + output Q2; + output Q3; + output Q4; + output Q5; + output Q6; + output Q7; + output Q8; + output SHIFTOUT1; + output SHIFTOUT2; + input BITSLIP; + input CE1; + input CE2; + input CLK; + input CLKB; + input CLKDIV; + input CLKDIVP; + input D; + input DDLY; + input DYNCLKDIVSEL; + input DYNCLKSEL; + input OCLK; + input OCLKB; + input OFB; + input RST; + input SHIFTIN1; + input SHIFTIN2; +endmodule + +module KEEPER (...); +endmodule + +module LDCE (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input CLR, D, G, GE; +endmodule + +module LDPE (...); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input D, G, GE, PRE; +endmodule + +module LUT6_2 (...); + parameter [63:0] INIT = 64'h0000000000000000; + input I0, I1, I2, I3, I4, I5; + output O5, O6; +endmodule + +module MMCME2_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter CLKFBOUT_USE_FINE_PS = "FALSE"; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 10.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter CLKOUT0_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUT1_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter CLKOUT2_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT3_USE_FINE_PS = "FALSE"; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter CLKOUT4_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter CLKOUT5_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter CLKOUT6_USE_FINE_PS = "FALSE"; + parameter real CLKPFD_FREQ_MAX = 550.000; + parameter real CLKPFD_FREQ_MIN = 10.000; + parameter COMPENSATION = "ZHOLD"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PSEN_INVERTED = 1'b0; + parameter [0:0] IS_PSINCDEC_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter SS_EN = "FALSE"; + parameter SS_MODE = "CENTER_HIGH"; + parameter integer SS_MOD_PERIOD = 10000; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1600.000; + parameter real VCOCLK_FREQ_MIN = 600.000; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKFBSTOPPED; + output CLKINSTOPPED; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output [15:0] DO; + output DRDY; + output LOCKED; + output PSDONE; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + input CLKINSEL; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input PSCLK; + input PSEN; + input PSINCDEC; + input PWRDWN; + input RST; +endmodule + +module MMCME2_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +module OBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O, OB; + input I; +endmodule + +module OBUFT (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter integer DRIVE = 12; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + input I, T; +endmodule + +module OBUFTDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O, OB; + input I, T; +endmodule + +module ODDR (...); + output Q; + input C; + input CE; + input D1; + input D2; + input R; + input S; + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; +endmodule + +module ODELAYE2 (...); + parameter CINVCTRL_SEL = "FALSE"; + parameter DELAY_SRC = "ODATAIN"; + parameter HIGH_PERFORMANCE_MODE = "FALSE"; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_ODATAIN_INVERTED = 1'b0; + parameter ODELAY_TYPE = "FIXED"; + parameter integer ODELAY_VALUE = 0; + parameter PIPE_SEL = "FALSE"; + parameter real REFCLK_FREQUENCY = 200.0; + parameter SIGNAL_PATTERN = "DATA"; + parameter integer SIM_DELAY_D = 0; + output [4:0] CNTVALUEOUT; + output DATAOUT; + input C; + input CE; + input CINVCTRL; + input CLKIN; + input [4:0] CNTVALUEIN; + input INC; + input LD; + input LDPIPEEN; + input ODATAIN; + input REGRST; +endmodule + +module OSERDESE2 (...); + parameter DATA_RATE_OQ = "DDR"; + parameter DATA_RATE_TQ = "DDR"; + parameter integer DATA_WIDTH = 4; + parameter [0:0] INIT_OQ = 1'b0; + parameter [0:0] INIT_TQ = 1'b0; + parameter [0:0] IS_CLKDIV_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter [0:0] IS_D3_INVERTED = 1'b0; + parameter [0:0] IS_D4_INVERTED = 1'b0; + parameter [0:0] IS_D5_INVERTED = 1'b0; + parameter [0:0] IS_D6_INVERTED = 1'b0; + parameter [0:0] IS_D7_INVERTED = 1'b0; + parameter [0:0] IS_D8_INVERTED = 1'b0; + parameter [0:0] IS_T1_INVERTED = 1'b0; + parameter [0:0] IS_T2_INVERTED = 1'b0; + parameter [0:0] IS_T3_INVERTED = 1'b0; + parameter [0:0] IS_T4_INVERTED = 1'b0; + parameter SERDES_MODE = "MASTER"; + parameter [0:0] SRVAL_OQ = 1'b0; + parameter [0:0] SRVAL_TQ = 1'b0; + parameter TBYTE_CTL = "FALSE"; + parameter TBYTE_SRC = "FALSE"; + parameter integer TRISTATE_WIDTH = 4; + output OFB; + output OQ; + output SHIFTOUT1; + output SHIFTOUT2; + output TBYTEOUT; + output TFB; + output TQ; + input CLK; + input CLKDIV; + input D1; + input D2; + input D3; + input D4; + input D5; + input D6; + input D7; + input D8; + input OCE; + input RST; + input SHIFTIN1; + input SHIFTIN2; + input T1; + input T2; + input T3; + input T4; + input TBYTEIN; + input TCE; +endmodule + +module OUT_FIFO (...); + parameter integer ALMOST_EMPTY_VALUE = 1; + parameter integer ALMOST_FULL_VALUE = 1; + parameter ARRAY_MODE = "ARRAY_MODE_8_X_4"; + parameter OUTPUT_DISABLE = "FALSE"; + parameter SYNCHRONOUS_MODE = "FALSE"; + output ALMOSTEMPTY; + output ALMOSTFULL; + output EMPTY; + output FULL; + output [3:0] Q0; + output [3:0] Q1; + output [3:0] Q2; + output [3:0] Q3; + output [3:0] Q4; + output [3:0] Q7; + output [3:0] Q8; + output [3:0] Q9; + output [7:0] Q5; + output [7:0] Q6; + input RDCLK; + input RDEN; + input RESET; + input WRCLK; + input WREN; + input [7:0] D0; + input [7:0] D1; + input [7:0] D2; + input [7:0] D3; + input [7:0] D4; + input [7:0] D5; + input [7:0] D6; + input [7:0] D7; + input [7:0] D8; + input [7:0] D9; +endmodule + +module PHASER_IN (...); + parameter integer CLKOUT_DIV = 4; + parameter DQS_BIAS_MODE = "FALSE"; + parameter EN_ISERDES_RST = "FALSE"; + parameter integer FINE_DELAY = 0; + parameter FREQ_REF_DIV = "NONE"; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter real REFCLK_PERIOD = 0.000; + parameter integer SEL_CLK_OFFSET = 5; + parameter SYNC_IN_DIV_RST = "FALSE"; + output FINEOVERFLOW; + output ICLK; + output ICLKDIV; + output ISERDESRST; + output RCLK; + output [5:0] COUNTERREADVAL; + input COUNTERLOADEN; + input COUNTERREADEN; + input DIVIDERST; + input EDGEADV; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input SYNCIN; + input SYSCLK; + input [1:0] RANKSEL; + input [5:0] COUNTERLOADVAL; +endmodule + +module PHASER_IN_PHY (...); + parameter BURST_MODE = "FALSE"; + parameter integer CLKOUT_DIV = 4; + parameter [0:0] DQS_AUTO_RECAL = 1'b1; + parameter DQS_BIAS_MODE = "FALSE"; + parameter [2:0] DQS_FIND_PATTERN = 3'b001; + parameter integer FINE_DELAY = 0; + parameter FREQ_REF_DIV = "NONE"; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter real REFCLK_PERIOD = 0.000; + parameter integer SEL_CLK_OFFSET = 5; + parameter SYNC_IN_DIV_RST = "FALSE"; + parameter WR_CYCLES = "FALSE"; + output DQSFOUND; + output DQSOUTOFRANGE; + output FINEOVERFLOW; + output ICLK; + output ICLKDIV; + output ISERDESRST; + output PHASELOCKED; + output RCLK; + output WRENABLE; + output [5:0] COUNTERREADVAL; + input BURSTPENDINGPHY; + input COUNTERLOADEN; + input COUNTERREADEN; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input RSTDQSFIND; + input SYNCIN; + input SYSCLK; + input [1:0] ENCALIBPHY; + input [1:0] RANKSELPHY; + input [5:0] COUNTERLOADVAL; +endmodule + +module PHASER_OUT (...); + parameter integer CLKOUT_DIV = 4; + parameter COARSE_BYPASS = "FALSE"; + parameter integer COARSE_DELAY = 0; + parameter EN_OSERDES_RST = "FALSE"; + parameter integer FINE_DELAY = 0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OCLKDELAY_INV = "FALSE"; + parameter integer OCLK_DELAY = 0; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter [2:0] PO = 3'b000; + parameter real REFCLK_PERIOD = 0.000; + parameter SYNC_IN_DIV_RST = "FALSE"; + output COARSEOVERFLOW; + output FINEOVERFLOW; + output OCLK; + output OCLKDELAYED; + output OCLKDIV; + output OSERDESRST; + output [8:0] COUNTERREADVAL; + input COARSEENABLE; + input COARSEINC; + input COUNTERLOADEN; + input COUNTERREADEN; + input DIVIDERST; + input EDGEADV; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input SELFINEOCLKDELAY; + input SYNCIN; + input SYSCLK; + input [8:0] COUNTERLOADVAL; +endmodule + +module PHASER_OUT_PHY (...); + parameter integer CLKOUT_DIV = 4; + parameter COARSE_BYPASS = "FALSE"; + parameter integer COARSE_DELAY = 0; + parameter DATA_CTL_N = "FALSE"; + parameter DATA_RD_CYCLES = "FALSE"; + parameter integer FINE_DELAY = 0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real MEMREFCLK_PERIOD = 0.000; + parameter OCLKDELAY_INV = "FALSE"; + parameter integer OCLK_DELAY = 0; + parameter OUTPUT_CLK_SRC = "PHASE_REF"; + parameter real PHASEREFCLK_PERIOD = 0.000; + parameter [2:0] PO = 3'b000; + parameter real REFCLK_PERIOD = 0.000; + parameter SYNC_IN_DIV_RST = "FALSE"; + output COARSEOVERFLOW; + output FINEOVERFLOW; + output OCLK; + output OCLKDELAYED; + output OCLKDIV; + output OSERDESRST; + output RDENABLE; + output [1:0] CTSBUS; + output [1:0] DQSBUS; + output [1:0] DTSBUS; + output [8:0] COUNTERREADVAL; + input BURSTPENDINGPHY; + input COARSEENABLE; + input COARSEINC; + input COUNTERLOADEN; + input COUNTERREADEN; + input FINEENABLE; + input FINEINC; + input FREQREFCLK; + input MEMREFCLK; + input PHASEREFCLK; + input RST; + input SELFINEOCLKDELAY; + input SYNCIN; + input SYSCLK; + input [1:0] ENCALIBPHY; + input [8:0] COUNTERLOADVAL; +endmodule + +module PHASER_REF (...); + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + output LOCKED; + input CLKIN; + input PWRDWN; + input RST; +endmodule + +module PHY_CONTROL (...); + parameter integer AO_TOGGLE = 0; + parameter [3:0] AO_WRLVL_EN = 4'b0000; + parameter BURST_MODE = "FALSE"; + parameter integer CLK_RATIO = 1; + parameter integer CMD_OFFSET = 0; + parameter integer CO_DURATION = 0; + parameter DATA_CTL_A_N = "FALSE"; + parameter DATA_CTL_B_N = "FALSE"; + parameter DATA_CTL_C_N = "FALSE"; + parameter DATA_CTL_D_N = "FALSE"; + parameter DISABLE_SEQ_MATCH = "TRUE"; + parameter integer DI_DURATION = 0; + parameter integer DO_DURATION = 0; + parameter integer EVENTS_DELAY = 63; + parameter integer FOUR_WINDOW_CLOCKS = 63; + parameter MULTI_REGION = "FALSE"; + parameter PHY_COUNT_ENABLE = "FALSE"; + parameter integer RD_CMD_OFFSET_0 = 0; + parameter integer RD_CMD_OFFSET_1 = 00; + parameter integer RD_CMD_OFFSET_2 = 0; + parameter integer RD_CMD_OFFSET_3 = 0; + parameter integer RD_DURATION_0 = 0; + parameter integer RD_DURATION_1 = 0; + parameter integer RD_DURATION_2 = 0; + parameter integer RD_DURATION_3 = 0; + parameter SYNC_MODE = "FALSE"; + parameter integer WR_CMD_OFFSET_0 = 0; + parameter integer WR_CMD_OFFSET_1 = 0; + parameter integer WR_CMD_OFFSET_2 = 0; + parameter integer WR_CMD_OFFSET_3 = 0; + parameter integer WR_DURATION_0 = 0; + parameter integer WR_DURATION_1 = 0; + parameter integer WR_DURATION_2 = 0; + parameter integer WR_DURATION_3 = 0; + output PHYCTLALMOSTFULL; + output PHYCTLEMPTY; + output PHYCTLFULL; + output PHYCTLREADY; + output [1:0] INRANKA; + output [1:0] INRANKB; + output [1:0] INRANKC; + output [1:0] INRANKD; + output [1:0] PCENABLECALIB; + output [3:0] AUXOUTPUT; + output [3:0] INBURSTPENDING; + output [3:0] OUTBURSTPENDING; + input MEMREFCLK; + input PHYCLK; + input PHYCTLMSTREMPTY; + input PHYCTLWRENABLE; + input PLLLOCK; + input READCALIBENABLE; + input REFDLLLOCK; + input RESET; + input SYNCIN; + input WRITECALIBENABLE; + input [31:0] PHYCTLWD; +endmodule + +module PLLE2_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter COMPENSATION = "ZHOLD"; + parameter STARTUP_WAIT = "FALSE"; + parameter integer CLKOUT0_DIVIDE = 1; + parameter integer CLKOUT1_DIVIDE = 1; + parameter integer CLKOUT2_DIVIDE = 1; + parameter integer CLKOUT3_DIVIDE = 1; + parameter integer CLKOUT4_DIVIDE = 1; + parameter integer CLKOUT5_DIVIDE = 1; + parameter integer DIVCLK_DIVIDE = 1; + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter real VCOCLK_FREQ_MAX = 2133.000; + parameter real VCOCLK_FREQ_MIN = 800.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 19.000; + parameter real CLKPFD_FREQ_MAX = 550.0; + parameter real CLKPFD_FREQ_MIN = 19.0; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output DRDY; + output LOCKED; + output [15:0] DO; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + input CLKINSEL; + input DCLK; + input DEN; + input DWE; + input PWRDWN; + input RST; + input [15:0] DI; + input [6:0] DADDR; +endmodule + +module PLLE2_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +module PULLDOWN (...); + output O; +endmodule + +module PULLUP (...); + output O; +endmodule + +module RAM128X1S (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; +endmodule + +module RAM256X1S (...); + parameter [255:0] INIT = 256'h0; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input [7:0] A; + input D; + input WCLK; + input WE; +endmodule + +module RAM32M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output [1:0] DOA; + output [1:0] DOB; + output [1:0] DOC; + output [1:0] DOD; + input [4:0] ADDRA; + input [4:0] ADDRB; + input [4:0] ADDRC; + input [4:0] ADDRD; + input [1:0] DIA; + input [1:0] DIB; + input [1:0] DIC; + input [1:0] DID; + input WCLK; + input WE; +endmodule + +module RAM32X1D (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DPO, SPO; + input A0, A1, A2, A3, A4, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, WCLK, WE; +endmodule + +module RAM32X1S (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, D, WCLK, WE; +endmodule + +module RAM32X1S_1 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, D, WCLK, WE; +endmodule + +module RAM32X2S (...); + parameter [31:0] INIT_00 = 32'h00000000; + parameter [31:0] INIT_01 = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0, O1; + input A0, A1, A2, A3, A4, D0, D1, WCLK, WE; +endmodule + +module RAM64M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DOA; + output DOB; + output DOC; + output DOD; + input [5:0] ADDRA; + input [5:0] ADDRB; + input [5:0] ADDRC; + input [5:0] ADDRD; + input DIA; + input DIB; + input DIC; + input DID; + input WCLK; + input WE; +endmodule + +module RAM64X1S (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, A5, D, WCLK, WE; +endmodule + +module RAM64X1S_1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0, A1, A2, A3, A4, A5, D, WCLK, WE; +endmodule + +module RAM64X2S (...); + parameter [63:0] INIT_00 = 64'h0000000000000000; + parameter [63:0] INIT_01 = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0, O1; + input A0, A1, A2, A3, A4, A5, D0, D1, WCLK, WE; +endmodule + +module ROM128X1 (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + output O; + input A0, A1, A2, A3, A4, A5, A6; +endmodule + +module ROM256X1 (...); + parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; + output O; + input A0, A1, A2, A3, A4, A5, A6, A7; +endmodule + +module ROM32X1 (...); + parameter [31:0] INIT = 32'h00000000; + output O; + input A0, A1, A2, A3, A4; +endmodule + +module ROM64X1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + output O; + input A0, A1, A2, A3, A4, A5; +endmodule + +module SRL16E (...); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output Q; + input A0, A1, A2, A3, CE, CLK, D; +endmodule + +module SRLC32E (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output Q; + output Q31; + input [4:0] A; + input CE, CLK, D; +endmodule + +module STARTUPE2 (...); + parameter PROG_USR = "FALSE"; + parameter real SIM_CCLK_FREQ = 0.0; + output CFGCLK; + output CFGMCLK; + output EOS; + output PREQ; + input CLK; + input GSR; + input GTS; + input KEYCLEARB; + input PACK; + input USRCCLKO; + input USRCCLKTS; + input USRDONEO; + input USRDONETS; +endmodule + +module USR_ACCESSE2 (...); + output CFGCLK; + output DATAVALID; + output [31:0] DATA; +endmodule + +module XADC (...); + output BUSY; + output DRDY; + output EOC; + output EOS; + output JTAGBUSY; + output JTAGLOCKED; + output JTAGMODIFIED; + output OT; + output [15:0] DO; + output [7:0] ALM; + output [4:0] CHANNEL; + output [4:0] MUXADDR; + input CONVST; + input CONVSTCLK; + input DCLK; + input DEN; + input DWE; + input RESET; + input VN; + input VP; + input [15:0] DI; + input [15:0] VAUXN; + input [15:0] VAUXP; + input [6:0] DADDR; + parameter [15:0] INIT_40 = 16'h0; + parameter [15:0] INIT_41 = 16'h0; + parameter [15:0] INIT_42 = 16'h0800; + parameter [15:0] INIT_43 = 16'h0; + parameter [15:0] INIT_44 = 16'h0; + parameter [15:0] INIT_45 = 16'h0; + parameter [15:0] INIT_46 = 16'h0; + parameter [15:0] INIT_47 = 16'h0; + parameter [15:0] INIT_48 = 16'h0; + parameter [15:0] INIT_49 = 16'h0; + parameter [15:0] INIT_4A = 16'h0; + parameter [15:0] INIT_4B = 16'h0; + parameter [15:0] INIT_4C = 16'h0; + parameter [15:0] INIT_4D = 16'h0; + parameter [15:0] INIT_4E = 16'h0; + parameter [15:0] INIT_4F = 16'h0; + parameter [15:0] INIT_50 = 16'h0; + parameter [15:0] INIT_51 = 16'h0; + parameter [15:0] INIT_52 = 16'h0; + parameter [15:0] INIT_53 = 16'h0; + parameter [15:0] INIT_54 = 16'h0; + parameter [15:0] INIT_55 = 16'h0; + parameter [15:0] INIT_56 = 16'h0; + parameter [15:0] INIT_57 = 16'h0; + parameter [15:0] INIT_58 = 16'h0; + parameter [15:0] INIT_59 = 16'h0; + parameter [15:0] INIT_5A = 16'h0; + parameter [15:0] INIT_5B = 16'h0; + parameter [15:0] INIT_5C = 16'h0; + parameter [15:0] INIT_5D = 16'h0; + parameter [15:0] INIT_5E = 16'h0; + parameter [15:0] INIT_5F = 16'h0; + parameter IS_CONVSTCLK_INVERTED = 1'b0; + parameter IS_DCLK_INVERTED = 1'b0; + parameter SIM_DEVICE = "7SERIES"; + parameter SIM_MONITOR_FILE = "design.txt"; +endmodule + diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 21d1fb1e..e7ec1e6e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -69,6 +69,7 @@ struct SynthXilinxPass : public Pass { log("\n"); log(" begin:\n"); log(" read_verilog -lib +/xilinx/cells_sim.v\n"); + log(" read_verilog -lib +/xilinx/cells_xtra.v\n"); log(" read_verilog -lib +/xilinx/brams_bb.v\n"); log(" read_verilog -lib +/xilinx/drams_bb.v\n"); log(" hierarchy -check -top \n"); @@ -159,12 +160,13 @@ struct SynthXilinxPass : public Pass { bool active = run_from.empty(); - log_header("Executing SYNTH_XILINX pass.\n"); + log_header(design, "Executing SYNTH_XILINX pass.\n"); log_push(); if (check_label(active, run_from, run_to, "begin")) { Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); + Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); Pass::call(design, "read_verilog -lib +/xilinx/drams_bb.v"); Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); diff --git a/tests/asicworld/code_hdl_models_arbiter_tb.v b/tests/asicworld/code_hdl_models_arbiter_tb.v index 5e7bf46b..78d1168e 100644 --- a/tests/asicworld/code_hdl_models_arbiter_tb.v +++ b/tests/asicworld/code_hdl_models_arbiter_tb.v @@ -1,11 +1,11 @@ module testbench (); -reg clk; -reg rst; -reg req3; -reg req2; -reg req1; -reg req0; +reg clk = 0; +reg rst = 1; +reg req3 = 0; +reg req2 = 0; +reg req1 = 0; +reg req0 = 0; wire gnt3; wire gnt2; wire gnt1; @@ -13,17 +13,15 @@ wire gnt0; // Clock generator always #1 clk = ~clk; +integer file; + +always @(posedge clk) + $fdisplay(file, "%b", {gnt3, gnt2, gnt1, gnt0}); initial begin - $dumpfile ("arbiter.vcd"); - $dumpvars(); - clk = 0; - rst = 1; - req0 = 0; - req1 = 0; - req2 = 0; - req3 = 0; - #10 rst = 0; + file = $fopen(`outfile); + repeat (5) @ (posedge clk); + rst <= 0; repeat (1) @ (posedge clk); req0 <= 1; repeat (1) @ (posedge clk); diff --git a/tests/asicworld/code_verilog_tutorial_counter_tb.v b/tests/asicworld/code_verilog_tutorial_counter_tb.v index 50481454..33d54050 100644 --- a/tests/asicworld/code_verilog_tutorial_counter_tb.v +++ b/tests/asicworld/code_verilog_tutorial_counter_tb.v @@ -15,9 +15,10 @@ /////////////////////////////////////////////////////////////////////////// module testbench; -reg clk, reset, enable; +integer file; +reg clk = 0, reset = 0, enable = 0; wire [3:0] count; -reg dut_error; +reg dut_error = 0; counter U0 ( .clk (clk), @@ -30,34 +31,21 @@ event reset_enable; event terminate_sim; initial -begin - $display ("###################################################"); - clk = 0; - reset = 0; - enable = 0; - dut_error = 0; -end + file = $fopen(`outfile); always #5 clk = !clk; -initial -begin - $dumpfile ("counter.vcd"); - $dumpvars; -end - - initial @ (terminate_sim) begin - $display ("Terminating simulation"); + $fdisplay (file, "Terminating simulation"); if (dut_error == 0) begin - $display ("Simulation Result : PASSED"); + $fdisplay (file, "Simulation Result : PASSED"); end else begin - $display ("Simulation Result : FAILED"); + $fdisplay (file, "Simulation Result : FAILED"); end - $display ("###################################################"); + $fdisplay (file, "###################################################"); #1 $finish; end @@ -69,11 +57,11 @@ initial forever begin @ (reset_enable); @ (negedge clk) - $display ("Applying reset"); + $fdisplay (file, "Applying reset"); reset = 1; @ (negedge clk) reset = 0; - $display ("Came out of Reset"); + $fdisplay (file, "Came out of Reset"); -> reset_done; end @@ -103,8 +91,8 @@ else if ( enable == 1'b1) always @ (negedge clk) if (count_compare != count) begin - $display ("DUT ERROR AT TIME%d",$time); - $display ("Expected value %d, Got Value %d", count_compare, count); + $fdisplay (file, "DUT ERROR AT TIME%d",$time); + $fdisplay (file, "Expected value %d, Got Value %d", count_compare, count); dut_error = 1; #5 -> terminate_sim; end diff --git a/tests/asicworld/code_verilog_tutorial_first_counter_tb.v b/tests/asicworld/code_verilog_tutorial_first_counter_tb.v index f065732b..806e1773 100644 --- a/tests/asicworld/code_verilog_tutorial_first_counter_tb.v +++ b/tests/asicworld/code_verilog_tutorial_first_counter_tb.v @@ -1,16 +1,13 @@ module testbench(); // Declare inputs as regs and outputs as wires -reg clock, reset, enable; +reg clock = 1, reset = 0, enable = 0; wire [3:0] counter_out; +integer file; // Initialize all variables initial begin - $display ("time\t clk reset enable counter"); - $monitor ("%g\t %b %b %b %b", - $time, clock, reset, enable, counter_out); - clock = 1; // initial value of clock - reset = 0; // initial value of reset - enable = 0; // initial value of enable + file = $fopen(`outfile); + $fdisplay (file, "time\t clk reset enable counter"); #5 reset = 1; // Assert the reset #10 reset = 0; // De-assert the reset #10 enable = 1; // Assert enable @@ -18,6 +15,10 @@ initial begin #5 $finish; // Terminate simulation end +always @(negedge clock) + $fdisplay (file, "%g\t %b %b %b %b", + $time, clock, reset, enable, counter_out); + // Clock generator initial begin #1; diff --git a/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v b/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v index 2e944895..a8e15568 100644 --- a/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v +++ b/tests/asicworld/code_verilog_tutorial_fsm_full_tb.v @@ -1,14 +1,14 @@ module testbench(); -reg clock , reset ; +reg clock = 0 , reset ; reg req_0 , req_1 , req_2 , req_3; wire gnt_0 , gnt_1 , gnt_2 , gnt_3 ; +integer file; initial begin // $dumpfile("testbench.vcd"); // $dumpvars(0, testbench); - $display("Time\t R0 R1 R2 R3 G0 G1 G2 G3"); - $monitor("%g\t %b %b %b %b %b %b %b %b", - $time, req_0, req_1, req_2, req_3, gnt_0, gnt_1, gnt_2, gnt_3); + file = $fopen(`outfile); + $fdisplay(file, "Time\t R0 R1 R2 R3 G0 G1 G2 G3"); clock = 0; reset = 1; req_0 = 0; @@ -28,6 +28,10 @@ initial begin #10 $finish; end +always @(negedge clock) + $fdisplay(file, "%g\t %b %b %b %b %b %b %b %b", + $time, req_0, req_1, req_2, req_3, gnt_0, gnt_1, gnt_2, gnt_3); + initial begin #1; forever diff --git a/tests/simple/constmuldivmod.v b/tests/simple/constmuldivmod.v new file mode 100644 index 00000000..d1d8be86 --- /dev/null +++ b/tests/simple/constmuldivmod.v @@ -0,0 +1,27 @@ +module constmuldivmod(input [7:0] A, input [2:0] mode, output reg [7:0] Y); + always @* begin + case (mode) + 0: Y = A / 8'd0; + 1: Y = A % 8'd0; + 2: Y = A * 8'd0; + + 3: Y = A / 8'd1; + 4: Y = A % 8'd1; + 5: Y = A * 8'd1; + + 6: Y = A / 8'd2; + 7: Y = A % 8'd2; + 8: Y = A * 8'd2; + + 9: Y = A / 8'd4; + 10: Y = A % 8'd4; + 11: Y = A * 8'd4; + + 12: Y = A / 8'd8; + 13: Y = A % 8'd8; + 14: Y = A * 8'd8; + + default: Y = 8'd16 * A; + endcase + end +endmodule diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v index 40f490b7..9839fd4a 100644 --- a/tests/simple/mem2reg.v +++ b/tests/simple/mem2reg.v @@ -19,9 +19,9 @@ endmodule // ------------------------------------------------------ -module mem2reg_test2(clk, mode, addr, data); +module mem2reg_test2(clk, reset, mode, addr, data); -input clk, mode; +input clk, reset, mode; input [2:0] addr; output [3:0] data; @@ -33,6 +33,10 @@ assign data = mem[addr]; integer i; always @(posedge clk) begin + if (reset) begin + for (i=0; i<8; i=i+1) + mem[i] <= i; + end else if (mode) begin for (i=0; i<8; i=i+1) mem[i] <= mem[i]+1; @@ -55,3 +59,36 @@ always @(posedge clk) assign dout_b = dint_c[3]; endmodule +// ------------------------------------------------------ + +module mem2reg_test4(result1, result2, result3); + output signed [9:0] result1; + output signed [9:0] result2; + output signed [9:0] result3; + + wire signed [9:0] intermediate [0:3]; + + function integer depth2Index; + input integer depth; + depth2Index = depth; + endfunction + + assign intermediate[depth2Index(1)] = 1; + assign intermediate[depth2Index(2)] = 2; + assign intermediate[3] = 3; + assign result1 = intermediate[1]; + assign result2 = intermediate[depth2Index(2)]; + assign result3 = intermediate[depth2Index(3)]; +endmodule + +// ------------------------------------------------------ + +module mem2reg_test5(input ctrl, output out); + wire [0:0] foo[0:0]; + wire [0:0] bar[0:1]; + + assign foo[0] = ctrl; + assign bar[0] = 0, bar[1] = 1; + assign out = bar[foo[0]]; +endmodule + diff --git a/tests/simple/memory.v b/tests/simple/memory.v index d58ed9d1..f38bdafd 100644 --- a/tests/simple/memory.v +++ b/tests/simple/memory.v @@ -243,3 +243,67 @@ module memtest10(input clk, input [5:0] din, output [5:0] dout); assign dout = queue[3]; endmodule + +// ---------------------------------------------------------- + +module memtest11(clk, wen, waddr, raddr, wdata, rdata); + input clk, wen; + input [1:0] waddr, raddr; + input [7:0] wdata; + output [7:0] rdata; + + reg [7:0] mem [3:0]; + + assign rdata = mem[raddr]; + + always @(posedge clk) begin + if (wen) + mem[waddr] <= wdata; + else + mem[waddr] <= mem[waddr]; + end +endmodule + +// ---------------------------------------------------------- + +module memtest12 ( + input clk, + input [1:0] adr, + input [1:0] din, + output reg [1:0] q +); + reg [1:0] ram [3:0]; + always@(posedge clk) + {ram[adr], q} <= {din, ram[adr]}; +endmodule + +// ---------------------------------------------------------- + +module memtest13 ( + input clk, rst, + input [1:0] a1, a2, a3, a4, a5, a6, + input [3:0] off1, off2, + input [31:5] din1, + input [3:0] din2, din3, + output reg [3:0] dout1, dout2, + output reg [31:5] dout3 +); + reg [31:5] mem [0:3]; + + always @(posedge clk) begin + if (rst) begin + mem[0] <= 0; + mem[1] <= 0; + mem[2] <= 0; + mem[3] <= 0; + end else begin + mem[a1] <= din1; + mem[a2][14:11] <= din2; + mem[a3][5 + off1 +: 4] <= din3; + dout1 <= mem[a4][12:9]; + dout2 <= mem[a5][5 + off2 +: 4]; + dout3 <= mem[a6]; + end + end +endmodule + diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 76668bed..d0b0a89d 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -10,16 +10,19 @@ makejmode=false frontend="verilog" backend_opts="-noattr -noexpr" autotb_opts="" +include_opts="" +xinclude_opts="" +minclude_opts="" scriptfiles="" scriptopt="" toolsdir="$(cd $(dirname $0); pwd)" warn_iverilog_git=false if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then - ( set -ex; gcc -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 + ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I: opt; do case "$opt" in x) use_xsim=true ;; @@ -50,34 +53,32 @@ while getopts xmGl:wkjvref:s:p:n: opt; do scriptopt="$OPTARG" ;; n) autotb_opts="$autotb_opts -n $OPTARG" ;; + S) + autotb_opts="$autotb_opts -seed $OPTARG" ;; + I) + include_opts="$include_opts -I $OPTARG" + xinclude_opts="$xinclude_opts -i $OPTARG" + minclude_opts="$minclude_opts +incdir+$OPTARG" ;; *) - echo "Usage: $0 [-x|-m] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] verilog-files\n" >&2 exit 1 esac done -create_ref() { - cp "$1" "$2.v" -} - compile_and_run() { exe="$1"; output="$2"; shift 2 if $use_modelsim; then altver=$( ls -v /opt/altera/ | grep '^[0-9]' | tail -n1; ) /opt/altera/$altver/modelsim_ase/bin/vlib work - /opt/altera/$altver/modelsim_ase/bin/vlog "$@" - /opt/altera/$altver/modelsim_ase/bin/vsim -c -do 'run -all; exit;' testbench | grep '#OUT#' > "$output" + /opt/altera/$altver/modelsim_ase/bin/vlog $minclude_opts +define+outfile=\"$output\" "$@" + /opt/altera/$altver/modelsim_ase/bin/vsim -c -do 'run -all; exit;' testbench elif $use_xsim; then - ( - set +x - files=( "$@" ) - xilver=$( ls -v /opt/Xilinx/Vivado/ | grep '^[0-9]' | tail -n1; ) - /opt/Xilinx/Vivado/$xilver/bin/xvlog "${files[@]}" - /opt/Xilinx/Vivado/$xilver/bin/xelab -R work.testbench | grep '#OUT#' > "$output" - ) + xilver=$( ls -v /opt/Xilinx/Vivado/ | grep '^[0-9]' | tail -n1; ) + /opt/Xilinx/Vivado/$xilver/bin/xvlog $xinclude_opts -d outfile=\"$output\" "$@" + /opt/Xilinx/Vivado/$xilver/bin/xelab -R work.testbench else - iverilog -s testbench -o "$exe" "$@" - vvp -n "$exe" > "$output" + iverilog $include_opts -Doutfile=\"$output\" -s testbench -o "$exe" "$@" + vvp -n "$exe" fi } @@ -108,15 +109,15 @@ do fn=$(basename $fn) bn=$(basename $bn) - cp ../$fn $fn + egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.v + if [ ! -f ../${bn}_tb.v ]; then - "$toolsdir"/../../yosys -b "test_autotb $autotb_opts" -o ${bn}_tb.v $fn + "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v else cp ../${bn}_tb.v ${bn}_tb.v fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi - create_ref $fn ${bn}_ref - compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs + compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi test_count=0 @@ -131,22 +132,22 @@ do test_count=$(( test_count + 1 )) } - if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP $fn; then + if [ "$frontend" = "verific" -o "$frontend" = "verific_gates" ] && grep -q VERIFIC-SKIP ${bn}_ref.v; then touch ../${bn}.skip return fi if [ -n "$scriptfiles" ]; then - test_passes $fn $scriptfiles + test_passes -f "$frontend $include_opts" ${bn}_ref.v $scriptfiles elif [ -n "$scriptopt" ]; then - test_passes -f "$frontend" -p "$scriptopt" $fn + test_passes -f "$frontend $include_opts" -p "$scriptopt" ${bn}_ref.v elif [ "$frontend" = "verific" ]; then - test_passes -p "verific -vlog2k $fn; verific -import -all; opt; memory;;" + test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -all; opt; memory;;" elif [ "$frontend" = "verific_gates" ]; then - test_passes -p "verific -vlog2k $fn; verific -import -gates -all; opt; memory;;" + test_passes -p "verific -vlog2k ${bn}_ref.v; verific -import -gates -all; opt; memory;;" else - test_passes -f "$frontend" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" $fn - test_passes -f "$frontend" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" $fn + test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v + test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v fi touch ../${bn}.log } diff --git a/tests/tools/cmp_tbdata.c b/tests/tools/cmp_tbdata.c index b81ae1ca..c0b12cd9 100644 --- a/tests/tools/cmp_tbdata.c +++ b/tests/tools/cmp_tbdata.c @@ -4,8 +4,8 @@ #include int line = 0; -char buffer1[1024]; -char buffer2[1024]; +char buffer1[8192]; +char buffer2[8192]; void check(bool ok) { -- cgit v1.2.3