pax_global_header00006660000000000000000000000064126020714300014505gustar00rootroot0000000000000052 comment=efdb0266d23c8a556bf91e48575f7eff9c6d67aa arachne-pnr-0~20150927gitefdb026/000077500000000000000000000000001260207143000162115ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/.gitignore000066400000000000000000000001051260207143000201750ustar00rootroot00000000000000*.d *~ *.o /bin/arachne-pnr /tests/test_bv /tests/test_us /diff save arachne-pnr-0~20150927gitefdb026/.travis.yml000066400000000000000000000027741260207143000203340ustar00rootroot00000000000000sudo: false script: if [ "$TRAVIS_OS_NAME" = "osx" ]; then make ICEBOX=$HOME/extras/share/icebox simpletest; else make ICEBOX=$HOME/extras/share/icebox test; fi language: cpp addons: apt: sources: - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.6 packages: - gperf - libftdi-dev - build-essential - clang - bison - flex - libreadline-dev - gawk - tcl-dev - libffi-dev - git - mercurial - graphviz - xdot - pkg-config - python - python3 - g++-4.8 - clang-3.6 before_install: - pwd - printenv - echo HOME=$HOME - ls -F $HOME - mkdir -p $HOME/extras/bin - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew list; brew install python3 bison gawk gnu-sed libftdi0 libffi graphviz; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi; if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.6" CC="clang-3.6"; fi; fi - echo CC=$CC CXX=$CXX - git clone git://github.com/steveicarus/iverilog.git - (cd iverilog && autoconf && ./configure --prefix=$HOME/extras && make && make install) - export PATH=$PATH:$HOME/extras/bin - git clone https://github.com/cliffordwolf/icestorm.git - (cd icestorm && make && make DESTDIR=$HOME/extras install) - git clone https://github.com/cliffordwolf/yosys.git - (cd yosys && make && make test && make DESTDIR=$HOME/extras install) compiler: - clang - gcc os: - linux - osx branches: except: - dummy arachne-pnr-0~20150927gitefdb026/COPYING000066400000000000000000000432541260207143000172540ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. arachne-pnr-0~20150927gitefdb026/Makefile000066400000000000000000000050641260207143000176560ustar00rootroot00000000000000 # build with default C/C++ compiler # CC = clang # CXX = clang++ # build optimized without -DNDEBUG # OPTDEBUGFLAGS = -O0 -fno-inline -g OPTDEBUGFLAGS = -O2 # -DNDEBUG SRC = src # clang only: -Wglobal-constructors CXXFLAGS = -I$(SRC) -std=c++11 -MD $(OPTDEBUGFLAGS) -Wall -Wshadow -Wsign-compare -Werror LIBS = -lm DESTDIR = /usr/local ICEBOX = /usr/local/share/icebox .PHONY: all all: bin/arachne-pnr share/arachne-pnr/chipdb-1k.bin share/arachne-pnr/chipdb-8k.bin bin/arachne-pnr: src/arachne-pnr.o src/netlist.o src/blif.o src/pack.o src/place.o src/util.o src/io.o src/route.o src/chipdb.o src/location.o src/configuration.o src/line_parser.o src/pcf.o src/global.o src/constant.o src/designstate.o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) share/arachne-pnr/chipdb-1k.bin: bin/arachne-pnr $(ICEBOX)/chipdb-1k.txt mkdir -p share/arachne-pnr bin/arachne-pnr -d 1k -c $(ICEBOX)/chipdb-1k.txt --write-binary-chipdb share/arachne-pnr/chipdb-1k.bin share/arachne-pnr/chipdb-8k.bin: bin/arachne-pnr $(ICEBOX)/chipdb-8k.txt mkdir -p share/arachne-pnr bin/arachne-pnr -d 8k -c $(ICEBOX)/chipdb-8k.txt --write-binary-chipdb share/arachne-pnr/chipdb-8k.bin tests/test_bv: tests/test_bv.o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ tests/test_us: tests/test_us.o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ # assumes icestorm installed simpletest: all tests/test_bv tests/test_us ./tests/test_bv ./tests/test_us cd tests/simple && ICEBOX=$(ICEBOX) bash run-test.sh cd tests/regression && bash run-test.sh @echo @echo 'All tests passed.' @echo # assumes icestorm, yosys installed test: all tests/test_bv ./tests/test_us ./tests/test_bv ./tests/test_us make -C examples/rot clean && make -C examples/rot cd tests/simple && ICEBOX=$(ICEBOX) bash run-test.sh cd tests/regression && bash run-test.sh cd tests/fsm && bash run-test.sh cd tests/combinatorial && bash run-test.sh @echo @echo 'All tests passed.' @echo # assumes valgrind installed testvg: cd tests/simple && bash run-valgrind-test.sh @echo @echo 'All tests passed.' @echo -include src/*.d .PHONY: install install: all mkdir -p $(DESTDIR)/bin cp bin/arachne-pnr $(DESTDIR)/bin/arachne-pnr mkdir -p $(DESTDIR)/share/arachne-pnr cp share/arachne-pnr/chipdb-1k.bin $(DESTDIR)/share/arachne-pnr/chipdb-1k.bin cp share/arachne-pnr/chipdb-8k.bin $(DESTDIR)/share/arachne-pnr/chipdb-8k.bin .PHONY: uninstall uninstall: rm -f $(DESTDIR)/bin/arachne-pnr rm -f $(DESTDIR)/bin/share/arachne-pnr/*.bin .PHONY: clean clean: rm -f src/*.o tests/*.o src/*.d tests/*.d bin/arachne-pnr tests/test_bv rm -f share/arachne-pnr/*.bin arachne-pnr-0~20150927gitefdb026/README.md000066400000000000000000000074331260207143000174770ustar00rootroot00000000000000# Arachne-pnr ## Updates 2015-08-06: Interface change: Default seed is 1, can be randomized with `-r` option. 2015-07-18: New version. Release notes: * IceStorm and arachne-pnr now support the iCE40LP/HX8K * huge speed improvements (~50x) * arachne-pnr now prints the random seed on each run. The seed can be set with the `-s` option. With the same seed, arachne-pnr should be deterministic across platforms and C++ compilers. ## What is arachne-pnr? Arachne-pnr implements the place and route step of the hardware compilation process for FPGAs. It accepts as input a technology-mapped netlist in BLIF format, as output by the [Yosys](http://www.clifford.at/yosys/) [0] synthesis suite for example. It currently targets the Lattice Semiconductor [iCE40](http://www.latticesemi.com/iCE40) family of FPGAs [1]. Its output is a textual bitstream representation for assembly by the [IceStorm](http://www.clifford.at/icestorm/) [2] `icepack` command. The output of `icepack` is a binary bitstream which can be uploaded to a harware device. Together, Yosys, arachne-pnr and IceStorm provide an fully open-source Verilog-to-bistream tool chain for iCE40 1K and 8K FPGA development. ## Warning! This is experimental software! It might have bugs that cause it to produce bitstreams which could damage your FPGA! So when you buy an evaluation board, get a few. We have done extensive verification-based testing (see `tests/`), but so far limited hardware-based testing. This will change. ## Status Arachne-pnr uses a simulated annealing-based algorithm for placement and a multi-pass congestion-based router. Arachne-pnr supports all features documented by IceStorm, although the Block RAM has not been extensively tested. This should include everything on the chip except PLLs and timing information. Support for PLLs is in the works. We hope to support timing information as soon as it is documented by the IceStorm project. ## Installing Arachne-pnr is written in C++11. It has been tested under OSX and Linux with LLVM/Clang and GCC. It should work on Windows, perhaps with a little work. (Patches welcome.) It depends on IceStorm. You should also install Yosys to synthesize designs. To install, just go to the arachne-pnr directory and run ``` $ make && sudo make install ``` ## Invoking/Example Lattice has several low-cost breakout boards: [iCEstick](http://latticesemi.com/iCEstick) for the 1K [3] and [iCE40-HX8K Breakout Board](http://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx) [4] for the 8K. There is a simple example for the iCEstick evaluation board in `example/rot` which generates a rotating pattern on the user LEDs. The Verilog input is in `rot.v` and the physical (pin) constraints are in `rot.pcf`. To build it, just run `make`, which executes the following commands: ``` yosys -q -p "synth_ice40 -blif rot.blif" rot.v ../../bin/arachne-pnr -p rot.pcf rot.blif -o rot.txt icepack rot.txt rot.bin ``` You can use the Lattice tools or `iceprog` from IceStorm to upload `rot.bin` onto the board. ## Feedback Feedback, feature requests, bug reports and patches welcome. Please email the author, Cotton Seed , or submit a issue on Github. ## Acknowledgements Arachne-pnr would not have been possible without Clifford Wolf and Mathias Lasser's IceStorm project to reverse-engineer the iCE40 FPGAs and build supporting tools. Also, it would not be useful without Clifford Wolf's Yosys project to synthesize and technology map designs. Thanks to contributors Larry Doolittle and Clifford Wolf. ## References [0] http://www.clifford.at/yosys/ [1] http://www.latticesemi.com/iCE40 [2] http://www.clifford.at/icestorm/ [3] http://latticesemi.com/iCEstick [4] http://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/iCE40HX8KBreakoutBoard.aspx arachne-pnr-0~20150927gitefdb026/bin/000077500000000000000000000000001260207143000167615ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/bin/.keep000066400000000000000000000000001260207143000176740ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/examples/000077500000000000000000000000001260207143000200275ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/examples/rot/000077500000000000000000000000001260207143000206335ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/examples/rot/.gitignore000066400000000000000000000000301260207143000226140ustar00rootroot00000000000000*.blif *.txt *.ex *.bin arachne-pnr-0~20150927gitefdb026/examples/rot/Makefile000066400000000000000000000003471260207143000222770ustar00rootroot00000000000000 rot.bin: rot.v rot.pcf yosys -q -p "synth_ice40 -blif rot.blif" rot.v ../../bin/arachne-pnr -p rot.pcf rot.blif -o rot.txt icebox_explain rot.txt > rot.ex icepack rot.txt rot.bin clean: rm -f rot.blif rot.txt rot.ex rot.bin arachne-pnr-0~20150927gitefdb026/examples/rot/rot.pcf000066400000000000000000000001171260207143000221300ustar00rootroot00000000000000set_io D1 99 set_io D2 98 set_io D3 97 set_io D4 96 set_io D5 95 set_io clk 21 arachne-pnr-0~20150927gitefdb026/examples/rot/rot.v000066400000000000000000000010661260207143000216310ustar00rootroot00000000000000 module top(input clk, output D1, output D2, output D3, output D4, output D5); reg ready = 0; reg [23:0] divider; reg [3:0] rot; always @(posedge clk) begin if (ready) begin if (divider == 12000000) begin divider <= 0; rot <= {rot[2:0], rot[3]}; end else divider <= divider + 1; end else begin ready <= 1; rot <= 4'b0001; divider <= 0; end end assign D1 = rot[0]; assign D2 = rot[1]; assign D3 = rot[2]; assign D4 = rot[3]; assign D5 = 1; endmodule // top arachne-pnr-0~20150927gitefdb026/scripts/000077500000000000000000000000001260207143000177005ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/scripts/build-test-linux.sh000066400000000000000000000010401260207143000234400ustar00rootroot00000000000000#!/bin/bash set -ex make clean make CC=clang CXX=clang++ OPTDEBUGFLAGS='-O0 -fno-inline -g' simpletest make clean make CC=gcc CXX=g++ OPTDEBUGFLAGS='-O0 -fno-inline -g' simpletest make clean make CC=clang CXX=clang++ OPTDEBUGFLAGS='-O2' simpletest make clean make CC=gcc CXX=g++ OPTDEBUGFLAGS='-O2' simpletest make clean make CC=clang CXX=clang++ OPTDEBUGFLAGS='-O2 -DNDEBUG' simpletest make clean make CC=gcc CXX=g++ OPTDEBUGFLAGS='-O2 -DNDEBUG' simpletest # full test with default options make clean make test make testvg make clean arachne-pnr-0~20150927gitefdb026/scripts/build-test-osx.sh000066400000000000000000000004001260207143000231110ustar00rootroot00000000000000#!/bin/bash set -ex make clean make OPTDEBUGFLAGS='-O0 -fno-inline -g' simpletest make clean make OPTDEBUGFLAGS='-O2' simpletest make clean make OPTDEBUGFLAGS='-O2 -DNDEBUG' simpletest # full test with default options make clean make test make clean arachne-pnr-0~20150927gitefdb026/src/000077500000000000000000000000001260207143000170005ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/src/arachne-pnr.cc000066400000000000000000000331101260207143000215030ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "netlist.hh" #include "chipdb.hh" #include "blif.hh" #include "pack.hh" #include "io.hh" #include "place.hh" #include "route.hh" #include "configuration.hh" #include "pcf.hh" #include "casting.hh" #include "global.hh" #include "carry.hh" #include "constant.hh" #include "designstate.hh" #include #include #include #include const char *program_name; class null_streambuf : public std::streambuf { public: int overflow(int c) override { return c; } }; void usage() { std::cout << "Usage:\n" << "\n" << " " << program_name << " [options] [input-file]\n" << "\n" << "Place and route netlist. Input file is in BLIF format. Output is\n" << "(text) bitstream.\n" << "\n" << " -h, --help\n" << " Print this usage message.\n" << "\n" << " -q, --quiet\n" << " Run quite. Don't output progress messages.\n" << "\n" << " -d , --device \n" << " Target device . Supported devices:\n" << " 1k - Lattice Semiconductor iCE40LP/HX1K\n" << " 8k - Lattice Semiconductor iCE40LP/HX8K\n" << " Default: 1k\n" << "\n" << " -c , --chipdb \n" << " Read chip database from .\n" << " Default: +/share/arachne-pnr/chipdb-.bin\n" << "\n" << " --write-binary-chipdb \n" << " Write binary chipdb to .\n" << "\n" << " -l, --no-promote-globals\n" << " Don't promote nets to globals.\n" << "\n" << " -B , --post-pack-blif \n" << " Write post-pack netlist to as BLIF.\n" << " -V , --post-pack-verilog \n" << " Write post-pack netlist to as Verilog.\n" << "\n" << " --post-place-blif \n" << " Write post-place netlist to as BLIF.\n" << "\n" << " --route-only\n" << " Input must include placement.\n" << "\n" << " -p , --pcf-file \n" << " Read physical constraints from .\n" << "\n" << " -P , --package \n" << " Target package .\n" << " Default: tq144 for 1k, ct256 for 8k\n" << "\n" << " -r\n" << " Randomize seed.\n" << "\n" << " -s , --seed \n" << " Set seed for random generator to .\n" << " Default: 1\n" << "\n" << " -w , --write-pcf \n" << " Write pin assignments to after placement.\n" << "\n" << " -o , --output-file \n" << " Write output to .\n"; } struct null_ostream : public std::ostream { null_ostream() : std::ostream(0) {} }; int main(int argc, const char **argv) { program_name = argv[0]; bool help = false, quiet = false, do_promote_globals = true, route_only = false, randomize_seed = false; std::string device = "1k"; const char *chipdb_file = nullptr, *input_file = nullptr, *package_name_cp = nullptr, *pcf_file = nullptr, *post_place_pcf = nullptr, *pack_blif = nullptr, *pack_verilog = nullptr, *place_blif = nullptr, *output_file = nullptr, *seed_str = nullptr, *binary_chipdb = nullptr; for (int i = 1; i < argc; ++i) { if (argv[i][0] == '-') { if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) help = true; else if (!strcmp(argv[i], "-q") || !strcmp(argv[i], "--quiet")) quiet = true; else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--device")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; device = argv[i]; } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--chipdb")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; chipdb_file = argv[i]; } else if (!strcmp(argv[i], "--write-binary-chipdb")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; binary_chipdb = argv[i]; } else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--no-promote-globals")) do_promote_globals = false; else if (!strcmp(argv[i], "-B") || !strcmp(argv[i], "--post-pack-blif")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; pack_blif = argv[i]; } else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--post-pack-verilog")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; pack_verilog = argv[i]; } else if (!strcmp(argv[i], "--post-place-blif")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; place_blif = argv[i]; } else if (!strcmp(argv[i], "--route-only")) route_only = true; else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--pcf-file")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; pcf_file = argv[i]; } else if (!strcmp(argv[i], "-P") || !strcmp(argv[i], "--package")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; package_name_cp = argv[i]; } else if (!strcmp(argv[i], "-r")) randomize_seed = true; else if (!strcmp(argv[i], "-w") || !strcmp(argv[i], "--write-pcf")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; post_place_pcf = argv[i]; } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--seed")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; seed_str = argv[i]; } else if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--output-file")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; output_file = argv[i]; } else fatal(fmt("unknown option `" << argv[i] << "'")); } else { if (input_file) fatal("too many command-line arguments"); else input_file = argv[i]; } } if (help) { usage(); exit(EXIT_SUCCESS); } if (device != "1k" && device != "8k") fatal(fmt("unknown device: " << device)); std::string package_name; if (package_name_cp) package_name = package_name_cp; else if (device == "1k") package_name = "tq144"; else { assert(device == "8k"); package_name = "ct256"; } std::ostream *null_ostream = nullptr; if (quiet) logs = null_ostream = new std::ostream(new null_streambuf); else logs = &std::cerr; unsigned seed = 0; if (seed_str) { std::string seed_s = seed_str; if (seed_s.empty()) fatal("invalid empty seed"); for (char ch : seed_s) { if (ch >= '0' && ch <= '9') seed = seed * 10 + (unsigned)(ch - '0'); else fatal(fmt("invalid character `" << ch << "' in unsigned integer literal in seed")); } } else seed = 1; if (randomize_seed) { std::random_device rd; do { seed = rd(); } while (seed == 0); } *logs << "seed: " << seed << "\n"; if (!seed) fatal("zero seed"); random_generator rg(seed); *logs << "device: " << device << "\n"; std::string chipdb_file_s; if (chipdb_file) chipdb_file_s = chipdb_file; else chipdb_file_s = (std::string("+/share/arachne-pnr/chipdb-") + device + ".bin"); *logs << "read_chipdb " << chipdb_file_s << "...\n"; const ChipDB *chipdb = read_chipdb(chipdb_file_s); if (binary_chipdb) { *logs << "write_binary_chipdb " << binary_chipdb << "\n"; std::string expanded = expand_filename(binary_chipdb); std::ofstream ofs(expanded); if (ofs.fail()) fatal(fmt("write_binary_chidpb: failed to open `" << expanded << "': " << strerror(errno))); obstream obs(ofs); chipdb->bwrite(obs); // clean up if (chipdb) delete chipdb; logs = nullptr; if (null_ostream) { delete null_ostream; null_ostream = nullptr; } return 0; } *logs << " supported packages: "; bool first = true; for (const auto &p : chipdb->packages) { if (first) first = false; else *logs << ", "; *logs << p.first; } *logs << "\n"; // chipdb->dump(std::cout); auto package_i = chipdb->packages.find(package_name); if (package_i == chipdb->packages.end()) fatal(fmt("unknown package `" << package_name << "'")); const Package &package = package_i->second; Design *d; if (input_file) { *logs << "read_blif " << input_file << "...\n"; d = read_blif(input_file); } else { *logs << "read_blif ...\n"; d = read_blif("", std::cin); } // d->dump(); *logs << "prune...\n"; d->prune(); #ifndef NDEBUG d->check(); #endif // d->dump(); { DesignState ds(chipdb, package, d); if (route_only) { for (Instance *inst : ds.top->instances()) { const std::string &loc_attr = inst->get_attr("loc").as_string(); int cell; if (sscanf(loc_attr.c_str(), "%d", &cell) != 1) fatal("parse error in loc attribute"); extend(ds.placement, inst, cell); } } else { if (pcf_file) { *logs << "read_pcf " << pcf_file << "...\n"; read_pcf(pcf_file, ds); } *logs << "instantiate_io...\n"; instantiate_io(d); #ifndef NDEBUG d->check(); #endif // d->dump(); *logs << "pack...\n"; pack(ds); #ifndef NDEBUG d->check(); #endif // d->dump(); if (pack_blif) { *logs << "write_blif " << pack_blif << "\n"; std::string expanded = expand_filename(pack_blif); std::ofstream fs(expanded); if (fs.fail()) fatal(fmt("write_blif: failed to open `" << expanded << "': " << strerror(errno))); d->write_blif(fs); } if (pack_verilog) { *logs << "write_verilog " << pack_verilog << "\n"; std::string expanded = expand_filename(pack_verilog); std::ofstream fs(expanded); if (fs.fail()) fatal(fmt("write_verilog: failed to open `" << expanded << "': " << strerror(errno))); d->write_verilog(fs); } *logs << "place_constraints...\n"; place_constraints(ds); #ifndef NDEBUG d->check(); #endif *logs << "promote_globals...\n"; promote_globals(ds, do_promote_globals); #ifndef NDEBUG d->check(); #endif // d->dump(); *logs << "realize_constants...\n"; realize_constants(chipdb, d); #ifndef NDEBUG d->check(); #endif *logs << "place...\n"; // d->dump(); place(rg, ds); #ifndef NDEBUG d->check(); #endif // d->dump(); if (post_place_pcf) { *logs << "write_pcf " << post_place_pcf << "...\n"; std::string expanded = expand_filename(post_place_pcf); std::ofstream fs(expanded); if (fs.fail()) fatal(fmt("write_pcf: failed to open `" << expanded << "': " << strerror(errno))); for (const auto &p : ds.placement) { if (ds.models.is_io(p.first)) { const Location &loc = chipdb->cell_location[p.second]; std::string pin = package.loc_pin.at(loc); Port *top_port = (p.first ->find_port("PACKAGE_PIN") ->connection_other_port()); assert(isa(top_port->node()) && cast(top_port->node()) == ds.top); fs << "set_io " << top_port->name() << " " << pin << "\n"; } } } if (place_blif) { for (const auto &p : ds.placement) { // p.first->set_attr("loc", fmt(p.second)); const Location &loc = chipdb->cell_location[p.second]; int t = loc.tile(); int pos = loc.pos(); p.first->set_attr("loc", fmt(chipdb->tile_x(t) << "," << chipdb->tile_y(t) << "/" << pos)); } *logs << "write_blif " << place_blif << "\n"; std::string expanded = expand_filename(place_blif); std::ofstream fs(expanded); if (fs.fail()) fatal(fmt("write_blif: failed to open `" << expanded << "': " << strerror(errno))); d->write_blif(fs); } } *logs << "route...\n"; route(ds); #ifndef NDEBUG d->check(); #endif if (output_file) { *logs << "write_txt " << output_file << "...\n"; std::string expanded = expand_filename(output_file); std::ofstream fs(expanded); if (fs.fail()) fatal(fmt("write_txt: failed to open `" << expanded << "': " << strerror(errno))); ds.conf.write_txt(fs, chipdb, d, ds.placement, ds.cnet_net); } else { *logs << "write_txt ...\n"; ds.conf.write_txt(std::cout, chipdb, d, ds.placement, ds.cnet_net); } } if (d) delete d; if (chipdb) delete chipdb; logs = nullptr; if (null_ostream) { delete null_ostream; null_ostream = nullptr; } return 0; } arachne-pnr-0~20150927gitefdb026/src/bitvector.hh000066400000000000000000000042341260207143000213250ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_BITVECTOR_HH #define PNR_BITVECTOR_HH #include #include #include #include template class BasedBitVector { int n; std::vector v; public: class BitRef { std::vector &v; size_t i; public: BitRef (std::vector &v_, size_t i_) : v(v_), i(i_) {} BitRef &operator=(bool x) { size_t w = (i - B) / 64, b = (i - B) & 63; uint64_t m = ((uint64_t)1 << b); assert(w < v.size()); if (x) v[w] |= m; else v[w] &= ~m; return *this; } operator bool() const { size_t w = (i - B) / 64, b = (i - B) & 63; uint64_t m = ((uint64_t)1 << b); assert(w < v.size()); return v[w] & m; } }; BasedBitVector() {} BasedBitVector(size_t n_) : n(n_), v((n + 63) / 64, 0) { } BasedBitVector(size_t n_, uint64_t init) : n(n_), v((n + 63) / 64, 0) { v[0] = init; } void resize(size_t n_) { n = n_; v.resize((n + 63) / 64, 0); } void zero() { std::fill(v.begin(), v.end(), 0); } size_t size() const { return n; } bool operator[](size_t i) const { assert(i >= B && i < n + B); size_t w = (i - B) / 64, b = (i - B) & 63; uint64_t m = ((uint64_t)1 << b); return v[w] & m; } BitRef operator[](size_t i) { assert(i >= B && i < n + B); return BitRef(v, i); } }; using BitVector = BasedBitVector<0>; using BitVector1 = BasedBitVector<1>; #endif arachne-pnr-0~20150927gitefdb026/src/blif.cc000066400000000000000000000202711260207143000202250ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "netlist.hh" #include "line_parser.hh" #include "bitvector.hh" #include "casting.hh" #include #include #include #include #include #include class BlifParser : public LineParser { BitVector stobv(const std::string &s_); public: BlifParser(const std::string &f, std::istream &s_) : LineParser(f, s_) {} Design *parse(); }; BitVector BlifParser::stobv(const std::string &s_) { int n = s_.size(); BitVector bv(n); for (int i = 0; i < n; ++i) { char c = s_[(n - 1) - i]; if (c == '1') bv[i] = true; else if (c == '0' || c == 'x' || c == 'X') ; else fatal("invalid character in integer constant"); } return bv; } Design * BlifParser::parse() { Design *d = new Design; d->create_standard_models(); Model *io_model = d->find_model("SB_IO"); Model *top = nullptr; std::vector> unify; Instance *inst = nullptr; for (;;) { if (eof()) goto M; read_line(); if (line.empty()) continue; if (line[0] == '.') { L: std::string cmd = words[0]; if (cmd == ".model") { if (words.size() != 2) fatal("invalid .model directive"); assert(top == nullptr); top = new Model(d, words[1]); d->set_top(top); } else if (cmd == ".inputs") { for (unsigned i = 1; i < words.size(); i ++) { Port *port = top->find_port(words[i]); if (port) { if (port->direction() == Direction::OUT) port->set_direction(Direction::INOUT); } else port = top->add_port(words[i], Direction::IN); Net *net = top->find_or_add_net(words[i]); port->connect(net); } } else if (cmd == ".outputs") { for (unsigned i = 1; i < words.size(); i ++) { Port *port = top->find_port(words[i]); if (port) { if (port->direction() == Direction::IN) port->set_direction(Direction::INOUT); } else port = top->add_port(words[i], Direction::OUT); Net *net = top->find_or_add_net(words[i]); port->connect(net); } } else if (cmd == ".names") { LexicalPosition names_lp = lp; Net *names_net = nullptr; unsigned n = words.size(); if (n == 2) { names_net = top->find_or_add_net(words[1]); names_net->set_is_constant(true); names_net->set_constant(Value::ZERO); } else if (n == 3) { unify.push_back(std::make_pair(top->find_or_add_net(words[1]), top->find_or_add_net(words[2]))); } else fatal("invalid .names directive"); bool saw11 = false; for (;;) { if (eof()) { if (n == 3 && !saw11) names_lp.fatal("invalid .names directive"); goto M; } read_line(); if (line.empty()) continue; if (line[0] == '.') { if (n == 3 && !saw11) names_lp.fatal("invalid .names directive"); goto L; } if (words.size() != n - 1) fatal("invalid .names entry"); if (n == 2) { const std::string &output = words[0]; if (output == "1") names_net->set_constant(Value::ONE); else if (output != "0") fatal("invalid .names entry"); } else { assert(n == 3); if (words[0] != "1" || words[1] != "1") fatal("invalid .names entry"); saw11 = true; } } } else if (cmd == ".gate") { if (words.size() < 2) fatal("invalid .gate directive, missing name"); const std::string &n = words[1]; Model *inst_of = d->find_model(n); if (!inst_of) fatal(fmt("unknown model `" << n << "'")); inst = top->add_instance(inst_of); for (unsigned i = 2; i < words.size(); i ++) { const std::string &w = words[i]; std::size_t p = w.find('='); if (p == std::string::npos) fatal("invalid formal-actual"); std::string formal(w, 0, p), actual(w, p+1); if (actual.empty()) continue; Port *port = inst->find_port(formal); if (!port) fatal(fmt("unknown formal `" << formal << "'")); Net *net = top->find_or_add_net(actual); port->connect(net); } } else if (cmd == ".attr") { if (words.size() != 3) fatal("invalid .attr directive"); if (!inst) fatal("no gate for .attr directive"); if (words[2][0] == '"') { assert(words[2].back() == '"'); inst->set_attr(words[1], Const(lp, words[2].substr(1, words[2].size() - 2))); } else { inst->set_attr(words[1], Const(lp, stobv(words[2]))); } } else if (cmd == ".param") { if (words.size() != 3) fatal("invalid .param directive"); if (!inst) fatal("no gate for .param directive"); if (words[2][0] == '"') { assert(words[2].back() == '"'); inst->set_param(words[1], Const(lp, words[2].substr(1, words[2].size() - 2))); } else { inst->set_param(words[1], Const(lp, stobv(words[2]))); } } else if (cmd == ".end") goto M; else fatal("unknown directive"); } else fatal("expected directive"); } M: // unify std::map replacement; for (const auto &p : unify) { // n1 drives n2 Net *n1 = p.first, *n2 = p.second; Net *r = n1; while (Net *t = lookup_or_default(replacement, r, nullptr)) r = t; Net *x = n1; while (x != r) { auto i = replacement.find(x); assert(i != replacement.end()); x = i->second; i->second = r; } if (n2 == r) fatal(".names cycle\n"); n2->replace(r); extend(replacement, n2, r); } for (const auto &p : replacement) { Net *n = p.first; top->remove_net(n); delete n; } for (const auto &p : top->ports()) { if (p.second->is_bidir()) { Net *n = p.second->connection(); if (n) { Port *q = p.second->connection_other_port(); if (!q || !isa(q->node()) || cast(q->node())->instance_of() != io_model || q->name() != "PACKAGE_PIN") fatal(fmt("toplevel inout port '" << p.second->name () << "' not connected to SB_IO PACKAGE_PIN")); } } } std::set boundary_nets; for (Instance *inst2 : top->instances()) { if (inst2->instance_of() == io_model) { Port *p = inst2->find_port("PACKAGE_PIN"); Net *n = p->connection(); Port *q = p->connection_other_port(); if (!n || !q || !isa(q->node())) fatal("SB_IO PACKAGE_PIN not connected to toplevel port"); extend(boundary_nets, n); } } for (const auto &p : top->nets()) { Net *n = p.second; if (contains(boundary_nets, n)) continue; int n_drivers = 0; if (n->is_constant()) ++n_drivers; for (Port *p2 : n->connections()) { if (p2->is_output()) ++n_drivers; } if (n_drivers > 1) fatal(fmt("net `" << n->name() << "' has multiple drivers")); } return d; } Design * read_blif(const std::string &filename) { std::string expanded = expand_filename(filename); std::ifstream fs(expanded); if (fs.fail()) fatal(fmt("read_blif: failed to open `" << expanded << "': " << strerror(errno))); BlifParser parser(filename, fs); return parser.parse(); } Design * read_blif(const std::string &filename, std::istream &s) { BlifParser parser(filename, s); return parser.parse(); } arachne-pnr-0~20150927gitefdb026/src/blif.hh000066400000000000000000000015541260207143000202420ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_BLIF_HH #define PNR_BLIF_HH #include #include class Design; Design *read_blif(const std::string &filename); Design *read_blif(const std::string &filename, std::istream &s); #endif arachne-pnr-0~20150927gitefdb026/src/bstream.hh000066400000000000000000000154251260207143000207650ustar00rootroot00000000000000#ifndef PNR_BSTREAM_HH #define PNR_BSTREAM_HH #include "util.hh" #include #include #include #include #include #include #include #include class obstream { private: std::ostream &os; public: obstream(std::ostream &os_) : os(os_) {} void write(const char *p, size_t n) { os.write(p, n); if (os.bad()) fatal(fmt("std::ostream::write: " << strerror(errno))); } }; inline obstream &operator<<(obstream &obs, bool x) { // *logs << "bwrite bool " << x << "\n"; obs.write(reinterpret_cast(&x), sizeof(x)); return obs; } inline obstream &operator<<(obstream &obs, char x) { // *logs << "bwrite char " << x << "\n"; obs.write(reinterpret_cast(&x), sizeof(x)); return obs; } inline obstream &operator<<(obstream &obs, unsigned char x) { // *logs << "bwrite unsigned char " << x << "\n"; obs.write(reinterpret_cast(&x), sizeof(x)); return obs; } template obstream & bwrite_signed_integral_type(obstream &obs, T x) { char buf[sizeof(T) + 1]; size_t n = 0; bool more = true; while (more) { char b = (char)(x & 0x7f); x >>= 7; if ((x == 0 && !(b & 0x40)) || (x == -1 && (b & 0x40) == 0x40)) more = false; else b |= 0x80; assert(n < sizeof(T) + 1); buf[n] = b; n ++; } obs.write(buf, n); return obs; } template obstream & bwrite_unsigned_integral_type(obstream &obs, T x) { char buf[sizeof(T) + 1]; size_t n = 0; bool more = true; while (more) { char b = (char)(x & 0x7f); x >>= 7; if ((x == 0 && ! (b & 0x40))) more = false; else b |= 0x80; assert(n < sizeof(T) + 1); buf[n] = b; n ++; } obs.write(buf, n); return obs; } inline obstream &operator<<(obstream &obs, short x) { return bwrite_signed_integral_type(obs, x); } inline obstream &operator<<(obstream &obs, unsigned short x) { return bwrite_unsigned_integral_type(obs, x); } inline obstream &operator<<(obstream &obs, int x) { return bwrite_signed_integral_type(obs, x); } inline obstream &operator<<(obstream &obs, unsigned x) { return bwrite_unsigned_integral_type(obs, x); } inline obstream &operator<<(obstream &obs, long x) { return bwrite_signed_integral_type(obs, x); } inline obstream &operator<<(obstream &obs, unsigned long x) { return bwrite_unsigned_integral_type(obs, x); } inline obstream &operator<<(obstream &obs, const std::string &s) { obs << s.size(); obs.write(&s[0], s.size()); return obs; } template obstream & operator<<(obstream &obs, const std::vector &v) { obs << v.size(); for (const auto &x : v) obs << x; return obs; } template obstream & operator<<(obstream &obs, const std::set &s) { obs << s.size(); for (const auto &x : s) obs << x; return obs; } template obstream & operator<<(obstream &obs, const std::map &m) { obs << m.size(); for (const auto &x : m) obs << x; return obs; } template inline obstream & operator<<(obstream &obs, const std::pair &p) { return obs << p.first << p.second; } template inline obstream & operator<<(obstream &obs, const std::tuple &t) { return obs << std::get<0>(t) << std::get<1>(t) << std::get<2>(t); } class ibstream { private: std::istream &is; public: ibstream(std::istream &is_) : is(is_) {} void read(char *p, size_t n) { is.read(p, n); size_t rn = is.gcount(); if (is.bad() || rn != n) fatal(fmt("std::istream::read: " << strerror(errno))); } }; inline ibstream &operator>>(ibstream &ibs, bool &x) { ibs.read(reinterpret_cast(&x), sizeof(x)); // *logs << "bread bool " << x << "\n"; return ibs; } inline ibstream &operator>>(ibstream &ibs, char &x) { ibs.read(reinterpret_cast(&x), sizeof(x)); // *logs << "bread char " << x << "\n"; return ibs; } inline ibstream &operator>>(ibstream &ibs, unsigned char &x) { ibs.read(reinterpret_cast(&x), sizeof(x)); // *logs << "bread unsigned char " << x << "\n"; return ibs; } template ibstream & bread_signed_integral_type(ibstream &ibs, T &x) { x = 0; constexpr int T_bits = CHAR_BIT*sizeof(T); int shift = 0; for (;;) { char b; ibs >> b; x |= (int)(b & 0x7f) << shift; shift += 7; if (! (b & 0x80)) { if (shift < T_bits && (b & 0x40)) x = (x << (T_bits - shift)) >> (T_bits - shift); break; } } return ibs; } template ibstream & bread_unsigned_integral_type(ibstream &ibs, T &x) { x = 0; unsigned shift = 0; for (;;) { char b; ibs >> b; x |= ((unsigned)(b & 0x7f) << shift); shift += 7; if (! (b & 0x80)) break; } return ibs; } inline ibstream &operator>>(ibstream &ibs, short &x) { return bread_signed_integral_type(ibs, x); } inline ibstream &operator>>(ibstream &ibs, unsigned short &x) { return bread_unsigned_integral_type(ibs, x); } inline ibstream &operator>>(ibstream &ibs, int &x) { return bread_signed_integral_type(ibs, x); } inline ibstream &operator>>(ibstream &ibs, unsigned &x) { return bread_unsigned_integral_type(ibs, x); } inline ibstream &operator>>(ibstream &ibs, long &x) { return bread_signed_integral_type(ibs, x); } inline ibstream &operator>>(ibstream &ibs, unsigned long &x) { return bread_unsigned_integral_type(ibs, x); } inline ibstream &operator>>(ibstream &ibs, std::string &s) { size_t n; ibs >> n; s.resize(n); ibs.read(&s[0], n); s[n] = 0; return ibs; } template ibstream & operator>>(ibstream &ibs, std::vector &v) { size_t n; ibs >> n; v.resize(n); for (size_t i = 0; i < n; ++i) ibs >> v[i]; return ibs; } template ibstream & operator<<(ibstream &ibs, std::set &s) { s.clear(); size_t n; ibs >> n; for (size_t i = 0; i < n; ++i) { T x; ibs >> x; s.insert(x); } return ibs; } template ibstream & operator>>(ibstream &ibs, std::map &m) { m.clear(); size_t n; ibs >> n; for (size_t i = 0; i < n; ++i) { std::pair x; ibs >> x; m.insert(x); } return ibs; } template inline ibstream & operator>>(ibstream &ibs, std::pair &p) { return ibs >> p.first >> p.second; } template inline ibstream & operator>>(ibstream &ibs, std::tuple &t) { return ibs >> std::get<0>(t) >> std::get<1>(t) >> std::get<2>(t); } #endif arachne-pnr-0~20150927gitefdb026/src/carry.hh000066400000000000000000000015071260207143000204440ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_CARRY_HH #define PNR_CARRY_HH #include class CarryChains { public: std::vector> chains; public: CarryChains() {} }; #endif arachne-pnr-0~20150927gitefdb026/src/casting.hh000066400000000000000000000024331260207143000207530ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_CASTING_HH #define PNR_CASTING_HH template bool isa(const typename T::Base *v) { return v->kind() == T::kindof; } template const T * cast(const typename T::Base *v) { assert (isa(v)); return static_cast(v); } template T * cast(typename T::Base *v) { assert (isa(v)); return static_cast(v); } template const T * dyn_cast(const typename T::Base *v) { if (isa(v)) return static_cast(v); else return 0; } template T * dyn_cast(typename T::Base *v) { if (isa(v)) return static_cast(v); else return 0; } #endif arachne-pnr-0~20150927gitefdb026/src/chipdb.cc000066400000000000000000000527051260207143000205510ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "chipdb.hh" #include "line_parser.hh" #include #include #include #include std::ostream & operator<<(std::ostream &s, const CBit &cbit) { return s << cbit.tile << " B" << cbit.row << "[" << cbit.col << "]"; } bool CBit::operator==(const CBit &rhs) const { return tile == rhs.tile && row == rhs.row && col == rhs.col; } bool CBit::operator<(const CBit &rhs) const { if (tile < rhs.tile) return true; if (tile > rhs.tile) return false; if (row < rhs.row) return true; if (row > rhs.row) return false; return col < rhs.col; } std::ostream & operator<<(std::ostream &s, const CBitVal &cv) { for (const auto &p : cv.cbit_val) { if (p.second) s << "1"; else s << "0"; } for (const auto &p : cv.cbit_val) s << " " << p.first; return s; } std::set CBitVal::cbits() const { return keys(cbit_val); } std::string tile_type_name(TileType t) { assert(t != TileType::EMPTY); switch(t) { case TileType::IO: return "io_tile"; case TileType::LOGIC: return "logic_tile"; case TileType::RAMB: return "ramb_tile"; case TileType::RAMT: return "ramt_tile"; case TileType::EMPTY: abort(); } return std::string(); } obstream &operator<<(obstream &obs, const Switch &sw) { obs << sw.bidir << sw.tile << sw.out << sw.cbits.size(); for (const CBit &cbit : sw.cbits) { assert(cbit.tile == sw.tile); obs << cbit.row << cbit.col; } obs << sw.in_val; return obs; } ibstream &operator>>(ibstream &ibs, Switch &sw) { size_t n_cbits; ibs >> sw.bidir >> sw.tile >> sw.out >> n_cbits; sw.cbits.resize(n_cbits); for (size_t i = 0; i < n_cbits; ++i) { int row, col; ibs >> row >> col; sw.cbits[i] = CBit(sw.tile, row, col); } ibs >> sw.in_val; return ibs; } ChipDB::ChipDB() : width(0), height(0), n_tiles(0), n_nets(0), n_global_nets(8), n_cells(0), cell_type_cells(n_cell_types), bank_cells(4) { } int ChipDB::add_cell(CellType type, const Location &loc) { int cell = ++n_cells; cell_type.push_back(type); cell_location.push_back(loc); cell_type_cells[cell_type_idx(type)].push_back(cell); return cell; } int ChipDB::tile_bank(int t) const { assert(tile_type[t] == TileType::IO); int x = tile_x(t), y = tile_y(t); if (x == 0) return 3; else if (y == 0) return 2; else if (x == width - 1) return 1; else { assert(y == height - 1); return 0; } } void ChipDB::dump(std::ostream &s) const { s << ".device " << device << "\n\n"; for (const auto &p : packages) { s << ".pins " << p.first << "\n"; for (const auto &p2 : p.second.pin_loc) { int t = p2.second.tile(); s << p2.first << " " << tile_x(t) << " " << tile_y(t) << " " << p2.second.pos() << "\n"; } s << "\n"; } s << ".colbuf\n"; for (const auto &p : tile_colbuf_tile) s << tile_x(p.second) << " " << tile_y(p.second) << " " << tile_x(p.first) << " " << tile_y(p.first) << "\n"; s << "\n"; for (int i = 0; i < width; i ++) for (int j = 0; j < height; j ++) { int t = tile(i, j); switch(tile_type[t]) { case TileType::EMPTY: break; case TileType::IO: s << ".io_tile " << i << " " << j << "\n"; break; case TileType::LOGIC: s << ".logic_tile " << i << " " << j << "\n"; break; case TileType::RAMB: s << ".ramb_tile " << i << " " << j << "\n"; break; case TileType::RAMT: s << ".ramt_tile " << i << " " << j << "\n"; break; } for (const auto &p : tile_nonrouting_cbits.at(tile_type[t])) { s << p.first; for (const auto &cbit : p.second) s << " " << cbit; s << "\n"; } s << "\n"; } std::vector>> net_tile_names(n_nets); for (int i = 0; i < n_tiles; ++i) for (const auto &p : tile_nets[i]) net_tile_names[p.second].push_back(std::make_pair(i, p.first)); for (int i = 0; i < n_nets; ++i) { s << ".net " << i << "\n"; for (const auto &p : net_tile_names[i]) s << tile_x(p.first) << " " << tile_y(p.first) << " " << p.second << "\n"; s << "\n"; } for (unsigned i = 0; i < switches.size(); ++i) { const Switch &sw = switches[i]; s << (sw.bidir ? ".routing" : ".buffer") << " " << tile_x(sw.tile) << " " << tile_y(sw.tile) << " " << sw.out; for (const CBit &cb : sw.cbits) s << " B" << cb.row << "[" << cb.col << "]"; s << "\n"; for (const auto &p : sw.in_val) { for (int j = 0; j < (int)sw.cbits.size(); ++j) { if (p.second & (1 << j)) s << "1"; else s << "0"; } s << " " << p.first << "\n"; } s << "\n"; } } void ChipDB::set_device(const std::string &d, int w, int h, int n_nets_) { device = d; width = w; height = h; n_tiles = width * height; n_nets = n_nets_; tile_type.resize(n_tiles, TileType::EMPTY); tile_nets.resize(n_tiles); net_tile_name.resize(n_nets); out_switches.resize(n_nets); in_switches.resize(n_nets); } class ChipDBParser : public LineParser { ChipDB *chipdb; CBit parse_cbit(int tile, const std::string &s); void parse_cmd_device(); void parse_cmd_pins(); void parse_cmd_gbufpin(); void parse_cmd_tile(); void parse_cmd_tile_bits(); void parse_cmd_net(); void parse_cmd_buffer_routing(); void parse_cmd_colbuf(); void parse_cmd_gbufin(); void parse_cmd_iolatch(); void parse_cmd_ieren(); void parse_cmd_extra_bits(); void parse_cmd_extra_cell(); public: ChipDBParser(const std::string &f, std::istream &s_) : LineParser(f, s_), chipdb(nullptr) {} ChipDB *parse(); }; CBit ChipDBParser::parse_cbit(int t, const std::string &s_) { std::size_t lbr = s_.find('['), rbr = s_.find(']'); if (s_[0] != 'B' || lbr == std::string::npos || rbr == std::string::npos) fatal("invalid cbit spec"); std::string rows(&s_[1], &s_[lbr]), cols(&s_[lbr + 1], &s_[rbr]); int r = std::stoi(rows), c = std::stoi(cols); return CBit(t, r, c); } void ChipDBParser::parse_cmd_device() { if (words.size() != 5) fatal("wrong number of arguments"); chipdb->set_device(words[1], std::stoi(words[2]), std::stoi(words[3]), std::stoi(words[4])); // next command read_line(); } void ChipDBParser::parse_cmd_pins() { if (words.size() != 2) fatal("wrong number of arguments"); const std::string &package_name = words[1]; Package &package = chipdb->packages[package_name]; package.name = package_name; for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 4) fatal("invalid .pins entry"); const std::string &pin = words[0]; int x = std::stoi(words[1]), y = std::stoi(words[2]), pos = std::stoi(words[3]); int t = chipdb->tile(x, y); Location loc(t, pos); extend(package.pin_loc, pin, loc); extend(package.loc_pin, loc, pin); chipdb->add_cell(CellType::IO, loc); } } void ChipDBParser::parse_cmd_gbufpin() { if (words.size() != 1) fatal("wrong number of arguments"); for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 4) fatal("invalid .gbufpin entry"); int x = std::stoi(words[0]), y = std::stoi(words[1]), pos = std::stoi(words[2]), glb_num = std::stoi(words[3]); int t = chipdb->tile(x, y); Location loc(t, pos); extend(chipdb->loc_pin_glb_num, loc, glb_num); chipdb->add_cell(CellType::GB, Location(t, 2)); } } void ChipDBParser::parse_cmd_tile() { if (words.size() != 3) fatal("wrong number of arguments"); int x = std::stoi(words[1]), y = std::stoi(words[2]); if (x < 0 || x >= chipdb->width) fatal("tile x out of range"); if (y < 0 || y >= chipdb->height) fatal("tile y out of range"); int t = chipdb->tile(x, y); const std::string &cmd = words[0]; if (cmd == ".io_tile") { chipdb->tile_type[t] = TileType::IO; } else if (cmd == ".logic_tile") { chipdb->tile_type[t] = TileType::LOGIC; for (int p = 0; p < 8; ++p) chipdb->add_cell(CellType::LOGIC, Location(t, p)); } else if (cmd == ".ramb_tile") chipdb->tile_type[t] = TileType::RAMB; else { assert(cmd == ".ramt_tile"); chipdb->tile_type[t] = TileType::RAMT; chipdb->add_cell(CellType::RAM, Location(t, 0)); } // next command read_line(); } void ChipDBParser::parse_cmd_tile_bits() { if (words.size() != 3) fatal("wrong number of arguments"); TileType ty; const std::string &cmd = words[0]; if (cmd == ".io_tile_bits") ty = TileType::IO; else if (cmd == ".logic_tile_bits") ty = TileType::LOGIC; else if (cmd == ".ramb_tile_bits") ty = TileType::RAMB; else { assert(cmd == ".ramt_tile_bits"); ty = TileType::RAMT; } int n_columns = std::stoi(words[1]), n_rows = std::stoi(words[2]); extend(chipdb->tile_cbits_block_size, ty, std::make_pair(n_columns, n_rows)); for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() < 2) fatal("invalid tile entry"); const std::string &func = words[0]; std::vector cbits(words.size() - 1); for (unsigned i = 1; i < words.size(); ++i) cbits[i - 1] = parse_cbit(0, words[i]); extend(chipdb->tile_nonrouting_cbits[ty], func, cbits); } } void ChipDBParser::parse_cmd_net() { if (words.size() != 2) fatal("wrong number of arguments"); int n = std::stoi(words[1]); if (n < 0) fatal("invalid net index"); bool first = true; for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 3) fatal("invalid .net entry"); int x = std::stoi(words[0]), y = std::stoi(words[1]); if (x < 0 || x >= chipdb->width) fatal("tile x out of range"); if (y < 0 || y >= chipdb->height) fatal("tile y out of range"); int t = chipdb->tile(x, y); if (first) { chipdb->net_tile_name[n] = std::make_pair(t, words[2]); first = false; } extend(chipdb->tile_nets[t], words[2], n); } } void ChipDBParser::parse_cmd_buffer_routing() { if (words.size() < 5) fatal("too few arguments"); bool bidir = words[0] == ".routing"; int x = std::stoi(words[1]), y = std::stoi(words[2]); if (x < 0 || x >= chipdb->width) fatal("tile x out of range"); if (y < 0 || y >= chipdb->height) fatal("tile y out of range"); int t = chipdb->tile(x, y); int n = std::stoi(words[3]); if (n < 0) fatal("invalid net index"); std::vector cbits(words.size() - 4); for (unsigned i = 4; i < words.size(); i ++) cbits[i - 4] = parse_cbit(t, words[i]); std::map in_val; for (;;) { read_line(); if (eof() || line[0] == '.') { chipdb->switches.push_back(Switch(bidir, t, n, in_val, cbits)); return; } const std::string &sval = words[0]; if (words.size() != 2 || sval.size() != cbits.size()) fatal("invalid .buffer/.routing entry"); int n2 = std::stoi(words[1]); unsigned val = 0; for (unsigned i = 0; i < sval.size(); i ++) { if (sval[i] == '1') val |= (1 << i); else { if (sval[i] != '0') fatal("invalid binary string"); } } extend(in_val, n2, val); } } void ChipDBParser::parse_cmd_colbuf() { for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 4) fatal("invalid .colbuf entry"); int src_x = std::stoi(words[0]); int src_y = std::stoi(words[1]); int dst_x = std::stoi(words[2]); int dst_y = std::stoi(words[3]); chipdb->tile_colbuf_tile[chipdb->tile(dst_x, dst_y)] = chipdb->tile(src_x, src_y); } } void ChipDBParser::parse_cmd_gbufin() { for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 3) fatal("invalid .gbufin entry"); int g = std::stoi(words[2]); assert(g < chipdb->n_global_nets); extend(chipdb->gbufin, std::make_pair(std::stoi(words[0]), std::stoi(words[1])), g); } } void ChipDBParser::parse_cmd_iolatch() { for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 2) fatal("invalid .iolatch entry"); int x = std::stoi(words[0]), y = std::stoi(words[1]); chipdb->iolatch.push_back(chipdb->tile(x, y)); } } void ChipDBParser::parse_cmd_ieren() { for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 6) fatal("invalid .ieren entry"); int pio_t = chipdb->tile(std::stoi(words[0]), std::stoi(words[1])), ieren_t = chipdb->tile(std::stoi(words[3]), std::stoi(words[4])); Location pio(pio_t, std::stoi(words[2])), ieren(ieren_t, std::stoi(words[5])); extend(chipdb->ieren, pio, ieren); } } void ChipDBParser::parse_cmd_extra_bits() { for (;;) { read_line(); if (eof() || line[0] == '.') return; if (words.size() != 4) fatal("invalid .extra_bits entry"); int bank_num = std::stoi(words[1]), addr_x = std::stoi(words[2]), addr_y = std::stoi(words[3]); extend(chipdb->extra_bits, words[0], std::make_tuple(bank_num, addr_x, addr_y)); } } void ChipDBParser::parse_cmd_extra_cell() { if (words.size() != 4) fatal("wrong number of arguments to .extra_cell"); const std::string &cell_type = words[3]; int x = std::stoi(words[1]), y = std::stoi(words[2]); int t = chipdb->tile(x, y); int c = 0; if (cell_type == "WARMBOOT") c = chipdb->add_cell(CellType::WARMBOOT, Location(t, 0)); else if (cell_type == "PLL") c = chipdb->add_cell(CellType::PLL, Location(t, 3)); else fatal(fmt("unknown extra cell type `" << cell_type << "'")); std::map> mfvs; for (;;) { read_line(); if (eof() || line[0] == '.') { extend(chipdb->cell_mfvs, c, mfvs); return; } if (words.size() != 4) fatal("invalid .extra_cell entry"); int mfv_t = chipdb->tile(std::stoi(words[1]), std::stoi(words[2])); extend(mfvs, words[0], std::make_pair(mfv_t, words[3])); } } ChipDB * ChipDBParser::parse() { chipdb = new ChipDB; read_line(); for (;;) { if (eof()) break; if (line[0] != '.') fatal(fmt("expected command, got '" << words[0] << "'")); const std::string &cmd = words[0]; if (cmd == ".device") parse_cmd_device(); else if (cmd == ".pins") parse_cmd_pins(); else if (cmd == ".gbufpin") parse_cmd_gbufpin(); else if (cmd == ".io_tile" || cmd == ".logic_tile" || cmd == ".ramb_tile" || cmd == ".ramt_tile") parse_cmd_tile(); else if (cmd == ".io_tile_bits" || cmd == ".logic_tile_bits" || cmd == ".ramb_tile_bits" || cmd == ".ramt_tile_bits") parse_cmd_tile_bits(); else if (cmd == ".net") parse_cmd_net(); else if (cmd == ".buffer" || cmd == ".routing") parse_cmd_buffer_routing(); else if (cmd == ".colbuf") parse_cmd_colbuf(); else if (cmd == ".gbufin") parse_cmd_gbufin(); else if (cmd == ".iolatch") parse_cmd_iolatch(); else if (cmd == ".ieren") parse_cmd_ieren(); else if (cmd == ".extra_bits") parse_cmd_extra_bits(); else if (cmd == ".extra_cell") parse_cmd_extra_cell(); else fatal(fmt("unknown directive '" << cmd << "'")); } chipdb->finalize(); return chipdb; } void ChipDB::finalize() { int t1c1 = tile(1, 1); for (const auto &p : tile_nets[t1c1]) { if (is_prefix("glb_netwk_", p.first)) { int n = std::stoi(&p.first[10]); extend(net_global, p.second, n); } } for (int i = 1; i <= n_cells; ++i) { int t = cell_location[i].tile(); if (tile_type[t] != TileType::IO) continue; int b = tile_bank(t); bank_cells[b].push_back(i); } tile_pos_cell.resize(n_tiles); for (int i = 0; i < n_tiles; ++i) { switch(tile_type[i]) { case TileType::LOGIC: tile_pos_cell[i].resize(8, 0); break; case TileType::IO: tile_pos_cell[i].resize(4, 0); break; case TileType::RAMT: tile_pos_cell[i].resize(1, 0); break; default: break; } } for (int i = 1; i <= n_cells; ++i) { const Location &loc = cell_location[i]; // *logs << i << " " << loc << "\n"; int t = loc.tile(); int pos = loc.pos(); if ((int)tile_pos_cell[t].size() <= pos) tile_pos_cell[t].resize(pos + 1, 0); assert(tile_pos_cell[t][pos] == 0); tile_pos_cell[t][pos] = i; } in_switches.resize(n_nets); out_switches.resize(n_nets); for (size_t s = 0; s < switches.size(); ++s) { int out = switches[s].out; extend(out_switches[out], s); for (const auto &p : switches[s].in_val) extend(in_switches[p.first], s); } } int ChipDB::find_switch(int in, int out) const { std::vector t; std::set_intersection(out_switches[out].begin(), out_switches[out].end(), in_switches[in].begin(), in_switches[in].end(), std::back_insert_iterator>(t)); assert(t.size() == 1); int s = t[0]; assert(switches[s].out == out); assert(contains_key(switches[s].in_val, in)); return s; } void ChipDB::bwrite(obstream &obs) const { std::vector net_names; std::map net_name_idx; std::vector> tile_nets_idx(n_tiles); for (int t = 0; t < n_tiles; ++t) { for (const auto &p : tile_nets[t]) { int ni; auto i = net_name_idx.find(p.first); if (i == net_name_idx.end()) { ni = net_name_idx.size(); net_names.push_back(p.first); net_name_idx.insert(std::make_pair(p.first, ni)); } else ni = i->second; extend(tile_nets_idx[t], ni, p.second); } } obs << device << width << height // n_tiles = width * height << n_nets // n_global_nets = 8 << packages << loc_pin_glb_num << iolatch << ieren << extra_bits << gbufin << tile_colbuf_tile << tile_type // net_tile_name << net_names << tile_nets_idx // tile_nets << tile_nonrouting_cbits << n_cells << cell_type << cell_location << cell_mfvs << cell_type_cells // bank_cells << switches // in_switches, out_switches << tile_cbits_block_size; } void ChipDB::bread(ibstream &ibs) { std::vector net_names; std::vector> tile_nets_idx; ibs >> device >> width >> height // n_tiles = width * height >> n_nets // n_global_nets = 8 >> packages >> loc_pin_glb_num >> iolatch >> ieren >> extra_bits >> gbufin >> tile_colbuf_tile >> tile_type // net_tile_name >> net_names >> tile_nets_idx // tile_nets >> tile_nonrouting_cbits >> n_cells >> cell_type >> cell_location >> cell_mfvs >> cell_type_cells // bank_cells >> switches // in_switches, out_switches >> tile_cbits_block_size; n_tiles = width * height; tile_nets_idx.resize(n_tiles); tile_nets.resize(n_tiles); for (int i = 0; i < n_tiles; ++i) { for (const auto &p : tile_nets_idx[i]) extend(tile_nets[i], net_names[p.first], p.second); } finalize(); } ChipDB * read_chipdb(const std::string &filename) { std::string expanded = expand_filename(filename); std::ifstream ifs(expanded); if (ifs.fail()) fatal(fmt("read_chipdb: failed to open `" << expanded << "': " << strerror(errno))); ChipDB *chipdb; if (is_suffix(expanded, ".bin")) { chipdb = new ChipDB; ibstream ibs(ifs); chipdb->bread(ibs); } else { ChipDBParser parser(filename, ifs); chipdb = parser.parse(); } return chipdb; } std::string cell_type_name(CellType ct) { switch(ct) { case CellType::LOGIC: return "LC"; case CellType::IO: return "IO"; case CellType::GB: return "GB"; case CellType::RAM: return "RAM"; case CellType::WARMBOOT: return "WARMBOOT"; case CellType::PLL: return "PLL"; default: abort(); } } CBit ChipDB::extra_cell_cbit(int c, const std::string &name) const { const auto &p = cell_mfvs.at(c).at(name); const auto &cbits = tile_nonrouting_cbits.at(tile_type[p.first]).at(std::string("PLL.") + p.second); assert(cbits.size() == 1); const CBit &cbit0 = cbits[0]; return cbit0.with_tile(p.first); } arachne-pnr-0~20150927gitefdb026/src/chipdb.hh000066400000000000000000000155551260207143000205650ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_CHIPDB_HH #define PNR_CHIPDB_HH #include "location.hh" #include "util.hh" #include "hashmap.hh" #include "bstream.hh" #include "vector.hh" #include #include #include #include #include #include class CBit { public: friend std::ostream &operator<<(std::ostream &s, const CBit &cbit); friend obstream &operator<<(obstream &obs, const CBit &cbit); friend ibstream &operator>>(ibstream &ibs, CBit &cbit); template friend struct std::hash; int tile; int row; int col; public: CBit() : tile(0), row(0), col(0) {} CBit(int tile_, int r, int c) : tile(tile_), row(r), col(c) {} CBit with_tile(int new_t) const { return CBit(new_t, row, col); } bool operator==(const CBit &rhs) const; bool operator!=(const CBit &rhs) const { return !operator==(rhs); } bool operator<(const CBit &rhs) const; }; inline obstream &operator<<(obstream &obs, const CBit &cbit) { return obs << cbit.tile << cbit.row << cbit.col; } inline ibstream &operator>>(ibstream &ibs, CBit &cbit) { return ibs >> cbit.tile >> cbit.row >> cbit.col; } namespace std { template<> struct hash { public: size_t operator() (const CBit &cbit) const { std::hash hasher; size_t h = hasher(cbit.tile); h = hash_combine(h, hasher(cbit.row)); return hash_combine(h, hasher(cbit.col)); } }; } class CBitVal { public: friend std::ostream &operator<<(std::ostream &s, const CBitVal &cbits); std::map cbit_val; public: CBitVal() {} CBitVal(const std::map &cbv) : cbit_val(cbv) {} std::set cbits() const; }; class Switch { public: friend obstream &operator<<(obstream &obs, const Switch &sw); friend ibstream &operator>>(ibstream &ibs, Switch &sw); bool bidir; // routing int tile; int out; std::map in_val; std::vector cbits; public: Switch() {} Switch(bool bi, int t, int o, const std::map &iv, const std::vector &cb) : bidir(bi), tile(t), out(o), in_val(iv), cbits(cb) {} }; extern obstream &operator<<(obstream &obs, const Switch &sw); extern ibstream &operator>>(ibstream &ibs, Switch &sw); enum class TileType : int { EMPTY, IO, LOGIC, RAMB, RAMT, }; enum class CellType : int { LOGIC, IO, GB, RAM, WARMBOOT, PLL, }; extern std::string cell_type_name(CellType ct); inline obstream &operator<<(obstream &obs, TileType t) { return obs << static_cast(t); } inline ibstream &operator>>(ibstream &ibs, TileType &t) { int x; ibs >> x; t = static_cast(x); return ibs; } constexpr int cell_type_idx(CellType type) { return static_cast(type); } static const int n_cell_types = cell_type_idx(CellType::PLL) + 1; inline obstream &operator<<(obstream &obs, CellType t) { return obs << static_cast(t); } inline ibstream &operator>>(ibstream &ibs, CellType &t) { int x; ibs >> x; t = static_cast(x); return ibs; } namespace std { template<> struct hash { public: size_t operator() (TileType x) const { std::hash hasher; return hasher(static_cast(x)); } }; } extern std::string tile_type_name(TileType t); class Package { friend obstream &operator<<(obstream &obs, const Package &pkg); friend ibstream &operator>>(ibstream &ibs, Package &pkg); public: std::string name; std::map pin_loc; std::map loc_pin; }; inline obstream &operator<<(obstream &obs, const Package &pkg) { return obs << pkg.name << pkg.pin_loc; } inline ibstream &operator>>(ibstream &ibs, Package &pkg) { ibs >> pkg.name >> pkg.pin_loc; for (const auto &p : pkg.pin_loc) extend(pkg.loc_pin, p.second, p.first); return ibs; } class ChipDB { public: std::string device; int width; int height; int n_tiles; int n_nets; int n_global_nets; std::map net_global; std::map packages; std::map loc_pin_glb_num; std::vector iolatch; // tiles std::map ieren; std::map> extra_bits; std::map, int> gbufin; std::map tile_colbuf_tile; std::vector tile_type; std::vector> net_tile_name; std::vector> tile_nets; std::map>> tile_nonrouting_cbits; CBit extra_cell_cbit(int ec, const std::string &name) const; int n_cells; BasedVector cell_type; BasedVector cell_location; std::map>> cell_mfvs; std::vector> tile_pos_cell; int loc_cell(const Location &loc) const { return tile_pos_cell[loc.tile()][loc.pos()]; } std::vector> cell_type_cells; std::vector> bank_cells; // buffers and routing std::vector switches; std::vector> out_switches; std::vector> in_switches; std::map> tile_cbits_block_size; int add_cell(CellType type, const Location &loc); bool is_global_net(int i) const { return i < n_global_nets; } int find_switch(int in, int out) const; int tile(int x, int y) const { assert(x >= 0 && x < width); assert(y >= 0 && y < height); return x + width*y; } int tile_x(int t) const { assert(t >= 0 && t <= n_tiles); return t % width; } int tile_y(int t) const { assert(t >= 0 && t <= n_tiles); return t / width; } int tile_bank(int t) const; int ramt_ramb_tile(int ramt_t) const { assert(tile_type[ramt_t] == TileType::RAMT); int ramb_t = ramt_t - width; assert(ramb_t == tile(tile_x(ramt_t), tile_y(ramt_t)-1)); assert(tile_type[ramb_t] == TileType::RAMB); return ramb_t; } void set_device(const std::string &d, int w, int h, int n_nets_); void finalize(); public: ChipDB(); void dump(std::ostream &s) const; void bwrite(obstream &obs) const; void bread(ibstream &ibs); }; extern ChipDB *read_chipdb(const std::string &filename); #endif arachne-pnr-0~20150927gitefdb026/src/configuration.cc000066400000000000000000000063521260207143000221640ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "chipdb.hh" #include "configuration.hh" #include "util.hh" #include "netlist.hh" #include #include Configuration::Configuration() { } void Configuration::set_cbit(const CBit &value_cbit, bool value) { assert(!contains_key(cbits, value_cbit) || cbits.at(value_cbit) == value); // *logs << value_cbit << " = " << value << "\n"; cbits[value_cbit] = value; } void Configuration::set_cbits(const std::vector &value_cbits, unsigned value) { for (unsigned i = 0; i < value_cbits.size(); ++i) set_cbit(value_cbits[i], (bool)(value & (1 << i))); } void Configuration::set_extra_cbit(const std::tuple &t) { extend(extra_cbits, t); } void Configuration::write_txt(std::ostream &s, const ChipDB *chipdb, Design *d, const std::map &placement, const std::vector &cnet_net) { s << ".device " << chipdb->device << "\n"; for (int t = 0; t < chipdb->n_tiles; ++t) { TileType ty = chipdb->tile_type[t]; if (ty == TileType::EMPTY) continue; int x = chipdb->tile_x(t), y = chipdb->tile_y(t); s << "." << tile_type_name(ty) << " " << x << " " << y << "\n"; int bw, bh; std::tie(bw, bh) = chipdb->tile_cbits_block_size.at(ty); for (int r = 0; r < bh; r ++) { for (int c = 0; c < bw; c ++) { auto i = cbits.find(CBit(t, r, c)); if (i != cbits.end()) { if (i->second) s << "1"; else s << "0"; } else s << "0"; } s << "\n"; } } for (const auto &t : extra_cbits) { s << ".extra_bit " << std::get<0>(t) << " " << std::get<1>(t) << " " << std::get<2>(t) << "\n"; } Models models(d); for (const auto &p : placement) { if (models.is_ramX(p.first)) { int cell = p.second; const Location &loc = chipdb->cell_location[cell]; int t = loc.tile(); assert(chipdb->tile_type[t] == TileType::RAMT); int x = chipdb->tile_x(t), y = chipdb->tile_y(t); s << ".ram_data " << x << " " << (y-1) << "\n"; for (int i = 0; i < 16; ++i) { BitVector init_i = p.first->get_param(fmt("INIT_" << hexdigit(i, 'A'))).as_bits(); init_i.resize(256); for (int j = 63; j >= 0; --j) { int v = (((int)init_i[j*4 + 3] << 3) | ((int)init_i[j*4 + 2] << 2) | ((int)init_i[j*4 + 1] << 1) | ((int)init_i[j*4 + 0])); s << hexdigit(v); } s << "\n"; } } } for (int i = 0; i < chipdb->n_nets; ++i) { Net *n = cnet_net[i]; if (n) s << ".sym " << i << " " << n->name() << "\n"; } } arachne-pnr-0~20150927gitefdb026/src/configuration.hh000066400000000000000000000024711260207143000221740ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_CONFIGURATION_HH #define PNR_CONFIGURATION_HH #include "util.hh" #include class ChipDB; class Design; class Instance; class Net; class IdLess; class Configuration { private: std::map cbits; std::set> extra_cbits; public: Configuration(); void set_cbit(const CBit &cbit, bool value); void set_cbits(const std::vector &value_cbits, unsigned value); void set_extra_cbit(const std::tuple &t); void write_txt(std::ostream &s, const ChipDB *chipdb, Design *d, const std::map &placement, const std::vector &cnet_net); }; #endif arachne-pnr-0~20150927gitefdb026/src/constant.cc000066400000000000000000000061701260207143000211440ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "netlist.hh" #include "constant.hh" #include "chipdb.hh" #include void realize_constants(const ChipDB *chipdb, Design *d) { Models models(d); Model *top = d->top(); Net *const0 = nullptr; for (const auto &p : top->nets()) { if (p.second->is_constant() && p.second->constant() == Value::ZERO) { const0 = p.second; break; } } Net *actual_const0 = nullptr, *actual_const1 = nullptr; for (Instance *inst : top->instances()) { for (const auto &p : inst->ports()) { if ((models.is_io(inst) && p.second->name() == "PACKAGE_PIN") || (models.is_lc(inst) && p.second->name() == "CIN")) continue; Net *n = p.second->connection(); if (n && n->is_constant() && n->constant() != p.second->undriven()) { Value v = n->constant(); Net *new_n = nullptr; if (v == Value::ZERO) { if (!actual_const0) { actual_const0 = top->add_net("$false"); Instance *lc_inst = top->add_instance(models.lc); assert(const0); lc_inst->find_port("I0")->connect(const0); lc_inst->find_port("I1")->connect(const0); lc_inst->find_port("I2")->connect(const0); lc_inst->find_port("I3")->connect(const0); lc_inst->find_port("O")->connect(actual_const0); lc_inst->set_param("LUT_INIT", BitVector(1, 0)); } new_n = actual_const0; } else { assert(v == Value::ONE); if (!actual_const1) { actual_const1 = top->add_net("$true"); Instance *lc_inst = top->add_instance(models.lc); if (!const0) { const0 = top->add_net("$false"); const0->set_is_constant(true); const0->set_constant(Value::ZERO); } lc_inst->find_port("I0")->connect(const0); lc_inst->find_port("I1")->connect(const0); lc_inst->find_port("I2")->connect(const0); lc_inst->find_port("I3")->connect(const0); lc_inst->find_port("O")->connect(actual_const1); lc_inst->set_param("LUT_INIT", BitVector(16, 1)); } new_n = actual_const1; } p.second->connect(new_n); if (n->connections().empty()) { top->remove_net(n); delete n; } } } } if (actual_const0) { if (actual_const1) *logs << " realized 0, 1\n"; else *logs << " realized 0\n"; } else if (actual_const1) *logs << " realized 1\n"; } arachne-pnr-0~20150927gitefdb026/src/constant.hh000066400000000000000000000014531260207143000211550ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_CONSTANT_HH #define PNR_CONSTANT_HH class Design; class ChipDB; extern void realize_constants(const ChipDB *chipdb, Design *d); #endif arachne-pnr-0~20150927gitefdb026/src/designstate.cc000066400000000000000000000024311260207143000216210ustar00rootroot00000000000000 #include "designstate.hh" DesignState::DesignState(const ChipDB *chipdb_, const Package &package_, Design *d_) : chipdb(chipdb_), package(package_), d(d_), models(d_), top(d_->top()) { } bool DesignState::is_dual_pll(Instance *inst) const { assert(models.is_pllX(inst)); if (inst->instance_of()->name() == "SB_PLL40_2F_CORE" || inst->instance_of()->name() == "SB_PLL40_2_PAD" || inst->instance_of()->name() == "SB_PLL40_2F_PAD") return true; else { assert(inst->instance_of()->name() == "SB_PLL40_PAD" || inst->instance_of()->name() == "SB_PLL40_CORE"); return false; } } std::vector DesignState::pll_out_io_cells(Instance *inst, int cell) const { assert(models.is_pllX(inst) && chipdb->cell_type[cell] == CellType::PLL); bool dual = is_dual_pll(inst); const auto &p_a = chipdb->cell_mfvs.at(cell).at("PLLOUT_A"); Location io_loc_a(p_a.first, std::stoi(p_a.second)); int io_cell_a = chipdb->loc_cell(io_loc_a); std::vector r; r.push_back(io_cell_a); if (dual) { const auto &p_b = chipdb->cell_mfvs.at(cell).at("PLLOUT_B"); Location io_loc_b(p_b.first, std::stoi(p_b.second)); int io_cell_b = chipdb->loc_cell(io_loc_b); r.push_back(io_cell_b); } return r; } arachne-pnr-0~20150927gitefdb026/src/designstate.hh000066400000000000000000000012441260207143000216340ustar00rootroot00000000000000 #include "netlist.hh" #include "chipdb.hh" #include "pcf.hh" #include "carry.hh" #include "configuration.hh" class DesignState { public: const ChipDB *chipdb; const Package &package; Design *d; Models models; Model *top; Constraints constraints; CarryChains chains; std::set locked; std::map placement; std::map gb_inst_gc; std::vector cnet_net; Configuration conf; public: DesignState(const ChipDB *chipdb_, const Package &package_, Design *d_); bool is_dual_pll(Instance *inst) const; std::vector pll_out_io_cells(Instance *inst, int cell) const; }; arachne-pnr-0~20150927gitefdb026/src/global.cc000066400000000000000000000252331260207143000205540ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "netlist.hh" #include "global.hh" #include "chipdb.hh" #include "casting.hh" #include "util.hh" #include "designstate.hh" #include #include #include class Promoter { std::vector global_classes; static const char *global_class_name(uint8_t gc); DesignState &ds; const ChipDB *chipdb; Design *d; Model *top; const Models ⊧ std::map &gb_inst_gc; Net *const0; uint8_t port_gc(Port *conn, bool indirect); void pll_pass_through(Instance *inst, int cell, const char *p_name); bool routable(int g, Port *p); void make_routable(Net *n, int g); public: Promoter(DesignState &ds_); void promote(bool do_promote); }; const char * Promoter::global_class_name(uint8_t gc) { switch(gc) { case gc_clk: return "clk"; case gc_cen: return "cen/wclke"; case gc_sr: return "sr/we"; case gc_rclke: return "rclke"; case gc_re: return "re"; default: abort(); return nullptr; } } Promoter::Promoter(DesignState &ds_) : global_classes{ gc_clk, gc_cen, gc_sr, gc_rclke, gc_re, }, ds(ds_), chipdb(ds.chipdb), d(ds.d), top(ds.top), models(ds.models), gb_inst_gc(ds.gb_inst_gc), const0(nullptr) { for (const auto &p : top->nets()) { if (p.second->is_constant() && p.second->constant() == Value::ZERO) { const0 = p.second; break; } } // will prune if (!const0) { const0 = top->add_net("$false"); const0->set_is_constant(true); const0->set_constant(Value::ZERO); } } uint8_t Promoter::port_gc(Port *conn, bool indirect) { Instance *inst = dyn_cast(conn->node()); assert(inst); if (models.is_lc(inst)) { if (conn->name() == "CLK") return gc_clk; else if (conn->name() == "CEN") return gc_cen; else if (conn->name() == "SR") return gc_sr; else if (indirect && (conn->name() == "I0" || conn->name() == "I1" || conn->name() == "I2" || conn->name() == "I3")) return gc_clk; } else if (models.is_ioX(inst)) { if (conn->name() == "INPUT_CLOCK" || conn->name() == "OUTPUT_CLOCK") return gc_clk; } else if (models.is_gb(inst) || models.is_warmboot(inst) || models.is_pllX(inst)) ; else { assert(models.is_ramX(inst)); if (conn->name() == "WCLK" || conn->name() == "WCLKN" || conn->name() == "RCLK" || conn->name() == "RCLKN") return gc_clk; else if (conn->name() == "WCLKE") return gc_wclke; else if (conn->name() == "WE") return gc_we; else if (conn->name() == "RCLKE") return gc_rclke; else if (conn->name() == "RE") return gc_re; } return 0; } bool Promoter::routable(int g, Port *p) { return (bool)(port_gc(p, true) & (1 << g)); } void Promoter::pll_pass_through(Instance *inst, int cell, const char *p_name) { Port *p = inst->find_port(p_name); Net *n = p->connection(); if (!n) return; Net *t = top->add_net(n); p->connect(t); Instance *pass_inst = top->add_instance(models.lc); pass_inst->find_port("I0")->connect(t); pass_inst->find_port("I1")->connect(const0); pass_inst->find_port("I2")->connect(const0); pass_inst->find_port("I3")->connect(const0); pass_inst->set_param("LUT_INIT", BitVector(2, 2)); pass_inst->find_port("O")->connect(n); const auto &p2 = chipdb->cell_mfvs.at(cell).at(p_name); int pass_cell = chipdb->loc_cell(Location(p2.first, 0)); *logs << "pass_cell = " << pass_cell << "\n"; extend(ds.placement, pass_inst, pass_cell); } void Promoter::make_routable(Net *n, int g) { Net *internal = nullptr; for (auto i = n->connections().begin(); i != n->connections().end();) { Port *p = *i; ++i; if (!p->is_input()) continue; if (routable(g, p)) continue; if (!internal) { internal = top->add_net(n); Instance *pass_inst = top->add_instance(models.lc); pass_inst->find_port("I0")->connect(n); pass_inst->find_port("I1")->connect(const0); pass_inst->find_port("I2")->connect(const0); pass_inst->find_port("I3")->connect(const0); pass_inst->set_param("LUT_INIT", BitVector(2, 2)); pass_inst->find_port("O")->connect(internal); } p->connect(internal); } } void Promoter::promote(bool do_promote) { std::vector nets; std::map net_idx; std::tie(nets, net_idx) = top->index_nets(); int n_nets = nets.size(); int n_global = 0; std::map gc_global; std::map gc_used; for (uint8_t gc : global_classes) { extend(gc_global, gc, 0); extend(gc_used, gc, 0); } std::vector> plls; for (const auto &p : ds.placement) { Instance *inst = p.first; int c = p.second; if (models.is_gb_io(inst)) { Port *out = inst->find_port("GLOBAL_BUFFER_OUTPUT"); if (out->connected()) { int g = chipdb->loc_pin_glb_num.at(chipdb->cell_location[c]); for (uint8_t gc : global_classes) { if (gc & (1 << g)) ++gc_used[gc]; } make_routable(out->connection(), g); } } else if (models.is_pllX(inst)) { plls.push_back(std::make_pair(inst, c)); Port *a = inst->find_port("PLLOUTGLOBAL"); if (!a) a = inst->find_port("PLLOUTGLOBALA"); assert(a); if (a->connected()) { const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_A"); Location loc(p2.first, std::stoi(p2.second)); int g = chipdb->loc_pin_glb_num.at(loc); for (uint8_t gc : global_classes) { if (gc & (1 << g)) ++gc_used[gc]; } make_routable(a->connection(), g); } Port *b = inst->find_port("PLLOUTGLOBALB"); if (b && b->connected()) { const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_B"); Location loc(p2.first, std::stoi(p2.second)); int g = chipdb->loc_pin_glb_num.at(loc); for (uint8_t gc : global_classes) { if (gc & (1 << g)) ++gc_used[gc]; } make_routable(b->connection(), g); } } } for (const auto &p : plls) { Instance *inst = p.first; int c = p.second; pll_pass_through(inst, c, "LOCK"); pll_pass_through(inst, c, "SDO"); } std::set boundary_nets = top->boundary_nets(d); std::set, std::greater>> promote_q; std::map net_gc; std::map net_driver; for (int i = 1; i < n_nets; ++i) // skip 0, nullptr { Net *n = nets[i]; if (contains(boundary_nets, n) || n->is_constant()) continue; std::map n_gc; for (uint8_t gc : global_classes) extend(n_gc, gc, 0); Port *driver = nullptr; for (Port *conn : n->connections()) { assert(!conn->is_bidir()); if (conn->is_output()) { assert(!driver); driver = conn; } int gc = port_gc(conn, false); if (gc) ++n_gc[gc]; } int max_gc = 0; int max_n = 0; for (const auto &p : n_gc) { if (p.second > max_n) { max_gc = p.first; max_n = p.second; } } if (driver && isa(driver->node()) && ((models.is_gbX(cast(driver->node())) && driver->name() == "GLOBAL_BUFFER_OUTPUT") || (models.is_pllX(cast(driver->node())) && (driver->name() == "PLLOUTGLOBAL" || driver->name() == "PLLOUTGLOBALA" || driver->name() == "PLLOUTGLOBALB")))) { Instance *gb_inst = cast(driver->node()); uint8_t gc = max_gc ? max_gc : gc_clk; ++n_global; ++gc_global[gc]; if (models.is_gbX(gb_inst)) extend(gb_inst_gc, gb_inst, gc); for (uint8_t gc2 : global_classes) { if ((gc2 & gc) == gc) ++gc_used[gc2]; } } else if (do_promote && driver && max_gc && max_n > 4) { extend(net_driver, i, driver); extend(net_gc, i, max_gc); promote_q.insert(std::make_pair(max_n, i)); } } int n_promoted = 0; std::map gc_promoted; for (int gc : global_classes) extend(gc_promoted, gc, 0); while(!promote_q.empty()) { std::pair p = *promote_q.begin(); promote_q.erase(promote_q.begin()); assert(promote_q.empty() || promote_q.begin()->first <= p.first); Net *n = nets[p.second]; uint8_t gc = net_gc.at(p.second); for (int gc2 : global_classes) { int k2 = 0; for (int i = 0; i < 8; ++i) { if (gc2 & (1 << i)) ++k2; } if ((gc2 & gc) == gc) { if (gc_used.at(gc2) >= k2) goto L; } } { ++n_promoted; ++gc_promoted[gc]; Instance *gb_inst = top->add_instance(models.gb); Net *t = top->add_net(n); int n_conn = 0; int n_conn_promoted = 0; for (auto i = n->connections().begin(); i != n->connections().end();) { Port *conn = *i; ++i; if (conn->is_output() || conn->is_bidir()) continue; ++n_conn; int conn_gc = port_gc(conn, true); if ((conn_gc & gc) == gc) { ++n_conn_promoted; conn->connect(t); } } gb_inst->find_port("USER_SIGNAL_TO_GLOBAL_BUFFER")->connect(n); gb_inst->find_port("GLOBAL_BUFFER_OUTPUT")->connect(t); ++n_global; ++gc_global[gc]; extend(gb_inst_gc, gb_inst, gc); for (uint8_t gc2 : global_classes) { if ((gc2 & gc) == gc) ++gc_used[gc2]; } *logs << " promoted " << n->name() << ", " << n_conn_promoted << " / " << n_conn << "\n"; } L:; } *logs << " promoted " << n_promoted << " nets\n"; for (const auto &p : gc_promoted) { if (p.second) *logs << " " << p.second << " " << global_class_name(p.first) << "\n"; } *logs << " " << n_global << " globals\n"; for (const auto &p : gc_global) { if (p.second) *logs << " " << p.second << " " << global_class_name(p.first) << "\n"; } d->prune(); } void promote_globals(DesignState &ds, bool do_promote) { Promoter promoter(ds); promoter.promote(do_promote); } arachne-pnr-0~20150927gitefdb026/src/global.hh000066400000000000000000000023011260207143000205550ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_GLOBAL_HH #define PNR_GLOBAL_HH class DesignState; #include "util.hh" static const uint8_t gc_clk = 0xff; static const uint8_t gc_cen = 0xaa; // 1357 static const uint8_t gc_rclke = 0x8a; // 137, 5 missing static const uint8_t gc_sr = 0x55; // 0246 static const uint8_t gc_re = 0x54; // 246, 0 missing static const uint8_t gc_wclke = gc_cen; static const uint8_t gc_we = gc_sr; extern const char *global_class_name(uint8_t gc); extern std::vector global_classes; void promote_globals(DesignState &ds, bool do_promote); #endif arachne-pnr-0~20150927gitefdb026/src/hashmap.hh000066400000000000000000000100771260207143000207470ustar00rootroot00000000000000 #ifndef PNR_HASHMAP_HH #define PNR_HASHMAP_HH #include #include template, typename KeyEqual = std::equal_to> class HashMap { using underlying_t = std::unordered_map; underlying_t m; public: using key_type = typename underlying_t::key_type; using mapped_type = typename underlying_t::mapped_type; using value_type = typename underlying_t::value_type; using size_type = typename underlying_t::size_type; using difference_type = typename underlying_t::difference_type; using hasher = typename underlying_t::hasher; using key_equal = typename underlying_t::key_equal; using allocator_type = typename underlying_t::allocator_type; using reference = typename underlying_t::reference; using const_reference = typename underlying_t::const_reference; using pointer = typename underlying_t::pointer; using const_pointer = typename underlying_t::const_pointer; class const_iterator { friend class HashMap; typename underlying_t::const_iterator i; public: const_iterator() {} const_iterator(typename underlying_t::const_iterator i_) : i(i_) {} bool operator==(const const_iterator &that) { return i == that.i; } bool operator!=(const const_iterator &that) { return i != that.i; } // hash table: cannot modify keys const value_type &operator*() { return *i; } const value_type &operator*() const { return *i; } const value_type *operator->() { return i.operator->(); } const value_type *operator->() const { return i.operator->(); } // not incrementable }; using iterator = const_iterator; public: HashMap() {} iterator begin() { return iterator(m.begin()); } const_iterator begin() const { return const_iterator(m.begin()); } const_iterator cbegin() const { return const_iterator(m.cbegin()); } iterator end() { return iterator(m.end()); } const_iterator end() const { return const_iterator(m.end()); } const_iterator cend() const { return const_iterator(m.cend()); } bool empty() const { return m.empty(); } size_type size() const { return m.size(); } size_type max_size() const { return m.max_size(); } iterator erase(const_iterator pos) { return iterator(m.erase(pos.i)); } // no first, last: can't iterate size_type erase(const key_type &key) { return m.erase(key); } void clear() { return m.clear(); } std::pair insert(const value_type &value) { const auto &p = m.insert(value); return std::make_pair(iterator(p.first), p.second); } template std::pair insert(P &&value) { const auto &p = m.insert(value); return std::make_pair(iterator(p.first), p.second); } std::pair insert(value_type &&value) { const auto &p = m.insert(value); return std::make_pair(iterator(p.first), p.second); } iterator insert(const_iterator hint, const value_type &value) { return iterator(m.insert(hint, value)); } template iterator insert(const_iterator hint, P &&value) { return iterator(m.insert(hint, value)); } iterator insert(const_iterator hint, value_type &&value) { return iterator(m.insert(hint, value)); } template void insert(InputIt first, InputIt last) { m.insert(first, last); } void insert(std::initializer_list ilist) { return m.insert(ilist); } T &operator[](const Key &key) { return m[key]; } T &operator[](Key &&key) { return m[key]; } iterator find(const Key &key) { return iterator(m.find(key)); } const_iterator find(const Key &key) const { return const_iterator(m.find(key)); } T &at(const Key &key) { return m.at(key); } const T &at(const Key &key) const { return m.at(key); } size_type count(const key_type &key) const { return m.key(); } bool operator ==(const HashMap &hs) { return m == hs.m; } bool operator !=(const HashMap &hs) { return m != hs.m; } underlying_t &underlying() { return m; } const underlying_t &underlying() const { return m; } }; #endif arachne-pnr-0~20150927gitefdb026/src/hashset.hh000066400000000000000000000065741260207143000207740ustar00rootroot00000000000000#ifndef PNR_HASHSET_HH #define PNR_HASHSET_HH #include #include template struct Hash; template, typename KeyEqual = std::equal_to> class HashSet { using underlying_t = std::unordered_set; underlying_t s; public: using key_type = typename underlying_t::key_type; using value_type = typename underlying_t::value_type; using size_type = typename underlying_t::size_type; using difference_type = typename underlying_t::difference_type; using hasher = typename underlying_t::hasher; using key_equal = typename underlying_t::key_equal; using allocator_type = typename underlying_t::allocator_type; using reference = typename underlying_t::reference; using const_reference = typename underlying_t::const_reference; using pointer = typename underlying_t::pointer; using const_pointer = typename underlying_t::const_pointer; class const_iterator { friend class HashSet; typename underlying_t::const_iterator i; public: const_iterator() {} const_iterator(typename underlying_t::const_iterator i_) : i(i_) {} bool operator==(const const_iterator &that) { return i == that.i; } bool operator!=(const const_iterator &that) { return i != that.i; } // hash table: cannot modify keys const value_type &operator*() { return *i; } const value_type &operator*() const { return *i; } const value_type *operator->() { return operator->(i); } const value_type *operator->() const { return operator->(i); } // not incrementable }; using iterator = const_iterator; public: HashSet() {} iterator begin() { return iterator(s.begin()); } const_iterator begin() const { return const_iterator(s.begin()); } const_iterator cbegin() const { return const_iterator(s.cbegin()); } iterator end() { return iterator(s.end()); } const_iterator end() const { return const_iterator(s.end()); } const_iterator cend() const { return const_iterator(s.cend()); } bool empty() const { return s.empty(); } size_type size() const { return s.size(); } size_type max_size() const { return s.max_size(); } iterator erase(const_iterator pos) { return iterator(s.erase(pos.i)); } // no first, last: can't iterate size_type erase(const key_type &key) { return s.erase(key); } void clear() { return s.clear(); } std::pair insert(const value_type &value) { const auto &p = s.insert(value); return std::make_pair(iterator(p.first), p.second); } std::pair insert(value_type &&value) { const auto &p = s.insert(value); return std::make_pair(iterator(p.first), p.second); } iterator insert(const_iterator hint, const value_type &value) { return iterator(s.insert(hint, value)); } iterator insert(const_iterator hint, value_type &&value) { return iterator(s.insert(hint, value)); } template void insert(InputIt first, InputIt last) { s.insert(first, last); } void insert(std::initializer_list ilist) { return s.insert(ilist); } size_type count(const key_type &key) const { return s.key(); } bool operator ==(const HashSet &hs) { return s == hs.s; } bool operator !=(const HashSet &hs) { return s != hs.s; } underlying_t &underlying() { return s; } const underlying_t &underlying() const { return s; } }; #endif arachne-pnr-0~20150927gitefdb026/src/io.cc000066400000000000000000000056171260207143000177270ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "netlist.hh" #include "io.hh" #include "casting.hh" #include void instantiate_io(Design *d) { Models models(d); Model *top = d->top(); Model *io_model = d->find_model("SB_IO"); Model *tbuf_model = d->find_model("$_TBUF_"); for (auto i : top->ports()) { Port *p = i.second; Port *q = p->connection_other_port(); if (q && isa(q->node()) && ((models.is_ioX(cast(q->node())) && q->name() == "PACKAGE_PIN") || (models.is_pllX(cast(q->node())) && q->name() == "PACKAGEPIN"))) continue; #ifndef NDEBUG bool matched = false; #endif Net *n = p->connection(); if (n && n->name() == p->name()) { #ifndef NDEBUG matched = true; #endif top->rename_net(n, n->name()); } Net *t = top->add_net(p->name()); assert(t); p->connect(t); assert(!matched || t->name() == p->name()); Instance *io_inst = top->add_instance(io_model); io_inst->find_port("PACKAGE_PIN")->connect(t); switch(p->direction()) { case Direction::IN: { io_inst->find_port("D_IN_0")->connect(n); io_inst->set_param("PIN_TYPE", BitVector(6, 1)); // 000001 } break; case Direction::OUT: case Direction::INOUT: { if (q && isa(q->node()) && cast(q->node())->instance_of() == tbuf_model && q->name() == "Y") { Instance *tbuf = cast(q->node()); io_inst->find_port("D_OUT_0")->connect(tbuf->find_port("A")->connection()); io_inst->find_port("D_IN_0")->connect(tbuf->find_port("Y")->connection()); io_inst->find_port("OUTPUT_ENABLE")->connect(tbuf->find_port("E")->connection()); io_inst->set_param("PIN_TYPE", BitVector(6, 0x29)); // 101001 tbuf->find_port("A")->disconnect(); tbuf->find_port("E")->disconnect(); tbuf->find_port("Y")->disconnect(); tbuf->remove(); delete tbuf; } else { if (p->direction() == Direction::INOUT) fatal(fmt("bidirectional port `" << p->name() << "' must be driven by tri-state buffer")); io_inst->find_port("D_OUT_0")->connect(n); io_inst->set_param("PIN_TYPE", BitVector(6, 0x19)); // 011001 } } break; default: abort(); } } d->prune(); } arachne-pnr-0~20150927gitefdb026/src/io.hh000066400000000000000000000013701260207143000177310ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_IO_HH #define PNR_IO_HH class Design; extern void instantiate_io(Design *d); #endif arachne-pnr-0~20150927gitefdb026/src/line_parser.cc000066400000000000000000000045651260207143000216240ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "line_parser.hh" std::ostream & operator<<(std::ostream &s, const LexicalPosition &lp) { if (lp.internal) s << ""; else s << lp.file << ":" << lp.line; return s; } void LexicalPosition::fatal(const std::string &msg) const { std::cerr << *this << ": fatal error: " << msg << "\n"; exit(EXIT_FAILURE); } void LexicalPosition::warning(const std::string &msg) const { std::cerr << *this << ": warning: " << msg << "\n"; } void LineParser::split_line() { words.clear(); std::string t; bool instr = false, quote = false; for (char ch : line) { if (instr) { t.push_back(ch); if (quote) quote = false; else if (ch == '\\') quote = true; else if (ch == '"') { words.push_back(unescape(t)); t.clear(); instr = false; } } else if (isspace(ch)) { if (!t.empty()) { words.push_back(t); t.clear(); } } else { t.push_back(ch); if (ch == '"') instr = true; } } if (instr) fatal("unterminated string constant"); else if (!t.empty()) { words.push_back(t); t.clear(); } } void LineParser::read_line() { words.clear(); do { line.clear(); if (s.eof()) return; lp.next_line(); std::getline(s, line); L: std::size_t p = line.find('#'); if (p != std::string::npos) line.resize(p); else if (!line.empty() && line.back() == '\\') { if (s.eof()) fatal("unexpected backslash before eof"); // drop backslash line.pop_back(); std::string line2; lp.next_line(); std::getline(s, line2); line.append(line2); goto L; } split_line(); } while (words.empty()); } arachne-pnr-0~20150927gitefdb026/src/line_parser.hh000066400000000000000000000033421260207143000216260ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_LINE_PARSER_HH #define PNR_LINE_PARSER_HH #include #include #include #include class LexicalPosition { public: friend std::ostream &operator<<(std::ostream &s, const LexicalPosition &lp); bool internal; std::string file; int line; public: LexicalPosition() : internal(true), line(0) {} LexicalPosition(const std::string &f) : internal(false), file(f), line(0) {} LexicalPosition(const std::string &f, int n) : internal(false), file(f), line(n) {} void next_line() { ++line; } void fatal(const std::string &msg) const; void warning(const std::string &msg) const; }; class LineParser { std::istream &s; protected: LexicalPosition lp; std::string line; std::vector words; void fatal(const std::string &msg) const { lp.fatal(msg); } void warning(const std::string &msg) const { lp.warning(msg); } bool eof() { return s.eof(); } void split_line(); void read_line(); LineParser(const std::string &f, std::istream &s_) : s(s_), lp(f) {} }; #endif arachne-pnr-0~20150927gitefdb026/src/location.cc000066400000000000000000000014371260207143000211240ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "location.hh" std::ostream & operator<<(std::ostream &s, const Location &loc) { return s << loc.m_tile << "/" << loc.m_pos; } arachne-pnr-0~20150927gitefdb026/src/location.hh000066400000000000000000000042041260207143000211310ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_LOCATION_HH #define PNR_LOCATION_HH #include "util.hh" #include "bstream.hh" #include class Location { friend std::ostream &operator<<(std::ostream &s, const Location &loc); friend obstream &operator<<(obstream &obs, const Location &loc); friend ibstream &operator>>(ibstream &ibs, Location &loc); template friend struct std::hash; // pos is 0-7 for logic tiles, 0-4 (io_1, io_2, gb, pll) for io tiles int m_tile, m_pos; public: int tile() const { return m_tile; } int pos() const { return m_pos; } Location() : m_tile(0), m_pos(0) {} Location(int tile_, int pos_) : m_tile(tile_), m_pos(pos_) {} bool operator==(const Location &loc2) const { return (m_tile == loc2.m_tile && m_pos == loc2.m_pos); } bool operator!=(const Location &loc2) const { return !operator==(loc2); } bool operator<(const Location &loc2) const { if (m_tile < loc2.m_tile) return true; if (m_tile > loc2.m_tile) return false; return m_pos < loc2.m_pos; } }; inline obstream &operator<<(obstream &obs, const Location &loc) { return obs << loc.m_tile << loc.m_pos; } inline ibstream &operator>>(ibstream &ibs, Location &loc) { return ibs >> loc.m_tile >> loc.m_pos; } namespace std { template<> struct hash { public: size_t operator()(const Location &loc) const { std::hash hasher; size_t h = hasher(loc.m_tile); return hash_combine(h, hasher(loc.m_pos)); } }; } #endif arachne-pnr-0~20150927gitefdb026/src/netlist.cc000066400000000000000000001051331260207143000207740ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "netlist.hh" #include "casting.hh" #include #include #include #include static void write_string_escaped(std::ostream &s, const std::string &str) { s << '"'; for (char ch : str) { if (ch == '"' || ch == '\\') s << '\\' << ch; else if (isprint(ch)) s << ch; else if (ch == '\n') s << "\n"; else if (ch == '\t') s << "\t"; else s << fmt(std::oct << std::setw(3) << std::setfill('0') << (int)ch); } s << '"'; } std::ostream & operator<<(std::ostream &s, const Const &c) { if (c.m_is_bits) { for (int i = c.m_bitval.size() - 1; i >= 0; --i) s << (c.m_bitval[i] ? '1' : '0'); } else write_string_escaped(s, c.m_strval); return s; } Direction opposite_direction(Direction d) { switch(d) { case Direction::IN: return Direction::OUT; case Direction::OUT: return Direction::IN; case Direction::INOUT: return Direction::INOUT; default: abort(); return Direction::IN; } } int Identified::id_counter = 0; void Const::write_verilog(std::ostream &s) const { if (m_is_bits) { s << m_bitval.size() << "'b"; for (int i = m_bitval.size() - 1; i >= 0; --i) s << (m_bitval[i] ? '1' : '0'); } else write_string_escaped(s, m_strval); } void Net::replace(Net *new_n) { assert(new_n != this); for (auto i = m_connections.begin(); i != m_connections.end();) { Port *p = *i; ++i; p->connect(new_n); } assert(m_connections.empty()); } void Port::disconnect() { if (m_connection) { m_connection->m_connections.erase(this); m_connection = nullptr; } } void Port::connect(Net *n) { if (m_connection) disconnect(); assert(!m_connection); m_connection = n; if (n) n->m_connections.insert(this); } Port * Port::connection_other_port() const { Net *n = connection(); if (!n || n->connections().size() != 2) return nullptr; auto i = n->connections().begin(); if (*i == this) ++i; return *i; } bool Port::is_output() const { assert(m_node && (isa(m_node) || isa(m_node))); return (isa(m_node) ? m_dir == Direction::OUT : m_dir == Direction::IN); // model } bool Port::is_input() const { assert(m_node && (isa(m_node) || isa(m_node))); return (isa(m_node) ? m_dir == Direction::IN : m_dir == Direction::OUT); // model } Node::~Node() { for (Port *p : m_ordered_ports) { p->disconnect(); delete p; } m_ports.clear(); m_ordered_ports.clear(); } Port * Node::add_port(Port *t) { Port *new_port = new Port(this, t->name(), t->direction(), t->undriven()); extend(m_ports, new_port->name(), new_port); m_ordered_ports.push_back(new_port); return new_port; } Port * Node::add_port(const std::string &n, Direction dir) { Port *new_port = new Port(this, n, dir); extend(m_ports, new_port->name(), new_port); m_ordered_ports.push_back(new_port); return new_port; } Port * Node::add_port(const std::string &n, Direction dir, Value u) { Port *new_port = new Port(this, n, dir, u); extend(m_ports, new_port->name(), new_port); m_ordered_ports.push_back(new_port); return new_port; } Port * Node::find_port(const std::string &n) { return lookup_or_default(m_ports, n, nullptr); } Instance::Instance(Model *parent_, Model *inst_of) : Node(Node::Kind::instance), m_parent(parent_), m_instance_of(inst_of) { for (Port *p : m_instance_of->m_ordered_ports) add_port(p); } void Instance::merge_attrs(const Instance *inst) { auto i = inst->m_attrs.find("src"); if (i != inst->m_attrs.end()) { auto j = m_attrs.find("src"); if (j != m_attrs.end()) j->second = Const(j->second.as_string() + "|" + i->second.as_string()); else m_attrs.insert(*i); } } bool Instance::has_param(const std::string &pn) const { return (contains_key(m_params, pn) || m_instance_of->has_param(pn)); } const Const & Instance::get_param(const std::string &pn) const { auto i = m_params.find(pn); if (i == m_params.end()) return m_instance_of->get_param(pn); // default else return i->second; } void Instance::remove() { m_parent->m_instances.erase(this); for (const auto &p : ports()) p.second->disconnect(); } void Instance::write_blif(std::ostream &s, const std::map &net_name) const { s << ".gate " << m_instance_of->name(); for (Port *p : m_ordered_ports) { s << " " << p->name() << "="; if (p->connected()) s << net_name.at(p->connection()); } s << "\n"; for (const auto &p : m_attrs) s << ".attr " << p.first << " " << p.second << "\n"; for (const auto &p : m_params) s << ".param " << p.first << " " << p.second << "\n"; } void Instance::dump() const { *logs << ".gate " << m_instance_of->name(); for (Port *p : m_ordered_ports) { *logs << " " << p->name() << "="; if (p->connected()) *logs << p->connection()->name(); } *logs << " # " << this << "\n"; for (const auto &p : m_attrs) *logs << ".attr " << p.first << " " << p.second << "\n"; for (const auto &p : m_params) *logs << ".param " << p.first << " " << p.second << "\n"; } static void write_verilog_name(std::ostream &s, const std::string &name) { bool quote = false; for (char ch : name) { if (! (isalnum(ch) || ch == '_' || ch == '$')) { quote = true; break; } } if (quote) s << '\\'; s << name; if (quote) s << ' '; } void Instance::write_verilog(std::ostream &s, const std::map &net_name, const std::string &inst_name) const { if (!m_attrs.empty()) { s << " (* "; bool first = true; for (const auto &p : m_attrs) { if (first) first = false; else s << ", "; s << p.first << "="; p.second.write_verilog(s); } s << " *)\n"; } s << " "; write_verilog_name(s, m_instance_of->name()); if (!m_params.empty()) { s << " #("; bool first = true; for (const auto &p : m_params) { if (first) first = false; else s << ", "; s << "\n ."; write_verilog_name(s, p.first); s << "("; p.second.write_verilog(s); s << ")"; } s << "\n ) "; } write_verilog_name(s, inst_name); s << " ("; bool first = true; for (Port *p : m_ordered_ports) { Net *conn = p->connection(); if (conn) { if (first) first = false; else s << ","; s << "\n ."; write_verilog_name(s, p->name()); s << "("; write_verilog_name(s, conn->name()); s << ")"; } } s << "\n );\n"; } int Model::counter = 0; Model::Model(Design *d, const std::string &n) : Node(Node::Kind::model), m_name(n) { extend(d->m_models, n, this); } Model::~Model() { for (Instance *inst : m_instances) delete inst; m_instances.clear(); // disconnect ports before deleting nets for (Port *p : m_ordered_ports) p->disconnect(); for (const auto &p : m_nets) delete p.second; m_nets.clear(); } Net * Model::find_net(const std::string &n) { return lookup_or_default(m_nets, n, (Net *)nullptr); } Net * Model::find_or_add_net(const std::string &n) { assert(!n.empty()); return lookup_or_create(m_nets, n, [&n]() { return new Net(n); }); } Net * Model::add_net() { L: std::string net_name = fmt("$temp$" << counter); ++counter; if (contains_key(m_nets, net_name)) goto L; Net *new_n = new Net(net_name); extend(m_nets, net_name, new_n); return new_n; } Net * Model::add_net(const std::string &orig) { int i = 2; std::string net_name = orig; L: if (contains_key(m_nets, net_name)) { net_name = fmt(orig << "$" << i); ++i; goto L; } Net *new_n = new Net(net_name); extend(m_nets, net_name, new_n); return new_n; } void Model::remove_net(Net *n) { assert(n->connections().empty()); m_nets.erase(n->name()); } Instance * Model::add_instance(Model *inst_of) { Instance *new_inst = new Instance(this, inst_of); m_instances.insert(new_inst); return new_inst; } std::set Model::boundary_nets(const Design *d) const { Models models(d); std::set bnets; for (Port *p : m_ordered_ports) { Net *n = p->connection(); if (n) { Port *q = p->connection_other_port(); if (q && isa(q->node()) && ((models.is_ioX(cast(q->node())) && q->name() == "PACKAGE_PIN") || (models.is_pllX(cast(q->node())) && q->name() == "PACKAGEPIN"))) extend(bnets, n); } } return bnets; } std::pair, std::map> Model::index_nets() const { int n_nets = 0; std::vector vnets; std::map net_idx; vnets.push_back(nullptr); ++n_nets; for (const auto &p : m_nets) { Net *n = p.second; vnets.push_back(n); extend(net_idx, n, n_nets); ++n_nets; } return std::make_pair(vnets, net_idx); } std::pair, std::map> Model::index_internal_nets(const Design *d) const { std::set bnets = boundary_nets(d); std::vector vnets; std::map net_idx; int n_nets = 0; for (const auto &p : m_nets) { Net *n = p.second; if (contains(bnets, n)) continue; vnets.push_back(n); extend(net_idx, n, n_nets); ++n_nets; } return std::make_pair(vnets, net_idx); } std::pair, std::map> Model::index_instances() const { BasedVector gates; std::map gate_idx; int n_gates = 0; for (Instance *inst : m_instances) { ++n_gates; gates.push_back(inst); extend(gate_idx, inst, n_gates); } return std::make_pair(gates, gate_idx); } void Model::prune() { for (auto i = m_nets.begin(); i != m_nets.end();) { Net *n = i->second; auto t = i; ++i; int n_distinct = n->connections().size(); bool driver = false, input = false; if (n->is_constant()) { driver = true; ++n_distinct; } for (Port *p : n->connections()) { if (p->is_input() || p->is_bidir()) input = true; if (p->is_output() || p->is_bidir()) driver = true; if (input && driver) break; } if (input && driver && n_distinct > 1) continue; // remove n for (auto j = n->connections().begin(); j != n->connections().end();) { Port *p = *j; ++j; p->disconnect(); } m_nets.erase(t); delete n; } } void Model::rename_net(Net *n, const std::string &new_name) { const std::string &old_name = n->name(); int i = 2; std::string net_name = new_name; L: if (contains(m_nets, net_name) || net_name == old_name) { net_name = fmt(new_name << "$" << i); ++i; goto L; } m_nets.erase(old_name); n->m_name = net_name; extend(m_nets, net_name, n); } #ifndef NDEBUG void Model::check(const Design *d) const { Models models(d); for (Port *p : m_ordered_ports) { if (p->is_bidir()) { Net *n = p->connection(); if (n) { Port *q = p->connection_other_port(); assert (q && isa(q->node()) && ((models.is_ioX(cast(q->node())) && q->name() == "PACKAGE_PIN") || (models.is_pllX(cast(q->node())) && q->name() == "PACKAGEPIN"))); } } } std::set bnets = boundary_nets(d); for (const auto &p : m_nets) { Net *n = p.second; assert(p.first == n->name()); assert(!n->connections().empty()); if (contains(bnets, n)) continue; int n_drivers = 0; bool input = false; if (n->is_constant()) ++n_drivers; for (Port *p2 : n->connections()) { assert(!p2->is_bidir()); if (p2->is_input()) input = true; if (p2->is_output()) ++n_drivers; } assert(n_drivers == 1 && input); } } #endif std::pair, std::set> Model::shared_names() const { std::set names; std::map net_name; std::set is_port; for (Port *p : m_ordered_ports) { Net *n = p->connection(); extend(names, p->name()); if (n && n->name() == p->name()) { extend(net_name, n, p->name()); extend(is_port, n); } } for (const auto &p : m_nets) { if (contains(is_port, p.second)) continue; int i = 2; std::string shared_net_name = p.first; L: if (contains(names, shared_net_name)) { shared_net_name = fmt(p.first << "$" << i); ++i; goto L; } extend(names, shared_net_name); extend(net_name, p.second, shared_net_name); } return std::make_pair(net_name, is_port); } void Model::write_blif(std::ostream &s) const { s << ".model " << m_name << "\n"; s << ".inputs"; for (Port *p : m_ordered_ports) { if (p->direction() == Direction::IN || p->direction() == Direction::INOUT) s << " " << p->name(); } s << "\n"; s << ".outputs"; for (Port *p : m_ordered_ports) { if (p->direction() == Direction::OUT || p->direction() == Direction::INOUT) s << " " << p->name(); } s << "\n"; std::map net_name; std::set is_port; std::tie(net_name, is_port) = shared_names(); for (const auto &p : net_name) { if (p.second != p.first->name()) s << "# " << p.first->name() << " -> " << p.second << "\n"; } for (const auto &p : m_nets) { if (p.second->is_constant()) { s << ".names " << p.first << "\n"; if (p.second->constant() == Value::ONE) s << "1\n"; else assert(p.second->constant() == Value::ZERO); } } for (auto i : m_instances) i->write_blif(s, net_name); for (Port *p : m_ordered_ports) { Net *n = p->connection(); if (n && n->name() != p->name()) { if (p->is_input()) s << ".names " << net_name.at(n) << " " << p->name() << "\n"; else { assert(p->is_output()); s << ".names " << p->name() << " " << net_name.at(n) << "\n"; } s << "1 1\n"; } } s << ".end\n"; } void Model::write_verilog(std::ostream &s) const { s << "module "; write_verilog_name(s, m_name); s << "("; bool first = true; for (Port *p : m_ordered_ports) { if (first) first = false; else s << ", "; switch(p->direction()) { case Direction::IN: s << "input "; break; case Direction::OUT: s << "output "; break; case Direction::INOUT: s << "inout "; break; } write_verilog_name(s, p->name()); } s << ");\n"; std::map net_name; std::set is_port; std::tie(net_name, is_port) = shared_names(); for (const auto &p : net_name) { if (p.second != p.first->name()) s << " // " << p.first->name() << " -> " << p.second << "\n"; } for (const auto &p : m_nets) { if (contains(is_port, p.second)) continue; s << " wire "; write_verilog_name(s, net_name.at(p.second)); if (p.second->is_constant()) { s << " = "; if (p.second->constant() == Value::ONE) s << "1"; else { assert(p.second->constant() == Value::ZERO); s << "0"; } } s << ";\n"; } for (Port *p : m_ordered_ports) { Net *n = p->connection(); if (n && n->name() != p->name()) { if (p->is_input()) { s << " assign "; write_verilog_name(s, net_name.at(n)); s << " = " << p->name() << ";\n"; } else { assert(p->is_output()); s << " assign " << p->name() << " = "; write_verilog_name(s, net_name.at(n)); s << ";\n"; } } else assert(contains(is_port, n)); } int k = 0; for (Instance *inst : m_instances) { inst->write_verilog(s, net_name, fmt("$inst" << k)); ++k; } s << "endmodule\n"; } void Design::set_top(Model *t) { assert(m_top == nullptr); m_top = t; } Design::Design() : m_top(nullptr) { } Design::~Design() { for (const auto &p : m_models) delete p.second; m_models.clear(); } void Design::create_standard_models() { Model *lc = new Model(this, "ICESTORM_LC"); lc->add_port("I0", Direction::IN, Value::ZERO); lc->add_port("I1", Direction::IN, Value::ZERO); lc->add_port("I2", Direction::IN, Value::ZERO); lc->add_port("I3", Direction::IN, Value::ZERO); lc->add_port("CIN", Direction::IN, Value::ZERO); lc->add_port("CLK", Direction::IN, Value::ZERO); lc->add_port("CEN", Direction::IN, Value::ONE); lc->add_port("SR", Direction::IN, Value::ZERO); lc->add_port("O", Direction::OUT); lc->add_port("COUT", Direction::OUT); lc->set_param("LUT_INIT", BitVector(1, 0)); lc->set_param("NEG_CLK", BitVector(1, 0)); lc->set_param("CARRY_ENABLE", BitVector(1, 0)); lc->set_param("DFF_ENABLE", BitVector(1, 0)); lc->set_param("SET_NORESET", BitVector(1, 0)); lc->set_param("SET_ASYNC", BitVector(1, 0)); lc->set_param("ASYNC_SR", BitVector(1, 0)); Model *io = new Model(this, "SB_IO"); io->add_port("PACKAGE_PIN", Direction::INOUT); io->add_port("LATCH_INPUT_VALUE", Direction::IN, Value::ZERO); io->add_port("CLOCK_ENABLE", Direction::IN, Value::ONE); io->add_port("INPUT_CLK", Direction::IN, Value::ZERO); io->add_port("OUTPUT_CLK", Direction::IN, Value::ZERO); io->add_port("OUTPUT_ENABLE", Direction::IN, Value::ZERO); io->add_port("D_OUT_0", Direction::IN, Value::ZERO); io->add_port("D_OUT_1", Direction::IN, Value::ZERO); io->add_port("D_IN_0", Direction::OUT, Value::ZERO); io->add_port("D_IN_1", Direction::OUT, Value::ZERO); io->set_param("PIN_TYPE", BitVector(6, 0)); // 000000 io->set_param("PULLUP", BitVector(1, 0)); // default NO pullup io->set_param("NEG_TRIGGER", BitVector(1, 0)); io->set_param("IO_STANDARD", "SB_LVCMOS"); Model *gb = new Model(this, "SB_GB"); gb->add_port("USER_SIGNAL_TO_GLOBAL_BUFFER", Direction::IN); gb->add_port("GLOBAL_BUFFER_OUTPUT", Direction::OUT); Model *gb_io = new Model(this, "SB_GB_IO"); gb_io->add_port("PACKAGE_PIN", Direction::INOUT); gb_io->add_port("GLOBAL_BUFFER_OUTPUT", Direction::OUT); gb_io->add_port("LATCH_INPUT_VALUE", Direction::IN, Value::ZERO); gb_io->add_port("CLOCK_ENABLE", Direction::IN, Value::ONE); gb_io->add_port("INPUT_CLK", Direction::IN, Value::ZERO); gb_io->add_port("OUTPUT_CLK", Direction::IN, Value::ZERO); gb_io->add_port("OUTPUT_ENABLE", Direction::IN, Value::ZERO); gb_io->add_port("D_OUT_0", Direction::IN, Value::ZERO); gb_io->add_port("D_OUT_1", Direction::IN, Value::ZERO); gb_io->add_port("D_IN_0", Direction::OUT, Value::ZERO); gb_io->add_port("D_IN_1", Direction::OUT, Value::ZERO); gb_io->set_param("PIN_TYPE", BitVector(6, 0)); // 000000 gb_io->set_param("PULLUP", BitVector(1, 0)); // default NO pullup gb_io->set_param("NEG_TRIGGER", BitVector(1, 0)); gb_io->set_param("IO_STANDARD", "SB_LVCMOS"); Model *lut = new Model(this, "SB_LUT4"); lut->add_port("O", Direction::OUT); lut->add_port("I0", Direction::IN, Value::ZERO); lut->add_port("I1", Direction::IN, Value::ZERO); lut->add_port("I2", Direction::IN, Value::ZERO); lut->add_port("I3", Direction::IN, Value::ZERO); lut->set_param("LUT_INIT", BitVector(1, 0)); Model *carry = new Model(this, "SB_CARRY"); carry->add_port("CO", Direction::OUT); carry->add_port("I0", Direction::IN, Value::ZERO); carry->add_port("I1", Direction::IN, Value::ZERO); carry->add_port("CI", Direction::IN, Value::ZERO); for (int neg_clk = 0; neg_clk <= 1; ++neg_clk) for (int cen = 0; cen <= 1; ++cen) for (int sr = 0; sr <= 4; ++sr) { std::string name = "SB_DFF"; if (neg_clk) name.push_back('N'); if (cen) name.push_back('E'); switch(sr) { case 0: break; case 1: name.append("SR"); break; case 2: name.append("R"); break; case 3: name.append("SS"); break; case 4: name.append("S"); break; default: abort(); } Model *dff = new Model(this, name); dff->add_port("Q", Direction::OUT); dff->add_port("C", Direction::IN, Value::ZERO); if (cen) dff->add_port("E", Direction::IN, Value::ONE); switch(sr) { case 0: break; case 1: case 2: dff->add_port("R", Direction::IN, Value::ZERO); break; case 3: case 4: dff->add_port("S", Direction::IN, Value::ZERO); break; default: abort(); } dff->add_port("D", Direction::IN, Value::ZERO); } for (int nr = 0; nr <= 1; ++nr) for (int nw = 0; nw <= 1; ++nw) { std::string name = "SB_RAM40_4K"; if (nr) name.append("NR"); if (nw) name.append("NW"); Model *bram = new Model(this, name); for (int i = 0; i <= 15; ++i) bram->add_port(fmt("RDATA[" << i << "]"), Direction::OUT); for (int i = 0; i <= 10; ++i) bram->add_port(fmt("RADDR[" << i << "]"), Direction::IN, Value::ZERO); for (int i = 0; i <= 10; ++i) bram->add_port(fmt("WADDR[" << i << "]"), Direction::IN, Value::ZERO); for (int i = 0; i <= 15; ++i) bram->add_port(fmt("MASK[" << i << "]"), Direction::IN, Value::ZERO); for (int i = 0; i <= 15; ++i) bram->add_port(fmt("WDATA[" << i << "]"), Direction::IN, Value::ZERO); bram->add_port("RCLKE", Direction::IN, Value::ONE); if (nr) bram->add_port("RCLKN", Direction::IN, Value::ZERO); else bram->add_port("RCLK", Direction::IN, Value::ZERO); bram->add_port("RE", Direction::IN, Value::ZERO); bram->add_port("WCLKE", Direction::IN, Value::ONE); if (nw) bram->add_port("WCLKN", Direction::IN, Value::ZERO); else bram->add_port("WCLK", Direction::IN, Value::ZERO); bram->add_port("WE", Direction::IN, Value::ZERO); for (int i = 0; i <= 15; ++i) bram->set_param(fmt("INIT_" << hexdigit(i, 'A')), BitVector(256, 0)); bram->set_param("READ_MODE", BitVector(2, 0)); bram->set_param("WRITE_MODE", BitVector(2, 0)); } Model *pll_core = new Model(this, "SB_PLL40_CORE"); pll_core->add_port("REFERENCECLK", Direction::IN, Value::ZERO); pll_core->add_port("RESETB", Direction::IN, Value::ZERO); pll_core->add_port("BYPASS", Direction::IN, Value::ZERO); pll_core->add_port("EXTFEEDBACK", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[0]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[1]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[2]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[3]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[4]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[5]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[6]", Direction::IN, Value::ZERO); pll_core->add_port("DYNAMICDELAY[7]", Direction::IN, Value::ZERO); pll_core->add_port("LATCHINPUTVALUE", Direction::IN, Value::ZERO); pll_core->add_port("SCLK", Direction::IN, Value::ZERO); pll_core->add_port("SDI", Direction::IN, Value::ZERO); pll_core->add_port("SDO", Direction::IN, Value::ZERO); pll_core->add_port("LOCK", Direction::OUT); pll_core->add_port("PLLOUTGLOBAL", Direction::OUT); pll_core->add_port("PLLOUTCORE", Direction::OUT); pll_core->set_param("FEEDBACK_PATH", "SIMPLE"); pll_core->set_param("DELAY_ADJUSTMENT_MODE_FEEDBACK", "FIXED"); pll_core->set_param("FDA_FEEDBACK", BitVector(4, 0)); pll_core->set_param("DELAY_ADJUSTMENT_MODE_RELATIVE", "FIXED"); pll_core->set_param("FDA_RELATIVE", BitVector(4, 0)); pll_core->set_param("SHIFTREG_DIV_MODE", BitVector(1, 0)); pll_core->set_param("PLLOUT_SELECT", "GENCLK"); pll_core->set_param("DIVR", BitVector(4, 0)); pll_core->set_param("DIVF", BitVector(7, 0)); pll_core->set_param("DIVQ", BitVector(3, 0)); pll_core->set_param("FILTER_RANGE", BitVector(3, 0)); pll_core->set_param("EXTERNAL_DIVIDE_FACTOR", BitVector(32, 1)); pll_core->set_param("ENABLE_ICEGATE", BitVector(1, 0)); Model *pll_pad = new Model(this, "SB_PLL40_PAD"); pll_pad->add_port("PACKAGEPIN", Direction::IN); pll_pad->add_port("RESETB", Direction::IN, Value::ZERO); pll_pad->add_port("BYPASS", Direction::IN, Value::ZERO); pll_pad->add_port("EXTFEEDBACK", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[0]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[1]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[2]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[3]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[4]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[5]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[6]", Direction::IN, Value::ZERO); pll_pad->add_port("DYNAMICDELAY[7]", Direction::IN, Value::ZERO); pll_pad->add_port("LATCHINPUTVALUE", Direction::IN, Value::ZERO); pll_pad->add_port("SCLK", Direction::IN, Value::ZERO); pll_pad->add_port("SDI", Direction::IN, Value::ZERO); pll_pad->add_port("SDO", Direction::IN, Value::ZERO); pll_pad->add_port("LOCK", Direction::OUT); pll_pad->add_port("PLLOUTGLOBAL", Direction::OUT); pll_pad->add_port("PLLOUTCORE", Direction::OUT); pll_pad->set_param("FEEDBACK_PATH", "SIMPLE"); pll_pad->set_param("DELAY_ADJUSTMENT_MODE_FEEDBACK", "FIXED"); pll_pad->set_param("FDA_FEEDBACK", BitVector(4, 0)); pll_pad->set_param("DELAY_ADJUSTMENT_MODE_RELATIVE", "FIXED"); pll_pad->set_param("FDA_RELATIVE", BitVector(4, 0)); pll_pad->set_param("SHIFTREG_DIV_MODE", BitVector(1, 0)); pll_pad->set_param("PLLOUT_SELECT", "GENCLK"); pll_pad->set_param("DIVR", BitVector(4, 0)); pll_pad->set_param("DIVF", BitVector(7, 0)); pll_pad->set_param("DIVQ", BitVector(3, 0)); pll_pad->set_param("FILTER_RANGE", BitVector(3, 0)); pll_pad->set_param("EXTERNAL_DIVIDE_FACTOR", BitVector(32, 1)); pll_pad->set_param("ENABLE_ICEGATE", BitVector(1, 0)); Model *pll_2_pad = new Model(this, "SB_PLL40_2_PAD"); pll_2_pad->add_port("PACKAGEPIN", Direction::IN); pll_2_pad->add_port("RESETB", Direction::IN, Value::ZERO); pll_2_pad->add_port("BYPASS", Direction::IN, Value::ZERO); pll_2_pad->add_port("EXTFEEDBACK", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[0]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[1]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[2]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[3]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[4]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[5]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[6]", Direction::IN, Value::ZERO); pll_2_pad->add_port("DYNAMICDELAY[7]", Direction::IN, Value::ZERO); pll_2_pad->add_port("LATCHINPUTVALUE", Direction::IN, Value::ZERO); pll_2_pad->add_port("SCLK", Direction::IN, Value::ZERO); pll_2_pad->add_port("SDI", Direction::IN, Value::ZERO); pll_2_pad->add_port("SDO", Direction::IN, Value::ZERO); pll_2_pad->add_port("LOCK", Direction::OUT); pll_2_pad->add_port("PLLOUTGLOBALA", Direction::OUT); pll_2_pad->add_port("PLLOUTCOREA", Direction::OUT); pll_2_pad->add_port("PLLOUTGLOBALB", Direction::OUT); pll_2_pad->add_port("PLLOUTCOREB", Direction::OUT); pll_2_pad->set_param("FEEDBACK_PATH", "SIMPLE"); pll_2_pad->set_param("DELAY_ADJUSTMENT_MODE_FEEDBACK", "FIXED"); pll_2_pad->set_param("FDA_FEEDBACK", BitVector(4, 0)); pll_2_pad->set_param("DELAY_ADJUSTMENT_MODE_RELATIVE", "FIXED"); pll_2_pad->set_param("FDA_RELATIVE", BitVector(4, 0)); pll_2_pad->set_param("SHIFTREG_DIV_MODE", BitVector(1, 0)); pll_2_pad->set_param("PLLOUT_SELECT_PORTA", "GENCLK"); pll_2_pad->set_param("PLLOUT_SELECT_PORTB", "GENCLK"); pll_2_pad->set_param("DIVR", BitVector(4, 0)); pll_2_pad->set_param("DIVF", BitVector(7, 0)); pll_2_pad->set_param("DIVQ", BitVector(3, 0)); pll_2_pad->set_param("FILTER_RANGE", BitVector(3, 0)); pll_2_pad->set_param("EXTERNAL_DIVIDE_FACTOR", BitVector(32, 1)); pll_2_pad->set_param("ENABLE_ICEGATE_PORTA", BitVector(1, 0)); pll_2_pad->set_param("ENABLE_ICEGATE_PORTB", BitVector(1, 0)); Model *pll_2f_core = new Model(this, "SB_PLL40_2F_CORE"); pll_2f_core->add_port("REFERENCECLK", Direction::IN, Value::ZERO); pll_2f_core->add_port("RESETB", Direction::IN, Value::ZERO); pll_2f_core->add_port("BYPASS", Direction::IN, Value::ZERO); pll_2f_core->add_port("EXTFEEDBACK", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[0]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[1]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[2]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[3]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[4]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[5]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[6]", Direction::IN, Value::ZERO); pll_2f_core->add_port("DYNAMICDELAY[7]", Direction::IN, Value::ZERO); pll_2f_core->add_port("LATCHINPUTVALUE", Direction::IN, Value::ZERO); pll_2f_core->add_port("SCLK", Direction::IN, Value::ZERO); pll_2f_core->add_port("SDI", Direction::IN, Value::ZERO); pll_2f_core->add_port("SDO", Direction::IN, Value::ZERO); pll_2f_core->add_port("LOCK", Direction::OUT); pll_2f_core->add_port("PLLOUTGLOBALA", Direction::OUT); pll_2f_core->add_port("PLLOUTCOREA", Direction::OUT); pll_2f_core->add_port("PLLOUTGLOBALB", Direction::OUT); pll_2f_core->add_port("PLLOUTCOREB", Direction::OUT); pll_2f_core->set_param("FEEDBACK_PATH", "SIMPLE"); pll_2f_core->set_param("DELAY_ADJUSTMENT_MODE_FEEDBACK", "FIXED"); pll_2f_core->set_param("FDA_FEEDBACK", BitVector(4, 0)); pll_2f_core->set_param("DELAY_ADJUSTMENT_MODE_RELATIVE", "FIXED"); pll_2f_core->set_param("FDA_RELATIVE", BitVector(4, 0)); pll_2f_core->set_param("SHIFTREG_DIV_MODE", BitVector(1, 0)); pll_2f_core->set_param("PLLOUT_SELECT_PORTA", "GENCLK"); pll_2f_core->set_param("PLLOUT_SELECT_PORTB", "GENCLK"); pll_2f_core->set_param("DIVR", BitVector(4, 0)); pll_2f_core->set_param("DIVF", BitVector(7, 0)); pll_2f_core->set_param("DIVQ", BitVector(3, 0)); pll_2f_core->set_param("FILTER_RANGE", BitVector(3, 0)); pll_2f_core->set_param("EXTERNAL_DIVIDE_FACTOR", BitVector(32, 1)); pll_2f_core->set_param("ENABLE_ICEGATE_PORTA", BitVector(1, 0)); pll_2f_core->set_param("ENABLE_ICEGATE_PORTB", BitVector(1, 0)); Model *pll_2f_pad = new Model(this, "SB_PLL40_2F_PAD"); pll_2f_pad->add_port("PACKAGEPIN", Direction::IN); pll_2f_pad->add_port("RESETB", Direction::IN, Value::ZERO); pll_2f_pad->add_port("BYPASS", Direction::IN, Value::ZERO); pll_2f_pad->add_port("EXTFEEDBACK", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[0]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[1]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[2]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[3]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[4]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[5]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[6]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("DYNAMICDELAY[7]", Direction::IN, Value::ZERO); pll_2f_pad->add_port("LATCHINPUTVALUE", Direction::IN, Value::ZERO); pll_2f_pad->add_port("SCLK", Direction::IN, Value::ZERO); pll_2f_pad->add_port("SDI", Direction::IN, Value::ZERO); pll_2f_pad->add_port("SDO", Direction::IN, Value::ZERO); pll_2f_pad->add_port("LOCK", Direction::OUT); pll_2f_pad->add_port("PLLOUTGLOBALA", Direction::OUT); pll_2f_pad->add_port("PLLOUTCOREA", Direction::OUT); pll_2f_pad->add_port("PLLOUTGLOBALB", Direction::OUT); pll_2f_pad->add_port("PLLOUTCOREB", Direction::OUT); pll_2f_pad->set_param("FEEDBACK_PATH", "SIMPLE"); pll_2f_pad->set_param("DELAY_ADJUSTMENT_MODE_FEEDBACK", "FIXED"); pll_2f_pad->set_param("FDA_FEEDBACK", BitVector(4, 0)); pll_2f_pad->set_param("DELAY_ADJUSTMENT_MODE_RELATIVE", "FIXED"); pll_2f_pad->set_param("FDA_RELATIVE", BitVector(4, 0)); pll_2f_pad->set_param("SHIFTREG_DIV_MODE", BitVector(1, 0)); pll_2f_pad->set_param("PLLOUT_SELECT_PORTA", "GENCLK"); pll_2f_pad->set_param("PLLOUT_SELECT_PORTB", "GENCLK"); pll_2f_pad->set_param("DIVR", BitVector(4, 0)); pll_2f_pad->set_param("DIVF", BitVector(7, 0)); pll_2f_pad->set_param("DIVQ", BitVector(3, 0)); pll_2f_pad->set_param("FILTER_RANGE", BitVector(3, 0)); pll_2f_pad->set_param("EXTERNAL_DIVIDE_FACTOR", BitVector(32, 1)); pll_2f_pad->set_param("ENABLE_ICEGATE_PORTA", BitVector(1, 0)); pll_2f_pad->set_param("ENABLE_ICEGATE_PORTB", BitVector(1, 0)); Model *warmboot = new Model(this, "SB_WARMBOOT"); warmboot->add_port("BOOT", Direction::IN, Value::ZERO); warmboot->add_port("S1", Direction::IN, Value::ZERO); warmboot->add_port("S0", Direction::IN, Value::ZERO); Model *tbuf = new Model(this, "$_TBUF_"); tbuf->add_port("A", Direction::IN); tbuf->add_port("E", Direction::IN); tbuf->add_port("Y", Direction::OUT); } Model * Design::find_model(const std::string &n) const { return lookup_or_default(m_models, n, (Model *)nullptr); } void Design::prune() { for (const auto &p : m_models) p.second->prune(); } #ifndef NDEBUG void Design::check() const { for (const auto &p : m_models) p.second->check(this); } #endif void Design::write_blif(std::ostream &s) const { assert(m_top); m_top->write_blif(s); } void Design::write_verilog(std::ostream &s) const { assert(m_top); m_top->write_verilog(s); } void Design::dump() const { write_blif(*logs); } Models::Models(const Design *d) { lut4 = d->find_model("SB_LUT4"); carry = d->find_model("SB_CARRY"); lc = d->find_model("ICESTORM_LC"); io = d->find_model("SB_IO"); gb = d->find_model("SB_GB"); gb_io = d->find_model("SB_GB_IO"); ram = d->find_model("SB_RAM40_4K"); ramnr = d->find_model("SB_RAM40_4KNR"); ramnw = d->find_model("SB_RAM40_4KNW"); ramnrnw = d->find_model("SB_RAM40_4KNRNW"); warmboot = d->find_model("SB_WARMBOOT"); tbuf = d->find_model("$_TBUF_"); } arachne-pnr-0~20150927gitefdb026/src/netlist.hh000066400000000000000000000265071260207143000210150ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_NETLIST_HH #define PNR_NETLIST_HH #include "util.hh" #include "bitvector.hh" #include "line_parser.hh" #include "vector.hh" #include #include #include #include class Net; class Port; class Node; class Instance; class Model; class Design; class Identified { private: template friend struct std::hash; friend class IdLess; static int id_counter; int id; public: Identified() : id(id_counter++) { } }; class IdLess { public: bool operator()(const Identified *lhs, const Identified *rhs) const { return lhs->id < rhs->id; } }; namespace std { template<> struct hash { public: size_t operator()(const Identified *x) const { std::hash hasher; return hasher(x->id); } }; template<> struct hash : public std::hash {}; template<> struct hash : public std::hash {}; template<> struct hash : public std::hash {}; template<> struct hash : public std::hash {}; } enum class Direction { IN, OUT, INOUT, }; extern Direction opposite_direction(Direction d); enum class Value { ZERO, ONE, X, Z, }; // for parameters, attributes class Const { private: friend std::ostream &operator<<(std::ostream &s, const Const &c); LexicalPosition m_lp; bool m_is_bits; std::string m_strval; BitVector m_bitval; public: const LexicalPosition &lexpos() const { return m_lp; } public: Const() : m_is_bits(false) {} Const(const std::string &sv) : m_is_bits(false), m_strval(sv) {} Const(const LexicalPosition &lp, const std::string &sv) : m_lp(lp), m_is_bits(false), m_strval(sv) {} Const(const BitVector &bv) : m_is_bits(true), m_bitval(bv) {} Const(const LexicalPosition &lp, const BitVector &bv) : m_lp(lp), m_is_bits(true), m_bitval(bv) {} const std::string &as_string() const { if (m_is_bits) m_lp.fatal("expected string constant"); return m_strval; } const BitVector &as_bits() const { if (!m_is_bits) m_lp.fatal("expected integer constant"); return m_bitval; } bool get_bit(int i) const { if (!m_is_bits) m_lp.fatal("expected integer constant"); if (i >= (int)m_bitval.size()) return 0; else return m_bitval[i]; } void write_verilog(std::ostream &s) const; }; class Net : public Identified { friend class Port; friend class Model; std::string m_name; bool m_is_constant; Value m_constant; std::set m_connections; public: const std::string &name() const { return m_name; } bool is_constant() const { return m_is_constant; } void set_is_constant(bool c) { m_is_constant = c; } Value constant() const { return m_constant; } void set_constant(Value c) { m_constant = c; } const std::set &connections() const { return m_connections; } Net(const std::string &n) : m_name(n), m_is_constant(false), m_constant(Value::X) { } ~Net() { assert(m_connections.empty()); } void replace(Net *new_n); }; class Port : public Identified { Node *m_node; std::string m_name; Direction m_dir; Value m_undriven; Net *m_connection; public: Node *node() const { return m_node; } const std::string &name() const { return m_name; } Direction direction() const { return m_dir; } void set_direction(Direction dir) { m_dir = dir; } Value undriven() const { return m_undriven; } void set_undriven(Value u) { m_undriven = u; } Port(Node *node_, const std::string &name_) : m_node(node_), m_name(name_), m_dir(Direction::IN), m_undriven(Value::X), m_connection(nullptr) {} Port(Node *node_, const std::string &name_, Direction dir) : m_node(node_), m_name(name_), m_dir(dir), m_undriven(Value::X), m_connection(nullptr) {} Port(Node *node_, const std::string &name_, Direction dir, Value u) : m_node(node_), m_name(name_), m_dir(dir), m_undriven(u), m_connection(nullptr) {} ~Port() { assert(m_connection == nullptr); } /* from the perspective of the body of a model */ bool is_output() const; bool is_input() const; bool is_bidir() const { return m_dir == Direction::INOUT; } bool connected() const { return m_connection != nullptr; } void disconnect(); void connect(Net *n); Net *connection() const { return m_connection; } Port *connection_other_port() const; }; class Node : public Identified { protected: std::map m_ports; std::vector m_ordered_ports; public: typedef Node Base; enum class Kind { model, instance, }; private: Kind m_kind; public: const std::map &ports() const { return m_ports; } const std::vector &ordered_ports() const { return m_ordered_ports; } Kind kind() const { return m_kind; } Node(Kind k) : m_kind(k) {} ~Node(); Port *add_port(Port *t); Port *add_port(const std::string &n, Direction dir); Port *add_port(const std::string &n, Direction dir, Value u); Port *find_port(const std::string &n); }; class Instance : public Node { Model *m_parent; Model *m_instance_of; std::map m_params; std::map m_attrs; public: static const Kind kindof = Kind::instance; Model *parent() const { return m_parent; } Model *instance_of() const { return m_instance_of; } const std::map &attrs() const { return m_attrs; } const std::map ¶ms() const { return m_params; } Instance(Model *p, Model *inst_of); void set_attr(const std::string &an, const Const &val) { m_attrs[an] = val; } bool has_attr(const std::string &an) const { return contains_key(m_attrs, an); } const Const &get_attr(const std::string &an) const { return m_attrs.at(an); } void merge_attrs(const Instance *inst); void set_param(const std::string &pn, const Const &val) { m_params[pn] = val; } bool has_param(const std::string &pn) const; const Const &get_param(const std::string &pn) const; bool self_has_param(const std::string &pn) const { return contains_key(m_params, pn); } const Const & self_get_param(const std::string &pn) const { return m_params.at(pn); } void remove(); void dump() const; void write_blif(std::ostream &s, const std::map &net_name) const; void write_verilog(std::ostream &s, const std::map &net_name, const std::string &inst_name) const; }; class Model : public Node { friend class Instance; static int counter; std::string m_name; std::map m_nets; std::set m_instances; std::map m_params; public: static const Kind kindof = Kind::model; const std::string &name() const { return m_name; } const std::set &instances() const { return m_instances; } const std::map &nets() const { return m_nets; } const std::map ¶ms() const { return m_params; } Model(Design *d, const std::string &n); ~Model(); Net *find_net(const std::string &n); Net *find_or_add_net(const std::string &n); Net *add_net(); Net *add_net(const std::string &name); Net *add_net(Net *orig) { return add_net(orig->name()); } void remove_net(Net *n); Instance *add_instance(Model *inst_of); void set_param(const std::string &pn, const std::string &val) { m_params[pn] = Const(val); } void set_param(const std::string &pn, const BitVector &val) { m_params[pn] = Const(val); } const Const & get_param(const std::string &pn) { return m_params.at(pn); } bool has_param(const std::string &pn) { return contains_key(m_params, pn); } std::set boundary_nets(const Design *d) const; std::pair, std::map> index_nets() const; std::pair, std::map> index_internal_nets(const Design *d) const; std::pair, std::map> index_instances() const; void prune(); std::pair, std::set> shared_names() const; void write_verilog(std::ostream &s) const; void write_blif(std::ostream &s) const; void rename_net(Net *n, const std::string &new_name); #ifndef NDEBUG void check(const Design *d) const; #endif }; class Design { friend class Model; Model *m_top; std::map m_models; public: Model *top() const { return m_top; } void set_top(Model *t); Design(); ~Design(); void create_standard_models(); Model *find_model(const std::string &n) const; void prune(); void write_verilog(std::ostream &s) const; void write_blif(std::ostream &s) const; void dump() const; #ifndef NDEBUG void check() const; #endif }; class Models { public: Model *lut4, *carry; Model *lc, *io, *gb, *gb_io, *ram, *ramnr, *ramnw, *ramnrnw, *warmboot, *tbuf; public: Models(const Design *d); bool is_dff(Instance *inst) const { return is_prefix("SB_DFF", inst->instance_of()->name()); } bool is_lut4(Instance *inst) const { return inst->instance_of() == lut4; } bool is_carry(Instance *inst) const { return inst->instance_of() == carry; } bool is_lc(Instance *inst) const { return inst->instance_of() == lc; } bool is_io(Instance *inst) const { return inst->instance_of() == io; } bool is_gb(Instance *inst) const { return inst->instance_of() == gb; } bool is_gb_io(const Instance *inst) const { return inst->instance_of() == gb_io; } bool is_ioX(const Instance *inst) const { return inst->instance_of() == io || inst->instance_of() == gb_io; } bool is_gbX(const Instance *inst) const { return inst->instance_of() == gb || inst->instance_of() == gb_io; } bool is_ram(Instance *inst) const { return inst->instance_of() == ram; } bool is_ramnr(Instance *inst) const { return inst->instance_of() == ramnr; } bool is_ramnw(Instance *inst) const { return inst->instance_of() == ramnw; } bool is_ramnrnw(Instance *inst) const { return inst->instance_of() == ramnrnw; } bool is_warmboot(Instance *inst) const { return inst->instance_of() == warmboot; } bool is_tbuf(Instance *inst) const { return inst->instance_of() == tbuf; } bool is_ramX(Instance *inst) const { return (inst->instance_of() == ram || inst->instance_of() == ramnr || inst->instance_of() == ramnw || inst->instance_of() == ramnrnw); } bool is_pllX(const Instance *inst) const { return is_prefix("SB_PLL40_", inst->instance_of()->name()); } }; #endif arachne-pnr-0~20150927gitefdb026/src/pack.cc000066400000000000000000000343311260207143000202310ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "casting.hh" #include "netlist.hh" #include "chipdb.hh" #include "carry.hh" #include "designstate.hh" #include class Packer { const ChipDB *chipdb; const Package &package; Design *d; Models ⊧ Model *top; CarryChains &chains; int n_dff_pass_through, n_carry_pass_through; Net *const0; Net *const1; std::set ready; void lc_from_dff(Instance *lc_inst, Instance *dff_inst); void lc_from_lut(Instance *lc_inst, Instance *lut_inst); void pass_through_lc(Instance *lc_inst, Port *in); void carry_pass_through_lc(Instance *lc_inst, Port *cout); void lc_from_carry(Instance *lc_inst, Instance *carry_inst); Port *driver(Net *n); Instance *find_carry_lc(Instance *c); void pack_dffs(); void pack_luts(); void pack_carries_from(Instance *f); void pack_carries(); public: Packer(DesignState &ds); void pack(); }; Packer::Packer(DesignState &ds) : chipdb(ds.chipdb), package(ds.package), d(ds.d), models(ds.models), top(ds.top), chains(ds.chains), n_dff_pass_through(0), n_carry_pass_through(0), const0(nullptr), const1(nullptr) { for (const auto &p : top->nets()) { if (p.second->is_constant()) { if (p.second->constant() == Value::ONE) const1 = p.second; else { assert(p.second->constant() == Value::ZERO); const0 = p.second; } } if (const0 && const1) break; } // will prune if (!const0) { const0 = top->add_net("$false"); const0->set_is_constant(true); const0->set_constant(Value::ZERO); } if (!const1) { const1 = top->add_net("$true"); const1->set_is_constant(true); const1->set_constant(Value::ONE); } } void Packer::lc_from_dff(Instance *lc_inst, Instance *dff_inst) { const std::string &dff_name = dff_inst->instance_of()->name(); const char *suffix = &dff_name[6]; bool neg_clk = false; if (*suffix == 'N') { neg_clk = true; ++suffix; } bool cen = false; if (*suffix == 'E') { cen = true; ++suffix; } bool async_sr = false; bool set_noreset = false; bool sr = false; if (!strcmp(suffix, "S")) { set_noreset = true; async_sr = true; sr = true; } else if (!strcmp(suffix, "SS")) { set_noreset = true; sr = true; } else if (!strcmp(suffix, "R")) { async_sr = true; sr = true; } else if (!strcmp(suffix, "SR")) { sr = true; } else assert(*suffix == '\0'); lc_inst->find_port("O")->connect(dff_inst->find_port("Q")->connection()); lc_inst->find_port("CLK")->connect(dff_inst->find_port("C")->connection()); if (neg_clk) lc_inst->set_param("NEG_CLK", BitVector(1, 1)); if (cen) lc_inst->find_port("CEN")->connect(dff_inst->find_port("E")->connection()); else lc_inst->find_port("CEN")->connect(const1); if (sr) { if (set_noreset) { lc_inst->find_port("SR")->connect(dff_inst->find_port("S")->connection()); lc_inst->set_param("SET_NORESET", BitVector(1, 1)); } else { lc_inst->find_port("SR")->connect(dff_inst->find_port("R")->connection()); } if (async_sr) lc_inst->set_param("ASYNC_SR", BitVector(1, 1)); } else { lc_inst->find_port("SR")->connect(const0); } lc_inst->set_param("DFF_ENABLE", BitVector(1, 1)); lc_inst->merge_attrs(dff_inst); } void Packer::lc_from_lut(Instance *lc_inst, Instance *lut_inst) { lc_inst->find_port("I0")->connect(lut_inst->find_port("I0")->connection()); lc_inst->find_port("I1")->connect(lut_inst->find_port("I1")->connection()); lc_inst->find_port("I2")->connect(lut_inst->find_port("I2")->connection()); lc_inst->find_port("I3")->connect(lut_inst->find_port("I3")->connection()); if (lut_inst->self_has_param("LUT_INIT")) lc_inst->set_param("LUT_INIT", lut_inst->self_get_param("LUT_INIT")); lc_inst->merge_attrs(lut_inst); } void Packer::pass_through_lc(Instance *lc_inst, Port *in) { lc_inst->find_port("I0")->connect(in->connection()); lc_inst->find_port("I1")->connect(const0); lc_inst->find_port("I2")->connect(const0); lc_inst->find_port("I3")->connect(const0); lc_inst->set_param("LUT_INIT", BitVector(2, 2)); ++n_dff_pass_through; } void Packer::carry_pass_through_lc(Instance *lc_inst, Port *cout) { Net *n = cout->connection(); Net *t = top->add_net(n); cout->connect(t); lc_inst->find_port("I3")->connect(t); lc_inst->find_port("O")->connect(n); lc_inst->set_param("LUT_INIT", BitVector(16, 0xff00)); // 1111111100000000 ++n_carry_pass_through; } void Packer::lc_from_carry(Instance *lc_inst, Instance *carry_inst) { assert((lc_inst->find_port("I1")->connection() == carry_inst->find_port("I0")->connection()) && (lc_inst->find_port("I2")->connection() == carry_inst->find_port("I1")->connection())); lc_inst->find_port("CIN")->connect(carry_inst->find_port("CI")->connection()); lc_inst->find_port("COUT")->connect(carry_inst->find_port("CO")->connection()); lc_inst->set_param("CARRY_ENABLE", BitVector(1, 1)); } void Packer::pack_dffs() { const auto &instances = top->instances(); for (auto i = instances.begin(); i != instances.end();) { Instance *inst = *i; ++i; if (models.is_dff(inst)) { Instance *lc_inst = top->add_instance(models.lc); Port *d_port = inst->find_port("D"); Port *d_driver = d_port->connection_other_port(); Instance *lut_inst = nullptr; if (d_driver) { Instance *d_driver_inst = dyn_cast(d_driver->node()); if (d_driver_inst && models.is_lut4(d_driver_inst) && d_driver->name() == "O") lut_inst = d_driver_inst; } lc_from_dff(lc_inst, inst); if (lut_inst) lc_from_lut(lc_inst, lut_inst); else pass_through_lc(lc_inst, d_port); inst->remove(); delete inst; if (lut_inst) { if (i != instances.end() && *i == lut_inst) ++i; lut_inst->remove(); delete lut_inst; } } } } void Packer::pack_luts() { const auto &instances = top->instances(); for (auto i = instances.begin(); i != instances.end();) { Instance *inst = *i; ++i; if (models.is_lut4(inst)) { Instance *lc_inst = top->add_instance(models.lc); lc_from_lut(lc_inst, inst); lc_inst->find_port("O")->connect(inst->find_port("O")->connection()); inst->remove(); delete inst; } } } Port * Packer::driver(Net *n) { if (!n) return nullptr; for (Port *p : n->connections()) { if (p->is_output() || p->is_bidir()) return p; } return nullptr; } Instance * Packer::find_carry_lc(Instance *c) { Port *ci = c->find_port("CI"); Net *ci_conn = ci->connection(); if (!ci_conn || ci_conn->is_constant() || ci_conn->connections().size() != 3) return nullptr; // driver is previous COUT Net *i0_conn = c->find_port("I0")->connection(), *i1_conn = c->find_port("I1")->connection(); for (Port *p : ci_conn->connections()) { if (Instance *p_inst = dyn_cast(p->node())) { if (models.is_lc(p_inst) && p->name() == "I3" && i0_conn == p_inst->find_port("I1")->connection() && i1_conn == p_inst->find_port("I2")->connection()) return p_inst; } } return nullptr; } void Packer::pack_carries_from(Instance *f) { unsigned max_chain_length = (chipdb->height - 2)*8; std::vector chain; Net *global_clk = nullptr, *global_cen = nullptr, *global_sr = nullptr; for (Instance *c = f; c;) { Port *out = c->find_port("CO"); Net *out_conn = out->connection(); if (out_conn && chain.size() == max_chain_length - 1) { // break chain Instance *out_lc_inst = top->add_instance(models.lc); carry_pass_through_lc(out_lc_inst, chain.back()->find_port("COUT")); chain.push_back(out_lc_inst); chains.chains.push_back(chain); chain.clear(); } Port *in = c->find_port("CI"); Net *in_conn = in->connection(); if (chain.size() % 8 == 0) { global_clk = nullptr; global_cen = nullptr; global_sr = nullptr; } if (chain.empty() && in_conn && !in_conn->is_constant()) { // carry in Instance *in_lc_inst = top->add_instance(models.lc); Net *t = top->add_net(in_conn); in_lc_inst->find_port("COUT")->connect(t); in_lc_inst->find_port("I0")->connect(const0); in_lc_inst->find_port("I1")->connect(in_conn); in_lc_inst->find_port("I2")->connect(const0); in_lc_inst->find_port("I3")->connect(const0); in_lc_inst->find_port("CIN")->connect(const1); in_lc_inst->set_param("CARRY_ENABLE", BitVector(1, 1)); chain.push_back(in_lc_inst); in->connect(t); in_conn = t; ++n_carry_pass_through; } Instance *lc_inst = find_carry_lc(c); if (lc_inst) { Net *clk = lc_inst->find_port("CLK")->connection(), *cen = lc_inst->find_port("CEN")->connection(), *sr = lc_inst->find_port("SR")->connection(); if ((global_clk && global_clk != clk) || (global_cen && global_cen != cen) || (global_sr && global_sr != sr)) { lc_inst = nullptr; goto L; } if (!global_clk) global_clk = clk; if (!global_cen) global_cen = cen; if (!global_sr) global_sr = sr; } if (!lc_inst) { L: lc_inst = top->add_instance(models.lc); lc_inst->find_port("I1")->connect(c->find_port("I0")->connection()); lc_inst->find_port("I2")->connect(c->find_port("I1")->connection()); if (!in_conn || in_conn->is_constant() || in_conn->connections().size() == 2) { // could try to pack lut here } else { Port *p = chain.back()->find_port("COUT"); assert(p && p->connection() == in_conn); carry_pass_through_lc(lc_inst, p); c->find_port("CI")->connect(p->connection()); } } lc_from_carry(lc_inst, c); chain.push_back(lc_inst); Instance *next_c = nullptr; if (out_conn) { for (Port *p : out_conn->connections()) { if (Instance *inst = dyn_cast(p->node())) { if (models.is_carry(inst) && p->name() == "CI") { if (next_c) extend(ready, inst); else next_c = inst; } } } } if (!next_c && out_conn) { assert(chain.size() < max_chain_length); Instance *lc2_inst = top->add_instance(models.lc); Port *p = chain.back()->find_port("COUT"); assert(p && p->connection() == out_conn); carry_pass_through_lc(lc2_inst, p); chain.push_back(lc2_inst); } c->remove(); delete c; c = next_c; } chains.chains.push_back(chain); chain.clear(); } void Packer::pack_carries() { const auto &instances = top->instances(); for (Instance *inst : instances) { if (models.is_carry(inst)) { Port *in = inst->find_port("CI"); Net *in_conn = in->connection(); Port *p = driver(in_conn); if (!p || !isa(p->node()) || !models.is_carry(cast(p->node()))) extend(ready, inst); } } while (!ready.empty()) { Instance *inst = front(ready); ready.erase(inst); pack_carries_from(inst); } } void Packer::pack() { pack_dffs(); pack_luts(); pack_carries(); d->prune(); // d->dump(); int n_ramt_tiles = 0; for (int i = 0; i < chipdb->n_tiles; ++i) { if (chipdb->tile_type[i] == TileType::RAMT) ++n_ramt_tiles; } int n_io = 0, n_lc = 0, n_lc_carry = 0, n_lc_dff = 0, n_lc_carry_dff = 0, n_gb = 0, n_gb_io = 0, n_bram = 0, n_pll = 0, n_warmboot = 0; for (Instance *inst : top->instances()) { if (models.is_lc(inst)) { ++n_lc; if (inst->get_param("DFF_ENABLE").get_bit(0)) { if (inst->get_param("CARRY_ENABLE").get_bit(0)) ++n_lc_carry_dff; else ++n_lc_dff; } else { if (inst->get_param("CARRY_ENABLE").get_bit(0)) ++n_lc_carry; } } else if (models.is_io(inst)) ++n_io; else if (models.is_gb(inst)) ++n_gb; else if (models.is_warmboot(inst)) ++n_warmboot; else if (models.is_gb_io(inst)) { ++n_io; ++n_gb_io; } else if (models.is_pllX(inst)) ++n_pll; else { assert(models.is_ramX(inst)); ++n_bram; } } int n_logic_tiles = 0; for (int i = 0; i < chipdb->n_tiles; ++i) { if (chipdb->tile_type[i] == TileType::LOGIC) ++n_logic_tiles; } int n_warmboot_cells = 0; for (int i = 0; i < chipdb->n_cells; ++i) { if (chipdb->cell_type[i+1] == CellType::WARMBOOT) ++n_warmboot_cells; } *logs << "\nAfter packing:\n" << "IOs " << n_io << " / " << package.pin_loc.size() << "\n" << "GBs " << n_gb << " / " << chipdb->n_global_nets << "\n" << " GB_IOs " << n_gb_io << " / " << chipdb->n_global_nets << "\n" << "LCs " << n_lc << " / " << n_logic_tiles*8 << "\n" << " DFF " << n_lc_dff << "\n" << " CARRY " << n_lc_carry << "\n" << " CARRY, DFF " << n_lc_carry_dff << "\n" << " DFF PASS " << n_dff_pass_through << "\n" << " CARRY PASS " << n_carry_pass_through << "\n" << "BRAMs " << n_bram << " / " << n_ramt_tiles << "\n" << "WARMBOOTs " << n_warmboot << " / " << n_warmboot_cells << "\n" << "PLLs " << n_pll << " / " << chipdb->cell_type_cells[cell_type_idx(CellType::PLL)].size() << "\n\n"; } void pack(DesignState &ds) { Packer packer(ds); packer.pack(); } arachne-pnr-0~20150927gitefdb026/src/pack.hh000066400000000000000000000013751260207143000202450ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_PACK_HH #define PNR_PACK_HH class DesignState; extern void pack(DesignState &ds); #endif arachne-pnr-0~20150927gitefdb026/src/pcf.cc000066400000000000000000000175301260207143000200650ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "chipdb.hh" #include "netlist.hh" #include "pcf.hh" #include "line_parser.hh" #include "designstate.hh" #include "casting.hh" #include #include #include class PCFParser : public LineParser { const Package &package; Model *top; Constraints &constraints; public: PCFParser(const std::string &f, std::istream &s_, DesignState &ds) : LineParser(f, s_), package(ds.package), top(ds.top), constraints(ds.constraints) {} void parse(); }; void PCFParser::parse() { std::map net_pin_loc; for (;;) { if (eof()) break; read_line(); if (words.empty()) continue; const std::string &cmd = words[0]; if (cmd == "set_io") { bool err_no_port = true; const char *net_name = nullptr, *pin_name = nullptr; for (int i = 1; i < (int)words.size(); ++i) { if (words[i][0] == '-') { if (words[1] == "--warn-no-port") err_no_port = false; else fatal(fmt("unknown option `" << words[1] << "'")); } else { if (net_name == nullptr) net_name = words[i].c_str(); else if (pin_name == nullptr) pin_name = words[i].c_str(); else fatal("set_io: too many arguments"); } } if (!net_name || !pin_name) fatal("set_io: too few arguments"); Port *p = top->find_port(net_name); if (!p) { if (err_no_port) fatal(fmt("no port `" << net_name << "' in top-level module `" << top->name() << "'")); else { warning(fmt("no port `" << net_name << "' in top-level module `" << top->name() << "', constraint ignored.")); continue; } } auto i = package.pin_loc.find(pin_name); if (i == package.pin_loc.end()) fatal(fmt("unknown pin `" << pin_name << "' on package `" << package.name << "'")); const Location &loc = i->second; auto j = net_pin_loc.find(net_name); if (j != net_pin_loc.end()) fatal(fmt("duplicate pin constraints for net `" << net_name << "'")); extend(net_pin_loc, net_name, loc); } else fatal(fmt("unknown command `" << cmd << "'")); } constraints.net_pin_loc = net_pin_loc; } void read_pcf(const std::string &filename, DesignState &ds) { std::string expanded = expand_filename(filename); std::ifstream fs(expanded); if (fs.fail()) fatal(fmt("read_pcf: failed to open `" << expanded << "': " << strerror(errno))); PCFParser parser(filename, fs, ds); return parser.parse(); } class ConstraintsPlacer { DesignState &ds; const ChipDB *chipdb; const Models ⊧ Model *top; const Constraints &constraints; BasedVector cell_gate; Instance *top_port_io_gate(const std::string &net_name); public: ConstraintsPlacer(DesignState &ds_); void place(); }; Instance * ConstraintsPlacer::top_port_io_gate(const std::string &net_name) { Port *p = top->find_port(net_name); assert(p); Port *p2 = p->connection_other_port(); Instance *inst = cast(p2->node()); assert(models.is_ioX(inst) || models.is_pllX(inst)); return inst; } ConstraintsPlacer::ConstraintsPlacer(DesignState &ds_) : ds(ds_), chipdb(ds.chipdb), models(ds.models), top(ds.top), constraints(ds.constraints), cell_gate(chipdb->n_cells, nullptr) { assert(ds.placement.empty()); } void ConstraintsPlacer::place() { std::vector bank_latch(4, nullptr); for (const auto &p : constraints.net_pin_loc) { Instance *inst = top_port_io_gate(p.first); const Location &loc = p.second; int t = loc.tile(); assert(chipdb->tile_type[t] == TileType::IO); int b = chipdb->tile_bank(t); int c = 0; if (models.is_ioX(inst)) { Net *latch = inst->find_port("LATCH_INPUT_VALUE")->connection(); if (latch) { if (bank_latch[b]) { if (bank_latch[b] != latch) fatal(fmt("pcf error: multiple LATCH_INPUT_VALUE drivers in bank " << b)); } else bank_latch[b] = latch; } if (inst->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT" && b != 3) fatal(fmt("pcf error: LVDS port `" << p.first << "' not in bank 3\n")); Location loc_other(t, loc.pos() ? 0 : 1); int cell_other = chipdb->loc_cell(loc_other); if (cell_other) { Instance *inst_other = cell_gate[cell_other]; if (inst_other) { if (inst->get_param("NEG_TRIGGER").get_bit(0) != inst_other->get_param("NEG_TRIGGER").get_bit(0)) { int x = chipdb->tile_x(t), y = chipdb->tile_y(t); fatal(fmt("pcf error: incompatible NEG_TRIGGER parameters in PIO at (" << x << ", " << y << ")")); } } } c = chipdb->loc_cell(loc); } else { assert(models.is_pllX(inst)); Location pll_loc(loc.tile(), 3); c = chipdb->loc_cell(pll_loc); if (!c || chipdb->cell_type[c] != CellType::PLL) fatal(fmt("bad constraint on `" << p.first << "': no PLL at pin " << ds.package.loc_pin.at(loc))); } cell_gate[c] = inst; extend(ds.placement, inst, c); } for (int c : chipdb->cell_type_cells[cell_type_idx(CellType::PLL)]) { Instance *pll = cell_gate[c]; if (!pll) continue; assert(models.is_pllX(pll)); for (int io_cell : ds.pll_out_io_cells(pll, c)) { Instance *io = cell_gate[io_cell]; if (!io) continue; const BitVector &pin_type = pll->get_param("PIN_TYPE").as_bits(); if (io->find_port("D_IN_0")->connected() || io->find_port("D_IN_1")->connected() || !pin_type[0] || pin_type[1]) { const Location &pll_loc = chipdb->cell_location[c]; const std::string &io_pin = ds.package.loc_pin.at(chipdb->cell_location[io_cell]); fatal(fmt("PLL at `" << chipdb->tile_x(pll_loc.tile()) << " " << chipdb->tile_y(pll_loc.tile()) << "' conflicts with pin " << io_pin << " input path")); } } } int n_pll = 0, n_pll_placed = 0; for (Instance *inst : top->instances()) { if (contains(ds.placement, inst)) continue; // FIXME relax if (models.is_gb_io(inst)) fatal("physical constraint required for GB_IO"); else if (models.is_pllX(inst)) { ++n_pll; bool good = false; for (int c : chipdb->cell_type_cells[cell_type_idx(CellType::PLL)]) { if (cell_gate[c]) continue; good = true; for (int io_cell : ds.pll_out_io_cells(inst, c)) { Instance *io = cell_gate[io_cell]; if (io) { const BitVector &pin_type = inst->get_param("PIN_TYPE").as_bits(); if (io->find_port("D_IN_0")->connected() || io->find_port("D_IN_1")->connected() || !pin_type[0] || pin_type[1]) { good = false; break; } } } if (good) { cell_gate[c] = inst; extend(ds.placement, inst, c); ++n_pll_placed; break; } } if (!good) fatal(fmt("failed to place: placed " << n_pll_placed << " PLLs of " << n_pll << " / " << chipdb->cell_type_cells[cell_type_idx(CellType::PLL)].size())); } } } void place_constraints(DesignState &ds) { ConstraintsPlacer placer(ds); placer.place(); } arachne-pnr-0~20150927gitefdb026/src/pcf.hh000066400000000000000000000020601260207143000200670ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_PCF_HH #define PNR_PCF_HH #include #include class Design; class DesignState; class Constraints { public: std::map net_pin_loc; public: Constraints() {} Constraints(const std::map &np) : net_pin_loc(np) {} }; void read_pcf(const std::string &filename, DesignState &ds); void place_constraints(DesignState &ds); #endif arachne-pnr-0~20150927gitefdb026/src/place.cc000066400000000000000000001276001260207143000204010ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "casting.hh" #include "place.hh" #include "netlist.hh" #include "chipdb.hh" #include "location.hh" #include "configuration.hh" #include "pcf.hh" #include "carry.hh" #include "bitvector.hh" #include "ullmanset.hh" #include "hashmap.hh" #include "designstate.hh" #include #include #include #include #include #include #include #include #include class Placer { public: random_generator &rg; DesignState &ds; const ChipDB *chipdb; const Package &package; Design *d; Models ⊧ Model *top; const CarryChains &chains; const Constraints &constraints; const std::map &gb_inst_gc; std::map &placement; Configuration &conf; std::vector logic_columns; std::vector logic_tiles, ramt_tiles; std::vector> related_tiles; std::vector nets; std::map net_idx; int n_gates; BasedVector gates; std::map gate_idx; BasedBitVector<1> locked; BasedBitVector<1> chained; BasedVector gate_clk, gate_sr, gate_cen, gate_latch; BasedVector, 1> gate_local_np; UllmanSet tmp_local_np; BitVector net_global; std::vector free_gates; BasedVector gate_chain; CellType gate_cell_type(int g); int gate_random_cell(int g); std::pair chain_random_loc(int c); void move_gate(int g, int cell); void move_chain(int c, const Location &new_loc); int tile_n_pos(int t); std::vector> net_gates; BasedVector, 1> gate_nets; int diameter; double temp; bool improved; int n_move; int n_accept; bool move_failed; UllmanSet changed_tiles; std::vector> restore_cell; std::vector> restore_chain; std::vector> restore_net_length; UllmanSet recompute; void save_set(int cell, int g); void save_set_chain(int c, int x, int start); int save_recompute_wire_length(); void restore(); void discard(); void accept_or_restore(); std::vector chain_x, chain_start; BasedVector gate_cell; BasedVector cell_gate; std::vector net_length; bool valid(int t); int wire_length() const; int compute_net_length(int w); unsigned top_port_io_gate(const std::string &net_name); void place_initial(); void configure_io(const Location &loc, bool enable_input, bool pullup); void configure(); #ifndef NDEBUG void check(); #endif public: Placer(random_generator &rg_, DesignState &ds_); void place(); }; CellType Placer::gate_cell_type(int g) { Instance *inst = gates[g]; if (models.is_lc(inst)) return CellType::LOGIC; else if (models.is_ioX(inst)) return CellType::IO; else if (models.is_gb(inst)) return CellType::GB; else if (models.is_warmboot(inst)) return CellType::WARMBOOT; else if (models.is_pllX(inst)) return CellType::PLL; else { assert(models.is_ramX(inst)); return CellType::RAM; } } int Placer::gate_random_cell(int g) { CellType ct = gate_cell_type(g); if (ct == CellType::LOGIC) { int cell = gate_cell[g]; int t = chipdb->cell_location[cell].tile(); int x = chipdb->tile_x(t), y = chipdb->tile_y(t); L: int new_x = rg.random_int(std::max(0, x - diameter), std::min(chipdb->width-1, x + diameter)), new_y = rg.random_int(std::max(0, y - diameter), std::min(chipdb->height-1, y + diameter)); int new_t = chipdb->tile(new_x, new_y); if (chipdb->tile_type[new_t] != TileType::LOGIC) goto L; Location loc(new_t, rg.random_int(0, 7)); return chipdb->loc_cell(loc); } else { int ct_idx = cell_type_idx(ct); return random_element(chipdb->cell_type_cells[ct_idx], rg); } } std::pair Placer::chain_random_loc(int c) { const auto &v = chains.chains[c]; int nt = (v.size() + 7) / 8; int new_x = random_element(logic_columns, rg); int new_start = random_int(1, chipdb->height - 2 - (nt - 1), rg); int new_end = new_start + nt - 1; for (unsigned e = 0; e < chains.chains.size(); ++e) { if (chain_x[e] != new_x) // including self continue; int e_nt = (chains.chains[e].size() + 7) / 8; int e_start = chain_start[e], e_end = e_start + e_nt - 1; if ((new_start > e_start && new_start <= e_end) || (new_end >= e_start && new_end < e_end)) return std::make_pair(Location(), false); } int t = chipdb->tile(new_x, new_start); return std::make_pair(Location(t, 0), true); } void Placer::move_gate(int g, int new_cell) { assert(g); if (locked[g]) move_failed = true; int cell = gate_cell[g]; // copy if (new_cell == cell) return; int new_g = cell_gate[new_cell]; if (new_g && locked[new_g]) move_failed = true; save_set(new_cell, g); save_set(cell, new_g); } void Placer::move_chain(int c, const Location &new_base) { assert(new_base.pos() == 0); int nt = (chains.chains[c].size() + 7) / 8; int x = chain_x[c], start = chain_start[c]; int new_t = new_base.tile(); int new_x = chipdb->tile_x(new_t), new_start = chipdb->tile_y(new_t); if (new_x == x && new_start == start) return; for (int i = 0; i < nt; ++i) for (unsigned k = 0; k < 8; ++k) { Location loc(chipdb->tile(x, start + i), k), new_loc(chipdb->tile(new_x, new_start + i), k); int cell = chipdb->loc_cell(loc), new_cell = chipdb->loc_cell(new_loc); unsigned g = cell_gate[cell], new_g = cell_gate[new_cell]; if (g) move_gate(g, new_cell); if (new_g) move_gate(new_g, cell); } } int Placer::tile_n_pos(int t) { switch(chipdb->tile_type[t]) { case TileType::LOGIC: return 8; case TileType::IO: return 2; case TileType::RAMT: return 1; default: abort(); return 0; } } void Placer::save_set(int cell, int g) { const Location &loc = chipdb->cell_location[cell]; int t = loc.tile(); restore_cell.push_back(std::make_pair(cell, cell_gate[cell])); if (g) { for (int w : gate_nets[g]) recompute.insert(w); gate_cell[g] = cell; int c = gate_chain[g]; if (c != -1) { int x = chipdb->tile_x(t), y = chipdb->tile_y(t); save_set_chain(c, x, y); } } cell_gate[cell] = g; changed_tiles.insert(t); for (int t2 : related_tiles[t]) changed_tiles.insert(t2); } void Placer::save_set_chain(int c, int x, int start) { restore_chain.push_back(std::make_tuple(c, chain_x[c], chain_start[c])); chain_x[c] = x; chain_start[c] = start; } int Placer::save_recompute_wire_length() { int delta = 0; for (int i = 0; i < (int)recompute.size(); ++i) { int w = recompute.ith(i); int new_length = compute_net_length(w), old_length = net_length.at(w); restore_net_length.push_back(std::make_pair(w, old_length)); net_length[w] = new_length; delta += (new_length - old_length); } return delta; } void Placer::restore() { move_failed = false; for (const auto &p : restore_cell) { cell_gate[p.first] = p.second; if (p.second) gate_cell[p.second] = p.first; } for (const auto &p : restore_net_length) net_length[p.first] = p.second; for (const auto &t : restore_chain) { int e, x, start; std::tie(e, x, start) = t; chain_x[e] = x; chain_start[e] = start; } } void Placer::discard() { changed_tiles.clear(); restore_cell.clear(); restore_chain.clear(); restore_net_length.clear(); recompute.clear(); } bool Placer::valid(int t) { int x = chipdb->tile_x(t), y = chipdb->tile_y(t); if (chipdb->tile_type[t] == TileType::LOGIC) { int global_clk = 0, global_sr = 0, global_cen = 0; int neg_clk = -1; tmp_local_np.clear(); for (int q = 0; q < 8; q ++) { Location loc(t, q); int cell = chipdb->loc_cell(loc); int g = cell_gate[cell]; if (g) { Instance *inst = gates[g]; int clk = gate_clk[g], sr = gate_sr[g], cen = gate_cen[g]; if (!global_clk) global_clk = clk; else if (global_clk != clk) return false; if (!global_sr) global_sr = sr; else if (global_sr != sr) return false; if (!global_cen) global_cen = cen; else if (global_cen != cen) return false; int g_neg_clk = (int)inst->get_param("NEG_CLK").get_bit(0); if (neg_clk == -1) neg_clk = g_neg_clk; else if (neg_clk != g_neg_clk) return false; for (int np : gate_local_np[g]) tmp_local_np.insert(np ^ (q & 1)); } } if (global_clk && !net_global[global_clk]) tmp_local_np.insert(global_clk << 1); if (global_sr && !net_global[global_sr]) tmp_local_np.insert(global_sr << 1); if (global_cen && !net_global[global_cen]) tmp_local_np.insert(global_cen << 1); if (tmp_local_np.size() > 29) return false; } else if (chipdb->tile_type[t] == TileType::IO) { int b = chipdb->tile_bank(t); int latch = 0; for (int cell : chipdb->bank_cells[b]) { int g = cell_gate[cell]; if (g) { int n = gate_latch[g]; if (latch) { if (latch != n) return false; } else latch = n; } } Location loc0(t, 0), loc1(t, 1); int cell0 = chipdb->loc_cell(loc0), cell1 = chipdb->loc_cell(loc1); int g0 = cell0 ? cell_gate[cell0] : 0, g1 = cell1 ? cell_gate[cell1] : 0; if (g0) { Instance *inst0 = gates[g0]; if (inst0->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT") { if (b != 3) return false; if (g1) return false; } } if (g1) { Instance *inst0 = gates[g1]; if (inst0->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT") return false; } if (g0 && g1) { Instance *inst0 = gates[g0], *inst1 = gates[g1]; if (inst0->get_param("NEG_TRIGGER").get_bit(0) != inst1->get_param("NEG_TRIGGER").get_bit(0)) return false; } Location loc2(t, 2); int cell2 = chipdb->loc_cell(loc2); int g2 = cell2 ? cell_gate[cell2] : 0; if (g2) { if ((g0 && models.is_gb_io(gates[g0])) || (g1 && models.is_gb_io(gates[g1]))) return false; Instance *inst = gates[g2]; int gc = gb_inst_gc.at(inst); int global = chipdb->gbufin.at(std::make_pair(x, y)); if (! (gc & (1 << global))) return false; } Location loc3(t, 3); int cell3 = chipdb->loc_cell(loc3); int g3 = cell3 ? cell_gate[cell3] : 0; Instance *inst3 = g3 ? gates[g3] : nullptr; if (inst3) { const auto &pA = chipdb->cell_mfvs.at(cell3).at("PLLOUT_A"); int tA = pA.first; int iA = std::stoi(pA.second); int cA = chipdb->loc_cell(Location(tA, iA)); int gA = cell_gate[cA]; Instance *instA = gA ? gates[gA] : nullptr; if (instA && instA->find_port("D_IN_0")->connection()) return false; if (inst3->instance_of()->name() == "SB_PLL40_2F_CORE" || inst3->instance_of()->name() == "SB_PLL40_2_PAD" || inst3->instance_of()->name() == "SB_PLL40_2F_PAD") { const auto &pB = chipdb->cell_mfvs.at(cell3).at("PLLOUT_B"); int tB = pB.first; int iB = std::stoi(pB.second); int cB = chipdb->loc_cell(Location(tB, iB)); int gB = cell_gate[cB]; Instance *instB = gB ? gates[gB] : nullptr; if (instB && instB->find_port("D_IN_0")->connection()) return false; } } } else assert(chipdb->tile_type[t] == TileType::RAMT); return true; } void Placer::accept_or_restore() { int delta; if (move_failed) goto L; for (int i = 0; i < (int)changed_tiles.size(); ++i) { int t = changed_tiles.ith(i); if (!valid(t)) goto L; } delta = save_recompute_wire_length(); // check(); ++n_move; if (delta < 0 || (temp > 1e-6 && rg.random_real(0.0, 1.0) <= exp(-delta/temp))) { if (delta < 0) { // std::cout << "delta " << delta << "\n"; improved = true; } ++n_accept; } else { L: restore(); } discard(); // check(); } unsigned Placer::top_port_io_gate(const std::string &net_name) { Port *p = top->find_port(net_name); assert(p); Port *p2 = p->connection_other_port(); Instance *inst = cast(p2->node()); assert(models.is_io(inst)); return gate_idx.at(inst); } #ifndef NDEBUG void Placer::check() { for (Instance *inst : top->instances()) { int g = gate_idx.at(inst); assert(cell_gate[gate_cell[g]] == g); } for (int i = 1; i <= chipdb->n_cells; ++i) { int g = cell_gate[i]; if (g) assert(gate_cell[g] == i); } for (unsigned c = 0; c < chains.chains.size(); ++c) { const auto &v = chains.chains[c]; for (unsigned i = 0; i < v.size(); ++i) { Location loc (chipdb->tile(chain_x[c], chain_start[c] + i / 8), i % 8); int g = gate_idx.at(v[i]); int cell = chipdb->loc_cell(loc); int cell_g = cell_gate[cell]; assert(g == cell_g); } int nt = (v.size() + 7) / 8; int start = chain_start[c]; assert(start + nt - 1 <= chipdb->height - 2); } for (int w = 1; w < (int)nets.size(); ++w) // skip 0, nullptr assert(net_length[w] == compute_net_length(w)); } #endif int Placer::compute_net_length(int w) { if (net_global[w] || net_gates[w].empty()) return 0; const std::vector &w_gates = net_gates[w]; int g0 = w_gates[0]; int cell0 = gate_cell[g0]; const Location &loc0 = chipdb->cell_location[cell0]; int t0 = loc0.tile(); int x_min = chipdb->tile_x(t0), x_max = chipdb->tile_x(t0), y_min = chipdb->tile_y(t0), y_max = chipdb->tile_y(t0); for (int i = 1; i < (int)w_gates.size(); ++i) { int g = w_gates[i]; int cell = gate_cell[g]; const Location &loc = chipdb->cell_location[cell]; int t = loc.tile(); int x = chipdb->tile_x(t), y = chipdb->tile_y(t); x_min = std::min(x_min, x); x_max = std::max(x_max, x); y_min = std::min(y_min, y); y_max = std::max(y_max, y); } assert(x_min <= x_max && y_min <= y_max); return (x_max - x_min) + (y_max - y_min); } int Placer::wire_length() const { int length = 0; for (int ell : net_length) length += ell; return length; } Placer::Placer(random_generator &rg_, DesignState &ds_) : rg(rg_), ds(ds_), chipdb(ds.chipdb), package(ds.package), d(ds.d), models(ds.models), top(ds.top), chains(ds.chains), constraints(ds.constraints), gb_inst_gc(ds.gb_inst_gc), placement(ds.placement), conf(ds.conf), related_tiles(chipdb->n_tiles), diameter(std::max(chipdb->width, chipdb->height)), temp(10000.0), move_failed(false), changed_tiles(chipdb->n_tiles), cell_gate(chipdb->n_cells, 0) { for (int i = 1; i <= (int)chipdb->n_cells; ++i) { if (chipdb->cell_type[i] == CellType::PLL) { int t = chipdb->cell_location[i].tile(); std::vector t_related; t_related.push_back(t); const auto &pA = chipdb->cell_mfvs.at(i).at("PLLOUT_A"); int tA = pA.first; t_related.push_back(tA); const auto &pB = chipdb->cell_mfvs.at(i).at("PLLOUT_B"); int tB = pB.first; t_related.push_back(tB); for (int t2 : t_related) related_tiles[t2] = t_related; } } for (int i = 0; i < chipdb->width; ++i) { int t = chipdb->tile(i, 1); if (chipdb->tile_type[t] == TileType::LOGIC) logic_columns.push_back(i); } for (int i = 0; i < chipdb->n_tiles; ++i) { switch(chipdb->tile_type[i]) { case TileType::LOGIC: logic_tiles.push_back(i); break; case TileType::RAMT: ramt_tiles.push_back(i); break; default: break; } } std::tie(nets, net_idx) = top->index_nets(); int n_nets = nets.size(); net_global.resize(n_nets); net_length.resize(n_nets); net_gates.resize(n_nets); recompute.resize(n_nets); std::tie(gates, gate_idx) = top->index_instances(); n_gates = gates.size(); gate_clk.resize(n_gates, 0); gate_sr.resize(n_gates, 0); gate_cen.resize(n_gates, 0); gate_latch.resize(n_gates, 0); gate_local_np.resize(n_gates); tmp_local_np.resize(n_nets * 2); gate_chain.resize(n_gates, -1); gate_cell.resize(n_gates); gate_nets.resize(n_gates); for (int i = 1; i <= n_gates; ++i) { Instance *inst = gates[i]; if (models.is_lc(inst)) { Net *clk = inst->find_port("CLK")->connection(); if (clk) gate_clk[i] = net_idx.at(clk); Net *sr = inst->find_port("SR")->connection(); if (sr) gate_sr[i] = net_idx.at(sr); Net *cen = inst->find_port("CEN")->connection(); if (cen) gate_cen[i] = net_idx.at(cen); tmp_local_np.clear(); for (int j = 0; j < 4; ++j) { Net *n = inst->find_port(fmt("I" << j))->connection(); if (n && !n->is_constant()) tmp_local_np.insert((net_idx.at(n) << 1) | (j & 1)); } for (int j = 0; j < (int)tmp_local_np.size(); ++j) gate_local_np[i].push_back(tmp_local_np.ith(j)); } else if (models.is_io(inst)) { Net *latch = inst->find_port("LATCH_INPUT_VALUE")->connection(); if (latch) gate_cen[i] = net_idx.at(latch); } else if (models.is_gb(inst)) { Net *n = inst->find_port("GLOBAL_BUFFER_OUTPUT")->connection(); if (n) net_global[net_idx.at(n)] = true; } } } void Placer::place_initial() { locked.resize(n_gates); chained.resize(n_gates); // place chains std::vector logic_column_free(logic_columns.size(), 1); std::vector logic_column_last(logic_columns.size(), chipdb->height - 2); // FIXME apply only if present for (unsigned i = 0; i < logic_column_free.size(); ++i) { if (chipdb->device == "1k" && (logic_columns[i] == 1 || logic_columns[i] == 12)) logic_column_free[i] = 2; else if (chipdb->device == "8k" && (logic_columns[i] == 1 || logic_columns[i] == 32)) { logic_column_free[i] = 2; logic_column_last[i] = 31; } } for (unsigned i = 0; i < chains.chains.size(); ++i) { const auto &v = chains.chains[i]; int gate0 = gate_idx.at(v[0]); assert(gate_chain[gate0] == -1); gate_chain[gate0] = i; int nt = (v.size() + 7) / 8; for (unsigned k = 0; k < logic_columns.size(); ++k) { if (logic_column_free[k] + nt - 1 <= logic_column_last[k]) { int x = logic_columns[k]; int y = logic_column_free[k]; for (unsigned j = 0; j < v.size(); ++j) { Instance *inst = v[j]; int g = gate_idx.at(inst); Location loc(chipdb->tile(x, y + j / 8), j % 8); int cell = chipdb->loc_cell(loc); assert(cell_gate[cell] == 0); cell_gate[cell] = g; gate_cell[g] = cell; chained[g] = true; } chain_x.push_back(x); chain_start.push_back(y); logic_column_free[k] += nt; goto placed_chain; } } fatal(fmt("failed to place: placed " << i << " of " << chains.chains.size() << " carry chains")); placed_chain:; } std::vector cell_type_n_placed(n_cell_types, 0); for (const auto &p : placement) { Instance *inst = p.first; int g = gate_idx.at(inst); int c = p.second; assert(cell_gate[c] == 0); cell_gate[c] = g; gate_cell[g] = c; locked[g] = true; CellType ct = gate_cell_type(g); int ct_idx = cell_type_idx(ct); ++cell_type_n_placed[ct_idx]; assert(valid(chipdb->cell_location[c].tile())); } std::vector> cell_type_empty_cells = chipdb->cell_type_cells; for (int i = 0; i < n_cell_types; ++i) for (int j = 0; j < (int)cell_type_empty_cells[i].size();) { int c = cell_type_empty_cells[i][j]; if (cell_gate[c] != 0) pop(cell_type_empty_cells[i], j); else ++j; } std::vector cell_type_n_gates(n_cell_types, 0); for (int i = 1; i <= n_gates; ++i) ++cell_type_n_gates[cell_type_idx(gate_cell_type(i))]; std::set> io_q; for (int i = 1; i <= n_gates; ++i) { if (locked[i] || chained[i]) continue; free_gates.push_back(i); CellType ct = gate_cell_type(i); if (ct == CellType::GB) { Instance *inst = gates[i]; io_q.insert(std::make_pair(gb_inst_gc.at(inst), i)); } else { int ct_idx = cell_type_idx(ct); auto &v = cell_type_empty_cells[ct_idx]; for (int j = 0; j < (int)v.size(); ++j) { int c = v[j]; assert(cell_gate[c] == 0); cell_gate[c] = i; gate_cell[i] = c; if (ct != CellType::WARMBOOT && !valid(chipdb->cell_location[c].tile())) cell_gate[c] = 0; else { ++cell_type_n_placed[ct_idx]; pop(v, j); goto placed_gate; } } fatal(fmt("failed to place: placed " << cell_type_n_placed[ct_idx] << " " << cell_type_name(ct) << "s of " << cell_type_n_gates[ct_idx] << " / " << chipdb->cell_type_cells[ct_idx].size())); placed_gate:; } } // place gb int gb_idx = cell_type_idx(CellType::GB); while (!io_q.empty()) { std::pair p = *io_q.begin(); io_q.erase(io_q.begin()); int i = p.second; auto &v = cell_type_empty_cells[gb_idx]; for (unsigned j = 0; j < v.size(); ++j) { int c = v[j]; assert(cell_gate[c] == 0); cell_gate[c] = i; gate_cell[i] = c; if (!valid(chipdb->cell_location[c].tile())) cell_gate[c] = 0; else { ++cell_type_n_placed[gb_idx]; pop(v, j); goto placed_gb; } } fatal(fmt("failed to place: placed " << cell_type_n_placed[gb_idx] << " GBs of " << cell_type_n_gates[gb_idx] << " / " << chipdb->cell_type_cells[gb_idx].size())); placed_gb:; } for (int g = 1; g <= n_gates; ++g) { Instance *inst = gates[g]; for (const auto &p : inst->ports()) { Net *n = p.second->connection(); if (n && !n->is_constant()) // constants are not routed { int w = net_idx.at(n); net_gates[w].push_back(g); gate_nets[g].push_back(w); } } } for (int w = 0; w < (int)nets.size(); ++w) net_length[w] = compute_net_length(w); } void Placer::configure_io(const Location &loc, bool enable_input, bool pullup) { const auto &func_cbits = chipdb->tile_nonrouting_cbits.at(TileType::IO); const CBit &ie_0 = func_cbits.at("IoCtrl.IE_0")[0], &ie_1 = func_cbits.at("IoCtrl.IE_1")[0], &ren_0 = func_cbits.at("IoCtrl.REN_0")[0], &ren_1 = func_cbits.at("IoCtrl.REN_1")[0]; if (loc.pos() == 0) { conf.set_cbit(CBit(loc.tile(), ren_0.row, ren_0.col), !pullup); // active low } else { assert(loc.pos() == 1); conf.set_cbit(CBit(loc.tile(), ren_1.row, ren_1.col), !pullup); // active low } if (loc.pos() == 0) { conf.set_cbit(CBit(loc.tile(), ie_0.row, ie_0.col), // active low 1k, active high 8k (chipdb->device == "1k" ? !enable_input : enable_input)); } else { assert(loc.pos() == 1); conf.set_cbit(CBit(loc.tile(), ie_1.row, ie_1.col), // active low 1k, active high 8k (chipdb->device == "1k" ? !enable_input : enable_input)); } } void Placer::configure() { for (int g = 1; g <= n_gates; g ++) { Instance *inst = gates[g]; int cell = gate_cell[g]; if (g == 5) *logs << "cell = " << cell << "\n"; const Location &loc = chipdb->cell_location[cell]; if (models.is_warmboot(inst)) { placement[inst] = cell; continue; } int t = loc.tile(); const auto &func_cbits = chipdb->tile_nonrouting_cbits.at(chipdb->tile_type[t]); if (models.is_lc(inst)) { BitVector lut_init = inst->get_param("LUT_INIT").as_bits(); lut_init.resize(16); static std::vector lut_perm = { 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, }; const auto &cbits = func_cbits.at(fmt("LC_" << loc.pos())); for (int i = 0; i < 16; ++i) conf.set_cbit(CBit(t, cbits[lut_perm[i]].row, cbits[lut_perm[i]].col), lut_init[i]); bool carry_enable = inst->get_param("CARRY_ENABLE").get_bit(0); if (carry_enable) { conf.set_cbit(CBit(t, cbits[8].row, cbits[8].col), (bool)carry_enable); if (loc.pos() == 0) { Net *n = inst->find_port("CIN")->connection(); if (n && n->is_constant()) { const CBit &carryinset_cbit = func_cbits.at("CarryInSet")[0]; conf.set_cbit(CBit(t, carryinset_cbit.row, carryinset_cbit.col), n->constant() == Value::ONE); } } } bool dff_enable = inst->get_param("DFF_ENABLE").get_bit(0); conf.set_cbit(CBit(t, cbits[9].row, cbits[9].col), dff_enable); if (dff_enable) { bool neg_clk = inst->get_param("NEG_CLK").get_bit(0); const CBit &neg_clk_cbit = func_cbits.at("NegClk")[0]; conf.set_cbit(CBit(t, neg_clk_cbit.row, neg_clk_cbit.col), (bool)neg_clk); bool set_noreset = inst->get_param("SET_NORESET").get_bit(0); conf.set_cbit(CBit(t, cbits[18].row, cbits[18].col), (bool)set_noreset); bool async_sr = inst->get_param("ASYNC_SR").get_bit(0); conf.set_cbit(CBit(t, cbits[19].row, cbits[19].col), (bool)async_sr); } } else if (models.is_ioX(inst)) { const BitVector &pin_type = inst->get_param("PIN_TYPE").as_bits(); for (int i = 0; i < 6; ++i) { const CBit &cbit = func_cbits.at(fmt("IOB_" << loc.pos() << ".PINTYPE_" << i))[0]; conf.set_cbit(CBit(t, cbit.row, cbit.col), pin_type[i]); } const auto &negclk_cbits = func_cbits.at("NegClk"); bool neg_trigger = inst->get_param("NEG_TRIGGER").get_bit(0); for (int i = 0; i <= 1; ++i) conf.set_cbit(CBit(t, negclk_cbits[i].row, negclk_cbits[i].col), neg_trigger); if (models.is_gb_io(inst) && inst->find_port("GLOBAL_BUFFER_OUTPUT")->connected()) { int glb = chipdb->loc_pin_glb_num.at(loc); const auto &ecb = chipdb->extra_bits.at(fmt("padin_glb_netwk." << glb)); conf.set_extra_cbit(ecb); } } else if (models.is_gb(inst)) ; else if (models.is_ramX(inst)) { BitVector wm = inst->get_param("WRITE_MODE").as_bits(), rm = inst->get_param("READ_MODE").as_bits(); wm.resize(2); rm.resize(2); // powerup active low, don't set const auto &ramb_func_cbits = chipdb->tile_nonrouting_cbits.at(TileType::RAMB); const CBit &cbit0 = func_cbits.at("RamConfig.CBIT_0")[0], &cbit1 = func_cbits.at("RamConfig.CBIT_1")[0], &cbit2 = func_cbits.at("RamConfig.CBIT_2")[0], &cbit3 = func_cbits.at("RamConfig.CBIT_3")[0], &negclk = func_cbits.at("NegClk")[0], &ramb_negclk = ramb_func_cbits.at("NegClk")[0]; conf.set_cbit(CBit(t, cbit0.row, cbit0.col), wm[0]); conf.set_cbit(CBit(t, cbit1.row, cbit1.col), wm[1]); conf.set_cbit(CBit(t, cbit2.row, cbit2.col), rm[0]); conf.set_cbit(CBit(t, cbit3.row, cbit3.col), rm[1]); if (models.is_ramnr(inst) || models.is_ramnrnw(inst)) conf.set_cbit(CBit(t, negclk.row, negclk.col), true); if (models.is_ramnw(inst) || models.is_ramnrnw(inst)) conf.set_cbit(CBit(chipdb->ramt_ramb_tile(t), ramb_negclk.row, ramb_negclk.col), true); } else { assert(models.is_pllX(inst)); bool found = false; Location io_loc; for (const auto &p2 : chipdb->loc_pin_glb_num) { if (p2.first.tile() == t) { assert(!found); io_loc = p2.first; found = true; } } assert(found); const CBit &cbit_pt0 = func_cbits.at(fmt("IOB_" << io_loc.pos() << ".PINTYPE_0"))[0], &cbit_pt1 = func_cbits.at(fmt("IOB_" << io_loc.pos() << ".PINTYPE_1"))[0]; conf.set_cbit(CBit(t, cbit_pt0.row, cbit_pt0.col), true); conf.set_cbit(CBit(t, cbit_pt1.row, cbit_pt1.col), false); CBit delay_adjmode_fb_cb = chipdb->extra_cell_cbit(cell, "DELAY_ADJMODE_FB"); std::string delay_adjmode_fb = inst->get_param("DELAY_ADJUSTMENT_MODE_FEEDBACK").as_string(); if (delay_adjmode_fb == "FIXED") conf.set_cbit(delay_adjmode_fb_cb, false); else if (delay_adjmode_fb == "DYNAMIC") conf.set_cbit(delay_adjmode_fb_cb, true); else fatal(fmt("unknown DELAY_ADJUSTMENT_MODE_FEEDBACK value: " << delay_adjmode_fb)); CBit delay_adjmode_rel_cb = chipdb->extra_cell_cbit(cell, "DELAY_ADJMODE_REL"); std::string delay_adjmode_rel = inst->get_param("DELAY_ADJUSTMENT_MODE_RELATIVE").as_string(); if (delay_adjmode_rel == "FIXED") conf.set_cbit(delay_adjmode_rel_cb, false); else if (delay_adjmode_rel == "DYNAMIC") conf.set_cbit(delay_adjmode_rel_cb, true); else fatal(fmt("unknown DELAY_ADJUSTMENT_MODE_RELATIVE value: " << delay_adjmode_rel)); BitVector divf = inst->get_param("DIVF").as_bits(); divf.resize(7); for (int i = 0; i < (int)divf.size(); ++i) { CBit divf_i_cb = chipdb->extra_cell_cbit(cell, fmt("DIVF_" << i)); conf.set_cbit(divf_i_cb, divf[i]); } BitVector divq = inst->get_param("DIVQ").as_bits(); divq.resize(3); for (int i = 0; i < (int)divq.size(); ++i) { CBit divq_i_cb = chipdb->extra_cell_cbit(cell, fmt("DIVQ_" << i)); conf.set_cbit(divq_i_cb, divq[i]); } BitVector divr = inst->get_param("DIVR").as_bits(); divr.resize(4); for (int i = 0; i < (int)divr.size(); ++i) { CBit divr_i_cb = chipdb->extra_cell_cbit(cell, fmt("DIVR_" << i)); conf.set_cbit(divr_i_cb, divr[i]); } BitVector fda_feedback = inst->get_param("FDA_FEEDBACK").as_bits(); fda_feedback.resize(4); for (int i = 0; i < (int)fda_feedback.size(); ++i) { CBit fda_feedback_i_cb = chipdb->extra_cell_cbit(cell, fmt("FDA_FEEDBACK_" << i)); conf.set_cbit(fda_feedback_i_cb, fda_feedback[i]); } BitVector fda_relative = inst->get_param("FDA_RELATIVE").as_bits(); fda_relative.resize(4); for (int i = 0; i < (int)fda_relative.size(); ++i) { CBit fda_relative_i_cb = chipdb->extra_cell_cbit(cell, fmt("FDA_RELATIVE_" << i)); conf.set_cbit(fda_relative_i_cb, fda_relative[i]); } std::string feedback_path_str = inst->get_param("FEEDBACK_PATH").as_string(); int feedback_path_value = 0; if (feedback_path_str == "DELAY") feedback_path_value = 0; else if (feedback_path_str == "SIMPLE") feedback_path_value = 1; else if (feedback_path_str == "PHASE_AND_DELAY") feedback_path_value = 2; else { assert(feedback_path_str == "EXTERNAL"); feedback_path_value = 6; } BitVector feedback_path(3, feedback_path_value); for (int i = 0; i < (int)feedback_path.size(); ++i) { CBit feedback_path_i_cb = chipdb->extra_cell_cbit(cell, fmt("FEEDBACK_PATH_" << i)); conf.set_cbit(feedback_path_i_cb, feedback_path[i]); } BitVector filter_range = inst->get_param("FILTER_RANGE").as_bits(); filter_range.resize(3); for (int i = 0; i < (int)filter_range.size(); ++i) { CBit filter_range_i_cb = chipdb->extra_cell_cbit(cell, fmt("FILTER_RANGE_" << i)); conf.set_cbit(filter_range_i_cb, filter_range[i]); } std::string pllout_select_porta_str; if (inst->instance_of()->name() == "SB_PLL40_PAD" || inst->instance_of()->name() == "SB_PLL40_CORE") pllout_select_porta_str = inst->get_param("PLLOUT_SELECT").as_string(); else pllout_select_porta_str = inst->get_param("PLLOUT_SELECT_PORTA").as_string(); int pllout_select_porta_value = 0; if (pllout_select_porta_str == "GENCLK") pllout_select_porta_value = 0; else if (pllout_select_porta_str == "GENCLK_HALF") pllout_select_porta_value = 1; else if (pllout_select_porta_str == "SHIFTREG_90deg") pllout_select_porta_value = 2; else { assert(pllout_select_porta_str == "SHIFTREG_0deg"); pllout_select_porta_value = 3; } BitVector pllout_select_porta(2, pllout_select_porta_value); for (int i = 0; i < (int)pllout_select_porta.size(); ++i) { CBit pllout_select_porta_i_cb = chipdb->extra_cell_cbit(cell, fmt("PLLOUT_SELECT_A_" << i)); conf.set_cbit(pllout_select_porta_i_cb, pllout_select_porta[i]); } int pllout_select_portb_value = 0; if (inst->instance_of()->name() == "SB_PLL40_2_PAD" || inst->instance_of()->name() == "SB_PLL40_2F_PAD" || inst->instance_of()->name() == "SB_PLL40_2F_CORE") { std::string pllout_select_portb_str = inst->get_param("PLLOUT_SELECT_PORTB").as_string(); if (pllout_select_portb_str == "GENCLK") pllout_select_portb_value = 0; else if (pllout_select_portb_str == "GENCLK_HALF") pllout_select_portb_value = 1; else if (pllout_select_portb_str == "SHIFTREG_90deg") pllout_select_portb_value = 2; else { assert(pllout_select_portb_str == "SHIFTREG_0deg"); pllout_select_portb_value = 3; } } BitVector pllout_select_portb(2, pllout_select_portb_value); for (int i = 0; i < (int)pllout_select_portb.size(); ++i) { CBit pllout_select_portb_i_cb = chipdb->extra_cell_cbit(cell, fmt("PLLOUT_SELECT_B_" << i)); conf.set_cbit(pllout_select_portb_i_cb, pllout_select_portb[i]); } int pll_type_value = 0; if (inst->instance_of()->name() == "SB_PLL40_PAD") pll_type_value = 2; else if (inst->instance_of()->name() == "SB_PLL40_2_PAD") pll_type_value = 4; else if (inst->instance_of()->name() == "SB_PLL40_2F_PAD") pll_type_value = 6; else if (inst->instance_of()->name() == "SB_PLL40_CORE") pll_type_value = 3; else { assert(inst->instance_of()->name() == "SB_PLL40_2F_CORE"); pll_type_value = 7; } BitVector pll_type(3, pll_type_value); for (int i = 0; i < (int)pll_type.size(); ++i) { CBit pll_type_i_cb = chipdb->extra_cell_cbit(cell, fmt("PLLTYPE_" << i)); conf.set_cbit(pll_type_i_cb, pll_type[i]); } BitVector shiftreg_div_mode = inst->get_param("SHIFTREG_DIV_MODE").as_bits(); CBit shiftreg_div_mode_cb = chipdb->extra_cell_cbit(cell, "SHIFTREG_DIV_MODE"); conf.set_cbit(shiftreg_div_mode_cb, shiftreg_div_mode[0]); Port *a = inst->find_port("PLLOUTGLOBAL"); if (!a) a = inst->find_port("PLLOUTGLOBALA"); assert(a); if (a->connected()) { const auto &p2 = chipdb->cell_mfvs.at(cell).at("PLLOUT_A"); Location glb_loc(p2.first, std::stoi(p2.second)); int glb = chipdb->loc_pin_glb_num.at(glb_loc); const auto &ecb = chipdb->extra_bits.at(fmt("padin_glb_netwk." << glb)); conf.set_extra_cbit(ecb); } Port *b = inst->find_port("PLLOUTGLOBALB"); if (b && b->connected()) { const auto &p2 = chipdb->cell_mfvs.at(cell).at("PLLOUT_B"); Location glb_loc(p2.first, std::stoi(p2.second)); int glb = chipdb->loc_pin_glb_num.at(glb_loc); const auto &ecb = chipdb->extra_bits.at(fmt("padin_glb_netwk." << glb)); conf.set_extra_cbit(ecb); } } placement[inst] = cell; } // set IoCtrl configuration bits { const auto &func_cbits = chipdb->tile_nonrouting_cbits.at(TileType::IO); const CBit &lvds = func_cbits.at("IoCtrl.LVDS")[0]; std::map loc_pll; int pll_idx = cell_type_idx(CellType::PLL); for (int cell : chipdb->cell_type_cells[pll_idx]) { const auto &p2a = chipdb->cell_mfvs.at(cell).at("PLLOUT_A"); Location a_loc(p2a.first, std::stoi(p2a.second)); extend(loc_pll, a_loc, cell); const auto &p2b = chipdb->cell_mfvs.at(cell).at("PLLOUT_B"); Location b_loc(p2b.first, std::stoi(p2b.second)); extend(loc_pll, b_loc, cell); } for (const auto &p : package.pin_loc) { // unused io bool enable_input = false; bool pullup = true; // default pullup const Location &loc = p.second; int pll_cell = lookup_or_default(loc_pll, loc, 0); if (pll_cell) { // FIXME only enable if inputs present enable_input = true; pullup = false; } else { int cell = chipdb->loc_cell(loc); int g = cell_gate[cell]; if (g) { Instance *inst = gates[g]; if (inst->find_port("D_IN_0")->connected() || inst->find_port("D_IN_1")->connected() || (models.is_gb_io(inst) && inst->find_port("GLOBAL_BUFFER_OUTPUT")->connected())) enable_input = true; pullup = inst->get_param("PULLUP").get_bit(0); conf.set_cbit(CBit(loc.tile(), lvds.row, lvds.col), inst->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT"); } } const Location &ieren_loc = chipdb->ieren.at(loc); configure_io(ieren_loc, enable_input, pullup); } std::set ieren_image; for (const auto &p : chipdb->ieren) extend(ieren_image, p.second); for (int t = 0; t < chipdb->n_tiles; ++t) { if (chipdb->tile_type[t] != TileType::IO) continue; for (int p = 0; p <= 1; ++p) { bool enable_input = false; bool pullup = true; // default pullup Location loc(t, p); if (contains(ieren_image, loc)) continue; configure_io(loc, enable_input, pullup); } } } // set RamConfig.PowerUp configuration bit { const CBit &powerup = (chipdb->tile_nonrouting_cbits.at(TileType::RAMB) .at("RamConfig.PowerUp") [0]); for (int t : ramt_tiles) { Location loc(t, 0); int cell = chipdb->loc_cell(loc); int g = cell_gate[cell]; assert(!g || models.is_ramX(gates[g])); conf.set_cbit(CBit(chipdb->ramt_ramb_tile(loc.tile()), // PowerUp on ramb tile powerup.row, powerup.col), // active low (chipdb->device == "1k" ? !g : (bool)g)); } } } void Placer::place() { place_initial(); // check(); *logs << " initial wire length = " << wire_length() << "\n"; int n_no_progress = 0; for (;;) { n_move = n_accept = 0; improved = false; for (int m = 0; m < 15; ++m) { for (int g : free_gates) { int new_cell = gate_random_cell(g); int new_g = cell_gate[new_cell]; if (new_g && chained[new_g]) continue; assert(!move_failed); move_gate(g, new_cell); accept_or_restore(); // check(); } for (int c = 0; c < (int)chains.chains.size(); ++c) { std::pair new_loc = chain_random_loc(c); if (new_loc.second) { assert(!move_failed); move_chain(c, new_loc.first); accept_or_restore(); } // check(); } } if (improved) { n_no_progress = 0; // std::cout << "improved\n"; } else ++n_no_progress; if (temp <= 1e-3 && n_no_progress >= 5) break; double Raccept = (double)n_accept / (double)n_move; #if 0 std::cout << "Raccept " << Raccept << ", diameter = " << diameter << ", temp " << temp << "\n"; #endif int M = std::max(chipdb->width, chipdb->height); double upper = 0.6, lower = 0.4; if (Raccept >= 0.8) temp *= 0.5; else if (Raccept > upper) { if (diameter < M) ++diameter; else temp *= 0.9; } else if (Raccept > lower) temp *= 0.95; else { // Raccept < 0.3 if (diameter > 1) --diameter; else temp *= 0.8; } } *logs << " final wire length = " << wire_length() << "\n"; configure(); #if 0 int max_demand = 0; for (int t = 0; t < chipdb->n_tiles; ++t) { if (chipdb->tile_type[t] != TileType::LOGIC) continue; std::set> demand; for (int q = 0; q < 8; q ++) { Location loc(t, q); int cell = chipdb->loc_cell(loc); int g = cell_gate[cell]; if (g) { Instance *inst = gates[g]; for (int i = 0; i < 4; ++i) { Net *n = inst->find_port(fmt("I" << i))->connection(); if (n && !n->is_constant()) { int parity = (q + i) & 1; demand.insert(std::make_pair(n, parity)); } } Net *clk = inst->find_port("CLK")->connection(); if (clk && !clk->is_constant()) { int n = net_idx.at(clk); if (!net_global[n]) demand.insert(std::make_pair(clk, 0)); } Net *cen = inst->find_port("CEN")->connection(); if (cen && !cen->is_constant()) { int n = net_idx.at(cen); if (!net_global[n]) demand.insert(std::make_pair(cen, 0)); } Net *sr = inst->find_port("SR")->connection(); if (sr && !sr->is_constant()) { int n = net_idx.at(sr); if (!net_global[n]) demand.insert(std::make_pair(sr, 0)); } } } *logs << t << " " << chipdb->tile_x(t) << " " << chipdb->tile_y(t) << " " << demand.size() << "\n"; if ((int)demand.size() > max_demand) max_demand = demand.size(); } *logs << "max_demand " << max_demand << "\n"; #endif #if 0 { int t = chipdb->tile(17, 16); for (const auto &p : placement) { int cell = p.second; const Location &loc = chipdb->cell_location[cell]; if (loc.tile() == t) { Instance *inst = p.first; *logs << "LC " << inst << " " << loc.pos() << "\n"; *logs << " I0 " << inst->find_port("I0")->connection()->name() << "\n"; *logs << " I1 " << inst->find_port("I1")->connection()->name() << "\n"; *logs << " I2 " << inst->find_port("I2")->connection()->name() << "\n"; *logs << " I3 " << inst->find_port("I3")->connection()->name() << "\n"; if (inst->find_port("CIN")->connected()) *logs << " CIN " << inst->find_port("CIN")->connection()->name() << "\n"; if (inst->find_port("CLK")->connected()) *logs << " CLK " << inst->find_port("CLK")->connection()->name() << "\n"; if (inst->find_port("SR")->connected()) *logs << " SR " << inst->find_port("SR")->connection()->name() << "\n"; if (inst->find_port("CEN")->connected()) *logs << " CEN " << inst->find_port("CEN")->connection()->name() << "\n"; } } } #endif int n_pio = 0, n_plb = 0, n_bram = 0; std::set seen; for (int i = 1; i <= n_gates; ++i) { int cell = gate_cell[i]; int t = chipdb->cell_location[cell].tile(); seen.insert(t); } for (int t : seen) { if (chipdb->tile_type[t] == TileType::LOGIC) ++n_plb; else if (chipdb->tile_type[t] == TileType::IO) ++n_pio; else if (chipdb->tile_type[t] == TileType::RAMT) ++n_bram; } *logs << "\nAfter placement:\n" << "PIOs " << n_pio << " / " << package.pin_loc.size() << "\n" << "PLBs " << n_plb << " / " << logic_tiles.size() << "\n" << "BRAMs " << n_bram << " / " << ramt_tiles.size() << "\n" << "\n"; } void place(random_generator &rg, DesignState &ds) { Placer placer(rg, ds); clock_t start = clock(); placer.place(); clock_t end = clock(); *logs << " place time " << std::fixed << std::setprecision(2) << (double)(end - start) / (double)CLOCKS_PER_SEC << "s\n"; } arachne-pnr-0~20150927gitefdb026/src/place.hh000066400000000000000000000017011260207143000204040ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_PLACE_HH #define PNR_PLACE_HH #include "util.hh" #include class Design; class Instance; class Configuration; class ChipDB; class Package; class Constraints; class CarryChains; class IdLess; class DesignState; extern void place(random_generator &rg, DesignState &ds); #endif arachne-pnr-0~20150927gitefdb026/src/priorityq.hh000066400000000000000000000012751260207143000213700ustar00rootroot00000000000000 #include #include template> class PriorityQ { public: Comp comp; std::vector v; unsigned n; public: PriorityQ() : n(0) {} PriorityQ(Comp comp_) : comp(comp_), n(0) {} size_t size() const { return n; } void clear() { n = 0; } bool empty() { return n == 0; } void push(const T &x) { assert(v.size() >= n); if (v.size() == n) v.push_back(x); else v[n] = x; ++n; std::push_heap(&v[0], &v[n], comp); } const T &pop() { assert(n > 0); std::pop_heap(&v[0], &v[n], comp); --n; return v[n]; } const T &top() { assert(n > 0); return v[0]; } }; arachne-pnr-0~20150927gitefdb026/src/route.cc000066400000000000000000000470051260207143000204530ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include "casting.hh" #include "netlist.hh" #include "location.hh" #include "chipdb.hh" #include "configuration.hh" #include "bitvector.hh" #include "ullmanset.hh" #include "priorityq.hh" #include "designstate.hh" #include #include #include #include #include #include #include #include #include class Router; class Comp { public: Comp() {} bool operator()(const std::pair &lhs, const std::pair &rhs) const { return (lhs.second > rhs.second || (lhs.second == rhs.second && lhs.first > rhs.first)); } }; class Router { const ChipDB *chipdb; Design *d; Models ⊧ const std::map &placement; std::vector &cnet_net; Configuration &conf; BitVector cnet_global, cnet_local; std::vector> cnet_outs; std::map> ram_gate_chip; std::map pll_gate_chip; std::vector> cnet_tiles; // cnet_bbox std::vector cnet_xmin, cnet_xmax, cnet_ymin, cnet_ymax; int n_nets; // to route std::vector net_source; std::vector> net_targets; std::vector net_net; static const int max_passes = 50; int passes; int n_shared; std::vector demand; std::vector historical_demand; std::vector>> net_route; // per net int current_net; UllmanSet unrouted; UllmanSet visited; UllmanSet frontier; // cn, cost[cn] PriorityQ, Comp> frontierq; std::vector backptr; std::vector cost; void start(int net); int pop(); void visit(int cn); void ripup(int net); void traceback(int net, int target); int port_cnet(Instance *inst, Port *p); #ifndef NDEBUG void check(); #endif public: Router(DesignState &ds); void route(); }; int Router::port_cnet(Instance *inst, Port *p) { const auto &p_name = p->name(); int cell = placement.at(inst); const Location &loc = chipdb->cell_location[cell]; int t = loc.tile(); std::string tile_net_name; if (models.is_lc(inst)) { if (p_name == "CLK") tile_net_name = fmt("lutff_global/clk"); else if (p_name == "CEN") tile_net_name = fmt("lutff_global/cen"); else if (p_name == "SR") tile_net_name = fmt("lutff_global/s_r"); else if (p_name == "I0") tile_net_name = fmt("lutff_" << loc.pos() << "/in_0"); else if (p_name == "I1") tile_net_name = fmt("lutff_" << loc.pos() << "/in_1"); else if (p_name == "I2") tile_net_name = fmt("lutff_" << loc.pos() << "/in_2"); else if (p_name == "I3") tile_net_name = fmt("lutff_" << loc.pos() << "/in_3"); else if (p_name == "CIN") { if (loc.pos() == 0) tile_net_name = "carry_in_mux"; else return -1; } else if (p_name == "COUT") tile_net_name = fmt("lutff_" << loc.pos() << "/cout"); else { assert(p_name == "O"); tile_net_name = fmt("lutff_" << loc.pos() << "/out"); } } else if (models.is_ioX(inst)) { if (p_name == "LATCH_INPUT_VALUE") tile_net_name = fmt("io_global/latch"); else if (p_name == "CLOCK_ENABLE") tile_net_name = fmt("io_global/cen"); else if (p_name == "INPUT_CLK") tile_net_name = fmt("io_global/inclk"); else if (p_name == "OUTPUT_CLK") tile_net_name = fmt("io_global/outclk"); else if (p_name == "OUTPUT_ENABLE") tile_net_name = fmt("io_" << loc.pos() << "/OUT_ENB"); else if (p_name == "D_OUT_0") tile_net_name = fmt("io_" << loc.pos() << "/D_OUT_0"); else if (p_name == "D_OUT_1") tile_net_name = fmt("io_" << loc.pos() << "/D_OUT_1"); else if (p_name == "D_IN_0") tile_net_name = fmt("io_" << loc.pos() << "/D_IN_0"); else if (p_name == "D_IN_1") tile_net_name = fmt("io_" << loc.pos() << "/D_IN_1"); else { assert(models.is_gb_io(inst) && p_name == "GLOBAL_BUFFER_OUTPUT"); int g = chipdb->loc_pin_glb_num.at(loc); tile_net_name = fmt("glb_netwk_" << g); } } else if (models.is_gb(inst)) { if (p_name == "USER_SIGNAL_TO_GLOBAL_BUFFER") tile_net_name = fmt("fabout"); else { assert(p_name == "GLOBAL_BUFFER_OUTPUT"); int g = chipdb->gbufin.at(std::make_pair(chipdb->tile_x(t), chipdb->tile_y(t))); tile_net_name = fmt("glb_netwk_" << g); } } else if (models.is_warmboot(inst)) { const auto &p2 = chipdb->cell_mfvs.at(cell).at(p_name); t = p2.first; tile_net_name = p2.second; } else if (models.is_ramX(inst)) { auto r = ram_gate_chip.at(p_name); tile_net_name = r.first; // FIXME if (r.second) if (!contains(chipdb->tile_nets[t], tile_net_name)) t = chipdb->tile(chipdb->tile_x(loc.tile()), chipdb->tile_y(loc.tile()) - 1); } else { assert(models.is_pllX(inst)); // FIXME std::string r = lookup_or_default(pll_gate_chip, p_name, p_name); if (r == "PLLOUTGLOBAL" || r == "PLLOUTGLOBALA") { const auto &p2 = chipdb->cell_mfvs.at(cell).at("PLLOUT_A"); Location g_loc(p2.first, std::stoi(p2.second)); int g = chipdb->loc_pin_glb_num.at(g_loc); tile_net_name = fmt("glb_netwk_" << g); } else if (r == "PLLOUTGLOBALB") { const auto &p2 = chipdb->cell_mfvs.at(cell).at("PLLOUT_B"); Location g_loc(p2.first, std::stoi(p2.second)); int g = chipdb->loc_pin_glb_num.at(g_loc); tile_net_name = fmt("glb_netwk_" << g); } else { const auto &p2 = chipdb->cell_mfvs.at(cell).at(r); t = p2.first; if (r == "PLLOUT_A" || r == "PLLOUT_B") tile_net_name = fmt("io_" << p2.second << "/D_IN_0"); else tile_net_name = p2.second; } #if 0 *logs << p_name << " aka " << r << " -> (" << chipdb->tile_x(t) << " " << chipdb->tile_y(t) << ") " << tile_net_name << "\n"; #endif } int n = chipdb->tile_nets[t].at(tile_net_name); return n; } #ifndef NDEBUG void Router::check() { std::vector demand2 (chipdb->n_nets, 0); for (int i = 0; i < n_nets; ++i) { for (const auto &p : net_route[i]) ++demand2[p.second]; } int n_shared2 = 0; for (int i = 0; i < chipdb->n_nets; ++i) { assert(demand2[i] == demand[i]); if (demand2[i] > 1) ++n_shared2; } assert(n_shared2 == n_shared); } #endif Router::Router(DesignState &ds) : chipdb(ds.chipdb), d(ds.d), models(ds.models), placement(ds.placement), cnet_net(ds.cnet_net), conf(ds.conf), cnet_global(chipdb->n_nets), cnet_local(chipdb->n_nets), cnet_outs(chipdb->n_nets), cnet_tiles(chipdb->n_nets), cnet_xmin(chipdb->n_nets), cnet_xmax(chipdb->n_nets), cnet_ymin(chipdb->n_nets), cnet_ymax(chipdb->n_nets), n_nets(0), n_shared(0), demand(chipdb->n_nets, 0), historical_demand(chipdb->n_nets, 0), unrouted(chipdb->n_nets), visited(chipdb->n_nets), frontier(chipdb->n_nets), backptr(chipdb->n_nets), cost(chipdb->n_nets) { cnet_net = std::vector(chipdb->n_nets, nullptr); for (int t = 0; t < chipdb->n_tiles; ++t) { for (const auto &p : chipdb->tile_nets[t]) { if (is_prefix("local_", p.first)) { if (!cnet_local[p.second]) { cnet_local[p.second] = true; break; } } else if (is_prefix("glb_netwk_", p.first)) { if (!cnet_global[p.second]) { cnet_global[p.second] = true; break; } } } } for (int i = 0; i < chipdb->n_nets; ++i) { for (int s : chipdb->in_switches[i]) { assert(contains_key(chipdb->switches[s].in_val, i)); int j = chipdb->switches[s].out; assert(j != i); cnet_outs[i].push_back(j); } } for (int i = 0; i <= 7; ++i) extend(ram_gate_chip, fmt("RDATA[" << i << "]"), std::make_pair(fmt("ram/RDATA_" << i), true)); for (int i = 8; i <= 15; ++i) extend(ram_gate_chip, fmt("RDATA[" << i << "]"), std::make_pair(fmt("ram/RDATA_" << i), false)); for (int i = 0; i <= 10; ++i) extend(ram_gate_chip, fmt("RADDR[" << i << "]"), std::make_pair(fmt("ram/RADDR_" << i), false)); for (int i = 0; i <= 10; ++i) extend(ram_gate_chip, fmt("WADDR[" << i << "]"), std::make_pair(fmt("ram/WADDR_" << i), true)); if (chipdb->device == "1k") { for (int i = 0; i <= 7; ++i) extend(ram_gate_chip, fmt("MASK[" << i << "]"), std::make_pair(fmt("ram/MASK_" << i), true)); for (int i = 8; i <= 15; ++i) extend(ram_gate_chip, fmt("MASK[" << i << "]"), std::make_pair(fmt("ram/MASK_" << i), false)); } else { assert(chipdb->device == "8k"); for (int i = 0; i <= 7; ++i) extend(ram_gate_chip, fmt("MASK[" << i << "]"), std::make_pair(fmt("ram/MASK_" << i), false)); for (int i = 8; i <= 15; ++i) extend(ram_gate_chip, fmt("MASK[" << i << "]"), std::make_pair(fmt("ram/MASK_" << i), true)); } for (int i = 0; i <= 7; ++i) extend(ram_gate_chip, fmt("WDATA[" << i << "]"), std::make_pair(fmt("ram/WDATA_" << i), true)); for (int i = 8; i <= 15; ++i) extend(ram_gate_chip, fmt("WDATA[" << i << "]"), std::make_pair(fmt("ram/WDATA_" << i), false)); extend(ram_gate_chip, "RCLKE", std::make_pair("ram/RCLKE", false)); extend(ram_gate_chip, "RCLK", std::make_pair("ram/RCLK", false)); extend(ram_gate_chip, "RCLKN", std::make_pair("ram/RCLK", false)); extend(ram_gate_chip, "RE", std::make_pair("ram/RE", false)); extend(ram_gate_chip, "WCLKE", std::make_pair("ram/WCLKE", true)); extend(ram_gate_chip, "WCLK", std::make_pair("ram/WCLK", true)); extend(ram_gate_chip, "WCLKN", std::make_pair("ram/WCLK", true)); extend(ram_gate_chip, "WE", std::make_pair("ram/WE", true)); for (int i = 0; i < 8; ++i) extend(pll_gate_chip, fmt("DYNAMICDELAY[" << i << "]"), fmt("DYNAMICDELAY_" << i)); extend(pll_gate_chip, "PLLOUTCORE", "PLLOUT_A"); extend(pll_gate_chip, "PLLOUTCOREA", "PLLOUT_A"); extend(pll_gate_chip, "PLLOUTCOREB", "PLLOUT_B"); for (int t = 0; t < chipdb->n_tiles; ++t) for (const auto &p : chipdb->tile_nets[t]) cnet_tiles[p.second].push_back(t); for (int i = 0; i < chipdb->n_nets; ++i) { assert(!cnet_tiles[i].empty()); int t0 = cnet_tiles[i][0]; int xmin, xmax, ymin, ymax; xmin = xmax = chipdb->tile_x(t0); ymin = ymax = chipdb->tile_y(t0); for (int j = 1; j < (int)cnet_tiles[i].size(); ++j) { int t = cnet_tiles[i][j]; xmin = std::min(xmin, chipdb->tile_x(t)); xmax = std::max(xmax, chipdb->tile_x(t)); ymin = std::min(ymin, chipdb->tile_y(t)); ymax = std::max(ymax, chipdb->tile_y(t)); } cnet_xmin[i] = xmin; cnet_xmax[i] = xmax; cnet_ymin[i] = ymin; cnet_ymax[i] = ymax; } } void Router::start(int net) { visited.clear(); frontier.clear(); frontierq.clear(); int source = net_source[net]; cost[source] = 0; backptr[source] = -1; visit(source); for (const auto &p : net_route[net]) { frontier.erase(p.second); cost[p.second] = 0; backptr[p.second] = -1; visit(p.second); } } void Router::visit(int cn) { assert(!frontier.contains(cn)); visited.extend(cn); for (int cn2 : cnet_outs[cn]) { if (visited.contains(cn2)) continue; int cn2_cost = 1; // base if (passes == max_passes) { if (demand[cn2]) cn2_cost = 1000000; } else // if (passes > 1) { cn2_cost += historical_demand[cn2]; cn2_cost *= (1 + 3 * demand[cn2]); } int new_cost = cost[cn] + cn2_cost; if (frontier.contains(cn2)) { if (new_cost < cost[cn2]) { #if 0 std::cout << "update cn " << cn2 << " old_cost " << cost[cn2] << " new_cost " << new_cost << "\n"; #endif cost[cn2] = new_cost; backptr[cn2] = cn; frontierq.push(std::make_pair(cn2, new_cost)); } } else { cost[cn2] = new_cost; backptr[cn2] = cn; #if 0 std::cout << "add cn " << cn2 << " cost " << new_cost << "\n"; #endif frontier.insert(cn2); frontierq.push(std::make_pair(cn2, new_cost)); } } } int Router::pop() { L: assert(!frontierq.empty()); int cn, cn_cost; std::tie(cn, cn_cost) = frontierq.pop(); if (!frontier.contains(cn)) goto L; // *logs << "pop " << cn << "\n"; assert(cn_cost == cost[cn]); assert(frontierq.empty() || cn_cost <= frontierq.top().second); frontier.erase(cn); return cn; } void Router::ripup(int net) { for (const auto &p : net_route[net]) { int cn = p.second; --demand[cn]; if (demand[cn] == 1) --n_shared; } net_route[net].clear(); } void Router::traceback(int net, int target) { int cn = target; while (cn >= 0) { int prev = backptr[cn]; if (prev >= 0) { if (demand[cn] == 1) ++n_shared; ++demand[cn]; net_route[net].push_back(std::make_pair(prev, cn)); } cn = prev; } } void Router::route() { // d->dump(); Model *top = d->top(); std::set boundary_nets = top->boundary_nets(d); for (const auto &p : top->nets()) { Net *n = p.second; if (contains(boundary_nets, n)) continue; #ifndef NDEBUG if (n->is_constant()) { Value v = n->constant(); assert(v == Value::ZERO || v == Value::ONE); for (auto p2 : n->connections()) { Instance *inst = cast(p2->node()); if (models.is_lc(inst) && p2->name() == "CIN") { int cell = placement.at(inst); const Location &loc = chipdb->cell_location[cell]; if (loc.pos() == 0) continue; } assert(p2->is_input() && !p2->is_bidir() && p2->undriven() == v); } } #endif int source = -1; std::vector targets; // *logs << n->name() << "\n"; for (auto p2 : n->connections()) { assert(p2->connection() == n); assert(isa(p2->node())); Instance *inst = cast(p2->node()); int cn = port_cnet(inst, p2); // like lutff_i/cin if (cn < 0) continue; #if 1 if (cnet_net[cn] && cnet_net[cn] != n) *logs << "n " << n->name() << " cn " << cn << " cnet_net[cn] " << cnet_net[cn]->name() << "\n"; #endif assert(cnet_net[cn] == nullptr // like lutff_global/clk || cnet_net[cn] == n); cnet_net[cn] = n; assert(!p2->is_bidir()); if (p2->is_output()) { assert(source < 0); source = cn; } else { assert(p2->is_input()); targets.push_back(cn); } } if (source >= 0 && !targets.empty()) { ++n_nets; #if 0 *logs << "net " << n_nets << " " << n->name() << " " << source; for (int cn : targets) *logs << " " << cn; *logs << "\n"; #endif net_source.push_back(source); net_targets.push_back(std::move(targets)); net_net.push_back(n); } } net_route.resize(n_nets); for (passes = 1; passes <= max_passes; ++passes) { for (int n = 0; n < n_nets; ++n) { current_net = n; const auto &targets = net_targets[n]; if (passes > 1) { assert(net_route[n].size() > 0); for (const auto &p : net_route[n]) { if (demand[p.second] > 1) goto M; } continue; } M: unrouted.clear(); for (int i : targets) // not extend, e.g., lutff_global/clk unrouted.insert(i); ripup(n); L: // *logs << "start:"; start(n); while (!frontier.empty()) { int cn = pop(); if (unrouted.contains(cn)) { unrouted.erase(cn); traceback(n, cn); if (unrouted.empty()) break; else goto L; } else visit(cn); } if (!unrouted.empty()) { *logs << net_source[n] << " ->"; for (int t : targets) *logs << " " << t; *logs << "\n"; } assert(unrouted.empty()); // *logs << "\n"; // check(); } *logs << " pass " << passes << ", " << n_shared << " shared.\n"; if (!n_shared) break; if (passes > 1) { for (int i = 0; i < chipdb->n_nets; ++i) { if (demand[i] > 1) historical_demand[i] += demand[i]; } } #if 0 for (int i = 0; i < n_nets; ++i) { for (const auto &p : net_route[i]) { bool print = false; if (demand[p.second] > 1) { print = true; *logs << "demand " << i << " " << p.second << "\n"; } if (print) { *logs << " net " << i << " " << net_net[i]->name() << "\n"; *logs << " " << net_source[i] << " -> "; for (int cn : net_targets[i]) *logs << " " << cn; *logs << "\n"; *logs << "route\n"; for (const auto &p2 : net_route[i]) *logs << " " << p2.first << " -> " << p2.second << "\n"; } } } #endif } if (n_shared) fatal("failed to route"); int n_span4 = 0, n_span12 = 0; BitVector is_span4(chipdb->n_nets), is_span12(chipdb->n_nets); for (int i = 0; i < chipdb->n_tiles; ++i) { for (const auto &p : chipdb->tile_nets[i]) { const std::string &name = p.first; int cn = p.second; if (is_span4[cn] || is_span12[cn]) continue; if (is_prefix("span4_", name) || is_prefix("sp4_", name)) { is_span4[cn] = true; ++n_span4; } else if (is_prefix("span12_", name) || is_prefix("sp12_", name)) { is_span12[cn] = true; ++n_span12; } } } int n_span4_used = 0, n_span12_used = 0; for (const auto &v : net_route) for (const auto &p : v) { if (is_span4[p.second]) ++n_span4_used; else if (is_span12[p.second]) ++n_span12_used; int s = chipdb->find_switch(p.first, p.second); const Switch &sw = chipdb->switches[s]; assert(!contains(chipdb->net_global, p.second)); if (contains(chipdb->net_global, p.first)) { int g = chipdb->net_global.at(p.first); int cb_t = chipdb->tile_colbuf_tile.at(sw.tile); if (chipdb->device == "1k" && chipdb->tile_type[cb_t] == TileType::RAMT) { cb_t = chipdb->tile(chipdb->tile_x(cb_t), chipdb->tile_y(cb_t) - 1); assert(chipdb->tile_type[cb_t] == TileType::RAMB); } const CBit &colbuf_cbit = (chipdb->tile_nonrouting_cbits .at(chipdb->tile_type[cb_t]) .at(fmt("ColBufCtrl.glb_netwk_" << g)) [0]); conf.set_cbit(CBit(cb_t, colbuf_cbit.row, colbuf_cbit.col), 1); } conf.set_cbits(sw.cbits, sw.in_val.at(p.first)); } *logs << "\n" << "After routing:\n" << "span_4 " << n_span4_used << " / " << n_span4 << "\n" << "span_12 " << n_span12_used << " / " << n_span12 << "\n\n"; } void route(DesignState &ds) { Router router(ds); clock_t start = clock(); router.route(); clock_t end = clock(); *logs << " route time " << std::fixed << std::setprecision(2) << (double)(end - start) / (double)CLOCKS_PER_SEC << "s\n"; } arachne-pnr-0~20150927gitefdb026/src/route.hh000066400000000000000000000015511260207143000204610ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_ROUTE_HH #define PNR_ROUTE_HH #include "location.hh" #include "util.hh" #include class Design; class Instance; class ChipDB; class Configuration; extern void route(DesignState &ds); #endif arachne-pnr-0~20150927gitefdb026/src/ullmanset.hh000066400000000000000000000035311260207143000213270ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "vector.hh" #include #include template class BasedUllmanSet { size_t n; std::vector key; BasedVector pos; public: BasedUllmanSet() : n(0) {} BasedUllmanSet(size_t cap) : n(0), key(cap), pos(cap) {} size_t capacity() const { return key.size(); } size_t size() const { return n; } bool empty() const { return n == 0; } void clear() { n = 0; } void resize(size_t cap) { key.resize(cap); pos.resize(cap); n = 0; } bool contains(int k) const { unsigned p = pos[k]; return (p < n && key[p] == k); } void insert(int k) { if (contains(k)) return; unsigned p = n++; key[p] = k; pos[k] = p; } void extend(int k) { assert(!contains(k)); unsigned p = n++; key[p] = k; pos[k] = p; } void erase(int k) { if (!contains(k)) return; unsigned p = pos[k]; --n; if (p != n) { int ell = key[n]; pos[ell] = p; key[p] = ell; } } int ith(int i) { assert(i >= 0 && i < (int)n); return key[i]; } }; using UllmanSet = BasedUllmanSet<0>; using UllmanSet1 = BasedUllmanSet<1>; arachne-pnr-0~20150927gitefdb026/src/util.cc000066400000000000000000000074731260207143000202770ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "util.hh" #include #include #include #ifdef _WIN32 # include # include #elif defined(__APPLE__) # include # include #else # include #endif #include std::ostream *logs; void fatal(const std::string &msg) { std::cerr << "fatal error: " << msg << "\n"; exit(EXIT_FAILURE); } void warning(const std::string &msg) { std::cerr << "warning: " << msg << "\n"; } std::string unescape(const std::string &s) { std::string r; for (auto i = s.begin(); i != s.end(); ++i) { if (*i == '\\') { ++i; assert(i != s.end()); switch(*i) { case '\'': r.push_back('\''); break; case '\"': r.push_back('\"'); break; case '\?': r.push_back('\?'); break; case '\\': r.push_back('\\'); break; case '\a': r.push_back('\a'); break; case '\b': r.push_back('\b'); break; case '\f': r.push_back('\f'); break; case 'n': r.push_back('\n'); break; case 'r': r.push_back('\r'); break; case 't': r.push_back('\t'); break; case 'v': r.push_back('\v'); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int x = *i++ - '0'; if (i != s.end()) x = x*8 + *i++ - '0'; if (i != s.end()) x = x*8 + *i++ - '0'; r.push_back(x); } break; } } else r.push_back(*i); } return r; } /* taken from Yosys, yosys/kernel/yosys.cc */ #if defined(__linux__) std::string proc_self_dirname() { char path[PATH_MAX]; ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path)); if (buflen < 0) { fatal(fmt("readlink(\"/proc/self/exe\") failed: " << strerror(errno))); } while (buflen > 0 && path[buflen-1] != '/') buflen--; return std::string(path, buflen); } #elif defined(__APPLE__) std::string proc_self_dirname() { char *path = NULL; uint32_t buflen = 0; while (_NSGetExecutablePath(path, &buflen) != 0) path = (char *) realloc((void *) path, buflen); while (buflen > 0 && path[buflen-1] != '/') buflen--; return std::string(path, buflen); } #elif defined(_WIN32) std::string proc_self_dirname() { int i = 0; # ifdef __MINGW32__ char longpath[MAX_PATH + 1]; char shortpath[MAX_PATH + 1]; # else WCHAR longpath[MAX_PATH + 1]; TCHAR shortpath[MAX_PATH + 1]; # endif if (!GetModuleFileName(0, longpath, MAX_PATH+1)) fatal("GetModuleFileName() failed."); if (!GetShortPathName(longpath, shortpath, MAX_PATH+1)) fatal("GetShortPathName() failed."); while (shortpath[i] != 0) i++; while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\') shortpath[--i] = 0; std::string path; for (i = 0; shortpath[i]; i++) path += char(shortpath[i]); return path; } #else #error Dont know how to determine process executable base path! #endif std::string expand_filename(const std::string &file) { if (file[0] == '+') return (proc_self_dirname() + ".." + std::string(file.begin() + 1, file.end())); else return file; } arachne-pnr-0~20150927gitefdb026/src/util.hh000066400000000000000000000152541260207143000203050ustar00rootroot00000000000000/* Copyright (C) 2015 Cotton Seed This file is part of arachne-pnr. Arachne-pnr is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PNR_UTIL_HH #define PNR_UTIL_HH #include #include #include #include #include #include #include #include #include #include #include #include #include #include class random_generator { static const unsigned m = 2147483647; static const unsigned a = 48271; unsigned long long state; public: random_generator() : state(1) {} random_generator(unsigned seed) : state(seed % m) { assert(seed != 0); } // uniformly random between 0 .. m unsigned random() { state = (a * state) % m; return (unsigned)state; } unsigned operator()() { return random(); } int random_int(int min, int max) { assert(max >= min); unsigned d = max - min + 1; assert(d <= m); unsigned k = m / d; assert(k >= 1); for (;;) { // randomly distributed 0 .. (m-1) unsigned x = random(); if (x >= k*d) continue; // randomly disributed 0 ..(k*m-1) int r = min + (int)(x % d); assert(min <= r && r <= max); return r; } } double random_real(double min, double max) { assert(max >= min); if (min == max) return min; double d = max - min; assert(d > 0); unsigned x = random(); double r = min + d*(double)x / (double)(m-1); assert(min <= r && r <= max); return r; } }; extern std::ostream *logs; template std::ostream & operator<<(std::ostream &s, const std::set &S) { s << "{"; std::copy(S.begin(), S.end(), std::ostream_iterator(s, ", ")); return s << "}"; } template std::ostream & operator<<(std::ostream &s, const std::unordered_set &S) { s << "{"; std::copy(S.begin(), S.end(), std::ostream_iterator(s, ", ")); return s << "}"; } template struct PrettyKV { const std::pair &p; PrettyKV(const std::pair &p_) : p(p_) {} }; template inline std::ostream & operator<<(std::ostream &s, const PrettyKV &x) { return s << x.p.first << ": " << x.p.second << "\n"; } template std::ostream & operator<<(std::ostream &s, const std::map &M) { s << "{"; std::transform(M.begin(), M.end(), std::ostream_iterator(s, ", "), [](const std::pair &p) { return PrettyKV(p); }); return s << "}"; } template std::ostream & operator<<(std::ostream &s, const std::unordered_map &M) { s << "{"; std::transform(M.begin(), M.end(), std::ostream_iterator(s, ", "), [](const std::pair &p) { return PrettyKV(p); }); return s << "}"; } #define fmt(x) (static_cast(std::ostringstream() << x).str()) extern void fatal(const std::string &msg); extern void warning(const std::string &msg); template void extend(S &s, const T &x) { assert(s.find(x) == s.end()); s.insert(x); } template inline bool contains(const S &s, const T &x) { return s.find(x) != s.end(); } template inline void extend(M &m, const K &k, const V &v) { assert(m.find(k) == m.end()); m.insert(std::make_pair(k, v)); } template inline bool contains_key(const M &m, const K &k) { return m.find(k) != m.end(); } template inline std::set keys(const M &m) { std::set keys; std::transform(m.begin(), m.end(), std::inserter(keys, keys.end()), [](const typename M::value_type &p) { return p.first; }); return std::move(keys); } extern std::string unescape(const std::string &s); template inline const V & lookup(const std::map &M, const K &key) { return M.at(key); } template inline typename M::mapped_type lookup_or_default(const M &m, const K &key, const V &def) { auto i = m.find(key); if (i != m.end()) return i->second; else return def; } template inline typename M::mapped_type & lookup_or_create(M &m, const K &key, const F &f) { auto i = m.find(key); if (i == m.end()) i = m.insert(std::make_pair(key, f())).first; return i->second; } template inline typename C::const_reference front(const C &c) { assert(c.begin() != c.end()); return *c.begin(); } inline bool is_prefix(const std::string &prefix, const std::string &s) { if (prefix.size() > s.size()) return false; auto r = std::mismatch(prefix.begin(), prefix.end(), s.begin(), std::equal_to()); return r.first == prefix.end(); } inline bool is_suffix(const std::string &s, const std::string &suffix) { if (suffix.size() > s.size()) return false; auto r = std::mismatch(suffix.rbegin(), suffix.rend(), s.rbegin(), std::equal_to()); return r.first == suffix.rend(); } extern std::string proc_self_dirname(); inline char hexdigit(int i, char a = 'a') { assert(i >= 0 && i < 16); return (i < 10 ? '0' + i : a + (i - 10)); } template inline const T & random_element(const std::vector &v, random_generator &rg) { return v[rg.random_int(0, v.size()-1)]; } inline int random_int(int min, int max, random_generator &rg) { assert(min <= max); return rg.random_int(min, max); } template inline std::size_t hash_combine(std::size_t h, const T &v) { std::hash hasher; return h ^ (hasher(v) + 0x9e3779b9 + (h << 6) + (h >> 2)); } namespace std { template struct hash> { public: size_t operator() (const std::pair &p) const { std::hash Shasher; size_t h = Shasher(p.first); std::hash Thasher; return hash_combine(h, Thasher(p.second)); } }; } extern std::string expand_filename(const std::string &file); template void pop(std::vector &v, int i) { assert(i < (int)v.size()); if (i != (int)v.size() - 1) std::swap(v[i], v.back()); v.pop_back(); } #endif arachne-pnr-0~20150927gitefdb026/src/vector.hh000066400000000000000000000062661260207143000206350ustar00rootroot00000000000000 #ifndef PNR_BASEDVECTOR_HH #define PNR_BASEDVECTOR_HH #include "bstream.hh" #include template::size_type B> class BasedVector { using underlying_t = std::vector; underlying_t v; using value_type = typename underlying_t::value_type; using size_type = typename underlying_t::size_type; using reference = typename underlying_t::reference; using const_reference = typename underlying_t::const_reference; using pointer = typename underlying_t::pointer; using const_pointer = typename underlying_t::const_pointer; using iterator = typename underlying_t::iterator; using const_iterator = typename underlying_t::const_iterator; using reverse_iterator = typename underlying_t::reverse_iterator; using const_reverse_iterator = typename underlying_t::const_reverse_iterator; public: BasedVector() {} BasedVector(size_type count) : v(count) {} BasedVector(size_type count, const T &value) : v(count, value) {} BasedVector(std::initializer_list init) : v(init) {} bool empty() const { return v.empty(); } size_type size() const { return v.size(); } size_type max_size() const { return v.max_size(); } void reserve(size_type new_cap) const { v.reserve(new_cap); } size_type capacity() const { return v.capacity(); } void clear() { v.clear(); } iterator begin() { return v.begin(); } const_iterator begin() const { return v.begin(); } const_iterator cbegin() const { return v.cbegin(); } iterator end() { return v.end(); } const_iterator end() const { return v.end(); } const_iterator cend() const { return v.cend(); } reverse_iterator rbegin() { return v.rbegin(); } const_reverse_iterator rbegin() const { return v.rbegin(); } const_reverse_iterator crbegin() const { return v.crbegin(); } reverse_iterator rend() { return v.rend(); } const_reverse_iterator rend() const { return v.rend(); } const_reverse_iterator crend() const { return v.crend(); } reference at(size_type i) { assert(i >= B && i < B + v.size()); return v.at(i - B); } const_reference at(size_type i) const { assert(i >= B && i < B + v.size()); return v.at(i - B); } reference operator[](size_type i) { assert(i >= B && i < B + v.size()); return v[i - B]; } const_reference operator[](size_type i) const { assert(i >= B && i < B + v.size()); return v[i - B]; } void push_back(const T &value) { v.push_back(value); } void push_back(T &&value) { v.push_back(value); } void pop_back() { v.pop_back(); } void resize(size_type count) { v.resize(count); } void resize(size_type count, const value_type &value) { v.resize(count, value); } underlying_t &underlying() { return v; } const underlying_t &underlying() const { return v; } }; template::size_type B> obstream &operator<<(obstream &obs, const BasedVector &bv) { return obs << bv.underlying(); } template::size_type B> ibstream &operator>>(ibstream &ibs, BasedVector &bv) { return ibs >> bv.underlying(); } template using Vector = BasedVector; template using Vector1 = BasedVector; #endif arachne-pnr-0~20150927gitefdb026/tests/000077500000000000000000000000001260207143000173535ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/tests/combinatorial/000077500000000000000000000000001260207143000221765ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/tests/combinatorial/.gitignore000066400000000000000000000000051260207143000241610ustar00rootroot00000000000000temp arachne-pnr-0~20150927gitefdb026/tests/combinatorial/generate.py000066400000000000000000000101161260207143000243410ustar00rootroot00000000000000#!/usr/bin/python from __future__ import division from __future__ import print_function import sys import random from contextlib import contextmanager @contextmanager def redirect_stdout(new_target): old_target, sys.stdout = sys.stdout, new_target try: yield new_target finally: sys.stdout = old_target def random_term(variables): n_inputs = random.randint(4, 9) inputs = [random.choice(variables) for i in range(0, n_inputs)] n_terms = random.randint(3, 5) term = ' | '.join([ ('(' + ' & '.join([ random.choice([v, '~' + v]) for v in inputs]) + ')') for i in range(0, n_terms)]) return term for idx in range(25): with file('temp/uut_%05d.v' % idx, 'w') as f: with redirect_stdout(f): pins = 96 n_inputs = random.randint(3, pins / 2) n_outputs = random.randint(3, pins / 2) print('module uut_%05d(' % (idx), end="") variables = ['i0'] print('input i0', end='') for i in range(1, n_inputs+1): v = 'i%d' % (i) print(', input %s' % (v), end='') variables.append(v) for i in range(0, n_outputs+1): print(', output o%d' % (i), end='') print(');') n_temps = random.randint(3,50) for i in range(0, n_temps): p = random.random() if p < 0.05: width = random.randint(3, 16) a = ('{' + ', '.join([random.choice(variables) for j in range(0, width)]) + '}') b = ('{' + ', '.join([random.choice(variables) for j in range(0, width)]) + '}') op = random.choice(['+', '-']) print(' wire [%d:0] t%d = %s %s %s;' % (width - 1, i, a, op, b)) for j in range(0, width): variables.append('t%d[%d]' % (i, j)) elif p < 0.1: width = random.randint(3, 16) a = ('{' + ', '.join([random.choice(variables) for j in range(0, width)]) + '}') b = ('{' + ', '.join([random.choice(variables) for j in range(0, width)]) + '}') op = random.choice(['<', '<=', '>', '>=', '==', '!=']) print(' wire t%d = %s %s %s;' % (i, a, op, b)) variables.append('t%d' % (i)) else: term = random_term(variables) print(' wire t%d = %s;' % (i, term)) variables.append('t%d' % (i)) for i in range(0, n_outputs+1): term = random_term(variables) print(' assign o%d = %s;' % (i, term)) print('endmodule') with file('temp/uut_%05d.ys' % idx, 'w') as f: with redirect_stdout(f): print('rename uut_%05d gate' % idx) print('read_verilog temp/uut_%05d.v' % idx) print('rename uut_%05d gold' % idx) print('hierarchy; proc;;') print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter') print('sat -verify-no-timeout -timeout 20 -prove trigger 0 -show-inputs -show-outputs miter') with file('temp/uut_%05d_pp.ys' % idx, 'w') as f: with redirect_stdout(f): print('rename uut_%05d gate' % idx) print('read_verilog temp/uut_%05d.v' % idx) print('rename uut_%05d gold' % idx) print('hierarchy; proc;;') print('techmap -map +/adff2dff.v; opt;;') print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter') print('sat -verify-no-timeout -timeout 20 -prove trigger 0 -show-inputs -show-outputs miter') arachne-pnr-0~20150927gitefdb026/tests/combinatorial/run-test.sh000066400000000000000000000024371260207143000243210ustar00rootroot00000000000000#!/bin/bash set -ex arachne_pnr=../../bin/arachne-pnr rm -rf temp mkdir temp python generate.py for d in 1k 8k; do rm -rf ${d} mkdir ${d} for i in temp/uut_?????.v; do pf=${i%.*} # temp/uut_00000 base=${pf##*/} # uut_00000 dpf=${d}/${base} # 1k/uut_00000 yosys -q -p "synth_ice40 -blif ${dpf}_gate.blif" ${pf}.v rm -f ${dpf}_gate.chip.txt # don't pick up stale copy $arachne_pnr -d ${d} -w ${dpf}_gate.pcf -V ${dpf}_pp.v -o ${dpf}_gate.chip.txt ${dpf}_gate.blif > ${dpf}.pnr-log 2>&1 \ || grep -q 'failed to route' ${dpf}.pnr-log if [ -f ${dpf}_gate.chip.txt ]; then # check pp yosys -q -l ${dpf}_pp.log -p "read_verilog +/ice40/cells_sim.v ${dpf}_pp.v; script ${pf}_pp.ys" grep -q 'SAT proof finished - no model found: SUCCESS!' ${dpf}_pp.log \ || grep -q 'Interrupted SAT solver: TIMEOUT!' ${dpf}_pp.log # check bitstream icepack ${dpf}_gate.chip.txt ${dpf}_gate.bin # icebox_explain ${dpf}_gate.chip.txt > ${dpf}_gate.ex icebox_vlog -n ${base} -p ${dpf}_gate.pcf ${dpf}_gate.chip.txt > ${dpf}_gate.v yosys -q -l ${dpf}.log -p "read_verilog ${dpf}_gate.v; script ${pf}.ys" grep -q 'SAT proof finished - no model found: SUCCESS!' ${dpf}.log \ || grep -q 'Interrupted SAT solver: TIMEOUT!' ${dpf}.log fi done done echo OK. arachne-pnr-0~20150927gitefdb026/tests/fsm/000077500000000000000000000000001260207143000201405ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/tests/fsm/.gitignore000066400000000000000000000000051260207143000221230ustar00rootroot00000000000000temp arachne-pnr-0~20150927gitefdb026/tests/fsm/generate.py000066400000000000000000000144401260207143000223070ustar00rootroot00000000000000#!/usr/bin/python from __future__ import division from __future__ import print_function import sys import random from contextlib import contextmanager @contextmanager def redirect_stdout(new_target): old_target, sys.stdout = sys.stdout, new_target try: yield new_target finally: sys.stdout = old_target def random_simple_expr(variables): c = random.choice(['uni', 'var', 'const']) if c == 'uni': op = random.choice(['+', '-', '~', '|', '&', '^', '~^', '!', '$signed', '$unsigned']) return "%s(%s)" % (op, random_simple_expr(variables)) if c == 'var': return random.choice(variables) if c == 'const': bits = random.randint(1, 10) return "%d'd%s" % (bits, random.randint(0, 2**bits-1)) raise AssertionError def random_expr(variables): c = random.choice(['bin', 'uni', 'var', 'const']) if c == 'bin': op = random.choice(['+', '-', '*', '<', '<=', '==', '!=', '>=', '>', '<<', '>>', '<<<', '>>>', '|', '&', '^', '~^', '||', '&&']) return "(%s %s %s)" % (random_simple_expr(variables), op, random_simple_expr(variables)) if c == 'uni': op = random.choice(['+', '-', '~', '|', '&', '^', '~^', '!', '$signed', '$unsigned']) return "%s(%s)" % (op, random_expr(variables)) if c == 'var': return random.choice(variables) if c == 'const': bits = random.randint(1, 10) return "%d'd%s" % (bits, random.randint(0, 2**bits-1)) raise AssertionError for idx in range(25): with file('temp/uut_%05d.v' % idx, 'w') as f: with redirect_stdout(f): rst2 = random.choice([False, True]) if rst2: print('module uut_%05d(clk, rst1, rst2, rst' % (idx), end="") else: print('module uut_%05d(clk, rst' % (idx), end="") variables=['a', 'b', 'c', 'x', 'y', 'z'] io = {'a': 'input', 'b': 'input', 'c': 'input', 'x': 'output', 'y': 'output', 'z': 'output'} h = {} for v in variables: h[v] = random.randint(0, 12) for v in variables: for i in range(0,h[v]+1): print(", %s%d" % (v, i), end="") print(');') if rst2: print(' input clk, rst1, rst2;') print(' output rst;') print(' assign rst = rst1 || rst2;') else: print(' input clk, rst;') for v in ['x', 'y', 'z']: print(' reg%s [%d:0] %s;' % (random.choice(['', ' signed']), h[v], v)) for v in ['a', 'b', 'c']: for i in range(0,h[v]+1): print(' %s %s%d;' % (io[v], v, i)) for v in ['x', 'y', 'z']: for i in range(0,h[v]+1): print(' %s %s%d = %s[%d];' % (io[v], v, i, v, i)) for v in ['a', 'b', 'c']: print(' wire%s [%d:0] %s = {' % (random.choice(['', ' signed']), h[v], v), end="") for i in range(h[v],-1,-1): if i < h[v]: print(',', end="") print('%s%d' % (v, i), end="") print('};') state_bits = random.randint(5, 16); print(' %sreg [%d:0] state;' % (random.choice(['', '(* fsm_encoding = "one-hot" *)', '(* fsm_encoding = "binary" *)']), state_bits-1)) states=[] for i in range(random.randint(2, 9)): n = random.randint(0, 2**state_bits-1) if n not in states: states.append(n) print(' always @(posedge clk) begin') print(' if (%s) begin' % ('rst1' if rst2 else 'rst')) print(' x <= %d;' % random.randint(0, 2**31-1)) print(' y <= %d;' % random.randint(0, 2**31-1)) print(' z <= %d;' % random.randint(0, 2**31-1)) print(' state <= %d;' % random.choice(states)) print(' end else begin') print(' case (state)') for state in states: print(' %d: begin' % state) for var in ('x', 'y', 'z'): print(' %s <= %s;' % (var, random_expr(variables))) next_states = states[:] for i in range(random.randint(0, len(states))): next_state = random.choice(next_states) next_states.remove(next_state) print(' if ((%s) %s (%s)) state <= %s;' % (random_expr(variables), random.choice(['<', '<=', '>=', '>']), random_expr(variables), next_state)) print(' end') print(' endcase') if rst2: print(' if (rst2) begin') print(' x <= a;') print(' y <= b;') print(' z <= c;') print(' state <= %d;' % random.choice(states)) print(' end') print(' end') print(' end') print('endmodule') with file('temp/uut_%05d.ys' % idx, 'w') as f: with redirect_stdout(f): print('rename uut_%05d gate' % idx) print('read_verilog temp/uut_%05d.v' % idx) print('rename uut_%05d gold' % idx) print('hierarchy; proc;;') print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter') print('sat -verify-no-timeout -timeout 20 -seq 5 -set-at 1 %s_rst 1 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter' % ('gold' if rst2 else 'in')) with file('temp/uut_%05d_pp.ys' % idx, 'w') as f: with redirect_stdout(f): print('rename uut_%05d gate' % idx) print('read_verilog temp/uut_%05d.v' % idx) print('rename uut_%05d gold' % idx) print('hierarchy; proc;;') print('techmap -map +/adff2dff.v; opt;;') print('miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter') print('sat -verify-no-timeout -timeout 20 -seq 5 -set-at 1 %s_rst 1 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter' % ('gold' if rst2 else 'in')) arachne-pnr-0~20150927gitefdb026/tests/fsm/run-test.sh000066400000000000000000000024371260207143000222630ustar00rootroot00000000000000#!/bin/bash set -ex arachne_pnr=../../bin/arachne-pnr rm -rf temp mkdir temp python generate.py for d in 1k 8k; do rm -rf ${d} mkdir ${d} for i in temp/uut_?????.v; do pf=${i%.*} # temp/uut_00000 base=${pf##*/} # uut_00000 dpf=${d}/${base} # 1k/uut_00000 yosys -q -p "synth_ice40 -blif ${dpf}_gate.blif" ${pf}.v rm -f ${dpf}_gate.chip.txt # don't pick up stale copy $arachne_pnr -d ${d} -w ${dpf}_gate.pcf -V ${dpf}_pp.v -o ${dpf}_gate.chip.txt ${dpf}_gate.blif > ${dpf}.pnr-log 2>&1 \ || grep -q 'failed to route' ${dpf}.pnr-log if [ -f ${dpf}_gate.chip.txt ]; then # check pp yosys -q -l ${dpf}_pp.log -p "read_verilog +/ice40/cells_sim.v ${dpf}_pp.v; script ${pf}_pp.ys" grep -q 'SAT proof finished - no model found: SUCCESS!' ${dpf}_pp.log \ || grep -q 'Interrupted SAT solver: TIMEOUT!' ${dpf}_pp.log # check bitstream icepack ${dpf}_gate.chip.txt ${dpf}_gate.bin # icebox_explain ${dpf}_gate.chip.txt > ${dpf}_gate.ex icebox_vlog -n ${base} -p ${dpf}_gate.pcf ${dpf}_gate.chip.txt > ${dpf}_gate.v yosys -q -l ${dpf}.log -p "read_verilog ${dpf}_gate.v; script ${pf}.ys" grep -q 'SAT proof finished - no model found: SUCCESS!' ${dpf}.log \ || grep -q 'Interrupted SAT solver: TIMEOUT!' ${dpf}.log fi done done echo OK. arachne-pnr-0~20150927gitefdb026/tests/regression/000077500000000000000000000000001260207143000215335ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/tests/regression/.gitignore000066400000000000000000000000141260207143000235160ustar00rootroot00000000000000*.txt *.bin arachne-pnr-0~20150927gitefdb026/tests/regression/bram1.blif000066400000000000000000000026651260207143000234040ustar00rootroot00000000000000# Generated by Yosys 0.5+ 286 (git sha1 eb38722, clang 6.1.0 -fPIC -Os) .model top .inputs clk .outputs D1 .names $false .names $true 1 .names $undef .gate SB_RAM40_4K MASK[0]=$false MASK[1]=$false MASK[2]=$false MASK[3]=$false MASK[4]=$false MASK[5]=$false MASK[6]=$false MASK[7]=$false MASK[8]=$false MASK[9]=$false MASK[10]=$false MASK[11]=$false MASK[12]=$false MASK[13]=$false MASK[14]=$false MASK[15]=$false RADDR[0]=$false RADDR[1]=$false RADDR[2]=$false RADDR[3]=$false RADDR[4]=$false RADDR[5]=$false RADDR[6]=$false RADDR[7]=$false RCLK=$false RCLKE=$false RDATA[0]=rdata[0] RDATA[1]=rdata[1] RDATA[2]=rdata[2] RDATA[3]=rdata[3] RDATA[4]=rdata[4] RDATA[5]=rdata[5] RDATA[6]=rdata[6] RDATA[7]=rdata[7] RDATA[8]=rdata[8] RDATA[9]=rdata[9] RDATA[10]=rdata[10] RDATA[11]=rdata[11] RDATA[12]=rdata[12] RDATA[13]=rdata[13] RDATA[14]=rdata[14] RDATA[15]=rdata[15] RE=$false WADDR[0]=$false WADDR[1]=$false WADDR[2]=$false WADDR[3]=$false WADDR[4]=$false WADDR[5]=$false WADDR[6]=$false WADDR[7]=$false WCLK=$false WCLKE=$false WDATA[0]=$false WDATA[1]=$false WDATA[2]=$false WDATA[3]=$false WDATA[4]=$false WDATA[5]=$false WDATA[6]=$false WDATA[7]=$false WDATA[8]=$false WDATA[9]=$false WDATA[10]=$false WDATA[11]=$false WDATA[12]=$false WDATA[13]=$false WDATA[14]=$false WDATA[15]=$false WE=$false .attr src "ramtest.v:10" .param READ_MODE 00000000000000000000000000000000 .param WRITE_MODE 00000000000000000000000000000000 .names rdata[0] D1 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/regression/carry_pack_fail1.blif000066400000000000000000000043231260207143000255650ustar00rootroot00000000000000# Generated by Yosys 0.5+ 277 (git sha1 d5b1a90, clang 6.1.0 -fPIC -Os) .model uut_00040 .inputs clk .outputs z0 .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=$auto$alumacc.cc:412:extract_cmp_alu$18[9] I1=$auto$alumacc.cc:484:replace_alu$33[9] I2=$auto$alumacc.cc:484:replace_alu$33[8] I3=$false O=$procmux$12_Y .attr src "/usr/local/bin/../share/yosys/ice40/cells_map.v:47" .param LUT_INIT 01101001 .gate SB_CARRY CI=z CO=$auto$alumacc.cc:484:replace_alu$33[2] I0=z I1=$false .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[2] CO=$auto$alumacc.cc:484:replace_alu$33[3] I0=z I1=$true .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[3] CO=$auto$alumacc.cc:484:replace_alu$33[4] I0=z I1=$true .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[4] CO=$auto$alumacc.cc:484:replace_alu$33[5] I0=z I1=$false .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[5] CO=$auto$alumacc.cc:484:replace_alu$33[6] I0=z I1=$true .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[6] CO=$auto$alumacc.cc:484:replace_alu$33[7] I0=z I1=$true .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[7] CO=$auto$alumacc.cc:484:replace_alu$33[8] I0=z I1=$false .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=z I2=$true I3=$auto$alumacc.cc:484:replace_alu$33[8] O=$auto$alumacc.cc:412:extract_cmp_alu$18[9] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$33[8] CO=$auto$alumacc.cc:484:replace_alu$33[9] I0=z I1=$true .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_DFF C=clk D=state Q=z .attr src "bar.v:6|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFFSS C=clk D=$procmux$12_Y Q=state S=state .attr src "bar.v:6|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .names z z0 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/regression/carry_route_fail1.blif000066400000000000000000000042641260207143000260110ustar00rootroot00000000000000# Generated by Yosys 0.5+ 277 (git sha1 d5b1a90, clang 6.1.0 -fPIC -Os) .model test .inputs i0 i2 i4 i5 i6 i7 i8 i9 i13 i14 i15 i16 i17 i18 i19 i20 i22 i23 i24 i25 i27 i28 i29 i31 i32 i34 i35 i36 i37 i38 i39 i40 i41 .outputs o0 .names $false .names $true 1 .names $undef .gate SB_CARRY CI=$false CO=$auto$alumacc.cc:484:replace_alu$4[0] I0=i7 I1=i16 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[0] CO=$auto$alumacc.cc:484:replace_alu$4[1] I0=i38 I1=i31 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[1] CO=$auto$alumacc.cc:484:replace_alu$4[2] I0=i14 I1=i25 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[2] CO=$auto$alumacc.cc:484:replace_alu$4[3] I0=i41 I1=i15 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[3] CO=$auto$alumacc.cc:484:replace_alu$4[4] I0=i35 I1=i36 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[4] CO=$auto$alumacc.cc:484:replace_alu$4[5] I0=i0 I1=i39 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[5] CO=$auto$alumacc.cc:484:replace_alu$4[6] I0=i13 I1=i18 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[6] CO=$auto$alumacc.cc:484:replace_alu$4[7] I0=i29 I1=i2 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$4[7] CO=$auto$alumacc.cc:484:replace_alu$4[8] I0=i4 I1=i37 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=i24 I2=i40 I3=$auto$alumacc.cc:484:replace_alu$4[8] O=o0 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .names $undef t7[0] 1 1 .names $undef t7[1] 1 1 .names $undef t7[2] 1 1 .names $undef t7[3] 1 1 .names $undef t7[4] 1 1 .names $undef t7[5] 1 1 .names $undef t7[6] 1 1 .names $undef t7[7] 1 1 .names $undef t7[8] 1 1 .names o0 t7[9] 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/regression/carry_route_fail1.v000066400000000000000000000010211260207143000253260ustar00rootroot00000000000000module test(input i0, input i2, input i4, input i5, input i6, input i7, input i8, input i9, input i13, input i14, input i15, input i16, input i17, input i18, input i19, input i20, input i22, input i23, input i24, input i25, input i27, input i28, input i29, input i31, input i32, input i34, input i35, input i36, input i37, input i38, input i39, input i40, input i41, output o0); wire [9:0] t7 = {i24, i4, i29, i13, i0, i35, i41, i14, i38, i7} + {i40, i37, i2, i18, i39, i36, i15, i25, i31, i16}; assign o0 = t7[9]; endmodule arachne-pnr-0~20150927gitefdb026/tests/regression/j1a_gb_fail.blif000066400000000000000000000314701260207143000245140ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model top .inputs oscillator .outputs D1 D2 D3 D4 D5 .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=ticks[0] I1=ticks[1] I2=$false I3=$false O=$0\ticks[25:0][1] .attr src "/usr/local/bin/../share/yosys/ice40/cells_map.v:43" .param LUT_INIT 0110 .gate SB_LUT4 I0=$false I1=$true I2=ticks[0] I3=$false O=$0\ticks[25:0][0] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_LUT4 I0=$false I1=$false I2=ticks[10] I3=$auto$alumacc.cc:484:replace_alu$6[9] O=$0\ticks[25:0][10] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[9] CO=$auto$alumacc.cc:484:replace_alu$6[10] I0=$false I1=ticks[10] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[11] I3=$auto$alumacc.cc:484:replace_alu$6[10] O=$0\ticks[25:0][11] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[10] CO=$auto$alumacc.cc:484:replace_alu$6[11] I0=$false I1=ticks[11] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[12] I3=$auto$alumacc.cc:484:replace_alu$6[11] O=$0\ticks[25:0][12] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[11] CO=$auto$alumacc.cc:484:replace_alu$6[12] I0=$false I1=ticks[12] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[13] I3=$auto$alumacc.cc:484:replace_alu$6[12] O=$0\ticks[25:0][13] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[12] CO=$auto$alumacc.cc:484:replace_alu$6[13] I0=$false I1=ticks[13] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[14] I3=$auto$alumacc.cc:484:replace_alu$6[13] O=$0\ticks[25:0][14] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[13] CO=$auto$alumacc.cc:484:replace_alu$6[14] I0=$false I1=ticks[14] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[15] I3=$auto$alumacc.cc:484:replace_alu$6[14] O=$0\ticks[25:0][15] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[14] CO=$auto$alumacc.cc:484:replace_alu$6[15] I0=$false I1=ticks[15] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[16] I3=$auto$alumacc.cc:484:replace_alu$6[15] O=$0\ticks[25:0][16] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[15] CO=$auto$alumacc.cc:484:replace_alu$6[16] I0=$false I1=ticks[16] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[17] I3=$auto$alumacc.cc:484:replace_alu$6[16] O=$0\ticks[25:0][17] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[16] CO=$auto$alumacc.cc:484:replace_alu$6[17] I0=$false I1=ticks[17] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[18] I3=$auto$alumacc.cc:484:replace_alu$6[17] O=$0\ticks[25:0][18] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[17] CO=$auto$alumacc.cc:484:replace_alu$6[18] I0=$false I1=ticks[18] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[19] I3=$auto$alumacc.cc:484:replace_alu$6[18] O=$0\ticks[25:0][19] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[18] CO=$auto$alumacc.cc:484:replace_alu$6[19] I0=$false I1=ticks[19] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_CARRY CI=ticks[0] CO=$auto$alumacc.cc:484:replace_alu$6[1] I0=$false I1=ticks[1] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[20] I3=$auto$alumacc.cc:484:replace_alu$6[19] O=$0\ticks[25:0][20] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[19] CO=$auto$alumacc.cc:484:replace_alu$6[20] I0=$false I1=ticks[20] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=D5 I3=$auto$alumacc.cc:484:replace_alu$6[20] O=$0\ticks[25:0][21] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[20] CO=$auto$alumacc.cc:484:replace_alu$6[21] I0=$false I1=D5 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=D4 I3=$auto$alumacc.cc:484:replace_alu$6[21] O=$0\ticks[25:0][22] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[21] CO=$auto$alumacc.cc:484:replace_alu$6[22] I0=$false I1=D4 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=D3 I3=$auto$alumacc.cc:484:replace_alu$6[22] O=$0\ticks[25:0][23] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[22] CO=$auto$alumacc.cc:484:replace_alu$6[23] I0=$false I1=D3 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=D2 I3=$auto$alumacc.cc:484:replace_alu$6[23] O=$0\ticks[25:0][24] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[23] CO=$auto$alumacc.cc:484:replace_alu$6[24] I0=$false I1=D2 .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=D1 I3=$auto$alumacc.cc:484:replace_alu$6[24] O=$0\ticks[25:0][25] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_LUT4 I0=$false I1=$false I2=ticks[2] I3=$auto$alumacc.cc:484:replace_alu$6[1] O=$0\ticks[25:0][2] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[1] CO=$auto$alumacc.cc:484:replace_alu$6[2] I0=$false I1=ticks[2] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[3] I3=$auto$alumacc.cc:484:replace_alu$6[2] O=$0\ticks[25:0][3] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[2] CO=$auto$alumacc.cc:484:replace_alu$6[3] I0=$false I1=ticks[3] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[4] I3=$auto$alumacc.cc:484:replace_alu$6[3] O=$0\ticks[25:0][4] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[3] CO=$auto$alumacc.cc:484:replace_alu$6[4] I0=$false I1=ticks[4] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[5] I3=$auto$alumacc.cc:484:replace_alu$6[4] O=$0\ticks[25:0][5] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[4] CO=$auto$alumacc.cc:484:replace_alu$6[5] I0=$false I1=ticks[5] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[6] I3=$auto$alumacc.cc:484:replace_alu$6[5] O=$0\ticks[25:0][6] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[5] CO=$auto$alumacc.cc:484:replace_alu$6[6] I0=$false I1=ticks[6] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[7] I3=$auto$alumacc.cc:484:replace_alu$6[6] O=$0\ticks[25:0][7] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[6] CO=$auto$alumacc.cc:484:replace_alu$6[7] I0=$false I1=ticks[7] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[8] I3=$auto$alumacc.cc:484:replace_alu$6[7] O=$0\ticks[25:0][8] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[7] CO=$auto$alumacc.cc:484:replace_alu$6[8] I0=$false I1=ticks[8] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=ticks[9] I3=$auto$alumacc.cc:484:replace_alu$6[8] O=$0\ticks[25:0][9] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[8] CO=$auto$alumacc.cc:484:replace_alu$6[9] I0=$false I1=ticks[9] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_DFF C=clk D=$0\ticks[25:0][0] Q=ticks[0] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][1] Q=ticks[1] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][2] Q=ticks[2] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][3] Q=ticks[3] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][4] Q=ticks[4] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][5] Q=ticks[5] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][6] Q=ticks[6] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][7] Q=ticks[7] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][8] Q=ticks[8] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][9] Q=ticks[9] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][10] Q=ticks[10] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][11] Q=ticks[11] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][12] Q=ticks[12] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][13] Q=ticks[13] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][14] Q=ticks[14] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][15] Q=ticks[15] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][16] Q=ticks[16] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][17] Q=ticks[17] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][18] Q=ticks[18] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][19] Q=ticks[19] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][20] Q=ticks[20] .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][21] Q=D5 .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][22] Q=D4 .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][23] Q=D3 .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][24] Q=D2 .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\ticks[25:0][25] Q=D1 .attr src "j1a.v:13|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_GB GLOBAL_BUFFER_OUTPUT=clk USER_SIGNAL_TO_GLOBAL_BUFFER=oscillator .attr src "j1a.v:10" .names D5 ticks[21] 1 1 .names D4 ticks[22] 1 1 .names D3 ticks[23] 1 1 .names D2 ticks[24] 1 1 .names D1 ticks[25] 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/regression/j1a_gb_fail.v000066400000000000000000000006361260207143000240450ustar00rootroot00000000000000`timescale 1 ns / 1 ps `default_nettype none module top(input oscillator, output D1, output D2, output D3, output D4, output D5); wire clk; // assign clk = oscillator; // This works SB_GB clockbuffer ( .USER_SIGNAL_TO_GLOBAL_BUFFER (oscillator), .GLOBAL_BUFFER_OUTPUT (clk) ); reg [25:0] ticks; always @(posedge clk) ticks <= ticks + 16'd1; assign {D1,D2,D3,D4,D5} = ticks[25:21]; endmodule arachne-pnr-0~20150927gitefdb026/tests/regression/run-test.sh000066400000000000000000000022511260207143000236500ustar00rootroot00000000000000#!/bin/bash set -ex arachne_pnr=../../bin/arachne-pnr for d in 1k 8k; do rm -rf $d mkdir $d $arachne_pnr -d $d bram1.blif -o $d/bram1.txt icepack $d/bram1.txt $d/bram1.bin $arachne_pnr -d $d carry_pack_fail1.blif -o $d/carry_pack_fail1.txt icepack $d/carry_pack_fail1.txt $d/carry_pack_fail1.bin $arachne_pnr -d $d test1.blif -o $d/test1.txt icepack $d/test1.txt $d/test1.bin $arachne_pnr -d $d test2.blif -o $d/test2.txt icepack $d/test2.txt $d/test2.bin $arachne_pnr -d $d -w $d/carry_route_fail1.pcf carry_route_fail1.blif -o $d/carry_route_fail1.txt icebox_vlog -n test -p $d/carry_route_fail1.pcf $d/carry_route_fail1.txt > $d/carry_route_fail1.chip.v yosys -q -l $d/carry_route_fail1.log -p "read_verilog carry_route_fail1.v; rename test gold; read_verilog $d/carry_route_fail1.chip.v; rename test gate; hierarchy; proc;; miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter; sat -verify-no-timeout -timeout 60 -prove trigger 0 -show-inputs -show-outputs miter" $arachne_pnr -d $d j1a_gb_fail.blif -o $d/j1a_gb_fail.txt icepack $d/j1a_gb_fail.txt $d/j1a_gb_fail.bin done arachne-pnr-0~20150927gitefdb026/tests/regression/test1.blif000066400000000000000000000044171260207143000234370ustar00rootroot00000000000000# Generated by Yosys 0.5+176 (git sha1 4744bb9, gcc 4.8.2-19ubuntu1 -fPIC -Os) .model uut_00035 .inputs clk rst a0 a1 a2 a3 a4 a5 a6 a7 b0 b1 c0 c1 c2 c3 .outputs x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 y0 y1 y2 y3 y4 y5 y6 z0 z1 z2 z3 z4 z5 z6 z7 z8 .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=$abc$163$n12 I1=z0 I2=c0 I3=c1 O=$eq$temp/uut_00035.v:63$3_Y[0] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:51" .param LUT_INIT 0010000000001000 .gate SB_LUT4 I0=z0 I1=c2 I2=c3 I3=$false O=$abc$163$n12 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:47" .param LUT_INIT 01000010 .gate SB_LUT4 I0=rst I1=$false I2=$false I3=$false O=$0\x[11:0][11] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:39" .param LUT_INIT 01 .gate SB_DFF C=clk D=$0\x[11:0][11] Q=x2 .attr src "temp/uut_00035.v:52|/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFFSS C=clk D=$eq$temp/uut_00035.v:63$3_Y[0] Q=z0 S=rst .attr src "temp/uut_00035.v:52|/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=rst Q=x0 .attr src "temp/uut_00035.v:52|/home/cotton/yosys/share/ice40/cells_map.v:2" .names a0 a[0] 1 1 .names a1 a[1] 1 1 .names a2 a[2] 1 1 .names a3 a[3] 1 1 .names a4 a[4] 1 1 .names a5 a[5] 1 1 .names a6 a[6] 1 1 .names a7 a[7] 1 1 .names b0 b[0] 1 1 .names b1 b[1] 1 1 .names c0 c[0] 1 1 .names c1 c[1] 1 1 .names c2 c[2] 1 1 .names c3 c[3] 1 1 .names x0 x[0] 1 1 .names $true x[1] 1 1 .names x2 x[2] 1 1 .names $true x[3] 1 1 .names $true x[4] 1 1 .names $true x[5] 1 1 .names $true x[6] 1 1 .names $true x[7] 1 1 .names $true x[8] 1 1 .names x2 x[9] 1 1 .names $true x[10] 1 1 .names x2 x[11] 1 1 .names $true x1 1 1 .names $true x10 1 1 .names x2 x11 1 1 .names $true x3 1 1 .names $true x4 1 1 .names $true x5 1 1 .names $true x6 1 1 .names $true x7 1 1 .names $true x8 1 1 .names x2 x9 1 1 .names $false y0 1 1 .names $true y1 1 1 .names $true y2 1 1 .names $true y3 1 1 .names $true y4 1 1 .names $true y5 1 1 .names $false y6 1 1 .names z0 z[0] 1 1 .names $false z[1] 1 1 .names x0 z[2] 1 1 .names $false z[3] 1 1 .names $false z[4] 1 1 .names x0 z[5] 1 1 .names x0 z[6] 1 1 .names x0 z[7] 1 1 .names $false z[8] 1 1 .names $false z1 1 1 .names x0 z2 1 1 .names $false z3 1 1 .names $false z4 1 1 .names x0 z5 1 1 .names x0 z6 1 1 .names x0 z7 1 1 .names $false z8 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/regression/test2.blif000066400000000000000000000102641260207143000234350ustar00rootroot00000000000000# Generated by Yosys 0.5+176 (git sha1 4744bb9, gcc 4.8.2-19ubuntu1 -fPIC -Os) .model uut_00014 .inputs clk rst a0 a1 a2 a3 b0 b1 b2 b3 c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 .outputs x0 y0 y1 z0 .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=$abc$430$n25 I1=$abc$430$n22 I2=b0 I3=$false O=$procmux$17_Y[0] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:47" .param LUT_INIT 11101010 .gate SB_LUT4 I0=$abc$430$n23 I1=$abc$430$n24 I2=state[7] I3=state[9] O=$abc$430$n22 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:51" .param LUT_INIT 1000000000000000 .gate SB_LUT4 I0=state[0] I1=state[1] I2=state[2] I3=state[3] O=$abc$430$n23 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:51" .param LUT_INIT 1000000000000000 .gate SB_LUT4 I0=state[5] I1=state[8] I2=state[4] I3=state[6] O=$abc$430$n24 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:51" .param LUT_INIT 0001000000000000 .gate SB_LUT4 I0=$abc$430$n23 I1=$abc$430$n26 I2=state[7] I3=state[9] O=$abc$430$n25 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:51" .param LUT_INIT 1000000000000000 .gate SB_LUT4 I0=state[5] I1=state[8] I2=state[4] I3=state[6] O=$abc$430$n26 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:51" .param LUT_INIT 0000000000000100 .gate SB_LUT4 I0=$abc$430$n25 I1=$abc$430$n22 I2=b1 I3=$false O=$procmux$17_Y[1] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:47" .param LUT_INIT 11101010 .gate SB_LUT4 I0=$abc$430$n22 I1=rst I2=$false I3=$false O=$abc$430$n37 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:43" .param LUT_INIT 1110 .gate SB_LUT4 I0=$abc$430$n22 I1=$abc$430$n25 I2=rst I3=$false O=$auto$dff2dffe.cc:158:make_patterns_logic$319 .attr src "/home/cotton/yosys/share/ice40/cells_map.v:47" .param LUT_INIT 11111110 .gate SB_LUT4 I0=$abc$430$n22 I1=x I2=$false I3=$false O=$procmux$26_Y .attr src "/home/cotton/yosys/share/ice40/cells_map.v:43" .param LUT_INIT 1000 .gate SB_DFFE C=clk D=$true E=$abc$430$n37 Q=x .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFESS C=clk D=$procmux$17_Y[0] E=$auto$dff2dffe.cc:158:make_patterns_logic$319 Q=y0 S=rst .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFESS C=clk D=$procmux$17_Y[1] E=$auto$dff2dffe.cc:158:make_patterns_logic$319 Q=y1 S=rst .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFESR C=clk D=$procmux$26_Y E=$auto$dff2dffe.cc:158:make_patterns_logic$319 Q=z R=rst .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[0] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[1] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[2] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[3] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$false E=rst Q=state[4] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$false E=rst Q=state[5] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$false E=rst Q=state[6] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[7] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[8] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .gate SB_DFFE C=clk D=$true E=rst Q=state[9] .attr src "temp/uut_00014.v:35|/home/cotton/yosys/share/ice40/cells_map.v:8" .names a0 a[0] 1 1 .names a1 a[1] 1 1 .names a2 a[2] 1 1 .names a3 a[3] 1 1 .names b0 b[0] 1 1 .names b1 b[1] 1 1 .names b2 b[2] 1 1 .names b3 b[3] 1 1 .names c0 c[0] 1 1 .names c1 c[1] 1 1 .names c2 c[2] 1 1 .names c3 c[3] 1 1 .names c4 c[4] 1 1 .names c5 c[5] 1 1 .names c6 c[6] 1 1 .names c7 c[7] 1 1 .names c8 c[8] 1 1 .names c9 c[9] 1 1 .names c10 c[10] 1 1 .names c11 c[11] 1 1 .names c12 c[12] 1 1 .names x x0 1 1 .names y0 y[0] 1 1 .names y1 y[1] 1 1 .names z z0 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/simple/000077500000000000000000000000001260207143000206445ustar00rootroot00000000000000arachne-pnr-0~20150927gitefdb026/tests/simple/.gitignore000066400000000000000000000000541260207143000226330ustar00rootroot00000000000000*.txt *.bin sb_up3down5_packed.blif txt.sum arachne-pnr-0~20150927gitefdb026/tests/simple/bram.blif000066400000000000000000000140761260207143000224330ustar00rootroot00000000000000# Generated by Yosys 0.5+156 (git sha1 7528519, gcc 4.8.2-19ubuntu1 -fPIC -Os) .model top .inputs clk wdata[0] wdata[1] wdata[2] wdata[3] wdata[4] wdata[5] wdata[6] wdata[7] wdata[8] wdata[9] wdata[10] wdata[11] wdata[12] wdata[13] wdata[14] wdata[15] addr[0] addr[1] addr[2] addr[3] addr[4] addr[5] addr[6] addr[7] .outputs rdata[0] rdata[1] rdata[2] rdata[3] rdata[4] rdata[5] rdata[6] rdata[7] rdata[8] rdata[9] rdata[10] rdata[11] rdata[12] rdata[13] rdata[14] rdata[15] .names $false .names $true 1 .names $undef .gate SB_RAM40_4K MASK[0]=$false MASK[1]=$false MASK[2]=$false MASK[3]=$false MASK[4]=$false MASK[5]=$false MASK[6]=$false MASK[7]=$false MASK[8]=$false MASK[9]=$false MASK[10]=$false MASK[11]=$false MASK[12]=$false MASK[13]=$false MASK[14]=$false MASK[15]=$false RADDR[0]=addr[0] RADDR[1]=addr[1] RADDR[2]=addr[2] RADDR[3]=addr[3] RADDR[4]=addr[4] RADDR[5]=addr[5] RADDR[6]=addr[6] RADDR[7]=addr[7] RCLK=clk RCLKE=$true RDATA[0]=rdata[0] RDATA[1]=rdata[1] RDATA[2]=rdata[2] RDATA[3]=rdata[3] RDATA[4]=rdata[4] RDATA[5]=rdata[5] RDATA[6]=rdata[6] RDATA[7]=rdata[7] RDATA[8]=rdata[8] RDATA[9]=rdata[9] RDATA[10]=rdata[10] RDATA[11]=rdata[11] RDATA[12]=rdata[12] RDATA[13]=rdata[13] RDATA[14]=rdata[14] RDATA[15]=rdata[15] RE=$true WADDR[0]=addr[0] WADDR[1]=addr[1] WADDR[2]=addr[2] WADDR[3]=addr[3] WADDR[4]=addr[4] WADDR[5]=addr[5] WADDR[6]=addr[6] WADDR[7]=addr[7] WCLK=clk WCLKE=$true WDATA[0]=wdata[0] WDATA[1]=wdata[1] WDATA[2]=wdata[2] WDATA[3]=wdata[3] WDATA[4]=wdata[4] WDATA[5]=wdata[5] WDATA[6]=wdata[6] WDATA[7]=wdata[7] WDATA[8]=wdata[8] WDATA[9]=wdata[9] WDATA[10]=wdata[10] WDATA[11]=wdata[11] WDATA[12]=wdata[12] WDATA[13]=wdata[13] WDATA[14]=wdata[14] WDATA[15]=wdata[15] WE=$true .attr src "/home/cotton/icestorm/tests/bram.v:7" .param INIT_0 0001001000110100010101100111100010011010101111001101111011110000000000000000000011011101110111010000000000000000111011101110111000000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000000000000000000000000000000001 .param INIT_1 0101011001111000100110101011110011011110111100010010001101000000000000000000000011011101110111010000000000000000111011101110111000000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000000001000000000000000000000010 .param INIT_2 1010101111001101111011110001001000110100010101100111100010010000000000000000000011011101110111010000000000000000111011101110111000000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000000010000000000000000000000100 .param INIT_3 0000000000000000000000000000000000000000000000000000000000000000000000000000000011011101110111010000000000000000111011101110111000000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000000011000000000000000000001000 .param INIT_4 1111111111111111000000000000000000100010001000100000000000000000010001000100010000000000000000000110011001100110000000000000000010001000100010000000000000010010010010000011010101101001101011000000000100010001000001000100010000000100000000000000000000010000 .param INIT_5 1111111111111111000000000000000000100010001000100000000000000000010001000100010000000000000000000110011001100110000000000000000010001000100010000000000000010010010010000011010101101001101011000000000100010001000001000100010000000101000000000000000000100000 .param INIT_6 1111111111111111000000000000000000100010001000100000000000000000010001000100010000000000000000000110011001100110000000000000000010001000100010000000000000010010010010000011010101101001101011000000000100010001000001000100010000000110000000000000000001000000 .param INIT_7 1111111111111111000000000000000000100010001000100000000000000000010001000100010000000000000000000110011001100110000000000000000010001000100010000000000000010010010010000011010101101001101011000000000100010001000001000100010000000111000000000000000010000000 .param INIT_8 0000000000000000000100010001000100000000000000000011001100110011000000000000000001010101010101010000000000000000011101110111011100000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000001000000000000000000100000000 .param INIT_9 0000000000000000000100010001000100000000000000000011001100110011000000000000000001010101010101010000000000000000011101110111011100000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000001001000000000000001000000000 .param INIT_A 0000000000000000000100010001000100000000000000000011001100110011000000000000000001010101010101010000000000000000011101110111011100000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000001010000000000000010000000000 .param INIT_B 0000000000000000000100010001000100000000000000000011001100110011000000000000000001010101010101010000000000000000011101110111011100000000000000000000000000010010010010000011010101101001101011000000000100010001000001000100010000001011000000000000100000000000 .param INIT_C 0000000100100011000000000000000010011001100110010000000000000000101010101010101000000000000000001011101110111011000000000000000011001100110011000000000000010010010010000011010101101001101011000000000100010001000001000100010000001100000000000001000000000000 .param INIT_D 0100010101100111000000000000000010011001100110010000000000000000101010101010101000000000000000001011101110111011000000000000000011001100110011000000000000010010010010000011010101101001101011000000000100010001000001000100010000001101000000000010000000000000 .param INIT_E 1000100110101011000000000000000010011001100110010000000000000000101010101010101000000000000000001011101110111011000000000000000011001100110011000000000000010010010010000011010101101001101011000000000100010001000001000100010000001110000000000100000000000000 .param INIT_F 1100110111101111000000000000000010011001100110010000000000000000101010101010101000000000000000001011101110111011000000000000000011001100110011000000000000010010010010000011010101101001101011000000000100010001000001000100010000001111000000001000000000000000 .param READ_MODE 00000000000000000000000000000000 .param WRITE_MODE 00000000000000000000000000000000 .end arachne-pnr-0~20150927gitefdb026/tests/simple/carry.blif000066400000000000000000000222471260207143000226310ustar00rootroot00000000000000# Generated by Yosys 0.5+144 (git sha1 49ef830, gcc 4.8.2-19ubuntu1 -fPIC -Os) .model test .inputs clk cin a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9] c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9] .outputs d[0] d[1] d[2] d[3] d[4] d[5] d[6] d[7] d[8] d[9] .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=$false I1=b[0] I2=a[0] I3=$false O=$0\t[9:0][0] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$false CO=$auto$alumacc.cc:484:replace_alu$12[0] I0=b[0] I1=a[0] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[1] I2=a[1] I3=$auto$alumacc.cc:484:replace_alu$12[0] O=$0\t[9:0][1] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[0] CO=$auto$alumacc.cc:484:replace_alu$12[1] I0=b[1] I1=a[1] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[2] I2=a[2] I3=$auto$alumacc.cc:484:replace_alu$12[1] O=$0\t[9:0][2] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[1] CO=$auto$alumacc.cc:484:replace_alu$12[2] I0=b[2] I1=a[2] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[3] I2=a[3] I3=$auto$alumacc.cc:484:replace_alu$12[2] O=$0\t[9:0][3] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[2] CO=$auto$alumacc.cc:484:replace_alu$12[3] I0=b[3] I1=a[3] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[4] I2=a[4] I3=$auto$alumacc.cc:484:replace_alu$12[3] O=$0\t[9:0][4] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[3] CO=$auto$alumacc.cc:484:replace_alu$12[4] I0=b[4] I1=a[4] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[5] I2=a[5] I3=$auto$alumacc.cc:484:replace_alu$12[4] O=$0\t[9:0][5] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[4] CO=$auto$alumacc.cc:484:replace_alu$12[5] I0=b[5] I1=a[5] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[6] I2=a[6] I3=$auto$alumacc.cc:484:replace_alu$12[5] O=$0\t[9:0][6] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[5] CO=$auto$alumacc.cc:484:replace_alu$12[6] I0=b[6] I1=a[6] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[7] I2=a[7] I3=$auto$alumacc.cc:484:replace_alu$12[6] O=$0\t[9:0][7] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[6] CO=$auto$alumacc.cc:484:replace_alu$12[7] I0=b[7] I1=a[7] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[8] I2=a[8] I3=$auto$alumacc.cc:484:replace_alu$12[7] O=$0\t[9:0][8] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[7] CO=$auto$alumacc.cc:484:replace_alu$12[8] I0=b[8] I1=a[8] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=b[9] I2=a[9] I3=$auto$alumacc.cc:484:replace_alu$12[8] O=$0\t[9:0][9] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$12[8] CO=$auto$alumacc.cc:484:replace_alu$12[9] I0=b[9] I1=a[9] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[0] I2=c[0] I3=cin O=$0\d[9:0][0] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=cin CO=$auto$alumacc.cc:484:replace_alu$9[0] I0=t[0] I1=c[0] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[1] I2=c[1] I3=$auto$alumacc.cc:484:replace_alu$9[0] O=$0\d[9:0][1] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[0] CO=$auto$alumacc.cc:484:replace_alu$9[1] I0=t[1] I1=c[1] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[2] I2=c[2] I3=$auto$alumacc.cc:484:replace_alu$9[1] O=$0\d[9:0][2] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[1] CO=$auto$alumacc.cc:484:replace_alu$9[2] I0=t[2] I1=c[2] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[3] I2=c[3] I3=$auto$alumacc.cc:484:replace_alu$9[2] O=$0\d[9:0][3] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[2] CO=$auto$alumacc.cc:484:replace_alu$9[3] I0=t[3] I1=c[3] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[4] I2=c[4] I3=$auto$alumacc.cc:484:replace_alu$9[3] O=$0\d[9:0][4] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[3] CO=$auto$alumacc.cc:484:replace_alu$9[4] I0=t[4] I1=c[4] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[5] I2=c[5] I3=$auto$alumacc.cc:484:replace_alu$9[4] O=$0\d[9:0][5] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[4] CO=$auto$alumacc.cc:484:replace_alu$9[5] I0=t[5] I1=c[5] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[6] I2=c[6] I3=$auto$alumacc.cc:484:replace_alu$9[5] O=$0\d[9:0][6] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[5] CO=$auto$alumacc.cc:484:replace_alu$9[6] I0=t[6] I1=c[6] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[7] I2=c[7] I3=$auto$alumacc.cc:484:replace_alu$9[6] O=$0\d[9:0][7] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[6] CO=$auto$alumacc.cc:484:replace_alu$9[7] I0=t[7] I1=c[7] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[8] I2=c[8] I3=$auto$alumacc.cc:484:replace_alu$9[7] O=$0\d[9:0][8] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[7] CO=$auto$alumacc.cc:484:replace_alu$9[8] I0=t[8] I1=c[8] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=t[9] I2=c[9] I3=$auto$alumacc.cc:484:replace_alu$9[8] O=$0\d[9:0][9] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$9[8] CO=$auto$alumacc.cc:484:replace_alu$9[9] I0=t[9] I1=c[9] .attr src "/home/cotton/yosys/share/ice40/arith_map.v:47" .gate SB_DFF C=clk D=$0\t[9:0][0] Q=t[0] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][1] Q=t[1] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][2] Q=t[2] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][3] Q=t[3] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][4] Q=t[4] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][5] Q=t[5] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][6] Q=t[6] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][7] Q=t[7] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][8] Q=t[8] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\t[9:0][9] Q=t[9] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][0] Q=d[0] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][1] Q=d[1] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][2] Q=d[2] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][3] Q=d[3] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][4] Q=d[4] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][5] Q=d[5] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][6] Q=d[6] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][7] Q=d[7] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][8] Q=d[8] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\d[9:0][9] Q=d[9] .attr src "/home/cotton/yosys/share/ice40/cells_map.v:2" .end arachne-pnr-0~20150927gitefdb026/tests/simple/run-test.sh000066400000000000000000000032001260207143000227540ustar00rootroot00000000000000#!/bin/bash set -ex arachne_pnr="../../bin/arachne-pnr" devices='1k 8k' : ${ICEBOX:=/usr/local/share/icebox} rm -f txt.sum for d in $devices; do rm -rf $d mkdir $d $arachne_pnr -d $d -c $ICEBOX/chipdb-$d.txt --write-binary-chipdb $d/chipdb-$d.bin $arachne_pnr -d $d -c $d/chipdb-$d.bin --write-binary-chipdb $d/chipdb2-$d.bin cmp $d/chipdb-$d.bin $d/chipdb2-$d.bin # sb_up3down5.blif $arachne_pnr -d $d sb_up3down5.blif -o $d/sb_up3down5.txt shasum $d/sb_up3down5.txt >> txt.sum icepack $d/sb_up3down5.txt $d/sb_up3down5.bin $arachne_pnr -d $d -l sb_up3down5.blif -o $d/sb_up3down5_l.txt shasum $d/sb_up3down5_l.txt >> txt.sum icepack $d/sb_up3down5_l.txt $d/sb_up3down5_l.bin $arachne_pnr -d $d sb_up3down5.blif -B $d/sb_up3down5_packed.blif -o $d/sb_up3down5.txt $arachne_pnr -d $d $d/sb_up3down5_packed.blif -o $d/sb_up3down5_packed.txt shasum $d/sb_up3down5_packed.txt >> txt.sum icepack $d/sb_up3down5_packed.txt $d/sb_up3down5_packed.bin $arachne_pnr -d $d carry.blif -o $d/carry.txt shasum $d/carry.txt >> txt.sum icepack $d/carry.txt $d/carry.bin $arachne_pnr -d $d bram.blif -o $d/bram.txt shasum $d/bram.txt >> txt.sum icepack $d/bram.txt $d/bram.bin $arachne_pnr -d $d -p sb_gb_io.$d.pcf sb_gb_io.blif -o $d/sb_gb_io.txt shasum $d/sb_gb_io.txt >> txt.sum icepack $d/sb_gb_io.txt $d/sb_gb_io.bin for pll in sb_pll40_pad sb_pll40_core sb_pll40_2_pad sb_pll40_2f_pad sb_pll40_2f_core; do $arachne_pnr -d $d $pll.blif -o $d/$pll.txt shasum $d/$pll.txt >> txt.sum icepack $d/$pll.txt $d/$pll.bin done done arachne-pnr-0~20150927gitefdb026/tests/simple/run-valgrind-test.sh000066400000000000000000000002661260207143000245710ustar00rootroot00000000000000#!/bin/bash set -ex arachne_pnr=../../bin/arachne-pnr valgrind $arachne_pnr sb_up3down5.blif -o sb_up3down5_valgrind.txt icepack sb_up3down5_valgrind.txt sb_up3down5_valgrind.bin arachne-pnr-0~20150927gitefdb026/tests/simple/sb_gb_io.1k.pcf000066400000000000000000000000201260207143000234030ustar00rootroot00000000000000set_io inclk 50 arachne-pnr-0~20150927gitefdb026/tests/simple/sb_gb_io.8k.pcf000066400000000000000000000000201260207143000234120ustar00rootroot00000000000000set_io inclk F7 arachne-pnr-0~20150927gitefdb026/tests/simple/sb_gb_io.blif000066400000000000000000000035511260207143000232510ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model test .inputs inclk .outputs outclk out[0] out[1] out[2] out[3] .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=r[0] I1=r[1] I2=$false I3=$false O=$0\r[3:0][1] .attr src "/usr/local/bin/../share/yosys/ice40/cells_map.v:43" .param LUT_INIT 0110 .gate SB_LUT4 I0=$false I1=$true I2=r[0] I3=$false O=$0\r[3:0][0] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=r[0] CO=$auto$alumacc.cc:484:replace_alu$6[1] I0=$false I1=r[1] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=r[2] I3=$auto$alumacc.cc:484:replace_alu$6[1] O=$0\r[3:0][2] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=$auto$alumacc.cc:484:replace_alu$6[1] CO=$auto$alumacc.cc:484:replace_alu$6[2] I0=$false I1=r[2] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:47" .gate SB_LUT4 I0=$false I1=$false I2=r[3] I3=$auto$alumacc.cc:484:replace_alu$6[2] O=$0\r[3:0][3] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_DFF C=clk D=$0\r[3:0][0] Q=r[0] .attr src "sb_gb_io.v:14|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\r[3:0][1] Q=r[1] .attr src "sb_gb_io.v:14|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\r[3:0][2] Q=r[2] .attr src "sb_gb_io.v:14|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\r[3:0][3] Q=r[3] .attr src "sb_gb_io.v:14|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_GB_IO D_IN_0=outclk GLOBAL_BUFFER_OUTPUT=clk PACKAGE_PIN=inclk .attr src "sb_gb_io.v:4" .param PIN_TYPE 000001 .names r[0] out[0] 1 1 .names r[1] out[1] 1 1 .names r[2] out[2] 1 1 .names r[3] out[3] 1 1 .end arachne-pnr-0~20150927gitefdb026/tests/simple/sb_gb_io.v000066400000000000000000000004751260207143000226040ustar00rootroot00000000000000 module test(input inclk, output outclk, output [3:0] out); SB_GB_IO #(.PIN_TYPE(6'b000001)) gb_io_inst (.PACKAGE_PIN(inclk), .D_IN_0(outclk), .GLOBAL_BUFFER_OUTPUT(clk)); reg [3:0] r; assign out = r; always @(posedge clk) begin r <= r + 1; end endmodule arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_2_pad.blif000066400000000000000000000025251260207143000241720ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model top .inputs PACKAGEPIN EXTFEEDBACK DYNAMICDELAY[0] DYNAMICDELAY[1] DYNAMICDELAY[2] DYNAMICDELAY[3] DYNAMICDELAY[4] DYNAMICDELAY[5] DYNAMICDELAY[6] DYNAMICDELAY[7] BYPASS RESETB LATCHINPUTVALUE SDI SCLK .outputs PLLOUTCORE[0] PLLOUTCORE[1] PLLOUTGLOBAL[0] PLLOUTGLOBAL[1] LOCK SDO .names $false .names $true 1 .names $undef .gate SB_PLL40_2_PAD BYPASS=BYPASS DYNAMICDELAY[0]=DYNAMICDELAY[0] DYNAMICDELAY[1]=DYNAMICDELAY[1] DYNAMICDELAY[2]=DYNAMICDELAY[2] DYNAMICDELAY[3]=DYNAMICDELAY[3] DYNAMICDELAY[4]=DYNAMICDELAY[4] DYNAMICDELAY[5]=DYNAMICDELAY[5] DYNAMICDELAY[6]=DYNAMICDELAY[6] DYNAMICDELAY[7]=DYNAMICDELAY[7] EXTFEEDBACK=EXTFEEDBACK LATCHINPUTVALUE=LATCHINPUTVALUE LOCK=LOCK PACKAGEPIN=PACKAGEPIN PLLOUTCOREA=PLLOUTCORE[0] PLLOUTCOREB=PLLOUTCORE[1] PLLOUTGLOBALA=PLLOUTGLOBAL[0] PLLOUTGLOBALB=PLLOUTGLOBAL[1] RESETB=RESETB SCLK=SCLK SDI=SDI SDO=SDO .attr src "sb_pll40_2_pad.v:17" .param DELAY_ADJUSTMENT_MODE_FEEDBACK "FIXED" .param DELAY_ADJUSTMENT_MODE_RELATIVE "FIXED" .param DIVF 0000000 .param DIVQ 001 .param DIVR 0000 .param ENABLE_ICEGATE_PORTA 0 .param ENABLE_ICEGATE_PORTB 0 .param FDA_FEEDBACK 1111 .param FDA_RELATIVE 1111 .param FEEDBACK_PATH "DELAY" .param FILTER_RANGE 000 .param PLLOUT_SELECT_PORTB "GENCLK" .param SHIFTREG_DIV_MODE 0 .param TEST_MODE 0 .end arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_2_pad.v000066400000000000000000000030311260207143000235140ustar00rootroot00000000000000module top( input PACKAGEPIN, output [1:0] PLLOUTCORE, output [1:0] PLLOUTGLOBAL, input EXTFEEDBACK, input [7:0] DYNAMICDELAY, output LOCK, input BYPASS, input RESETB, input LATCHINPUTVALUE, //Test Pins output SDO, input SDI, input SCLK ); SB_PLL40_2_PAD #( .FEEDBACK_PATH("DELAY"), // .FEEDBACK_PATH("SIMPLE"), // .FEEDBACK_PATH("PHASE_AND_DELAY"), // .FEEDBACK_PATH("EXTERNAL"), .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), // .DELAY_ADJUSTMENT_MODE_FEEDBACK("DYNAMIC"), .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), // .DELAY_ADJUSTMENT_MODE_RELATIVE("DYNAMIC"), .PLLOUT_SELECT_PORTB("GENCLK"), // .PLLOUT_SELECT_PORTB("GENCLK_HALF"), // .PLLOUT_SELECT_PORTB("SHIFTREG_90deg"), // .PLLOUT_SELECT_PORTB("SHIFTREG_0deg"), .SHIFTREG_DIV_MODE(1'b0), .FDA_FEEDBACK(4'b1111), .FDA_RELATIVE(4'b1111), .DIVR(4'b0000), .DIVF(7'b0000000), .DIVQ(3'b001), .FILTER_RANGE(3'b000), .ENABLE_ICEGATE_PORTA(1'b0), .ENABLE_ICEGATE_PORTB(1'b0), .TEST_MODE(1'b0) ) uut ( .PACKAGEPIN (PACKAGEPIN ), .PLLOUTCOREA (PLLOUTCORE [0]), .PLLOUTGLOBALA (PLLOUTGLOBAL[0]), .PLLOUTCOREB (PLLOUTCORE [1]), .PLLOUTGLOBALB (PLLOUTGLOBAL[1]), .EXTFEEDBACK (EXTFEEDBACK ), .DYNAMICDELAY (DYNAMICDELAY ), .LOCK (LOCK ), .BYPASS (BYPASS ), .RESETB (RESETB ), .LATCHINPUTVALUE(LATCHINPUTVALUE), .SDO (SDO ), .SDI (SDI ), .SCLK (SCLK ) ); endmodule arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_2f_core.blif000066400000000000000000000026031260207143000245210ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model top .inputs REFERENCECLK EXTFEEDBACK DYNAMICDELAY[0] DYNAMICDELAY[1] DYNAMICDELAY[2] DYNAMICDELAY[3] DYNAMICDELAY[4] DYNAMICDELAY[5] DYNAMICDELAY[6] DYNAMICDELAY[7] BYPASS RESETB LATCHINPUTVALUE SDI SCLK .outputs PLLOUTCORE[0] PLLOUTCORE[1] PLLOUTGLOBAL[0] PLLOUTGLOBAL[1] LOCK SDO .names $false .names $true 1 .names $undef .gate SB_PLL40_2F_CORE BYPASS=BYPASS DYNAMICDELAY[0]=DYNAMICDELAY[0] DYNAMICDELAY[1]=DYNAMICDELAY[1] DYNAMICDELAY[2]=DYNAMICDELAY[2] DYNAMICDELAY[3]=DYNAMICDELAY[3] DYNAMICDELAY[4]=DYNAMICDELAY[4] DYNAMICDELAY[5]=DYNAMICDELAY[5] DYNAMICDELAY[6]=DYNAMICDELAY[6] DYNAMICDELAY[7]=DYNAMICDELAY[7] EXTFEEDBACK=EXTFEEDBACK LATCHINPUTVALUE=LATCHINPUTVALUE LOCK=LOCK PLLOUTCOREA=PLLOUTCORE[0] PLLOUTCOREB=PLLOUTCORE[1] PLLOUTGLOBALA=PLLOUTGLOBAL[0] PLLOUTGLOBALB=PLLOUTGLOBAL[1] REFERENCECLK=REFERENCECLK RESETB=RESETB SCLK=SCLK SDI=SDI SDO=SDO .attr src "sb_pll40_2f_core.v:17" .param DELAY_ADJUSTMENT_MODE_FEEDBACK "FIXED" .param DELAY_ADJUSTMENT_MODE_RELATIVE "FIXED" .param DIVF 0000000 .param DIVQ 001 .param DIVR 0000 .param ENABLE_ICEGATE_PORTA 0 .param ENABLE_ICEGATE_PORTB 0 .param FDA_FEEDBACK 1111 .param FDA_RELATIVE 1111 .param FEEDBACK_PATH "DELAY" .param FILTER_RANGE 000 .param PLLOUT_SELECT_PORTA "GENCLK" .param PLLOUT_SELECT_PORTB "GENCLK" .param SHIFTREG_DIV_MODE 0 .param TEST_MODE 0 .end arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_2f_core.v000066400000000000000000000033031260207143000240500ustar00rootroot00000000000000module top( input REFERENCECLK, output [1:0] PLLOUTCORE, output [1:0] PLLOUTGLOBAL, input EXTFEEDBACK, input [7:0] DYNAMICDELAY, output LOCK, input BYPASS, input RESETB, input LATCHINPUTVALUE, //Test Pins output SDO, input SDI, input SCLK ); SB_PLL40_2F_CORE #( .FEEDBACK_PATH("DELAY"), // .FEEDBACK_PATH("SIMPLE"), // .FEEDBACK_PATH("PHASE_AND_DELAY"), // .FEEDBACK_PATH("EXTERNAL"), .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), // .DELAY_ADJUSTMENT_MODE_FEEDBACK("DYNAMIC"), .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), // .DELAY_ADJUSTMENT_MODE_RELATIVE("DYNAMIC"), .PLLOUT_SELECT_PORTA("GENCLK"), // .PLLOUT_SELECT_PORTA("GENCLK_HALF"), // .PLLOUT_SELECT_PORTA("SHIFTREG_90deg"), // .PLLOUT_SELECT_PORTA("SHIFTREG_0deg"), .PLLOUT_SELECT_PORTB("GENCLK"), // .PLLOUT_SELECT_PORTB("GENCLK_HALF"), // .PLLOUT_SELECT_PORTB("SHIFTREG_90deg"), // .PLLOUT_SELECT_PORTB("SHIFTREG_0deg"), .SHIFTREG_DIV_MODE(1'b0), .FDA_FEEDBACK(4'b1111), .FDA_RELATIVE(4'b1111), .DIVR(4'b0000), .DIVF(7'b0000000), .DIVQ(3'b001), .FILTER_RANGE(3'b000), .ENABLE_ICEGATE_PORTA(1'b0), .ENABLE_ICEGATE_PORTB(1'b0), .TEST_MODE(1'b0) ) uut ( .REFERENCECLK (REFERENCECLK ), .PLLOUTCOREA (PLLOUTCORE [0]), .PLLOUTGLOBALA (PLLOUTGLOBAL[0]), .PLLOUTCOREB (PLLOUTCORE [1]), .PLLOUTGLOBALB (PLLOUTGLOBAL[1]), .EXTFEEDBACK (EXTFEEDBACK ), .DYNAMICDELAY (DYNAMICDELAY ), .LOCK (LOCK ), .BYPASS (BYPASS ), .RESETB (RESETB ), .LATCHINPUTVALUE(LATCHINPUTVALUE), .SDO (SDO ), .SDI (SDI ), .SCLK (SCLK ) ); endmodule arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_2f_pad.blif000066400000000000000000000025731260207143000243430ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model top .inputs PACKAGEPIN EXTFEEDBACK DYNAMICDELAY[0] DYNAMICDELAY[1] DYNAMICDELAY[2] DYNAMICDELAY[3] DYNAMICDELAY[4] DYNAMICDELAY[5] DYNAMICDELAY[6] DYNAMICDELAY[7] BYPASS RESETB LATCHINPUTVALUE SDI SCLK .outputs PLLOUTCORE[0] PLLOUTCORE[1] PLLOUTGLOBAL[0] PLLOUTGLOBAL[1] LOCK SDO .names $false .names $true 1 .names $undef .gate SB_PLL40_2F_PAD BYPASS=BYPASS DYNAMICDELAY[0]=DYNAMICDELAY[0] DYNAMICDELAY[1]=DYNAMICDELAY[1] DYNAMICDELAY[2]=DYNAMICDELAY[2] DYNAMICDELAY[3]=DYNAMICDELAY[3] DYNAMICDELAY[4]=DYNAMICDELAY[4] DYNAMICDELAY[5]=DYNAMICDELAY[5] DYNAMICDELAY[6]=DYNAMICDELAY[6] DYNAMICDELAY[7]=DYNAMICDELAY[7] EXTFEEDBACK=EXTFEEDBACK LATCHINPUTVALUE=LATCHINPUTVALUE LOCK=LOCK PACKAGEPIN=PACKAGEPIN PLLOUTCOREA=PLLOUTCORE[0] PLLOUTCOREB=PLLOUTCORE[1] PLLOUTGLOBALA=PLLOUTGLOBAL[0] PLLOUTGLOBALB=PLLOUTGLOBAL[1] RESETB=RESETB SCLK=SCLK SDI=SDI SDO=SDO .attr src "sb_pll40_2f_pad.v:17" .param DELAY_ADJUSTMENT_MODE_FEEDBACK "FIXED" .param DELAY_ADJUSTMENT_MODE_RELATIVE "FIXED" .param DIVF 0000000 .param DIVQ 001 .param DIVR 0000 .param ENABLE_ICEGATE_PORTA 0 .param ENABLE_ICEGATE_PORTB 0 .param FDA_FEEDBACK 1111 .param FDA_RELATIVE 1111 .param FEEDBACK_PATH "DELAY" .param FILTER_RANGE 000 .param PLLOUT_SELECT_PORTA "GENCLK" .param PLLOUT_SELECT_PORTB "GENCLK" .param SHIFTREG_DIV_MODE 0 .param TEST_MODE 0 .end arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_2f_pad.v000066400000000000000000000033001260207143000236610ustar00rootroot00000000000000module top( input PACKAGEPIN, output [1:0] PLLOUTCORE, output [1:0] PLLOUTGLOBAL, input EXTFEEDBACK, input [7:0] DYNAMICDELAY, output LOCK, input BYPASS, input RESETB, input LATCHINPUTVALUE, //Test Pins output SDO, input SDI, input SCLK ); SB_PLL40_2F_PAD #( .FEEDBACK_PATH("DELAY"), // .FEEDBACK_PATH("SIMPLE"), // .FEEDBACK_PATH("PHASE_AND_DELAY"), // .FEEDBACK_PATH("EXTERNAL"), .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), // .DELAY_ADJUSTMENT_MODE_FEEDBACK("DYNAMIC"), .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), // .DELAY_ADJUSTMENT_MODE_RELATIVE("DYNAMIC"), .PLLOUT_SELECT_PORTA("GENCLK"), // .PLLOUT_SELECT_PORTA("GENCLK_HALF"), // .PLLOUT_SELECT_PORTA("SHIFTREG_90deg"), // .PLLOUT_SELECT_PORTA("SHIFTREG_0deg"), .PLLOUT_SELECT_PORTB("GENCLK"), // .PLLOUT_SELECT_PORTB("GENCLK_HALF"), // .PLLOUT_SELECT_PORTB("SHIFTREG_90deg"), // .PLLOUT_SELECT_PORTB("SHIFTREG_0deg"), .SHIFTREG_DIV_MODE(1'b0), .FDA_FEEDBACK(4'b1111), .FDA_RELATIVE(4'b1111), .DIVR(4'b0000), .DIVF(7'b0000000), .DIVQ(3'b001), .FILTER_RANGE(3'b000), .ENABLE_ICEGATE_PORTA(1'b0), .ENABLE_ICEGATE_PORTB(1'b0), .TEST_MODE(1'b0) ) uut ( .PACKAGEPIN (PACKAGEPIN ), .PLLOUTCOREA (PLLOUTCORE [0]), .PLLOUTGLOBALA (PLLOUTGLOBAL[0]), .PLLOUTCOREB (PLLOUTCORE [1]), .PLLOUTGLOBALB (PLLOUTGLOBAL[1]), .EXTFEEDBACK (EXTFEEDBACK ), .DYNAMICDELAY (DYNAMICDELAY ), .LOCK (LOCK ), .BYPASS (BYPASS ), .RESETB (RESETB ), .LATCHINPUTVALUE(LATCHINPUTVALUE), .SDO (SDO ), .SDI (SDI ), .SCLK (SCLK ) ); endmodule arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_core.blif000066400000000000000000000023131260207143000241300ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model top .inputs REFERENCECLK EXTFEEDBACK DYNAMICDELAY[0] DYNAMICDELAY[1] DYNAMICDELAY[2] DYNAMICDELAY[3] DYNAMICDELAY[4] DYNAMICDELAY[5] DYNAMICDELAY[6] DYNAMICDELAY[7] BYPASS RESETB LATCHINPUTVALUE SDI SCLK .outputs PLLOUTCORE PLLOUTGLOBAL LOCK SDO .names $false .names $true 1 .names $undef .gate SB_PLL40_CORE BYPASS=BYPASS DYNAMICDELAY[0]=DYNAMICDELAY[0] DYNAMICDELAY[1]=DYNAMICDELAY[1] DYNAMICDELAY[2]=DYNAMICDELAY[2] DYNAMICDELAY[3]=DYNAMICDELAY[3] DYNAMICDELAY[4]=DYNAMICDELAY[4] DYNAMICDELAY[5]=DYNAMICDELAY[5] DYNAMICDELAY[6]=DYNAMICDELAY[6] DYNAMICDELAY[7]=DYNAMICDELAY[7] EXTFEEDBACK=EXTFEEDBACK LATCHINPUTVALUE=LATCHINPUTVALUE LOCK=LOCK PLLOUTCORE=PLLOUTCORE PLLOUTGLOBAL=PLLOUTGLOBAL REFERENCECLK=REFERENCECLK RESETB=RESETB SCLK=SCLK SDI=SDI SDO=SDO .attr src "sb_pll40_core.v:17" .param DELAY_ADJUSTMENT_MODE_FEEDBACK "FIXED" .param DELAY_ADJUSTMENT_MODE_RELATIVE "FIXED" .param DIVF 0000000 .param DIVQ 001 .param DIVR 0000 .param ENABLE_ICEGATE 0 .param FDA_FEEDBACK 1111 .param FDA_RELATIVE 1111 .param FEEDBACK_PATH "DELAY" .param FILTER_RANGE 000 .param PLLOUT_SELECT "GENCLK" .param SHIFTREG_DIV_MODE 0 .param TEST_MODE 0 .end arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_core.v000066400000000000000000000026071260207143000234670ustar00rootroot00000000000000module top( input REFERENCECLK, output PLLOUTCORE, output PLLOUTGLOBAL, input EXTFEEDBACK, input [7:0] DYNAMICDELAY, output LOCK, input BYPASS, input RESETB, input LATCHINPUTVALUE, //Test Pins output SDO, input SDI, input SCLK ); SB_PLL40_CORE #( .FEEDBACK_PATH("DELAY"), // .FEEDBACK_PATH("SIMPLE"), // .FEEDBACK_PATH("PHASE_AND_DELAY"), // .FEEDBACK_PATH("EXTERNAL"), .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), // .DELAY_ADJUSTMENT_MODE_FEEDBACK("DYNAMIC"), .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), // .DELAY_ADJUSTMENT_MODE_RELATIVE("DYNAMIC"), .PLLOUT_SELECT("GENCLK"), // .PLLOUT_SELECT("GENCLK_HALF"), // .PLLOUT_SELECT("SHIFTREG_90deg"), // .PLLOUT_SELECT("SHIFTREG_0deg"), .SHIFTREG_DIV_MODE(1'b0), .FDA_FEEDBACK(4'b1111), .FDA_RELATIVE(4'b1111), .DIVR(4'b0000), .DIVF(7'b0000000), .DIVQ(3'b001), .FILTER_RANGE(3'b000), .ENABLE_ICEGATE(1'b0), .TEST_MODE(1'b0) ) uut ( .REFERENCECLK (REFERENCECLK ), .PLLOUTCORE (PLLOUTCORE ), .PLLOUTGLOBAL (PLLOUTGLOBAL ), .EXTFEEDBACK (EXTFEEDBACK ), .DYNAMICDELAY (DYNAMICDELAY ), .LOCK (LOCK ), .BYPASS (BYPASS ), .RESETB (RESETB ), .LATCHINPUTVALUE(LATCHINPUTVALUE), .SDO (SDO ), .SDI (SDI ), .SCLK (SCLK ) ); endmodule arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_pad.blif000066400000000000000000000023031260207143000237430ustar00rootroot00000000000000# Generated by Yosys 0.5+ 292 (git sha1 6f9a6fd, clang 6.1.0 -fPIC -Os) .model top .inputs PACKAGEPIN EXTFEEDBACK DYNAMICDELAY[0] DYNAMICDELAY[1] DYNAMICDELAY[2] DYNAMICDELAY[3] DYNAMICDELAY[4] DYNAMICDELAY[5] DYNAMICDELAY[6] DYNAMICDELAY[7] BYPASS RESETB LATCHINPUTVALUE SDI SCLK .outputs PLLOUTCORE PLLOUTGLOBAL LOCK SDO .names $false .names $true 1 .names $undef .gate SB_PLL40_PAD BYPASS=BYPASS DYNAMICDELAY[0]=DYNAMICDELAY[0] DYNAMICDELAY[1]=DYNAMICDELAY[1] DYNAMICDELAY[2]=DYNAMICDELAY[2] DYNAMICDELAY[3]=DYNAMICDELAY[3] DYNAMICDELAY[4]=DYNAMICDELAY[4] DYNAMICDELAY[5]=DYNAMICDELAY[5] DYNAMICDELAY[6]=DYNAMICDELAY[6] DYNAMICDELAY[7]=DYNAMICDELAY[7] EXTFEEDBACK=EXTFEEDBACK LATCHINPUTVALUE=LATCHINPUTVALUE LOCK=LOCK PACKAGEPIN=PACKAGEPIN PLLOUTCORE=PLLOUTCORE PLLOUTGLOBAL=PLLOUTGLOBAL RESETB=RESETB SCLK=SCLK SDI=SDI SDO=SDO .attr src "sb_pll40_pad.v:17" .param DELAY_ADJUSTMENT_MODE_FEEDBACK "FIXED" .param DELAY_ADJUSTMENT_MODE_RELATIVE "FIXED" .param DIVF 0000000 .param DIVQ 001 .param DIVR 0000 .param ENABLE_ICEGATE 0 .param FDA_FEEDBACK 1111 .param FDA_RELATIVE 1111 .param FEEDBACK_PATH "DELAY" .param FILTER_RANGE 000 .param PLLOUT_SELECT "GENCLK" .param SHIFTREG_DIV_MODE 0 .param TEST_MODE 0 .end arachne-pnr-0~20150927gitefdb026/tests/simple/sb_pll40_pad.v000066400000000000000000000026051260207143000233010ustar00rootroot00000000000000module top( input PACKAGEPIN, output PLLOUTCORE, output PLLOUTGLOBAL, input EXTFEEDBACK, input [7:0] DYNAMICDELAY, output LOCK, input BYPASS, input RESETB, input LATCHINPUTVALUE, //Test Pins output SDO, input SDI, input SCLK ); SB_PLL40_PAD #( .FEEDBACK_PATH("DELAY"), // .FEEDBACK_PATH("SIMPLE"), // .FEEDBACK_PATH("PHASE_AND_DELAY"), // .FEEDBACK_PATH("EXTERNAL"), .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), // .DELAY_ADJUSTMENT_MODE_FEEDBACK("DYNAMIC"), .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), // .DELAY_ADJUSTMENT_MODE_RELATIVE("DYNAMIC"), .PLLOUT_SELECT("GENCLK"), // .PLLOUT_SELECT("GENCLK_HALF"), // .PLLOUT_SELECT("SHIFTREG_90deg"), // .PLLOUT_SELECT("SHIFTREG_0deg"), .SHIFTREG_DIV_MODE(1'b0), .FDA_FEEDBACK(4'b1111), .FDA_RELATIVE(4'b1111), .DIVR(4'b0000), .DIVF(7'b0000000), .DIVQ(3'b001), .FILTER_RANGE(3'b000), .ENABLE_ICEGATE(1'b0), .TEST_MODE(1'b0) ) uut ( .PACKAGEPIN (PACKAGEPIN ), .PLLOUTCORE (PLLOUTCORE ), .PLLOUTGLOBAL (PLLOUTGLOBAL ), .EXTFEEDBACK (EXTFEEDBACK ), .DYNAMICDELAY (DYNAMICDELAY ), .LOCK (LOCK ), .BYPASS (BYPASS ), .RESETB (RESETB ), .LATCHINPUTVALUE(LATCHINPUTVALUE), .SDO (SDO ), .SDI (SDI ), .SCLK (SCLK ) ); endmodule arachne-pnr-0~20150927gitefdb026/tests/simple/sb_up3down5.blif000066400000000000000000000227651260207143000236660ustar00rootroot00000000000000# Generated by Yosys 0.5+81 (git sha1 ed15400, clang 3.4-1ubuntu3 -fPIC -Os) .model up3down5 .inputs clock data_in[0] data_in[1] data_in[2] data_in[3] data_in[4] data_in[5] data_in[6] data_in[7] data_in[8] up down .outputs carry_out borrow_out count_out[0] count_out[1] count_out[2] count_out[3] count_out[4] count_out[5] count_out[6] count_out[7] count_out[8] parity_out .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=data_in[0] I1=count_out[0] I2=up I3=down O=$0\count_out[8:0][0] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1100001100111010 .gate SB_LUT4 I0=down I1=up I2=data_in[1] I3=$abc$493$n36 O=$0\count_out[8:0][1] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0001000011111111 .gate SB_LUT4 I0=down I1=up I2=count_out[0] I3=count_out[1] O=$abc$493$n36 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0001011111111001 .gate SB_LUT4 I0=$abc$493$n41 I1=$abc$493$n38 I2=$abc$493$n40 I3=$abc$493$n39 O=$0\count_out[8:0][2] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1111111111110010 .gate SB_LUT4 I0=down I1=up I2=$false I3=$false O=$abc$493$n38 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:18" .param LUT_INIT 1001 .gate SB_LUT4 I0=down I1=up I2=data_in[2] I3=$false O=$abc$493$n39 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 00010000 .gate SB_LUT4 I0=down I1=up I2=count_out[2] I3=$false O=$abc$493$n40 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 10000000 .gate SB_LUT4 I0=count_out[0] I1=count_out[1] I2=count_out[2] I3=$false O=$abc$493$n41 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 00011110 .gate SB_LUT4 I0=$abc$493$n44 I1=$abc$493$n43 I2=down I3=up O=$0\count_out[8:0][3] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0101110101110101 .gate SB_LUT4 I0=count_out[0] I1=count_out[1] I2=count_out[2] I3=count_out[3] O=$abc$493$n43 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0001111111100000 .gate SB_LUT4 I0=data_in[3] I1=count_out[3] I2=down I3=up O=$abc$493$n44 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0011111111110101 .gate SB_LUT4 I0=$abc$493$n46 I1=$abc$493$n50 I2=$abc$493$n51 I3=count_out[4] O=$0\count_out[8:0][4] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0101110111010101 .gate SB_LUT4 I0=$abc$493$n47 I1=$abc$493$n48 I2=count_out[4] I3=$abc$493$n49 O=$abc$493$n46 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1101011100000000 .gate SB_LUT4 I0=down I1=up I2=$false I3=$false O=$abc$493$n47 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:18" .param LUT_INIT 0010 .gate SB_LUT4 I0=count_out[2] I1=count_out[1] I2=count_out[0] I3=count_out[3] O=$abc$493$n48 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0000000001010111 .gate SB_LUT4 I0=data_in[4] I1=count_out[4] I2=down I3=up O=$abc$493$n49 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0011111111110101 .gate SB_LUT4 I0=down I1=up I2=$false I3=$false O=$abc$493$n50 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:18" .param LUT_INIT 0100 .gate SB_LUT4 I0=count_out[1] I1=count_out[0] I2=count_out[2] I3=count_out[3] O=$abc$493$n51 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1110000000000000 .gate SB_LUT4 I0=$abc$493$n53 I1=$abc$493$n54 I2=$abc$493$n55 I3=$false O=$0\count_out[8:0][5] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 11101111 .gate SB_LUT4 I0=$abc$493$n51 I1=count_out[4] I2=$abc$493$n50 I3=count_out[5] O=$abc$493$n53 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0111000010000000 .gate SB_LUT4 I0=$abc$493$n48 I1=count_out[4] I2=$abc$493$n47 I3=count_out[5] O=$abc$493$n54 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1101000000100000 .gate SB_LUT4 I0=data_in[5] I1=count_out[5] I2=down I3=up O=$abc$493$n55 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0011111111110101 .gate SB_LUT4 I0=$abc$493$n47 I1=$abc$493$n59 I2=$abc$493$n57 I3=$abc$493$n60 O=$0\count_out[8:0][6] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1111001011111111 .gate SB_LUT4 I0=$abc$493$n51 I1=$abc$493$n58 I2=$abc$493$n50 I3=count_out[6] O=$abc$493$n57 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0111000010000000 .gate SB_LUT4 I0=count_out[4] I1=count_out[5] I2=$false I3=$false O=$abc$493$n58 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:18" .param LUT_INIT 1000 .gate SB_LUT4 I0=$abc$493$n48 I1=count_out[4] I2=count_out[5] I3=count_out[6] O=$abc$493$n59 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0000001011111101 .gate SB_LUT4 I0=data_in[6] I1=count_out[6] I2=down I3=up O=$abc$493$n60 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0011111111110101 .gate SB_LUT4 I0=$abc$493$n62 I1=$abc$493$n64 I2=$abc$493$n66 I3=$false O=$0\count_out[8:0][7] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 11101111 .gate SB_LUT4 I0=$abc$493$n63 I1=$abc$493$n50 I2=count_out[7] I3=$false O=$abc$493$n62 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 01001000 .gate SB_LUT4 I0=$abc$493$n51 I1=$abc$493$n58 I2=count_out[6] I3=$false O=$abc$493$n63 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 10000000 .gate SB_LUT4 I0=$abc$493$n65 I1=$abc$493$n47 I2=count_out[7] I3=$false O=$abc$493$n64 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 01001000 .gate SB_LUT4 I0=$abc$493$n48 I1=count_out[4] I2=count_out[5] I3=count_out[6] O=$abc$493$n65 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0000000000000010 .gate SB_LUT4 I0=data_in[7] I1=count_out[7] I2=down I3=up O=$abc$493$n66 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0011111111110101 .gate SB_LUT4 I0=$abc$493$n68 I1=$abc$493$n69 I2=$abc$493$n70 I3=$false O=$0\count_out[8:0][8] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:22" .param LUT_INIT 11101111 .gate SB_LUT4 I0=$abc$493$n63 I1=count_out[7] I2=$abc$493$n50 I3=count_out[8] O=$abc$493$n68 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0111000010000000 .gate SB_LUT4 I0=$abc$493$n65 I1=count_out[7] I2=$abc$493$n47 I3=count_out[8] O=$abc$493$n69 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1101000000100000 .gate SB_LUT4 I0=data_in[8] I1=count_out[8] I2=down I3=up O=$abc$493$n70 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0011111111110101 .gate SB_LUT4 I0=$abc$493$n72 I1=$abc$493$n74_1 I2=$0\count_out[8:0][4] I3=$0\count_out[8:0][5] O=$0\parity_out[0:0] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0110100110010110 .gate SB_LUT4 I0=$abc$493$n62 I1=$abc$493$n64 I2=$abc$493$n66 I3=$abc$493$n73 O=$abc$493$n72 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0001000011101111 .gate SB_LUT4 I0=$0\count_out[8:0][1] I1=$0\count_out[8:0][2] I2=$0\count_out[8:0][3] I3=$0\count_out[8:0][0] O=$abc$493$n73 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1001011001101001 .gate SB_LUT4 I0=$abc$493$n68 I1=$abc$493$n69 I2=$abc$493$n70 I3=$0\count_out[8:0][6] O=$abc$493$n74_1 .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1110111100010000 .gate SB_LUT4 I0=$abc$493$n63 I1=up I2=count_out[7] I3=count_out[8] O=$0\carry_out[0:0] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 1000000000000000 .gate SB_LUT4 I0=$abc$493$n65 I1=down I2=count_out[7] I3=count_out[8] O=$0\borrow_out[0:0] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:26" .param LUT_INIT 0000000000001000 .gate SB_DFF C=clock D=$0\count_out[8:0][0] Q=count_out[0] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][1] Q=count_out[1] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][2] Q=count_out[2] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][3] Q=count_out[3] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][4] Q=count_out[4] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][5] Q=count_out[5] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][6] Q=count_out[6] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][7] Q=count_out[7] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\count_out[8:0][8] Q=count_out[8] .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\carry_out[0:0] Q=carry_out .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\borrow_out[0:0] Q=borrow_out .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .gate SB_DFF C=clock D=$0\parity_out[0:0] Q=parity_out .attr src "/home/clifford/Work/yosys/share/ice40/cells_map.v:2" .end arachne-pnr-0~20150927gitefdb026/tests/test_bv.cc000066400000000000000000000021031260207143000213240ustar00rootroot00000000000000 #include "bitvector.hh" #include "util.hh" #include #include #include void test(int n, random_generator &rg) { std::vector a(n); BitVector b(n); assert((int)a.size() == n); assert((int)b.size() == n); for (int i = 0; i < n; ++i) { assert(!a[i]); assert(!b[i]); } for (int k = 0; k < 2*n/3; ++k) { int i = random_int(0, n-1, rg); a[i] = true; b[i] = true; } for (int k = 0; k < n/3; ++k) { int i = random_int(0, n-1, rg); a[i] = false; b[i] = false; } int k = 0; for (int i = 0; i < n; ++i) { assert(a[i] == b[i]); if (b[i]) k++; } // std::cout << k << "\n"; int n2 = random_int(0, n, rg); a.resize(n2); b.resize(n2); assert((int)a.size() == n2); assert((int)b.size() == n2); for (int i = 0; i < n2; ++i) assert(a[i] == b[i]); b.zero(); for (int i = 0; i < n2; ++i) assert(!b[i]); } int main() { random_generator rg; for (int n = 0; n <= 1000; ++n) test(n, rg); test(10000, rg); } arachne-pnr-0~20150927gitefdb026/tests/test_us.cc000066400000000000000000000017641260207143000213600ustar00rootroot00000000000000 #include "ullmanset.hh" #include "util.hh" #include #include void test(int n, random_generator &rg) { std::set a; UllmanSet b(n); assert((int)b.capacity() == n); for (int i = 0; i < n; ++i) { assert(!contains(a, i)); assert(!b.contains(i)); } for (int k = 0; k < 2*n/3; ++k) { int i = random_int(0, n-1, rg); a.insert(i); b.insert(i); } assert(a.size() == b.size()); for (int k = 0; k < n/3; ++k) { int i = random_int(0, n-1, rg); a.erase(i); b.erase(i); } assert(a.size() == b.size()); int k = 0; for (int i = 0; i < n; ++i) { assert(contains(a, i) == b.contains(i)); if (b.contains(i)) ++k; } // std::cout << n << " " << k << "\n"; std::set a2; for (int i = 0; i < (int)b.size(); ++i) a2.insert(b.ith(i)); assert(a2 == a); } int main() { random_generator rg; for (int n = 0; n <= 1000; ++n) test(n, rg); test(10000, rg); }