pax_global_header00006660000000000000000000000064132761053410014514gustar00rootroot0000000000000052 comment=5d830dd94ad956d17d77168fe7718f22f8b55b33 arachne-pnr-0.1+20180513git5d830dd/000077500000000000000000000000001327610534100161515ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/.gitignore000066400000000000000000000002731327610534100201430ustar00rootroot00000000000000*.d *~ *.o *.host-o /bin/arachne-pnr /bin/arachne-pnr-host /bin/arachne-pnr.exe /tests/test_bv /tests/test_us /diff save /fuzz/*/findings /src/version_*.cc /tests/*/1k /tests/*/8k /share arachne-pnr-0.1+20180513git5d830dd/.travis.yml000066400000000000000000000010211327610534100202540ustar00rootroot00000000000000sudo: required dist: trusty script: make test language: cpp addons: apt: packages: - build-essential - libftdi-dev - llvm-3.6 - gcc-4.8 - git - python - python3 before_install: - sudo add-apt-repository -y ppa:saltmakrell/ppa - sudo apt-get -y update - sudo apt-get -y install yosys - git clone https://github.com/cliffordwolf/icestorm /tmp/icestorm - pushd /tmp/icestorm - make -j2 && sudo make install - popd os: linux compiler: - gcc - clang branches: except: - dummy arachne-pnr-0.1+20180513git5d830dd/COPYING000066400000000000000000000020611327610534100172030ustar00rootroot00000000000000MIT License Copyright (c) 2015-2018 Cotton Seed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. arachne-pnr-0.1+20180513git5d830dd/Makefile000066400000000000000000000163461327610534100176230ustar00rootroot00000000000000 # build with default C/C++ compiler # CC = clang # CXX = clang++ # build optimized without -DNDEBUG # OPTDEBUGFLAGS = -O0 -fno-inline -g # OPTDEBUGFLAGS = -O3 -DNDEBUG OPTDEBUGFLAGS ?= -MD -O2 SRC = src # clang only: -Wglobal-constructors CXXFLAGS += -I$(SRC) -std=c++11 $(OPTDEBUGFLAGS) -Wall -Wshadow -Wsign-compare -Werror LIBS = -lm DESTDIR ?= PREFIX ?= /usr/local ICEBOX ?= $(PREFIX)/share/icebox # Cross-compile logic HOST_CC ?= $(CC) HOST_CXX ?= $(CXX) HOST_CXXFLAGS += -I$(SRC) -std=c++11 $(OPTDEBUGFLAGS) -Wall -Wshadow -Wsign-compare -Werror HOST_LIBS ?= $(LIBS) IS_CROSS_COMPILING = no ifneq ($(CC),$(HOST_CC)) IS_CROSS_COMPILING = yes endif ifneq ($(CXX),$(HOST_CXX)) IS_CROSS_COMPILING = yes endif .PHONY: all all: bin/arachne-pnr$(EXE) share/arachne-pnr/chipdb-384.bin share/arachne-pnr/chipdb-1k.bin share/arachne-pnr/chipdb-8k.bin share/arachne-pnr/chipdb-5k.bin share/arachne-pnr/chipdb-lm4k.bin ARACHNE_VER = 0.1+$(shell test -e .git && echo `git log --oneline | wc -l`+`git diff --name-only HEAD | wc -l`) GIT_REV = $(shell git rev-parse --verify --short HEAD 2>/dev/null || echo UNKNOWN) VER_HASH = $(shell echo "$(ARACHNE_VER) $(GIT_REV)" | sum | cut -d ' ' -f -1) src/version_$(VER_HASH).cc: echo "const char *version_str = \"arachne-pnr $(ARACHNE_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) `$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\";" > src/version_$(VER_HASH).cc bin/arachne-pnr$(EXE): 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 src/version_$(VER_HASH).o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) ifeq ($(IS_CROSS_COMPILING),yes) bin/arachne-pnr-host: src/arachne-pnr.host-o src/netlist.host-o src/blif.host-o src/pack.host-o src/place.host-o src/util.host-o src/io.host-o src/route.host-o src/chipdb.host-o src/location.host-o src/configuration.host-o src/line_parser.host-o src/pcf.host-o src/global.host-o src/constant.host-o src/designstate.host-o src/version_$(VER_HASH).host-o $(HOST_CXX) $(HOST_CXXFLAGS) $(HOST_LDFLAGS) -o $@ $^ $(HOST_LIBS) else bin/arachne-pnr-host: bin/arachne-pnr$(EXE) cp $< $@ endif %.host-o: %.cc $(HOST_CXX) -c $(HOST_CPPFLAGS) $(HOST_CXXFLAGS) -o $@ $< ifeq ($(EXE),.js) # Special hack to make sure chipdb is built first bin/arachne-pnr$(EXE): | share/arachne-pnr/chipdb-384.bin share/arachne-pnr/chipdb-1k.bin share/arachne-pnr/chipdb-8k.bin share/arachne-pnr/chipdb-5k.bin endif share/arachne-pnr/chipdb-384.bin: bin/arachne-pnr-host $(ICEBOX)/chipdb-384.txt mkdir -p share/arachne-pnr ./bin/arachne-pnr-host -d 384 -c $(ICEBOX)/chipdb-384.txt --write-binary-chipdb share/arachne-pnr/chipdb-384.bin share/arachne-pnr/chipdb-1k.bin: bin/arachne-pnr-host $(ICEBOX)/chipdb-1k.txt mkdir -p share/arachne-pnr ./bin/arachne-pnr-host -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-host $(ICEBOX)/chipdb-8k.txt mkdir -p share/arachne-pnr ./bin/arachne-pnr-host -d 8k -c $(ICEBOX)/chipdb-8k.txt --write-binary-chipdb share/arachne-pnr/chipdb-8k.bin share/arachne-pnr/chipdb-5k.bin: bin/arachne-pnr-host $(ICEBOX)/chipdb-5k.txt mkdir -p share/arachne-pnr ./bin/arachne-pnr-host -d 8k -c $(ICEBOX)/chipdb-5k.txt --write-binary-chipdb share/arachne-pnr/chipdb-5k.bin share/arachne-pnr/chipdb-lm4k.bin: bin/arachne-pnr-host $(ICEBOX)/chipdb-lm4k.txt mkdir -p share/arachne-pnr ./bin/arachne-pnr-host -d 8k -c $(ICEBOX)/chipdb-lm4k.txt --write-binary-chipdb share/arachne-pnr/chipdb-lm4k.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/io && bash run-test.sh cd tests/regression && bash run-test.sh cd tests/blif && bash run-test.sh cd tests/error && 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/io && bash run-test.sh cd tests/regression && bash run-test.sh cd tests/blif && bash run-test.sh cd tests/error && 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 fuzz-pcf: all afl-fuzz -t 2500 -m 500 -x fuzz/pcf/pcf.dict -i fuzz/pcf/testcases -o fuzz/pcf/findings bin/arachne-pnr -p @@ fuzz/pcf/rot.blif -o /dev/null fuzz-blif: all afl-fuzz -t 2500 -m 500 -x fuzz/blif/blif.dict -i fuzz/blif/testcases -o fuzz/blif/findings bin/arachne-pnr @@ -o /dev/null -include src/*.d .PHONY: mxebin mxebin: $(MAKE) clean rm -rf arachne-pnr-win32 rm -f arachne-pnr-win32.zip mkdir -p arachne-pnr-win32 $(MAKE) share/arachne-pnr/chipdb-384.bin share/arachne-pnr/chipdb-1k.bin share/arachne-pnr/chipdb-8k.bin mv share/arachne-pnr/chipdb-384.bin arachne-pnr-win32/ mv share/arachne-pnr/chipdb-1k.bin arachne-pnr-win32/ mv share/arachne-pnr/chipdb-8k.bin arachne-pnr-win32/ mv share/arachne-pnr/chipdb-5k.bin arachne-pnr-win32/ mv share/arachne-pnr/chipdb-lm4k.bin arachne-pnr-win32/ $(MAKE) clean $(MAKE) CC=/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc CXX=/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ CXXFLAGS="$(CXXFLAGS) -DMXE_DIR_STRUCTURE" bin/arachne-pnr mv bin/arachne-pnr arachne-pnr-win32/arachne-pnr.exe zip -r arachne-pnr-win32.zip arachne-pnr-win32/ rm -rf arachne-pnr-win32 $(MAKE) clean .PHONY: install install: all mkdir -p $(DESTDIR)$(PREFIX)/bin cp bin/arachne-pnr$(EXE) $(DESTDIR)$(PREFIX)/bin/arachne-pnr$(EXE) mkdir -p $(DESTDIR)$(PREFIX)/share/arachne-pnr cp share/arachne-pnr/chipdb-384.bin $(DESTDIR)$(PREFIX)/share/arachne-pnr/chipdb-384.bin cp share/arachne-pnr/chipdb-1k.bin $(DESTDIR)$(PREFIX)/share/arachne-pnr/chipdb-1k.bin cp share/arachne-pnr/chipdb-8k.bin $(DESTDIR)$(PREFIX)/share/arachne-pnr/chipdb-8k.bin cp share/arachne-pnr/chipdb-5k.bin $(DESTDIR)$(PREFIX)/share/arachne-pnr/chipdb-5k.bin cp share/arachne-pnr/chipdb-lm4k.bin $(DESTDIR)$(PREFIX)/share/arachne-pnr/chipdb-lm4k.bin .PHONY: uninstall uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/arachne-pnr$(EXE) rm -f $(DESTDIR)$(PREFIX)/share/arachne-pnr/*.bin .PHONY: clean clean: rm -f src/*.o src/*.host-o tests/*.o src/*.d tests/*.d bin/arachne-pnr$(EXE) bin/arachne-pnr-host rm -f tests/test_bv tests/test_us rm -f share/arachne-pnr/*.bin rm -f src/version_* $(MAKE) -C examples/rot clean rm -rf tests/combinatorial/temp tests/combinatorial/1k tests/combinatorial/8k rm -rf tests/fsm/temp tests/fsm/1k tests/fsm/8k rm -rf tests/regression/1k tests/regression/8k rm -rf tests/simple/txt.sum tests/simple/1k tests/simple/8k .PHONY: emcc emcc: $(MAKE) EXE=.js clean $(MAKE) CC=emcc CXX=emcc HOST_CC=gcc HOST_CXX=g++ PREFIX=/ LDFLAGS="--memory-init-file 0 --embed-file share -s TOTAL_MEMORY=256*1024*1024" EXE=.js arachne-pnr-0.1+20180513git5d830dd/README.md000066400000000000000000000075011327610534100174330ustar00rootroot00000000000000# 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 hardware 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, jhol, laanwj, Clifford Wolf (cliffordwolf) and zeldin. ## 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.1+20180513git5d830dd/bin/000077500000000000000000000000001327610534100167215ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/bin/.keep000066400000000000000000000000001327610534100176340ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/examples/000077500000000000000000000000001327610534100177675ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/examples/rot/000077500000000000000000000000001327610534100205735ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/examples/rot/.gitignore000066400000000000000000000000301327610534100225540ustar00rootroot00000000000000*.blif *.txt *.ex *.bin arachne-pnr-0.1+20180513git5d830dd/examples/rot/Makefile000066400000000000000000000003471327610534100222370ustar00rootroot00000000000000 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.1+20180513git5d830dd/examples/rot/rot.pcf000066400000000000000000000001561327610534100220730ustar00rootroot00000000000000# For the iCE40HX-1K iCEstick set_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.1+20180513git5d830dd/examples/rot/rot.v000066400000000000000000000012511327610534100215650ustar00rootroot00000000000000 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.1+20180513git5d830dd/examples/rot/rot_8k.pcf000066400000000000000000000001641327610534100224740ustar00rootroot00000000000000# For the iCE40HX-8K Breakout Board set_io D1 B5 set_io D2 B4 set_io D3 A2 set_io D4 A1 set_io D5 C5 set_io clk J3 arachne-pnr-0.1+20180513git5d830dd/fuzz/000077500000000000000000000000001327610534100171475ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/000077500000000000000000000000001327610534100200635ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/blif.dict000066400000000000000000000100021327610534100216350ustar00rootroot00000000000000model_icestorm_lc=" ICESTORM_LC" model_io=" SB_IO" model_gb=" SB_GB" model_gb_io=" SB_GB_IO" model_lut4=" SB_LUT4" model_carry=" SB_CARRY" model_dff=" SB_DFF" model_dffn=" SB_DFFN" model_dffe=" SB_DFFE" model_dffen=" SB_DFFNE" model_dffsr=" SB_DFFSR" model_dffnsr=" SB_DFFNSR" model_dffesr=" SB_DFFESR" model_dffensr=" SB_DFFNESR" model_dffr=" SB_DFFR" model_dffnr=" SB_DFFNR" model_dffer=" SB_DFFER" model_dffenr=" SB_DFFNER" model_dffss=" SB_DFFSS" model_dffnss=" SB_DFFNSS" model_dffess=" SB_DFFESS" model_dffenss=" SB_DFFNESS" model_dffs=" SB_DFFS" model_dffns=" SB_DFFNS" model_dffes=" SB_DFFES" model_dffens=" SB_DFFNES" model_ram40_4k=" SB_RAM40_4K" model_ram40_4knr=" SB_RAM40_4KNR" model_ram40_4knw=" SB_RAM40_4KNW" model_ram40_4knrnw=" SB_RAM40_4KNRNW" model_pll40_core=" SB_PLL40_CORE" model_pll40_pad=" SB_PLL40_PAD" model_pll40_2_pad=" SB_PLL40_2_PAD" model_pll40_2f_core=" SB_PLL40_2F_CORE" model_pll40_2f_pad=" SB_PLL40_2F_PAD" model_warmboot=" SB_WARMBOOT" model_tbuf=" $_TBUF_" port_a=" A" port_e=" E" port_y=" Y" port_boot=" BOOT" port_s0=" S0" port_s1=" S1" port_i0=" I0" port_i1=" I1" port_i2=" I2" port_i3=" I3" port_cin=" CIN" port_clk=" CLK" port_cen=" CEN" port_sr=" SR" port_o=" O" port_cout=" COUT" param_lut_init=" LUT_INIT" param_neg_clk=" NEG_CLK" param_carry_enable=" CARRY_ENABLE" param_dff_enable=" DFF_ENABLE" param_set_noreset=" SET_NORESET" param_set_async=" SET_ASYNC" port_package_pin=" PACKAGE_PIN" port_latch_input_value=" LATCH_INPUT_VALUE" port_clock_enable=" CLOCK_ENABLE" port_input_clk=" INPUT_CLK" port_output_clk=" OUTPUT_CLK" port_output_enable=" OUTPUT_ENABLE" port_d_out_0=" D_OUT_0" port_d_out_1=" D_OUT_1" port_d_in_0=" D_IN_0" port_d_in_1=" D_IN_1" param_pin_type=" PIN_TYPE" param_pullup=" PULLUP" param_neg_trigger=" NEG_TRIGGER" param_io_standard=" IO_STANDARD" io_std_sb_lvcmos=" SB_LVCMOS" port_user_signal_to_global_buffer=" USER_SIGNAL_TO_GLOBAL_BUFFER" port_global_output_buffer=" GLOBAL_OUTPUT_BUFFER" port_co=" CO" port_ci=" CI" port_q=" Q" port_c=" C" port_e=" E" port_r=" R" port_s=" S" port_d=" D" port_rdata=" RDATA" port_waddr=" WADDR" port_mask=" MASK" port_wdata=" WDATA" port_rclke=" RCLKE" port_rclkn=" RCLKN" port_rclk=" RCLK" port_re=" RE" port_wclke=" WCLKE" port_wclkn=" WCLKN" port_wclk=" WCLK" port_we=" WE" param_read_mode=" READ_MODE" param_write_mode=" WRITE_MODE" port_referenceclk=" REFERENCECLK" port_resetb=" RESETB" port_bypass=" BYPASS" port_extfeedback=" EXTFEEDBACK" port_dynamicdelay=" DYNAMICDELAY" port_latchinputvalue=" LATCHINPUTVALUE" port_sclk=" SCLK" port_sdi=" SDI" port_sdo=" SDO" port_lock=" LOCK" port_plloutglobal=" PLLOUTGLOBAL" port_plloutcore=" PLLOUTCORE" param_feedback_path=" FEEDBACK_PATH" param_delay_adjustment_mode_feedback=" DELAY_ADJUSTMENT_MODE_FEEDBACK" param_fda_feedback=" FDA_FEEDBACK" param_delay_adjustment_mode_relative=" DELAY_ADJUSTMENT_MODE_RELATIVE" param_fda_relative=" FDA_RELATIVE" param_shiftreg_div_mode=" SHIFTREG_DIV_MODE" param_pllout_select=" PLLOUT_SELECT" param_divr=" DIVR" param_divf=" DIVF" param_divq=" DIVQ" param_filter_range=" FILTER_RANGE" param_external_divide_factor=" EXTERNAL_DIVIDE_FACTOR" param_enable_icegate=" ENABLE_ICEGATE" port_plloutglobala=" PLLOUTGLOBALA" port_plloutcorea=" PLLOUTCOREA" port_plloutglobalb=" PLLOUTGLOBALB" port_plloutcoreb=" PLLOUTCOREB" value_simple=" SIMPLE" value_fixed=" FIXED" value_dynamic=" DYNAMIC" value_genclk=" GENCLK" value_genclk_half=" GENCLK_HALF" value_shiftreg_0deg=" SHIFTREG_0deg" value_shiftreg_90deg=" SHIFTREG_90deg" index_0="[0]" index_1="[1]" index_2="[2]" index_3="[3]" index_4="[4]" index_5="[5]" index_6="[6]" index_7="[7]" index_8="[8]" index_9="[9]" index_10="[10]" index_11="[11]" index_12="[12]" index_13="[13]" index_14="[14]" index_15="[15]" digit_0="0" digit_0="1" punct_lb="[" punct_rb="]" punct_eq="=" punct_hash="#" punct_quote="\"" punct_dollar="$" blif_model=".model" blif_inputs=".inputs" blif_outputs=".outputs" blif_end=".end" blif_names=".names" blif_gate=".gate" blif_gate=".attr" blif_gate=".param" attr_src="src" var_c="c" var_clk="clk" var_f="f" var_t="t" arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/000077500000000000000000000000001327610534100220615ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/bram.blif000066400000000000000000000007661327610534100236510ustar00rootroot00000000000000.model top .inputs c w0 w1 w2 w3 a0 a1 a2 a3 .outputs r0 r1 r2 r3 .names t 1 .gate SB_RAM40_4K RADDR[0]=a0 RADDR[1]=a1 RADDR[2]=a2 RADDR[3]=a3 RADDR[4]=t RADDR[5]=t RADDR[6]=t RADDR[7]=t RCLK=c RCLKE=t RDATA[0]=r0 RDATA[1]=r1 RDATA[2]=r2 RDATA[3]=r3 RE=t WADDR[0]=a0 WADDR[1]=a1 WADDR[2]=a2 WADDR[3]=a3 WADDR[4]=t WADDR[5]=t WADDR[6]=t WADDR[7]=t WCLK=c WCLKE=t WDATA[0]=w0 WDATA[1]=w1 WDATA[2]=w2 WDATA[3]=w3 WE=t .attr src "bram.v:7" .param INIT_0 00111011101110111 .param READ_MODE 00000000000 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/carry.blif000066400000000000000000000005761327610534100240470ustar00rootroot00000000000000.model top .inputs a0 a1 b0 b1 .outputs o0 o1 o2 .names f .names t 1 .names $undef .gate SB_LUT4 I0=f I1=b0 I2=a0 I3=f O=o0 .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=f CO=a I0=b0 I1=a0 .gate SB_LUT4 I0=f I1=b1 I2=a1 I3=a O=o1 .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=a CO=b I0=b1 I1=a1 .gate SB_LUT4 I0=f I1=f I2=f I3=b O=o2 .param LUT_INIT 0110100110010110 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/empty.blif000066400000000000000000000000001327610534100240430ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/gb.blif000066400000000000000000000002421327610534100233050ustar00rootroot00000000000000.model test .inputs clk in .outputs out .gate SB_DFF C=gclk D=in Q=r .gate SB_GB GLOBAL_BUFFER_OUTPUT=gclk USER_SIGNAL_TO_GLOBAL_BUFFER=clk .names r out 1 1 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/gb_io.blif000066400000000000000000000011751327610534100240020ustar00rootroot00000000000000.model test .inputs ic .outputs oc o0 r1 r2 r3 .names f .names t 1 .gate SB_LUT4 I0=r0 I1=r1 I2=f I3=f O=d1 .param LUT_INIT 0110 .gate SB_LUT4 I0=f I1=t I2=r0 I3=f O=d0 .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=r0 CO=a I0=f I1=r1 .gate SB_LUT4 I0=f I1=f I2=r2 I3=a O=d2 .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=a CO=b I0=f I1=r2 .gate SB_LUT4 I0=f I1=f I2=r3 I3=b O=d3 .param LUT_INIT 0110100110010110 .gate SB_DFF C=c D=d0 Q=r0 .gate SB_DFF C=c D=d1 Q=r1 .gate SB_DFF C=c D=d2 Q=r2 .gate SB_DFF C=c D=d3 Q=r3 .gate SB_GB_IO D_IN_0=oc GLOBAL_BUFFER_OUTPUT=c PACKAGE_PIN=ic .param PIN_TYPE 000001 .names r0 o0 1 1 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/io.blif000066400000000000000000000001351327610534100233250ustar00rootroot00000000000000.model gate .inputs a .outputs t .gate SB_IO D_OUT_0=a PACKAGE_PIN=t .attr src "io.v:4" .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/pll.blif000066400000000000000000000004731327610534100235120ustar00rootroot00000000000000.model top .inputs dummy refclk .outputs clk D5 .names t 1 .gate SB_PLL40_CORE BYPASS=f PLLOUTCORE=clk REFERENCECLK=refclk RESETB=t .attr src "pll.v:3" .param DIVF 0000000 .param DIVQ 110 .param DIVR 0000 .param FEEDBACK_PATH "SIMPLE" .param FILTER_RANGE 001 .param PLLOUT_SELECT "GENCLK_HALF" .names t D5 1 1 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/rot.blif000066400000000000000000000011011327610534100235140ustar00rootroot00000000000000.model top .inputs clk .outputs D1 D2 D3 D4 D5 .names f .names t 1 .gate SB_LUT4 I0=D1 I1=D2 I2=f I3=f O=e .attr src "cells_map.v:43" .param LUT_INIT 0110 .gate SB_LUT4 I0=f I1=t I2=D1 I3=f O=d .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=D1 CO=a I0=f I1=D2 .gate SB_LUT4 I0=f I1=f I2=D3 I3=a O=g .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=a CO=b I0=f I1=D3 .gate SB_LUT4 I0=f I1=f I2=D4 I3=b O=h .param LUT_INIT 0110100110010110 .gate SB_DFF C=clk D=d Q=D1 .gate SB_DFF C=clk D=e Q=D2 .gate SB_DFF C=clk D=g Q=D3 .gate SB_DFF C=clk D=h Q=D4 .names t D5 1 1 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/blif/testcases/tri.blif000066400000000000000000000003241327610534100235140ustar00rootroot00000000000000.model test .inputs s1 s2 a1 a2 b .outputs y .names f .gate SB_LUT4 I0=s1 I1=s2 I2=f I3=f O=c .param LUT_INIT 1011 .gate SB_LUT4 I0=a1 I1=a2 I2=s2 I3=f O=d .param LUT_INIT 10101100 .gate $_TBUF_ A=d E=c Y=y .end arachne-pnr-0.1+20180513git5d830dd/fuzz/pcf/000077500000000000000000000000001327610534100177175ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/pcf/pcf.dict000066400000000000000000000003361327610534100213360ustar00rootroot00000000000000command_set_io="set_io" option_warn_no_port="--warn-no-port" pin_21="21" pin_98="98" pin_115="115" pin_7="7" pin_invalid="103" signal_D1="D1" signal_D2="D2" signal_D3="D3" signal_D4="D4" signal_D5="D5" signal_clk="clk" arachne-pnr-0.1+20180513git5d830dd/fuzz/pcf/rot.blif000066400000000000000000000033221327610534100213610ustar00rootroot00000000000000# Generated by Yosys 0.5+313 (git sha1 405cf67, clang 3.6.0-2ubuntu1~trusty1 -fPIC -Os) .model top .inputs clk .outputs D1 D2 D3 D4 D5 .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=D1 I1=D2 I2=$false I3=$false O=$0\rot[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=D1 I3=$false O=$0\rot[3:0][0] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=D1 CO=$auto$alumacc.cc:484:replace_alu$6[1] I0=$false I1=D2 .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[1] O=$0\rot[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=D3 .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[2] O=$0\rot[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\rot[3:0][0] Q=D1 .attr src "rot.v:6|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\rot[3:0][1] Q=D2 .attr src "rot.v:6|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\rot[3:0][2] Q=D3 .attr src "rot.v:6|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_DFF C=clk D=$0\rot[3:0][3] Q=D4 .attr src "rot.v:6|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .names $true D5 1 1 .names D1 rot[0] 1 1 .names D2 rot[1] 1 1 .names D3 rot[2] 1 1 .names D4 rot[3] 1 1 .end arachne-pnr-0.1+20180513git5d830dd/fuzz/pcf/testcases/000077500000000000000000000000001327610534100217155ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/pcf/testcases/empty.pcf000066400000000000000000000000001327610534100235330ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/fuzz/pcf/testcases/rot.pcf000066400000000000000000000001231327610534100232070ustar00rootroot00000000000000set_io D1 99 set_io --warn-no-port D2 98 set_io D3 97 set_io --warn-no-port clk 21 arachne-pnr-0.1+20180513git5d830dd/scripts/000077500000000000000000000000001327610534100176405ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/scripts/build-test-linux.sh000066400000000000000000000010401327610534100234000ustar00rootroot00000000000000#!/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.1+20180513git5d830dd/scripts/build-test-osx.sh000066400000000000000000000004001327610534100230510ustar00rootroot00000000000000#!/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.1+20180513git5d830dd/src/000077500000000000000000000000001327610534100167405ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/src/arachne-pnr.cc000066400000000000000000000441111327610534100214460ustar00rootroot00000000000000/* 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 "util.hh" #include #include #include #include #ifdef __EMSCRIPTEN__ #include #endif 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" << " 384 - Lattice Semiconductor iCE40LP384\n" << " 1k - Lattice Semiconductor iCE40LP/HX1K\n" << " 5k - Lattice Semiconductor iCE40UP5K\n" << " lm4k - Lattice Semiconductor iCE40LM4K\n" << " 8k - Lattice Semiconductor iCE40LP/HX8K\n" << " Default: 1k\n" << "\n" << " -c , --chipdb \n" << " Read chip database from .\n" #ifdef _WIN32 << " Default: +/chipdb-.bin\n" #else << " Default: +/share/arachne-pnr/chipdb-.bin\n" #endif << "\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: cm49 for 384, tq144 for 1k, ct256 for 8k\n" << "\n" << " -r\n" << " Randomize seed.\n" << "\n" << " -m , --max-passes \n" << " Maximum number of routing passes.\n" << " Default: 200\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" << "\n" << " -v, --version\n" << " Print version and exit.\n"; } struct null_ostream : public std::ostream { null_ostream() : std::ostream(0) {} }; int main(int argc, const char **argv) { #ifdef __EMSCRIPTEN__ EM_ASM( if (ENVIRONMENT_IS_NODE) { FS.mkdir('/hostcwd'); FS.mount(NODEFS, { root: '.' }, '/hostcwd'); FS.mkdir('/hostfs'); FS.mount(NODEFS, { root: '/' }, '/hostfs'); } ); #endif 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, *max_passes_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], "-m") || !strcmp(argv[i], "--max-passes")) { if (i + 1 >= argc) fatal(fmt(argv[i] << ": expected argument")); ++i; max_passes_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 if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { std::cout << version_str << "\n"; exit(EXIT_SUCCESS); } 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 != "384" && device != "1k" && device != "5k" && device != "lm4k" && device != "8k") fatal(fmt("unknown device: " << device)); std::string package_name; if (package_name_cp) package_name = package_name_cp; else if (device == "384") package_name = "cm49"; else if (device == "1k") package_name = "tq144"; else if (device == "5k") package_name = "sg48"; else if (device == "lm4k") package_name = "cm49"; 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; int max_passes = 0; if (max_passes_str) { std::string max_passes_s = max_passes_str; if (max_passes_s.empty()) fatal("invalid empty max-passes value"); for (char ch : max_passes_s) { if (ch >= '0' && ch <= '9') max_passes = max_passes * 10 + (unsigned)(ch - '0'); else fatal(fmt("invalid character `" << ch << "' in unsigned integer literal in max-passes value")); } } else max_passes = 200; 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 #if defined(_WIN32) && defined(MXE_DIR_STRUCTURE) chipdb_file_s = (std::string("+/chipdb-") + device + ".bin"); #else chipdb_file_s = (std::string("+/share/arachne-pnr/chipdb-") + device + ".bin"); #endif *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, std::ofstream::out | std::ofstream::binary); 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; #ifdef __AFL_HAVE_MANUAL_CONTROL __AFL_INIT(); #endif /* while (__AFL_LOOP(1000)) { */ 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))); fs << "# " << version_str << "\n"; 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))); fs << "/* " << version_str << " */\n"; d->write_verilog(fs); } *logs << "place_constraints...\n"; place_constraints(ds); #ifndef NDEBUG d->check(); #endif // d->dump(); *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))); fs << "# " << version_str << "\n"; 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))); fs << "# " << version_str << "\n"; d->write_blif(fs); } } // d->dump(); *logs << "route...\n"; route(ds, max_passes); #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.1+20180513git5d830dd/src/bitvector.hh000066400000000000000000000042701327610534100212650ustar00rootroot00000000000000/* 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.1+20180513git5d830dd/src/blif.cc000066400000000000000000000347671327610534100202040ustar00rootroot00000000000000/* 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 *io_od_model = d->find_model("SB_IO_OD"); Model *io_od_a_model = d->find_model("SB_IO_OD_A"); Model *top = nullptr; std::vector> unify; Instance *inst = nullptr; for (;;) { if (eof()) goto M; // parse current line into words read_line(); if (line.empty()) continue; // all directives begin with a dot if (line[0] == '.') { L: std::string cmd = words[0]; if (cmd == ".model") { if (words.size() != 2) fatal(fmt("invalid .model directive: expected exactly 1 argument, got " << words.size()-1)); if (top) fatal("definition of multiple models is not supported"); top = new Model(d, words[1]); d->set_top(top); } else if (cmd == ".inputs") { if (!top) fatal(".inputs directive outside of model definition"); 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") { if (!top) fatal(".outputs directive outside of model definition"); 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") { if (!top) fatal(".names directive outside of model definition"); LexicalPosition names_lp = lp; Net *names_net = nullptr; unsigned n = words.size(); // output is assigned no value; set to zero if (n == 2) { names_net = top->find_or_add_net(words[1]); names_net->set_is_constant(true); names_net->set_constant(Value::ZERO); } // output is assigned input; unify nets 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(fmt("invalid .names directive: expected 1 or 2 arguments, got " << n-1)); // parse PLA-style configuration bool saw11 = false; for (;;) { if (eof()) { if (n == 3 && !saw11) names_lp.fatal("invalid .names directive: unexpected end of file"); goto M; } read_line(); if (line.empty()) continue; if (line[0] == '.') { if (n == 3 && !saw11) names_lp.fatal("invalid .names directive: .names entry expected"); goto L; } if (words.size() != n - 1) fatal("invalid .names entry: number of gates does not match specified number of nets"); // .names + 1 argument 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: gate must be either 1 or 0"); } else { assert(n == 3); if (words[0] != "1" || words[1] != "1") fatal("invalid .names entry: both gates must be 1 here"); saw11 = true; } } } else if (cmd == ".gate") { if (!top) fatal(".gate directive outside of model definition"); 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(fmt("invalid .attr directive: expected exactly 2 arguments, got " << words.size()-1)); 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(fmt("invalid .param directive: expected exactly 2 arguments, got " << words.size()-1)); 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") { if (!top) fatal(".end directive outside of model definition"); goto M; } else fatal(fmt("unknown directive '" << cmd << "'")); } else fatal("expected directive"); } M: if (!top) fatal("no top model has been defined"); // 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); if (contains(replacement, n2)) fatal("conflicting .names outputs"); extend(replacement, n2, r); } for (const auto &p : replacement) { Net *n = p.first; top->remove_net(n); delete n; } // Replace SB_IO_ODs with inconsistent naming with SB_IO_OD_As with sensible // naming for internal use std::vector io_od_to_rep; for (auto od_i : top->instances()) { if(od_i->instance_of() == io_od_model) io_od_to_rep.push_back(od_i); } for (auto od_i : io_od_to_rep) { Instance *od_a_inst = top->add_instance(io_od_a_model); for (auto port : od_a_inst->ports()) { std::string sb_name; for (auto chr : port.first) if (chr != '_') sb_name += chr; od_a_inst->find_port(port.first)->connect(od_i->find_port(sb_name)->connection()); } for (auto param : od_i->params()) { od_a_inst->set_param(param.first, od_i->get_param(param.first)); } od_i->remove(); delete od_i; } Models models(d); std::map inout_redir; for (const auto &p : top->ports()) { if (p.second->is_bidir()) { Net *n = p.second->connection(); if (n) { bool has_input = false, has_output = false, has_tristate = false; for (const auto &q : n->connections()) { if (q == p.second) continue; if (q->is_input()) has_input = true; if (q->is_output()) has_output = true; if (isa(q->node()) && ((models.is_tbuf(cast(q->node())) && q->name() == "Y") || (models.is_ioX(cast(q->node())) && q->name() == "PACKAGE_PIN") || (models.is_pllX(cast(q->node())) && q->name() == "PACKAGEPIN") || (models.is_rgba_drv(cast(q->node())) && (q->name() == "RGB0" || q->name() == "RGB1" || q->name() == "RGB2")))) has_tristate = true; } // inout net has a tristate driver and used as an input, illegal if (has_input && has_tristate) fatal(fmt("toplevel inout port '" << p.second->name() << "' connected to tristate buffer and driving a net")); // inout net used as output else if (has_output && !has_tristate) inout_redir[p.second] = Direction::OUT; // inout net used as input else if (!has_output) inout_redir[p.second] = Direction::IN; // inout net unused else if (n->connections().size() == 1) inout_redir[p.second] = Direction::IN; } } } for (const auto &p : inout_redir) p.first->set_direction(p.second); 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.1+20180513git5d830dd/src/blif.hh000066400000000000000000000015541327610534100202020ustar00rootroot00000000000000/* 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.1+20180513git5d830dd/src/bstream.hh000066400000000000000000000175301327610534100207240ustar00rootroot00000000000000/* 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_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, unsigned long 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, unsigned long 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.1+20180513git5d830dd/src/carry.hh000066400000000000000000000015301327610534100204000ustar00rootroot00000000000000/* 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 Instance; class CarryChains { public: std::vector> chains; public: CarryChains() {} }; #endif arachne-pnr-0.1+20180513git5d830dd/src/casting.hh000066400000000000000000000024331327610534100207130ustar00rootroot00000000000000/* 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.1+20180513git5d830dd/src/chipdb.cc000066400000000000000000000702031327610534100205020ustar00rootroot00000000000000/* 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 "util.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::DSP0: return "dsp0_tile"; case TileType::DSP1: return "dsp1_tile"; case TileType::DSP2: return "dsp2_tile"; case TileType::DSP3: return "dsp3_tile"; case TileType::IPCON: return "ipcon_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; case TileType::DSP0: s << ".dsp0_tile " << i << " " << j << "\n"; break; case TileType::DSP1: s << ".dsp1_tile " << i << " " << j << "\n"; break; case TileType::DSP2: s << ".dsp2_tile " << i << " " << j << "\n"; break; case TileType::DSP3: s << ".dsp3_tile " << i << " " << j << "\n"; break; case TileType::IPCON: s << ".ipcon_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); } } 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; for (int p = 0; p < 2; ++p) chipdb->add_cell(CellType::IO, Location(t, p)); } 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 if (cmd == ".ramt_tile") { chipdb->tile_type[t] = TileType::RAMT; chipdb->add_cell(CellType::RAM, Location(t, 0)); } else if (cmd == ".dsp0_tile") //could add a cell here, but do it using extra_cell because the CBITs differ depending on //location, and extra_cell is a better way of specifying this chipdb->tile_type[t] = TileType::DSP0; else if (cmd == ".dsp1_tile") chipdb->tile_type[t] = TileType::DSP1; else if (cmd == ".dsp2_tile") chipdb->tile_type[t] = TileType::DSP2; else if (cmd == ".dsp3_tile") chipdb->tile_type[t] = TileType::DSP3; else { assert(cmd == ".ipcon_tile"); chipdb->tile_type[t] = TileType::IPCON; } // 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 if (cmd == ".ramt_tile_bits") ty = TileType::RAMT; else if (cmd == ".dsp0_tile_bits") ty = TileType::DSP0; else if (cmd == ".dsp1_tile_bits") ty = TileType::DSP1; else if (cmd == ".dsp2_tile_bits") ty = TileType::DSP2; else if (cmd == ".dsp3_tile_bits") ty = TileType::DSP3; else { assert(cmd == ".ipcon_tile_bits"); ty = TileType::IPCON; } 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[(words.size() >= 5) ? 4 : 3]; int x = std::stoi(words[1]), y = std::stoi(words[2]); int z = 0; if(words.size() >= 5) z = std::stoi(words[3]); 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 if (cell_type == "MAC16") c = chipdb->add_cell(CellType::MAC16, Location(t, z)); else if (cell_type == "SPRAM") c = chipdb->add_cell(CellType::SPRAM, Location(t, z)); else if (cell_type == "LFOSC") c = chipdb->add_cell(CellType::LFOSC, Location(t, z)); else if (cell_type == "HFOSC") c = chipdb->add_cell(CellType::HFOSC, Location(t, z)); else if (cell_type == "RGBA_DRV") c = chipdb->add_cell(CellType::RGBA_DRV, Location(t, z)); else if (cell_type == "LEDDA_IP") c = chipdb->add_cell(CellType::LEDDA_IP, Location(t, z)); else if (cell_type == "I2C") c = chipdb->add_cell(CellType::I2C_IP, Location(t, z)); else if (cell_type == "SPI") c = chipdb->add_cell(CellType::SPI_IP, Location(t, z)); else if (cell_type == "IO_I3C") c = chipdb->add_cell(CellType::IO_I3C, Location(t, z)); else fatal(fmt("unknown extra cell type `" << cell_type << "'")); std::map> mfvs; std::set locked_pkgs; for (;;) { read_line(); if (eof() || line[0] == '.') { extend(chipdb->cell_mfvs, c, mfvs); extend(chipdb->cell_locked_pkgs, c, locked_pkgs); return; } if (words.size() > 0 && words[0] == "LOCKED") { for (size_t i = 1; i < words.size(); i++) extend(locked_pkgs, words[i]); continue; } 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" || cmd == ".dsp0_tile" || cmd == ".dsp1_tile" || cmd == ".dsp2_tile" || cmd == ".dsp3_tile" || cmd == ".ipcon_tile") parse_cmd_tile(); else if (cmd == ".io_tile_bits" || cmd == ".logic_tile_bits" || cmd == ".ramb_tile_bits" || cmd == ".ramt_tile_bits" || cmd == ".dsp0_tile_bits" || cmd == ".dsp1_tile_bits" || cmd == ".dsp2_tile_bits" || cmd == ".dsp3_tile_bits" || cmd == ".ipcon_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; case TileType::DSP0: tile_pos_cell[i].resize(1, 0); break; case TileType::IPCON: 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 << std::string(version_str) << 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_locked_pkgs << 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; std::string dbversion; ibs >> dbversion; if(dbversion != version_str) { fatal(fmt("chipdb and arachne-pnr versions do not match (chipdb: " << dbversion << ", arachne-pnr: " << version_str << ")")); } 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_locked_pkgs >> 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, std::ifstream::in | std::ifstream::binary); 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"; case CellType::MAC16: return "MAC16"; case CellType::SPRAM: return "SPRAM"; case CellType::LFOSC: return "LFOSC"; case CellType::HFOSC: return "HFOSC"; case CellType::RGBA_DRV: return "RGBA_DRV"; case CellType::LEDDA_IP: return "LEDDA_IP"; case CellType::I2C_IP: return "I2C"; case CellType::SPI_IP: return "SPI"; case CellType::IO_I3C: return "IO_I3C"; default: abort(); } } CBit ChipDB::extra_cell_cbit(int c, const std::string &name, bool is_ip) const { const auto &p = cell_mfvs.at(c).at(name); std::string prefix = "PLL."; if((tile_type[p.first] == TileType::DSP0) || (tile_type[p.first] == TileType::DSP1) || (tile_type[p.first] == TileType::DSP2) || (tile_type[p.first] == TileType::DSP3) || (tile_type[p.first] == TileType::IPCON) || is_ip) prefix = "IpConfig."; const auto &cbits = tile_nonrouting_cbits.at(tile_type[p.first]).at(prefix + p.second); assert(cbits.size() == 1); const CBit &cbit0 = cbits[0]; return cbit0.with_tile(p.first); } std::string ChipDB::extra_cell_netname(int c, const std::string &name) const { const auto &p = cell_mfvs.at(c).at(name); return p.second; } int ChipDB::get_oscillator_glb(int cell, const std::string &net) const { std::string netname = extra_cell_netname(cell, net); const std::string prefix = "glb_netwk_"; assert(netname.substr(0, prefix.length()) == prefix); int driven_glb = std::stoi(netname.substr(prefix.length())); return driven_glb; } arachne-pnr-0.1+20180513git5d830dd/src/chipdb.hh000066400000000000000000000162571327610534100205250ustar00rootroot00000000000000/* 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 "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) {} }; obstream &operator<<(obstream &obs, const Switch &sw); ibstream &operator>>(ibstream &ibs, Switch &sw); enum class TileType : int { EMPTY, IO, LOGIC, RAMB, RAMT, DSP0, DSP1, DSP2, DSP3, IPCON }; enum class CellType : int { LOGIC, IO, GB, RAM, WARMBOOT, PLL, MAC16, SPRAM, LFOSC, HFOSC, RGBA_DRV, LEDDA_IP, I2C_IP, SPI_IP, IO_I3C }; 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::IO_I3C) + 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)); } }; } 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, bool is_ip = false) const; std::string extra_cell_netname(int ec, const std::string &name) const; int get_oscillator_glb(int cell, const std::string &net) const; int n_cells; BasedVector cell_type; BasedVector cell_location; std::map>> cell_mfvs; std::map> cell_locked_pkgs; 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); }; ChipDB *read_chipdb(const std::string &filename); #endif arachne-pnr-0.1+20180513git5d830dd/src/configuration.cc000066400000000000000000000075101327610534100221210ustar00rootroot00000000000000/* 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 "configuration.hh" #include "chipdb.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 << ".comment " << version_str << "\n"; 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.1+20180513git5d830dd/src/configuration.hh000066400000000000000000000025631327610534100221360ustar00rootroot00000000000000/* 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 "chipdb.hh" #include 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.1+20180513git5d830dd/src/constant.cc000066400000000000000000000100151327610534100210750ustar00rootroot00000000000000/* 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 "constant.hh" #include "netlist.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.1+20180513git5d830dd/src/constant.hh000066400000000000000000000014441327610534100211150ustar00rootroot00000000000000/* 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; void realize_constants(const ChipDB *chipdb, Design *d); #endif arachne-pnr-0.1+20180513git5d830dd/src/designstate.cc000066400000000000000000000036731327610534100215720ustar00rootroot00000000000000/* 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 "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.1+20180513git5d830dd/src/designstate.hh000066400000000000000000000025671327610534100216050ustar00rootroot00000000000000/* 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_DESIGNSTATE_HH #define PNR_DESIGNSTATE_HH #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; }; #endif arachne-pnr-0.1+20180513git5d830dd/src/global.cc000066400000000000000000000353471327610534100205230ustar00rootroot00000000000000/* 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_CLK" || conn->name() == "OUTPUT_CLK") return gc_clk; } else if (models.is_gb(inst) || models.is_warmboot(inst) || models.is_pllX(inst)) ; else if(models.is_mac16(inst)) { if(conn->name() == "CLK") return gc_clk; if(conn->name() == "CE") return gc_cen; if(conn->name() == "IRSTTOP" || conn->name() == "IRSTBOT" || conn->name() == "ORSTTOP" || conn->name() == "ORSTBOT") return gc_sr; } else if(models.is_hfosc(inst)) ; else if(models.is_lfosc(inst)) ; else if(models.is_spram(inst)) { if(conn->name() == "CLOCK") return gc_clk; } else if(models.is_rgba_drv(inst)) ; else if(models.is_i2c(inst) || models.is_spi(inst)) { if(conn->name() == "SBCLKI") return gc_clk; } else if(models.is_ledda_ip(inst)) { if(conn->name() == "LEDDCLK") return gc_clk; } 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 gc, Port *p) { return (bool)((port_gc(p, true) & gc) == gc); } 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)); extend(ds.placement, pass_inst, pass_cell); } void Promoter::make_routable(Net *n, int gc) { Net *internal = nullptr; for (auto i = n->connections().begin(); i != n->connections().end();) { Port *p = *i; ++i; if (!p->is_input()) continue; if (routable(gc, 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()) { auto loc = chipdb->cell_location[c]; if (chipdb->loc_pin_glb_num.find(loc) == chipdb->loc_pin_glb_num.end()) fatal(fmt("Not able to use pin " << ds.package.loc_pin.at(loc) << " for global buffer output")); int g = chipdb->loc_pin_glb_num.at(loc); for (uint8_t gc : global_classes) { if (gc & (1 << g)) ++gc_used[gc]; } make_routable(out->connection(), 1 << g); } } else if (models.is_hfosc(inst)) { Port *out = inst->find_port("CLKHF"); if (out->connected() && !inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { int driven_glb = chipdb->get_oscillator_glb(c, "CLKHF"); for (uint8_t gc : global_classes) { if (gc & (1 << driven_glb)) ++gc_used[gc]; } make_routable(out->connection(), 1 << driven_glb); } } else if (models.is_lfosc(inst)) { Port *out = inst->find_port("CLKLF"); if (out->connected() && !inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { int driven_glb = chipdb->get_oscillator_glb(c, "CLKLF"); for (uint8_t gc : global_classes) { if (gc & (1 << driven_glb)) ++gc_used[gc]; } make_routable(out->connection(), 1 << driven_glb); } } 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(), 1 << 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(), 1 << 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")) || (models.is_hfosc(cast(driver->node())) && driver->name() == "CLKHF" && !cast(driver->node())->is_attr_set("ROUTE_THROUGH_FABRIC")) || (models.is_lfosc(cast(driver->node())) && driver->name() == "CLKLF" && !cast(driver->node())->is_attr_set("ROUTE_THROUGH_FABRIC")))) { 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) || models.is_hfosc(gb_inst) || models.is_lfosc(gb_inst)) { if (driver->connected()) make_routable(driver->connection(), gc); 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.1+20180513git5d830dd/src/global.hh000066400000000000000000000022461327610534100205250ustar00rootroot00000000000000/* 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; 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; 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.1+20180513git5d830dd/src/hashmap.hh000066400000000000000000000113501327610534100207020ustar00rootroot00000000000000/* 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_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.1+20180513git5d830dd/src/hashset.hh000066400000000000000000000100371327610534100207210ustar00rootroot00000000000000/* 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_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.1+20180513git5d830dd/src/io.cc000066400000000000000000000141131327610534100176560ustar00rootroot00000000000000/* 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 "io.hh" #include "netlist.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_"); // Validate all $_TBUF_ outputs for (Instance *inst : top->instances()) { if (!models.is_tbuf(inst)) continue; // Look for the $_TBUF_ output (Y) Port *p = inst->find_port("Y"); Net *n = p->connection(); if (!n) fatal("Unconnected $_TBUF_ output"); // Its output must be connected to only one output port // Additionally it could be connected to one or more inputs if the port is inout unsigned found = 0; for (Port *j : n->connections()) { if (j != p && isa(j->node()) && (j->direction() == Direction::OUT || j->direction() == Direction::INOUT)) found++; } if (!found) fatal("$_TBUF_ gate must drive top-level output or inout port"); if (found != 1) fatal("$_TBUF_ gate must drive only one top-level output or inout port"); } // Replace top-level ports using SB_IOs 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") || (models.is_rgba_drv(cast(q->node())) && (q->name() == "RGB0" || q->name() == "RGB1" || q->name() == "RGB2") ))) { // Already connected to an SB_IO or a PLL continue; } // Now we need a net to connect the top-level port to the SB_IO output. // The name of this net will be the name of the top-level port. // If the net currently used (to connect $_TBUF_'s Y output to the top-level port) // is already using this name, we rename the net to NAME$n (n is a number to avoid // collisions). #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()); } // Connect the new net to the top-level port (disconnecting it from $_TBUF_) Net *t = top->add_net(p->name()); assert(t); p->connect(t); assert(!matched || t->name() == p->name()); // Now we create an SB_IO ... Instance *io_inst = top->add_instance(io_model); // and connect its PACKAGE_PIN output to the new net io_inst->find_port("PACKAGE_PIN")->connect(t); // The rest of the connection depends on the top-level port direction 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 the top-level port is connected to more than one internal port // the connection_other_port will return NULL and we must figure out // what's the $_TBUF_ output (Y) if (!q && n && n->connections().size() > 1) { for (auto j : n->connections()) { if (j != p && j->name() == "Y" && isa(j->node()) && cast(j->node())->instance_of() == tbuf_model) { q = j; // $_TBUF_'s Y output break; } } } // Analyze the internal port connected to this top-level port if (q && isa(q->node()) && cast(q->node())->instance_of() == tbuf_model && q->name() == "Y") { // Connected to a $_TBUF_'s Y output Instance *tbuf = cast(q->node()); // Connect the $_TBUF_ nets to the SB_IO port 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 // Remove the $_TBUF_ tbuf->find_port("A")->disconnect(); tbuf->find_port("E")->disconnect(); tbuf->find_port("Y")->disconnect(); tbuf->remove(); delete tbuf; } else { // This top-level port is an output, not connected to a $_TBUF_ 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.1+20180513git5d830dd/src/io.hh000066400000000000000000000013611327610534100176710ustar00rootroot00000000000000/* 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; void instantiate_io(Design *d); #endif arachne-pnr-0.1+20180513git5d830dd/src/line_parser.cc000066400000000000000000000051771327610534100215640ustar00rootroot00000000000000/* 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 "line_parser.hh" #include "util.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.1+20180513git5d830dd/src/line_parser.hh000066400000000000000000000033421327610534100215660ustar00rootroot00000000000000/* 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.1+20180513git5d830dd/src/location.cc000066400000000000000000000014371327610534100210640ustar00rootroot00000000000000/* 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.1+20180513git5d830dd/src/location.hh000066400000000000000000000041701327610534100210730ustar00rootroot00000000000000/* 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 "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.1+20180513git5d830dd/src/netlist.cc000066400000000000000000001400561327610534100207370ustar00rootroot00000000000000/* 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 "util.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) { if (contains(d->m_models, n)) { std::ostringstream s; s << "model name \"" << n << "\" conflicts with another defined model"; fatal(s.str()); } 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_tbuf(cast(q->node())) && q->name() == "Y") || (models.is_ioX(cast(q->node())) && q->name() == "PACKAGE_PIN") || (models.is_pllX(cast(q->node())) && q->name() == "PACKAGEPIN") || (models.is_rgba_drv(cast(q->node())) && (q->name() == "RGB0" || q->name() == "RGB1" || q->name() == "RGB2") ))) 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_tbuf(cast(q->node())) && q->name() == "Y") || (models.is_ioX(cast(q->node())) && q->name() == "PACKAGE_PIN") || (models.is_pllX(cast(q->node())) && q->name() == "PACKAGEPIN") || (models.is_rgba_drv(cast(q->node())) && (q->name() == "RGB0" || q->name() == "RGB1" || q->name() == "RGB2")))); } } } 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("LO", Direction::OUT); 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 *io_i3c = new Model(this, "SB_IO_I3C"); io_i3c->add_port("PACKAGE_PIN", Direction::INOUT); io_i3c->add_port("LATCH_INPUT_VALUE", Direction::IN, Value::ZERO); io_i3c->add_port("CLOCK_ENABLE", Direction::IN, Value::ONE); io_i3c->add_port("INPUT_CLK", Direction::IN, Value::ZERO); io_i3c->add_port("OUTPUT_CLK", Direction::IN, Value::ZERO); io_i3c->add_port("OUTPUT_ENABLE", Direction::IN, Value::ZERO); io_i3c->add_port("D_OUT_0", Direction::IN, Value::ZERO); io_i3c->add_port("D_OUT_1", Direction::IN, Value::ZERO); io_i3c->add_port("D_IN_0", Direction::OUT, Value::ZERO); io_i3c->add_port("D_IN_1", Direction::OUT, Value::ZERO); io_i3c->add_port("PU_ENB", Direction::IN, Value::ZERO); io_i3c->add_port("WEAK_PU_ENB", Direction::IN, Value::ZERO); io_i3c->set_param("PIN_TYPE", BitVector(6, 0)); // 000000 io_i3c->set_param("PULLUP", BitVector(1, 0)); // default NO pullup io_i3c->set_param("WEAK_PULLUP", BitVector(1, 0)); // default NO pullup io_i3c->set_param("NEG_TRIGGER", BitVector(1, 0)); io_i3c->set_param("IO_STANDARD", "SB_LVCMOS"); // The official SB_IO_OD, with inconsistent net naming Model *io_od = new Model(this, "SB_IO_OD"); io_od->add_port("PACKAGEPIN", Direction::INOUT); io_od->add_port("LATCHINPUTVALUE", Direction::IN, Value::ZERO); io_od->add_port("CLOCKENABLE", Direction::IN, Value::ONE); io_od->add_port("INPUTCLK", Direction::IN, Value::ZERO); io_od->add_port("OUTPUTCLK", Direction::IN, Value::ZERO); io_od->add_port("OUTPUTENABLE", Direction::IN, Value::ZERO); io_od->add_port("DOUT0", Direction::IN, Value::ZERO); io_od->add_port("DOUT1", Direction::IN, Value::ZERO); io_od->add_port("DIN0", Direction::OUT, Value::ZERO); io_od->add_port("DIN1", Direction::OUT, Value::ZERO); io_od->set_param("PIN_TYPE", BitVector(6, 0)); // 000000 io_od->set_param("PULLUP", BitVector(1, 0)); // default NO pullup io_od->set_param("NEG_TRIGGER", BitVector(1, 0)); io_od->set_param("IO_STANDARD", "SB_LVCMOS"); // As above, but with normalised net naming to minimise code changes throughout // arachne Model *io_od_a = new Model(this, "SB_IO_OD_A"); io_od_a->add_port("PACKAGE_PIN", Direction::INOUT); io_od_a->add_port("LATCH_INPUT_VALUE", Direction::IN, Value::ZERO); io_od_a->add_port("CLOCK_ENABLE", Direction::IN, Value::ONE); io_od_a->add_port("INPUT_CLK", Direction::IN, Value::ZERO); io_od_a->add_port("OUTPUT_CLK", Direction::IN, Value::ZERO); io_od_a->add_port("OUTPUT_ENABLE", Direction::IN, Value::ZERO); io_od_a->add_port("D_OUT_0", Direction::IN, Value::ZERO); io_od_a->add_port("D_OUT_1", Direction::IN, Value::ZERO); io_od_a->add_port("D_IN_0", Direction::OUT, Value::ZERO); io_od_a->add_port("D_IN_1", Direction::OUT, Value::ZERO); io_od_a->set_param("PIN_TYPE", BitVector(6, 0)); // 000000 io_od_a->set_param("PULLUP", BitVector(1, 0)); // default NO pullup io_od_a->set_param("NEG_TRIGGER", BitVector(1, 0)); io_od_a->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 *mac16 = new Model(this, "SB_MAC16"); mac16->add_port("CLK", Direction::IN); mac16->add_port("CE", Direction::IN, Value::ONE); for(int i = 0; i < 16; i++) { mac16->add_port("C[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); mac16->add_port("A[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); mac16->add_port("B[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); mac16->add_port("D[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); } mac16->add_port("AHOLD", Direction::IN, Value::ZERO); mac16->add_port("BHOLD", Direction::IN, Value::ZERO); mac16->add_port("CHOLD", Direction::IN, Value::ZERO); mac16->add_port("DHOLD", Direction::IN, Value::ZERO); mac16->add_port("IRSTTOP", Direction::IN, Value::ZERO); mac16->add_port("IRSTBOT", Direction::IN, Value::ZERO); mac16->add_port("ORSTTOP", Direction::IN, Value::ZERO); mac16->add_port("ORSTBOT", Direction::IN, Value::ZERO); mac16->add_port("OLOADTOP", Direction::IN, Value::ZERO); mac16->add_port("OLOADBOT", Direction::IN, Value::ZERO); mac16->add_port("ADDSUBTOP", Direction::IN, Value::ZERO); mac16->add_port("ADDSUBBOT", Direction::IN, Value::ZERO); mac16->add_port("OHOLDTOP", Direction::IN, Value::ZERO); mac16->add_port("OHOLDBOT", Direction::IN, Value::ZERO); mac16->add_port("CI", Direction::IN, Value::ZERO); mac16->add_port("ACCUMCI", Direction::IN, Value::ZERO); mac16->add_port("SIGNEXTIN", Direction::IN, Value::ZERO); for(int i = 0; i < 32; i++) mac16->add_port("O[" + std::to_string(i) + "]", Direction::OUT); mac16->add_port("CO", Direction::OUT); mac16->add_port("ACCUMCO", Direction::OUT); mac16->add_port("SIGNEXTOUT", Direction::OUT); const std::vector > mac16_params = {{"C_REG", 1}, {"A_REG", 1}, {"B_REG", 1}, {"D_REG", 1}, {"TOP_8x8_MULT_REG", 1}, {"BOT_8x8_MULT_REG", 1}, {"PIPELINE_16x16_MULT_REG1", 1}, {"PIPELINE_16x16_MULT_REG2", 1}, {"TOPOUTPUT_SELECT", 2}, {"TOPADDSUB_LOWERINPUT", 2}, {"TOPADDSUB_UPPERINPUT", 1}, {"TOPADDSUB_CARRYSELECT", 2}, {"BOTOUTPUT_SELECT", 2}, {"BOTADDSUB_LOWERINPUT", 2}, {"BOTADDSUB_UPPERINPUT", 1}, {"BOTADDSUB_CARRYSELECT", 2}, {"MODE_8x8", 1}, {"A_SIGNED", 1}, {"B_SIGNED", 1}}; for(auto p : mac16_params) mac16->set_param(p.first, BitVector(p.second, 0)); Model *hfosc = new Model(this, "SB_HFOSC"); hfosc->add_port("CLKHFPU", Direction::IN, Value::ZERO); hfosc->add_port("CLKHFEN", Direction::IN, Value::ZERO); hfosc->add_port("CLKHF", Direction::OUT); hfosc->set_param("CLKHF_DIV", "0b00"); Model *hfosc_trim = new Model(this, "SB_HFOSC_TRIM"); hfosc_trim->add_port("CLKHFPU", Direction::IN, Value::ZERO); hfosc_trim->add_port("CLKHFEN", Direction::IN, Value::ZERO); for(int i = 0; i < 10; i++) hfosc_trim->add_port("TRIM" + std::to_string(i), Direction::IN, Value::ZERO); hfosc_trim->add_port("CLKHF", Direction::OUT); hfosc_trim->set_param("CLKHF_DIV", "0b00"); Model *lfosc = new Model(this, "SB_LFOSC"); lfosc->add_port("CLKLFPU", Direction::IN, Value::ZERO); lfosc->add_port("CLKLFEN", Direction::IN, Value::ZERO); lfosc->add_port("CLKLF", Direction::OUT); Model *spram = new Model(this, "SB_SPRAM256KA"); for(int i = 0; i < 14; i++) spram->add_port("ADDRESS[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); for(int i = 0; i < 16; i++) spram->add_port("DATAIN[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); for(int i = 0; i < 4; i++) spram->add_port("MASKWREN[" + std::to_string(i) + "]", Direction::IN, Value::ZERO); spram->add_port("WREN", Direction::IN, Value::ZERO); spram->add_port("CHIPSELECT", Direction::IN, Value::ZERO); spram->add_port("CLOCK", Direction::IN); spram->add_port("STANDBY", Direction::IN, Value::ZERO); spram->add_port("SLEEP", Direction::IN, Value::ZERO); spram->add_port("POWEROFF", Direction::IN, Value::ZERO); for(int i = 0; i < 16; i++) spram->add_port("DATAOUT[" + std::to_string(i) + "]", Direction::OUT); Model *rgba_drv = new Model(this, "SB_RGBA_DRV"); rgba_drv->add_port("CURREN", Direction::IN, Value::ZERO); rgba_drv->add_port("RGBLEDEN", Direction::IN, Value::ZERO); rgba_drv->add_port("RGB0PWM", Direction::IN, Value::ZERO); rgba_drv->add_port("RGB1PWM", Direction::IN, Value::ZERO); rgba_drv->add_port("RGB2PWM", Direction::IN, Value::ZERO); rgba_drv->add_port("RGB0", Direction::OUT); rgba_drv->add_port("RGB1", Direction::OUT); rgba_drv->add_port("RGB2", Direction::OUT); rgba_drv->set_param("CURRENT_MODE", "0b0"); rgba_drv->set_param("RGB0_CURRENT", "0b000000"); rgba_drv->set_param("RGB1_CURRENT", "0b000000"); rgba_drv->set_param("RGB2_CURRENT", "0b000000"); Model *i2c = new Model(this, "SB_I2C"); i2c->add_port("SBCLKI", Direction::IN); i2c->add_port("SBRWI", Direction::IN, Value::ZERO); i2c->add_port("SBSTBI", Direction::IN, Value::ZERO); for(int i = 0; i < 8; i++) i2c->add_port("SBADRI" + std::to_string(i), Direction::IN, Value::ZERO); for(int i = 0; i < 8; i++) i2c->add_port("SBDATI" + std::to_string(i), Direction::IN, Value::ZERO); for(int i = 0; i < 8; i++) i2c->add_port("SBDATO" + std::to_string(i), Direction::OUT); i2c->add_port("SBACKO", Direction::OUT); i2c->add_port("I2CIRQ", Direction::OUT); i2c->add_port("I2CWKUP", Direction::OUT); i2c->add_port("SCLI", Direction::IN); i2c->add_port("SCLO", Direction::OUT); i2c->add_port("SCLOE", Direction::OUT); i2c->add_port("SDAI", Direction::IN); i2c->add_port("SDAO", Direction::OUT); i2c->add_port("SDAOE", Direction::OUT); //Default to upper left? i2c->set_param("BUS_ADDR74", "0b0001"); i2c->set_param("0b1111100001", "0b1111100001"); Model *spi = new Model(this, "SB_SPI"); spi->add_port("SBCLKI", Direction::IN); spi->add_port("SBRWI", Direction::IN, Value::ZERO); spi->add_port("SBSTBI", Direction::IN, Value::ZERO); for(int i = 0; i < 8; i++) spi->add_port("SBADRI" + std::to_string(i), Direction::IN, Value::ZERO); for(int i = 0; i < 8; i++) spi->add_port("SBDATI" + std::to_string(i), Direction::IN, Value::ZERO); for(int i = 0; i < 8; i++) spi->add_port("SBDATO" + std::to_string(i), Direction::OUT); spi->add_port("SBACKO", Direction::OUT); spi->add_port("SPIIRQ", Direction::OUT); spi->add_port("SPIWKUP", Direction::OUT); spi->add_port("MI", Direction::IN); spi->add_port("SO", Direction::OUT); spi->add_port("SOE", Direction::OUT); spi->add_port("SI", Direction::IN); spi->add_port("MO", Direction::OUT); spi->add_port("MOE", Direction::OUT); spi->add_port("SCKI", Direction::IN); spi->add_port("SCKO", Direction::OUT); spi->add_port("SCKOE", Direction::OUT); spi->add_port("SCSNI", Direction::IN); for(int i = 0; i < 4; i++) spi->add_port("MCSNO" + std::to_string(i), Direction::OUT); for(int i = 0; i < 4; i++) spi->add_port("MCSNOE" + std::to_string(i), Direction::OUT); spi->set_param("BUS_ADDR74", "0b0000"); Model *ledda = new Model(this, "SB_LEDDA_IP"); ledda->add_port("LEDDCS", Direction::IN, Value::ZERO); ledda->add_port("LEDDCLK", Direction::IN); for(int i = 7; i >= 0; i--) ledda->add_port("LEDDDAT" + std::to_string(i), Direction::IN, Value::ZERO); for(int i = 3; i >= 0; i--) ledda->add_port("LEDDADDR" + std::to_string(i), Direction::IN, Value::ZERO); ledda->add_port("LEDDDEN", Direction::IN, Value::ZERO); ledda->add_port("LEDDEXE", Direction::IN, Value::ZERO); ledda->add_port("LEDDRST", Direction::IN, Value::ZERO); //doesn't actually exist, for icecube code compatibility only ledda->add_port("PWMOUT0", Direction::OUT); ledda->add_port("PWMOUT1", Direction::OUT); ledda->add_port("PWMOUT2", Direction::OUT); ledda->add_port("LEDDON", 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"); io_i3c = d->find_model("SB_IO_I3C"); io_od = d->find_model("SB_IO_OD_A"); 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.1+20180513git5d830dd/src/netlist.hh000066400000000000000000000316241327610534100207510ustar00rootroot00000000000000/* 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 "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: template bool operator()(const T *lhs, const T *rhs) const { return static_cast(lhs)->id < static_cast(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, }; 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); } // Return true if an attr exists and is set to 1, defval otherwise // (for binary attributes like ROUTE_THROUGH_FABRIC) bool is_attr_set(const std::string &an, bool defval = false) const { if(!has_attr(an)) return defval; else return get_attr(an).get_bit(0); } 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, *io_i3c, *io_od; 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_io_i3c(const Instance *inst) const { return inst->instance_of() == io_i3c; } bool is_io_od(const Instance *inst) const { return inst->instance_of() == io_od; } bool is_ioX(const Instance *inst) const { return inst->instance_of() == io || inst->instance_of() == gb_io || inst->instance_of() == io_i3c || inst->instance_of() == io_od; } 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()); } bool is_mac16(const Instance *inst) const {return inst->instance_of()->name() == "SB_MAC16";} bool is_spram(const Instance *inst) const {return inst->instance_of()->name() == "SB_SPRAM256KA";} bool is_hfosc(const Instance *inst) const {return inst->instance_of()->name() == "SB_HFOSC" || inst->instance_of()->name() == "SB_HFOSC_TRIM";} bool is_hfosc_trim(const Instance *inst) const {return inst->instance_of()->name() == "SB_HFOSC_TRIM";} bool is_lfosc(const Instance *inst) const {return inst->instance_of()->name() == "SB_LFOSC";} bool is_rgba_drv(const Instance *inst) const {return inst->instance_of()->name() == "SB_RGBA_DRV";} bool is_ledda_ip(const Instance *inst) const {return inst->instance_of()->name() == "SB_LEDDA_IP";} bool is_i2c(const Instance *inst) const {return inst->instance_of()->name() == "SB_I2C";} bool is_spi(const Instance *inst) const {return inst->instance_of()->name() == "SB_SPI";} }; #endif arachne-pnr-0.1+20180513git5d830dd/src/pack.cc000066400000000000000000000551551327610534100202000ustar00rootroot00000000000000/* 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(); void optimize_luts(); int count_extra_cells(CellType ct); 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::optimize_luts() { const auto &instances = top->instances(); for (auto i = instances.begin(); i != instances.end(); ++i) { Instance *lut_inst = *i; if (models.is_lut4(lut_inst)) { if (!lut_inst->self_has_param("LUT_INIT")) continue; Const lut_init = lut_inst->self_get_param("LUT_INIT"); BitVector lut_bits = lut_init.as_bits(); if (lut_bits.size() != 16) continue; std::vector ports; ports.push_back(lut_inst->find_port("I0")); ports.push_back(lut_inst->find_port("I1")); ports.push_back(lut_inst->find_port("I2")); ports.push_back(lut_inst->find_port("I3")); int bit_nr = 0; for(Port *pi: ports) { if (pi && pi->connection() && pi->connection()->is_constant() && pi->connection()->constant() == Value::ONE) { for(int lut_entry=0; lut_entry<16; ++lut_entry) if (lut_entry & (1<connect(const0); } ++bit_nr; } lut_inst->set_param("LUT_INIT", lut_bits); } } } 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(); /* FIXME if two connections (CO -> CI), could return a LUT that matches I1/I2 */ 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; } } } } c->remove(); delete c; if (!next_c && out_conn) { assert(chain.size() < max_chain_length); Port *p = chain.back()->find_port("COUT"); assert(p && p->connection() == out_conn); Instance *lc2_inst = nullptr; // COUT might drive a LC I3 if (out_conn->connections().size() == 2) { Port *consumer = p->connection_other_port(); if (consumer->name() == "I3" && isa(consumer->node())) { Instance *inst = cast(consumer->node()); if (models.is_lc(inst)) lc2_inst = inst; } } bool break_chain = false; if (lc2_inst) { Net *clk = lc2_inst->find_port("CLK")->connection(), *cen = lc2_inst->find_port("CEN")->connection(), *sr = lc2_inst->find_port("SR")->connection(); if ((global_clk && global_clk != clk) || (global_cen && global_cen != cen) || (global_sr && global_sr != sr)) { break_chain = true; } if (!global_clk) global_clk = clk; if (!global_cen) global_cen = cen; if (!global_sr) global_sr = sr; } if (!lc2_inst) { lc2_inst = top->add_instance(models.lc); carry_pass_through_lc(lc2_inst, p); } if(break_chain) { // 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(); chain.push_back(lc2_inst); } else { chain.push_back(lc2_inst); } } 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); } std::set done; for (const auto &ch : chains.chains) for (Instance *inst : ch) extend(done, inst); for (Instance *inst : instances) { if (!models.is_carry(inst)) continue; if (!contains(done, inst)) fatal("carry chain loop"); } } int Packer::count_extra_cells(CellType ct) { int n = 0; for (auto cell : chipdb->cell_type_cells[cell_type_idx(ct)]) { if (!contains(chipdb->cell_locked_pkgs.at(cell), package.name)) n++; } return n; } void Packer::pack() { optimize_luts(); 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_mac16 = 0, n_spram = 0, n_lfosc = 0, n_hfosc = 0, n_rgba_drv = 0, n_ledda_ip = 0, n_i2c = 0, n_spi = 0, n_io_i3c = 0, n_io_od = 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 if (models.is_mac16(inst)) ++n_mac16; else if (models.is_spram(inst)) ++n_spram; else if (models.is_hfosc(inst)) ++n_hfosc; else if (models.is_lfosc(inst)) ++n_lfosc; else if (models.is_rgba_drv(inst)) ++n_rgba_drv; else if (models.is_ledda_ip(inst)) ++n_ledda_ip; else if (models.is_spi(inst)) ++n_spi; else if (models.is_i2c(inst)) ++n_i2c; else if (models.is_io_i3c(inst)) ++n_io_i3c; else if (models.is_io_od(inst)) ++n_io_od; 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; } if(chipdb->device == "5k") { *logs << "\nAfter packing:\n" << "IOs " << n_io << " / " << package.pin_loc.size() << "\n" << " IO_I3Cs " << n_io_i3c << " / " << count_extra_cells(CellType::IO_I3C) << "\n" << " IO_ODs " << n_io_od << " / " << (3 * count_extra_cells(CellType::RGBA_DRV)) << "\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 << " / " << count_extra_cells(CellType::PLL) << "\n" << "MAC16s " << n_mac16 << " / " << count_extra_cells(CellType::MAC16) << "\n" << "SPRAM256KAs " << n_spram << " / " << count_extra_cells(CellType::SPRAM) << "\n" << "HFOSCs " << n_hfosc << " / " << count_extra_cells(CellType::HFOSC) << "\n" << "LFOSCs " << n_lfosc << " / " << count_extra_cells(CellType::LFOSC) << "\n" << "RGBA_DRVs " << n_rgba_drv << " / " << count_extra_cells(CellType::RGBA_DRV) << "\n" << "LEDDA_IPs " << n_ledda_ip << " / " << count_extra_cells(CellType::LEDDA_IP) << "\n" << "I2Cs " << n_i2c << " / " << count_extra_cells(CellType::I2C_IP) << "\n" << "SPIs " << n_spi << " / " << count_extra_cells(CellType::SPI_IP) << "\n\n"; } else { *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 << " / " << count_extra_cells(CellType::PLL) << "\n\n"; } } void pack(DesignState &ds) { Packer packer(ds); packer.pack(); } arachne-pnr-0.1+20180513git5d830dd/src/pack.hh000066400000000000000000000013661327610534100202050ustar00rootroot00000000000000/* 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; void pack(DesignState &ds); #endif arachne-pnr-0.1+20180513git5d830dd/src/pcf.cc000066400000000000000000000473761327610534100200400ustar00rootroot00000000000000/* 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 #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(); }; namespace { // Extract integer ranges that don't have holes. std::vector> extract_ranges(const std::set &full_set) { using ReturnType = std::vector>; ReturnType result; ReturnType::iterator current; int last = -2; for (const int bit : full_set) { if (bit > last+1) { result.push_back({bit, bit}); current = result.end()-1; } current->second = bit; last = bit; } return result; } // Given a field prefix and a set of bit-positions, print a compact // representation. Resets the given fields. void print_coalesced_field_range(std::string *last_prefix, std::set *missing_bits) { if (last_prefix->empty()) return; for (auto range : extract_ranges(*missing_bits)) { if (range.first != range.second) { note(fmt("no set_io constraints for pins `" << *last_prefix << "[" << range.first << ".." << range.second << "]'")); } else { note(fmt("no set_io constraints for pin `" << *last_prefix << "[" << range.first << "]'")); } } last_prefix->clear(); missing_bits->clear(); } } // namespace void PCFParser::parse() { std::map net_pin_loc; std::map pin_loc_net; std::map net_pin_pull_up; std::set extra_ports; for (auto p : top->ordered_ports()) extra_ports.insert(p->name()); for (;;) { if (eof()) break; read_line(); if (words.empty()) continue; const std::string &cmd = words[0]; if (cmd == "set_io") { bool no_warn = false; bool pull_up = false; bool pull_up_set = false; const char *net_name = nullptr, *pin_name = nullptr; for (int i = 1; i < (int)words.size(); ++i) { if (words[i][0] == '-') { if (words[i] == "--warn-no-port") { /* ignored for backward compatibility */ } else if (words[i] == "-nowarn") { no_warn = true; } else if (words[i] == "-pullup") { if (i+1 == (int)words.size()) fatal(fmt("-pullup needs yes/no")); i++; if (words[i] == "yes") { pull_up = true; pull_up_set = true; } else if (words[i] == "no") pull_up_set = true; else fatal(fmt("unknown pullup option `" << words[i] << "'")); } else fatal(fmt("unknown option `" << words[i] << "'")); } 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 (!no_warn) warning(fmt("no port `" << net_name << "' in top-level module `" << top->name() << "', constraint ignored.")); continue; } extra_ports.erase(p->name()); auto i = package.pin_loc.find(pin_name); if (i == package.pin_loc.end()) fatal(fmt("unknown pin `" << pin_name << "' on package `" << package.name << "'")); if (contains(net_pin_loc, net_name)) fatal(fmt("duplicate pin constraints for net `" << net_name << "'")); const Location &loc = i->second; if (contains(pin_loc_net, loc)) fatal(fmt("duplicate pin constraints for pin `" << pin_name <<"'")); extend(net_pin_loc, net_name, loc); extend(pin_loc_net, loc, net_name); if (pull_up_set) extend(net_pin_pull_up, net_name, pull_up); } else fatal(fmt("unknown command `" << cmd << "'")); } if (!extra_ports.empty()) { // Print some somewhat compact list of all missing constraints, // coalescing bit numbers. std::string last_prefix; std::set missing_bits; for (const std::string &pin_name : extra_ports) { auto bracket = pin_name.find_first_of('['); if (bracket != std::string::npos) { std::string prefix = pin_name.substr(0, bracket); if (prefix != last_prefix) { print_coalesced_field_range(&last_prefix, &missing_bits); last_prefix = prefix; } missing_bits.insert(atoi(pin_name.substr(bracket+1).c_str())); } else { print_coalesced_field_range(&last_prefix, &missing_bits); note(fmt("no set_io constraints for pin `" << pin_name << "'")); } } fatal(fmt("Missing " << extra_ports.size() << " set_io constraints")); } constraints.net_pin_loc = net_pin_loc; constraints.net_pin_pull_up = net_pin_pull_up; } 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) || models.is_rgba_drv(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") { if (b != 3) fatal(fmt("pcf error: LVDS port `" << p.first << "' not in bank 3\n")); if (loc.pos() != 0) fatal(fmt("pcf error: LVDS port `" << p.first << "' not a DPxxB input\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) { int x = chipdb->tile_x(t), y = chipdb->tile_y(t); if (inst->get_param("NEG_TRIGGER").get_bit(0) != inst_other->get_param("NEG_TRIGGER").get_bit(0)) fatal(fmt("pcf error: incompatible NEG_TRIGGER parameters in PIO at (" << inst->find_port("PACKAGE_PIN")->connection()->name() << "," << inst_other->find_port("PACKAGE_PIN")->connection()->name() << ") at (" << x << ", " << y << ")")); Net *cen = inst->find_port("CLOCK_ENABLE")->connection(), *cen_other = inst_other->find_port("CLOCK_ENABLE")->connection(); if (cen && cen_other && cen != cen_other) fatal(fmt("pcf error: multiple CLOCK_ENABLE drivers in PIO at (" << inst->find_port("PACKAGE_PIN")->connection()->name() << "," << inst_other->find_port("PACKAGE_PIN")->connection()->name() << ") at (" << x << ", " << y << ")")); Net *inclk = inst->find_port("INPUT_CLK")->connection(), *inclk_other = inst_other->find_port("INPUT_CLK")->connection(); if (inclk && inclk_other && inclk != inclk_other) fatal(fmt("pcf error: multiple INPUT_CLK drivers in PIO at (" << inst->find_port("PACKAGE_PIN")->connection()->name() << "," << inst_other->find_port("PACKAGE_PIN")->connection()->name() << ") at (" << x << ", " << y << ")")); Net *outclk = inst->find_port("OUTPUT_CLK")->connection(), *outclk_other = inst_other->find_port("OUTPUT_CLK")->connection(); if (outclk && outclk_other && outclk != outclk_other) fatal(fmt("pcf error: multiple OUTPUT_CLK drivers in PIO at (" << inst->find_port("PACKAGE_PIN")->connection()->name() << "," << inst_other->find_port("PACKAGE_PIN")->connection()->name() << ") at (" << x << ", " << y << ")")); } } std::map::const_iterator it; it = constraints.net_pin_pull_up.find(p.first); if (it != constraints.net_pin_pull_up.end()) { // Pull-up constraint for this pin inst->set_param("PULLUP", BitVector(1, it->second ? 1 : 0)); note(fmt("forcing pull-up for `" << it->first << "' to `" << it->second << "'")); } if(models.is_io_i3c(inst)) { bool found = false; for (int icell : chipdb->cell_type_cells[cell_type_idx(CellType::IO_I3C)]) { auto pin = chipdb->cell_mfvs.at(icell).at("PACKAGE_PIN"); if(loc.tile() == pin.first && loc.pos() == std::stoi(pin.second)) { found = true; break; } } if(!found) { fatal(fmt("bad constraint on `" << p.first << "': pin " << ds.package.loc_pin.at(loc) << " is not I3C IO capable")); } } else if (models.is_io_od(inst)) { int rgb_cell = chipdb->cell_type_cells[cell_type_idx(CellType::RGBA_DRV)].at(0); bool found = false; for (int i = 0; i <= 2; i++) { std::string op = "RGB" + std::to_string(i); auto op_loc = chipdb->cell_mfvs.at(rgb_cell).at(op); if(loc.tile() == op_loc.first && loc.pos() == std::stoi(op_loc.second)) { for(auto rinst : top->instances()) { if(models.is_rgba_drv(rinst)) { if(rinst->get_param(op + "_CURRENT").as_string() != "0b000000") fatal(fmt("bad constraint on `" << p.first << "': IO_OD on pin " << ds.package.loc_pin.at(loc) << " conflicts with RGBA_DRV output " << op << " (set " << op << "_CURRENT to 0b000000 to use IO_OD)")); } } found = true; break; } } if(!found) fatal(fmt("bad constraint on `" << p.first << "': pin " << ds.package.loc_pin.at(loc) << " is not an IO_OD location")); } c = chipdb->loc_cell(loc); } else if (models.is_rgba_drv(inst)) { Port *port = top->find_port(p.first); assert(port); Port *p2 = port->connection_other_port(); std::string op = p2->name(); if (op == "RGB0" || op == "RGB1" || op == "RGB2") { int rgb_cell = chipdb->cell_type_cells[cell_type_idx(CellType::RGBA_DRV)].at(0); auto op_loc = chipdb->cell_mfvs.at(rgb_cell).at(op); if(loc.tile() != op_loc.first || loc.pos() != std::stoi(op_loc.second)) { fatal(fmt("bad constraint on `" << p.first << "': pin " << ds.package.loc_pin.at(loc) << " does not correspond to RGB driver output `" << op << "'")); } } continue; } 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 || contains(chipdb->cell_locked_pkgs.at(c), ds.package.name)) 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 = io->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_io_i3c(inst)) fatal("physical constraint required for IO_I3C"); else if(models.is_io_od(inst)) fatal("physical constraint required for IO_OD"); else if (models.is_lfosc(inst)) { bool good = false; for (int c : chipdb->cell_type_cells[cell_type_idx(CellType::LFOSC)]) { if (cell_gate[c]) continue; good = true; cell_gate[c] = inst; extend(ds.placement, inst, c); break; } if (!good) fatal("failed to place LFOSC"); } else if (models.is_hfosc(inst)) { bool good = false; for (int c : chipdb->cell_type_cells[cell_type_idx(CellType::HFOSC)]) { if (cell_gate[c]) continue; good = true; cell_gate[c] = inst; extend(ds.placement, inst, c); break; } if (!good) fatal("failed to place HFOSC"); } 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; if (contains(chipdb->cell_locked_pkgs.at(c), ds.package.name)) 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 = io->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; } } int n_pkg_pll = 0; for (auto cell : chipdb->cell_type_cells[cell_type_idx(CellType::PLL)]) { if (!contains(chipdb->cell_locked_pkgs.at(cell), ds.package.name)) n_pkg_pll++; } if (!good) fatal(fmt("failed to place: placed " << n_pll_placed << " PLLs of " << n_pll << " / " << n_pkg_pll)); } } } void place_constraints(DesignState &ds) { ConstraintsPlacer placer(ds); placer.place(); } arachne-pnr-0.1+20180513git5d830dd/src/pcf.hh000066400000000000000000000021211327610534100200250ustar00rootroot00000000000000/* 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 DesignState; class Constraints { public: std::map net_pin_loc; std::map net_pin_pull_up; 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.1+20180513git5d830dd/src/place.cc000066400000000000000000002264451327610534100203500ustar00rootroot00000000000000/* 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 "global.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; std::map> global_cells; 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 inst_drives_global(Instance *inst, int c, int glb); bool valid_global(int glb); 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 enable_output, bool pullup, bool weak_pullup, //I3C IO only std::string pullup_strength = "100K"); void configure(); //Configure a specific extra cell, given a list of the //parameters it takes in the form of a name and a size //If string_style is true, then it uses the "alternative //Lattice style" where parameters are a string like "0b000111" //rather than a numeric constant void configure_extra_cell(int c, Instance *inst, const std::vector > ¶ms, bool string_style); #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 if (models.is_mac16(inst)) return CellType::MAC16; else if (models.is_spram(inst)) return CellType::SPRAM; else if (models.is_hfosc(inst)) return CellType::HFOSC; else if (models.is_lfosc(inst)) return CellType::LFOSC; else if (models.is_rgba_drv(inst)) return CellType::RGBA_DRV; else if (models.is_ledda_ip(inst)) return CellType::LEDDA_IP; else if (models.is_i2c(inst)) return CellType::I2C_IP; else if (models.is_spi(inst)) return CellType::SPI_IP; 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::inst_drives_global(Instance *inst, int c, int glb) { #ifndef NDEBUG Location loc = chipdb->cell_location[c]; int t = loc.tile(); int x = chipdb->tile_x(t), y = chipdb->tile_y(t); #endif if (models.is_gb_io(inst) && inst->find_port("GLOBAL_BUFFER_OUTPUT")->connected()) { assert(chipdb->loc_pin_glb_num.at(loc) == glb); return true; } if (models.is_gb(inst) && inst->find_port("GLOBAL_BUFFER_OUTPUT")->connected()) { assert(chipdb->gbufin.at(std::make_pair(x, y)) == glb); return true; } if (models.is_hfosc(inst) && inst->find_port("CLKHF")->connected()) { if(!inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { int driven_glb = chipdb->get_oscillator_glb(c, "CLKHF"); if(glb == driven_glb) return true; } } if (models.is_lfosc(inst) && inst->find_port("CLKLF")->connected()) { if(!inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { int driven_glb = chipdb->get_oscillator_glb(c, "CLKLF"); if(glb == driven_glb) return true; } } if (models.is_pllX(inst)) { 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 glb_loc(p2.first, std::stoi(p2.second)); if (chipdb->loc_pin_glb_num.at(glb_loc) == glb) return true; } Port *b = inst->find_port("PLLOUTGLOBALB"); if (b && b->connected()) { const auto &p2 = chipdb->cell_mfvs.at(c).at("PLLOUT_B"); Location glb_loc(p2.first, std::stoi(p2.second)); if (chipdb->loc_pin_glb_num.at(glb_loc) == glb) return true; } } return false; } bool Placer::valid_global(int glb) { int n = 0; for (int c : global_cells.at(glb)) { int g = cell_gate[c]; if (!g) continue; Instance *inst = gates[g]; if (inst_drives_global(inst, c, glb)) { if (n > 0) return false; ++n; } } return true; } 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) { if (!contains(package.loc_pin, loc0)) return false; 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 (models.is_gb_io(inst0) && inst0->find_port("GLOBAL_BUFFER_OUTPUT")->connected()) { int glb = chipdb->loc_pin_glb_num.at(loc0); if (!valid_global(glb)) return false; } } if (g1) { if (!contains(package.loc_pin, loc1)) return false; Instance *inst1 = gates[g1]; if (inst1->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT") return false; if (models.is_gb_io(inst1) && inst1->find_port("GLOBAL_BUFFER_OUTPUT")->connected()) { int glb = chipdb->loc_pin_glb_num.at(loc1); if (!valid_global(glb)) 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; Net *cen0 = inst0->find_port("CLOCK_ENABLE")->connection(), *cen1 = inst1->find_port("CLOCK_ENABLE")->connection(); if (cen0 && cen1 && cen0 != cen1) return false; Net *inclk0 = inst0->find_port("INPUT_CLK")->connection(), *inclk1 = inst1->find_port("INPUT_CLK")->connection(); if (inclk0 && inclk1 && inclk0 != inclk1) return false; Net *outclk0 = inst0->find_port("OUTPUT_CLK")->connection(), *outclk1 = inst1->find_port("OUTPUT_CLK")->connection(); if (outclk0 && outclk1 && outclk0 != outclk1) 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 = lookup_or_default(gb_inst_gc, inst, gc_clk); int glb = chipdb->gbufin.at(std::make_pair(x, y)); if (! (gc & (1 << glb))) return false; if (!valid_global(glb)) 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) { if (contains(chipdb->cell_locked_pkgs.at(cell3), package.name)) return false; Port *pa = inst3->find_port("PLLOUTGLOBAL"); if (!pa) pa = inst3->find_port("PLLOUTGLOBALA"); assert(pa); if (pa->connected()) { const auto &p2 = chipdb->cell_mfvs.at(cell3).at("PLLOUT_A"); Location glb_loc(p2.first, std::stoi(p2.second)); int glb = chipdb->loc_pin_glb_num.at(glb_loc); if (!valid_global(glb)) return false; } Port *pb = inst3->find_port("PLLOUTGLOBALB"); if (pb && pb->connected()) { const auto &p2 = chipdb->cell_mfvs.at(cell3).at("PLLOUT_B"); Location glb_loc(p2.first, std::stoi(p2.second)); int glb = chipdb->loc_pin_glb_num.at(glb_loc); if (!valid_global(glb)) return false; } 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 if(chipdb->tile_type[t] == TileType::EMPTY) { for(auto cell : chipdb->cell_type_cells[cell_type_idx(CellType::I2C_IP)]) { if(chipdb->cell_location[cell].tile() == t) { int g = cell_gate[cell]; if (g) { Instance *inst = gates[g]; if(models.is_i2c(inst)) { if((x == 0) && (y == chipdb->height-1) && (inst->get_param("BUS_ADDR74").as_string() == "0b0001")) return true; if((x == chipdb->width-1) && (y == chipdb->height-1) && (inst->get_param("BUS_ADDR74").as_string() == "0b0011")) return true; return false; } } } } for(auto cell : chipdb->cell_type_cells[cell_type_idx(CellType::SPI_IP)]) { if(chipdb->cell_location[cell].tile() == t) { int g = cell_gate[cell]; if (g) { Instance *inst = gates[g]; if(models.is_spi(inst)) { if((x == 0) && (y == 0) && (inst->get_param("BUS_ADDR74").as_string() == "0b0000")) return true; // NOTE: the bus address of 0b0010 is not a typo, it appears the Technology Library (latest v3.0) // document is incorrect here if((x == chipdb->width-1) && (y == 0) && (inst->get_param("BUS_ADDR74").as_string() == "0b0010")) return true; return false; } } } } } else assert((chipdb->tile_type[t] == TileType::RAMT) || (chipdb->tile_type[t] == TileType::DSP0) || (chipdb->tile_type[t] == TileType::IPCON)); 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 (const auto &p : chipdb->loc_pin_glb_num) { const Location &loc = p.first; int c = chipdb->loc_cell(loc); int glb = p.second; global_cells[glb].push_back(c); } for (const auto &p : chipdb->gbufin) { int x = p.first.first, y = p.first.second; int glb = p.second; int t = chipdb->tile(x, y); Location loc(t, 2); int c = chipdb->loc_cell(loc); global_cells[glb].push_back(c); } for (int i = 1; i <= (int)chipdb->n_cells; ++i) { // FIXME if (chipdb->cell_type[i] == CellType::PLL) { int t = chipdb->cell_location[i].tile(); // global_cells const auto &p2a = chipdb->cell_mfvs.at(i).at("PLLOUT_A"); Location glb_loca(p2a.first, std::stoi(p2a.second)); int glba = chipdb->loc_pin_glb_num.at(glb_loca); global_cells[glba].push_back(i); const auto &p2b = chipdb->cell_mfvs.at(i).at("PLLOUT_B"); Location glb_locb(p2b.first, std::stoi(p2b.second)); int glbb = chipdb->loc_pin_glb_num.at(glb_locb); global_cells[glbb].push_back(i); // related tiles 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; } else if(chipdb->cell_type[i] == CellType::HFOSC) { global_cells[chipdb->get_oscillator_glb(i, "CLKHF")].push_back(i); } else if(chipdb->cell_type[i] == CellType::LFOSC) { global_cells[chipdb->get_oscillator_glb(i, "CLKLF")].push_back(i); } } 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; } else if (models.is_hfosc(inst)) { Net *n = inst->find_port("CLKHF")->connection(); if (n && !inst->is_attr_set("ROUTE_THROUGH_FABRIC")) net_global[net_idx.at(n)] = true; } else if (models.is_lfosc(inst)) { Net *n = inst->find_port("CLKLF")->connection(); if (n && !inst->is_attr_set("ROUTE_THROUGH_FABRIC")) 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; } else if ((chipdb->device == "5k" || chipdb->device == "lm4k") && (logic_columns[i] == 1 || logic_columns[i] == 24)) // FIXME(daveshah1): check this { logic_column_free[i] = 2; logic_column_last[i] = 23; } } 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(lookup_or_default(gb_inst_gc, inst, gc_clk), 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 enable_output, bool pullup, bool weak_pullup, std::string pullup_strength) { 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)); } // The 5k series have extra IO configuration required if(chipdb->device == "5k") { pullup_strength = str_to_upper(pullup_strength); const CBit &padeb_test_0 = func_cbits.at("IoCtrl.padeb_test_0")[0], &padeb_test_1 = func_cbits.at("IoCtrl.padeb_test_1")[0], &cf_bit_32 = func_cbits.at("IoCtrl.cf_bit_32")[0], &cf_bit_33 = func_cbits.at("IoCtrl.cf_bit_33")[0], &cf_bit_34 = func_cbits.at("IoCtrl.cf_bit_34")[0], &cf_bit_35 = func_cbits.at("IoCtrl.cf_bit_35")[0], &cf_bit_36 = func_cbits.at("IoCtrl.cf_bit_36")[0], &cf_bit_37 = func_cbits.at("IoCtrl.cf_bit_37")[0], &cf_bit_38 = func_cbits.at("IoCtrl.cf_bit_38")[0], &cf_bit_39 = func_cbits.at("IoCtrl.cf_bit_39")[0]; //padeb_test_x is set when a pin is not an output if (loc.pos() == 0) { conf.set_cbit(CBit(loc.tile(), padeb_test_1.row, padeb_test_1.col), !enable_output); // active low } else { assert(loc.pos() == 1); conf.set_cbit(CBit(loc.tile(), padeb_test_0.row, padeb_test_0.col), !enable_output); // active low } assert(pullup_strength == "100K" || pullup_strength == "10K" || pullup_strength == "6P8K" || pullup_strength == "3P3K"); //cf_bit_35 mirrors REN_1 and cf_bit_39 mirrors REN_0 (set low to //enable 100k pullup) bool enable_100k = (pullup && (pullup_strength == "100K")) || weak_pullup; if (loc.pos() == 0) { conf.set_cbit(CBit(loc.tile(), cf_bit_39.row, cf_bit_39.col), !enable_100k); // active low } else { assert(loc.pos() == 1); conf.set_cbit(CBit(loc.tile(), cf_bit_35.row, cf_bit_35.col), !enable_100k); // active low } //Lookup bits other than 100k which is a special case if((pullup_strength != "100K") && pullup) { const std::map > pullup_cbits = {{"3P3K", {cf_bit_36, cf_bit_32}}, {"6P8K", {cf_bit_37, cf_bit_33}}, {"10K", {cf_bit_38, cf_bit_34}}}; const CBit &pullup_cbit = (loc.pos() == 1) ? pullup_cbits.at(pullup_strength).second : pullup_cbits.at(pullup_strength).first; conf.set_cbit(CBit(loc.tile(), pullup_cbit.row, pullup_cbit.col), true); } } } void Placer::configure_extra_cell(int c, Instance *inst, const std::vector > ¶ms, bool string_style) { for(auto p : params) { BitVector value; if(string_style) { //Lattice's weird string style params (as of yet untested), not sure if //prefixes other than 0b should be supported, only 0b features in docs std::string raw = inst->get_param(p.first).as_string(); assert(raw.substr(0, 2) == "0b"); raw = raw.substr(2); value.resize(raw.length()); for(int i = 0; i < (int)raw.length(); i++) { if(raw[i] == '1') { value[(raw.length() - 1) - i] = 1; } else { assert(raw[i] == '0'); value[(raw.length() - 1) - i] = 0; } } } else { value = inst->get_param(p.first).as_bits(); } value.resize(p.second); if(p.second == 1) { CBit cb = chipdb->extra_cell_cbit(c, p.first); conf.set_cbit(cb, value[0]); } else { for (int i = 0; i < (int)p.second; ++i) { CBit cb = chipdb->extra_cell_cbit(c, fmt((p.first + std::string("_")) << i)); conf.set_cbit(cb, value[i]); } } } } void Placer::configure() { for (int g = 1; g <= n_gates; g ++) { Instance *inst = gates[g]; int cell = gate_cell[g]; const Location &loc = chipdb->cell_location[cell]; // These are located in an empty tile so must be handled differrently if (models.is_warmboot(inst)) { placement[inst] = cell; continue; } else if(models.is_hfosc(inst)) { placement[inst] = cell; const std::vector > hfosc_params = {{"CLKHF_DIV", 2}}; configure_extra_cell(cell, inst, hfosc_params, true); if(inst->find_port("CLKHF")->connected() && !inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { int driven_glb = chipdb->get_oscillator_glb(cell, "CLKHF"); const auto &ecb = chipdb->extra_bits.at(fmt("padin_glb_netwk." << driven_glb)); conf.set_extra_cbit(ecb); } if(models.is_hfosc_trim(inst)) { CBit trimen_cb = chipdb->extra_cell_cbit(cell, "TRIM_EN"); conf.set_cbit(trimen_cb, true); } continue; } else if(models.is_lfosc(inst)) { placement[inst] = cell; if(inst->find_port("CLKLF")->connected() && !inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { int driven_glb = chipdb->get_oscillator_glb(cell, "CLKLF"); const auto &ecb = chipdb->extra_bits.at(fmt("padin_glb_netwk." << driven_glb)); conf.set_extra_cbit(ecb); } continue; } else if(models.is_spram(inst)) { placement[inst] = cell; CBit spramen_cb = chipdb->extra_cell_cbit(cell, "SPRAM_EN"); conf.set_cbit(spramen_cb, true); continue; } else if(models.is_i2c(inst)) { placement[inst] = cell; for(auto bits : chipdb->cell_mfvs.at(cell)) { if(startswith(bits.first, "I2C_ENABLE_")) { CBit i2cen_cb = chipdb->extra_cell_cbit(cell, bits.first, true); conf.set_cbit(i2cen_cb, true); } } if(inst->is_attr_set("SDA_INPUT_DELAYED", true)) { //NB INPUT_DELAYED is default on in icecube CBit i2cen_cb = chipdb->extra_cell_cbit(cell, "SDA_INPUT_DELAYED", true); conf.set_cbit(i2cen_cb, true); } if(inst->is_attr_set("SDA_OUTPUT_DELAYED", false)) { CBit i2cen_cb = chipdb->extra_cell_cbit(cell, "SDA_OUTPUT_DELAYED", true); conf.set_cbit(i2cen_cb, true); } continue; } else if(models.is_spi(inst)) { placement[inst] = cell; for(auto bits : chipdb->cell_mfvs.at(cell)) { if(startswith(bits.first, "SPI_ENABLE_")) { CBit spien_cb = chipdb->extra_cell_cbit(cell, bits.first, true); conf.set_cbit(spien_cb, true); } } continue; } else if(models.is_ledda_ip(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)) { assert(contains(package.loc_pin, loc)); const BitVector &pin_type = inst->get_param("PIN_TYPE").as_bits(); if (pin_type.size()<6) { fatal(fmt("Wrong width of PIN_TYPE, should be 6 instead of " << pin_type.size())); } 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 if (models.is_mac16(inst)) { const std::vector > mac16_params = {{"C_REG", 1}, {"A_REG", 1}, {"B_REG", 1}, {"D_REG", 1}, {"TOP_8x8_MULT_REG", 1}, {"BOT_8x8_MULT_REG", 1}, {"PIPELINE_16x16_MULT_REG1", 1}, {"PIPELINE_16x16_MULT_REG2", 1}, {"TOPOUTPUT_SELECT", 2}, {"TOPADDSUB_LOWERINPUT", 2}, {"TOPADDSUB_UPPERINPUT", 1}, {"TOPADDSUB_CARRYSELECT", 2}, {"BOTOUTPUT_SELECT", 2}, {"BOTADDSUB_LOWERINPUT", 2}, {"BOTADDSUB_UPPERINPUT", 1}, {"BOTADDSUB_CARRYSELECT", 2}, {"MODE_8x8", 1}, {"A_SIGNED", 1}, {"B_SIGNED", 1}}; configure_extra_cell(cell, inst, mac16_params, false); int x = chipdb->tile_x(loc.tile()), y = chipdb->tile_y(loc.tile()); //Used DSP tiles must have LC and cascade bits set correctly to function, as these are //used for an unknown internal purpose for(int dsp_idx = 0; dsp_idx < 4; dsp_idx++) { const auto &dspi_func_cbits = chipdb->tile_nonrouting_cbits.at(TileType::DSP0); int dspt = chipdb->tile(x, y + dsp_idx); for(int lc_idx = 0; lc_idx < 8; lc_idx++) { const auto &cbits = dspi_func_cbits.at(fmt("LC_" << lc_idx)); static std::vector dsp_lut_perm = { 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, }; for (int i = 0; i < 16; ++i) conf.set_cbit(CBit(dspt, cbits[dsp_lut_perm[i]].row, cbits[dsp_lut_perm[i]].col), ((i % 8) >= 4)); const auto &casc_cbit = dspi_func_cbits.at("Cascade.MULT0_LC0" + std::to_string(lc_idx) + "_inmux02_5"); assert(casc_cbit.size() == 1); conf.set_cbit(CBit(dspt, casc_cbit[0].row, casc_cbit[0].col), 1); } } } else if(models.is_rgba_drv(inst)) { const std::vector > rgbadrv_params = {{"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}}; configure_extra_cell(cell, inst, rgbadrv_params, true); CBit rgben_cb = chipdb->extra_cell_cbit(cell, "RGBA_DRV_EN"); conf.set_cbit(rgben_cb, 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); // avoid "variable ‘found’ set but not used" in NDEBUG builds if (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_cbit = 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); } std::set ieren_partner_image; for (const auto &p : package.pin_loc) { bool is_lvds = false; const Location &loc = p.second; int pll_cell = lookup_or_default(loc_pll, loc, 0); if (!pll_cell) { int cell = chipdb->loc_cell(loc); int g = cell_gate[cell]; if (g) { Instance *inst = gates[g]; is_lvds = inst->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT"; } } if (is_lvds) { Location partner_loc(loc.tile(), !loc.pos()); extend(ieren_partner_image, partner_loc); } } for (const auto &p : package.pin_loc) { // unused io bool enable_input = false; bool enable_output = false; bool pullup = true; // default pullup bool weak_pullup = false; //I3C IO bool is_lvds = false; std::string pullup_strength = "100K"; 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; // FIXME as above? enable_output = 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; const Const &pin_type = inst->get_param("PIN_TYPE"); enable_output = pin_type.get_bit(5) || pin_type.get_bit(4) || pin_type.get_bit(3) || pin_type.get_bit(2); pullup = inst->get_param("PULLUP").get_bit(0); if(chipdb->device == "5k") { if(models.is_io_i3c(inst)) { //Default strong pullup for I3C IO? pullup_strength = "10K"; weak_pullup = inst->get_param("WEAK_PULLUP").get_bit(0); } if(inst->has_attr("PULLUP_RESISTOR")) pullup_strength = inst->get_attr("PULLUP_RESISTOR").as_string(); } is_lvds = inst->get_param("IO_STANDARD").as_string() == "SB_LVDS_INPUT"; conf.set_cbit(CBit(loc.tile(), lvds_cbit.row, lvds_cbit.col), is_lvds); } } if (contains(ieren_partner_image, loc)) continue; if (is_lvds) { enable_input = false; pullup = false; } const Location &ieren_loc = chipdb->ieren.at(loc); configure_io(ieren_loc, enable_input, enable_output, pullup, weak_pullup, pullup_strength); if (is_lvds) { Location partner_loc(loc.tile(), !loc.pos()); const Location &partner_ieren_loc = chipdb->ieren.at(partner_loc); configure_io(partner_ieren_loc, enable_input, enable_output, pullup, weak_pullup, pullup_strength); } } 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 enable_output = false; bool pullup = true; // default pullup Location loc(t, p); if (contains(ieren_image, loc)) continue; configure_io(loc, enable_input, enable_output, pullup, false); } } } // All but one IpCon tile has LC_ and Cascade bits set, like DSP tiles for (int t = 0; t < chipdb->n_tiles; ++t) { if (chipdb->tile_type[t] != TileType::IPCON) continue; assert(chipdb->device == "5k"); if(chipdb->tile_x(t) == 25 && chipdb->tile_y(t) == 14) continue; //Bits not set on this tile only const auto &ipcon_func_cbits = chipdb->tile_nonrouting_cbits.at(TileType::IPCON); for(int lc_idx = 0; lc_idx < 8; lc_idx++) { const auto &cbits = ipcon_func_cbits.at(fmt("LC_" << lc_idx)); static std::vector ipc_lut_perm = { 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, }; for (int i = 0; i < 16; ++i) conf.set_cbit(CBit(t, cbits[ipc_lut_perm[i]].row, cbits[ipc_lut_perm[i]].col), ((i % 8) >= 4)); const auto &casc_cbit = ipcon_func_cbits.at("Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5"); assert(casc_cbit.size() == 1); conf.set_cbit(CBit(t, casc_cbit[0].row, casc_cbit[0].col), 1); } } // set RamConfig.PowerUp configuration bit if (chipdb->tile_nonrouting_cbits.count(TileType::RAMB)) { 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; double avg_wire_length = wire_length(); for (int iter=1;; iter++) { n_move = n_accept = 0; improved = false; if (iter % 50 == 0) *logs << " at iteration #" << iter << ": temp = " << temp << ", wire length = " << wire_length() << "\n"; 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 (wire_length() < 0.95 * avg_wire_length) avg_wire_length = 0.8*avg_wire_length + 0.2*wire_length(); else { if (Raccept >= 0.8) { temp *= 0.7; } 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.1+20180513git5d830dd/src/place.hh000066400000000000000000000014471327610534100203530ustar00rootroot00000000000000/* 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 class random_generator; class DesignState; void place(random_generator &rg, DesignState &ds); #endif arachne-pnr-0.1+20180513git5d830dd/src/priorityq.hh000066400000000000000000000026161327610534100213300ustar00rootroot00000000000000/* 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_PRIORITYQQ_HH #define PNR_PRIORITYQQ_HH #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]; } }; #endif arachne-pnr-0.1+20180513git5d830dd/src/route.cc000066400000000000000000000651601327610534100204150ustar00rootroot00000000000000/* 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; int max_passes; 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, int max_passes_v); 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 if (p_name == "LO") tile_net_name = fmt("lutff_" << loc.pos() << "/lout"); else { assert(p_name == "O"); tile_net_name = fmt("lutff_" << loc.pos() << "/out"); } if (chipdb->tile_nets[t].find(tile_net_name) == chipdb->tile_nets[t].end()) { fatal(fmt("failed to rote: " << p->name() << " to " << tile_net_name)); } } 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 if (models.is_io_i3c(inst)) { assert(p_name == "PU_ENB" || p_name == "WEAK_PU_ENB"); bool found = false; int i3c_cell = -1; for (int c : chipdb->cell_type_cells[cell_type_idx(CellType::IO_I3C)]) { auto pin = chipdb->cell_mfvs.at(c).at("PACKAGE_PIN"); if(loc.tile() == pin.first && loc.pos() == std::stoi(pin.second)) { found = true; i3c_cell = c; break; } } assert(found); const auto &p2 = chipdb->cell_mfvs.at(i3c_cell).at(p_name); t = p2.first; tile_net_name = p2.second; } 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 if (models.is_mac16(inst) || models.is_spram(inst) || models.is_lfosc(inst) || models.is_hfosc(inst) || models.is_rgba_drv(inst) || models.is_ledda_ip(inst) || models.is_spi(inst) || models.is_i2c(inst)) { //Convert [x] to _x std::string db_name; //Deal with ROUTE_THROUGH_FABRIC if((models.is_hfosc(inst) || models.is_lfosc(inst)) && inst->is_attr_set("ROUTE_THROUGH_FABRIC")) { if(p_name == "CLKHF" || p_name == "CLKLF") db_name = std::string(p_name) + "_FABRIC"; else db_name = p_name; } else { for(auto c : p_name) { if(c == '[') db_name += "_"; else if(c == ']') ; else db_name += c; } } if(models.is_mac16(inst)) { if(p_name == "ACCUMCI" || p_name == "SIGNEXTIN") { assert(p->connection()->is_constant() && (p->connection()->constant() == Value::ZERO)); return -1; } } const auto &p2 = chipdb->cell_mfvs.at(cell).at(db_name); t = p2.first; tile_net_name = p2.second; } 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, int max_passes_v) : 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), max_passes(max_passes_v), 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 if (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)); } else if (chipdb->device == "5k" || chipdb->device == "lm4k") { 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)); } else assert(chipdb->device == "384"); 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 if (n_shared < 5) { std::map> net_route_reverse; for (int i = 0; i < n_nets; ++i) for (const auto &p : net_route[i]) if (demand[p.second] > 1) net_route_reverse[p.second].insert(i); for (int i = 0; i < chipdb->n_nets; ++i) if (demand[i] > 1) { if (chipdb->net_tile_name.empty()) *logs << " shared net #" << i << " (demand = " << demand[i] << ").\n"; else { auto &net_tile_name = chipdb->net_tile_name.at(i); int tile_x = chipdb->tile_x(net_tile_name.first), tile_y = chipdb->tile_y(net_tile_name.first); *logs << " shared net #" << i << " (demand = " << demand[i] << ") in tile " << tile_x << "," << tile_y << ": " << net_tile_name.second << "\n"; } for (auto j : net_route_reverse.at(i)) *logs << " used by wire " << net_net[j]->name() << "\n"; } } #endif #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) && (chipdb->device != "384")) { 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, int max_passes) { Router router(ds, max_passes); 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.1+20180513git5d830dd/src/route.hh000066400000000000000000000014111327610534100204140ustar00rootroot00000000000000/* 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 class DesignState; void route(DesignState &ds, int max_passes); #endif arachne-pnr-0.1+20180513git5d830dd/src/ullmanset.hh000066400000000000000000000044171327610534100212730ustar00rootroot00000000000000/* Copyright (c) 2015-2018 Cotton Seed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef PNR_ULLMANSET_HH #define PNR_ULLMANSET_HH #include "vector.hh" #include #include class UllmanSet { size_t n; std::vector key; std::vector pos; public: UllmanSet() : n(0) {} UllmanSet(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]; } }; #endif arachne-pnr-0.1+20180513git5d830dd/src/util.cc000066400000000000000000000130111327610534100202200ustar00rootroot00000000000000/* 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 . */ #if !defined(_WIN32) && !defined (_GNU_SOURCE) #define _GNU_SOURCE #endif #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"; } void note(const std::string &msg) { std::cerr << "note: " << 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() && *i >= '0' && *i <= '9') x = x*8 + *i++ - '0'; if (i != s.end() && *i >= '0' && *i <= '9') x = x*8 + *i++ - '0'; i--; r.push_back(x); } break; } } else r.push_back(*i); } return r; } /* taken from Yosys, yosys/kernel/yosys.cc */ #if defined(__linux__) || defined(__CYGWIN__) 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(__FreeBSD__) std::string proc_self_dirname() { char path[PATH_MAX]; ssize_t buflen = readlink("/proc/curproc/file", path, sizeof(path)); if (buflen < 0) { fatal(fmt("readlink(\"/proc/curproc/file\") 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; } #elif defined(__EMSCRIPTEN__) std::string proc_self_dirname() { // This is a fake path, but ../ will always be appended and this will still work. return "/bin/"; } #else #error Dont know how to determine process executable base path! #endif std::string expand_filename(const std::string &file) { if (file[0] == '+') #if defined(_WIN32) && defined(MXE_DIR_STRUCTURE) return (proc_self_dirname() + std::string(file.begin() + 2, file.end())); #else return (proc_self_dirname() + ".." + std::string(file.begin() + 1, file.end())); #endif else return file; } arachne-pnr-0.1+20180513git5d830dd/src/util.hh000066400000000000000000000163251327610534100202450ustar00rootroot00000000000000/* 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 extern const char *version_str; 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()) void fatal(const std::string &msg); void warning(const std::string &msg); void note(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); } 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(); } 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)); } }; } 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(); } inline std::string str_to_upper(const std::string &s) { std::string res; for(auto c : s) res += toupper(c); return res; } inline bool startswith(const std::string &s, const std::string & pattern) { return (s.substr(0, pattern.length()) == pattern); } #endif arachne-pnr-0.1+20180513git5d830dd/src/vector.hh000066400000000000000000000075211327610534100205700ustar00rootroot00000000000000/* 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_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.1+20180513git5d830dd/tests/000077500000000000000000000000001327610534100173135ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/blif/000077500000000000000000000000001327610534100202275ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/blif/attr-with-quoted-numeric-escape.blif000066400000000000000000000000651327610534100272060ustar00rootroot00000000000000.model top .gate SB_DFF C=c D=d Q=q .attr src "\040" arachne-pnr-0.1+20180513git5d830dd/tests/blif/conflicting-names-outputs.blif000066400000000000000000000000741327610534100262070ustar00rootroot00000000000000.model hello .outputs op1 .names a op1 1 1 .names b op1 1 1 arachne-pnr-0.1+20180513git5d830dd/tests/blif/empty.blif000066400000000000000000000000001327610534100222110ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/blif/escape-test.blif000066400000000000000000000000051327610534100232750ustar00rootroot00000000000000\9"" arachne-pnr-0.1+20180513git5d830dd/tests/blif/multiple-models.blif000066400000000000000000000000221327610534100241730ustar00rootroot00000000000000.model A .model B arachne-pnr-0.1+20180513git5d830dd/tests/blif/names-without-model.blif000066400000000000000000000000151327610534100247630ustar00rootroot00000000000000.names Hello arachne-pnr-0.1+20180513git5d830dd/tests/blif/run-test.sh000077500000000000000000000007211327610534100223470ustar00rootroot00000000000000#!/bin/bash set -x arachne_pnr=../../bin/arachne-pnr pass='attr-with-quoted-numeric-escape' fail='conflicting-names-outputs empty escape-test multiple-models names-without-model sb-dff-model' for t in $pass; do if ! $arachne_pnr -p test.pcf $t.blif -o /dev/null; then echo "$t failed, expected pass" exit 1 fi done for t in $fail; do if $arachne_pnr -p test.pcf $t.blif -o /dev/null; then echo "$t passed, expected fail" exit 1 fi done arachne-pnr-0.1+20180513git5d830dd/tests/blif/sb-dff-model.blif000066400000000000000000000000161327610534100233210ustar00rootroot00000000000000.model SB_DFF arachne-pnr-0.1+20180513git5d830dd/tests/blif/test.pcf000066400000000000000000000000341327610534100216750ustar00rootroot00000000000000set_io op1 99 set_io clk 21 arachne-pnr-0.1+20180513git5d830dd/tests/combinatorial/000077500000000000000000000000001327610534100221365ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/combinatorial/.gitignore000066400000000000000000000000051327610534100241210ustar00rootroot00000000000000temp arachne-pnr-0.1+20180513git5d830dd/tests/combinatorial/generate.py000066400000000000000000000101361327610534100243030ustar00rootroot00000000000000#!/usr/bin/python from __future__ import division from __future__ import print_function import sys import random from contextlib import contextmanager random.seed(1) @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 open('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 open('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 open('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.1+20180513git5d830dd/tests/combinatorial/run-test.sh000066400000000000000000000027001327610534100242520ustar00rootroot00000000000000#!/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.1+20180513git5d830dd/tests/error/000077500000000000000000000000001327610534100204445ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/error/carry_loop.blif000066400000000000000000000005721327610534100234570ustar00rootroot00000000000000.model top .inputs a0 a1 b0 b1 .outputs o0 o1 o2 .names f .names t 1 .names $undef .gate SB_LUT4 I0=f I1=b0 I2=a0 I3=f O=o0 .param LUT_INIT 0110100110010110 .gate SB_CARRY CI=b CO=a I0=b0 I1=a0 .gate SB_LUT4 I0=f I1=b1 I2=a1 I3=a O=o1 .param LUT_INIT 011010011110 .gate SB_CARRY CI=a CO=b I0=b1 I1=a1 .gate SB_LUT4 I0=f I1=f I2=f I3=b O=o2 .param LUT_INIT 0110100110010110 .end arachne-pnr-0.1+20180513git5d830dd/tests/error/dup_pin.blif000066400000000000000000000000641327610534100227400ustar00rootroot00000000000000.model top .inputs clk .outputs D1 D2 D3 D4 D5 .end arachne-pnr-0.1+20180513git5d830dd/tests/error/dup_pin.pcf000066400000000000000000000001171327610534100225730ustar00rootroot00000000000000set_io D1 98 set_io D2 98 set_io D3 97 set_io D4 96 set_io D5 95 set_io clk 21 arachne-pnr-0.1+20180513git5d830dd/tests/error/run-test.sh000066400000000000000000000006141327610534100225620ustar00rootroot00000000000000#!/bin/bash set -x arachne_pnr=../../bin/arachne-pnr $arachne_pnr -p dup_pin.pcf dup_pin.blif -o /dev/null if [ x"$?" != x"1" ]; then echo "error, stopping." exit 1 fi $arachne_pnr carry_loop.blif -o /dev/null if [ x"$?" != x"1" ]; then echo "error, stopping." exit 1 fi $arachne_pnr tri.blif -o /dev/null if [ x"$?" != x"1" ]; then echo "error, stopping." exit 1 fi arachne-pnr-0.1+20180513git5d830dd/tests/error/tri.blif000066400000000000000000000003241327610534100220770ustar00rootroot00000000000000.model test .inputs s1 s2 a1 a2 b .outputs gate mes f .gate SB_LUT4 I0=s1 I1=s2 I2=f I3=f O=c .param LUT_INIT 1011 .gate SB_LUT4 I0=a1 I1=a2 I2=s2 I3=f O=d .param LUT_INIT 10101100 .gate $_TBUF_ A=d E=c Y=y .end arachne-pnr-0.1+20180513git5d830dd/tests/fsm/000077500000000000000000000000001327610534100201005ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/fsm/.gitignore000066400000000000000000000000051327610534100220630ustar00rootroot00000000000000temp arachne-pnr-0.1+20180513git5d830dd/tests/fsm/generate.py000066400000000000000000000144601327610534100222510ustar00rootroot00000000000000#!/usr/bin/python from __future__ import division from __future__ import print_function import sys import random from contextlib import contextmanager random.seed(1) @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 open('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 open('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 open('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.1+20180513git5d830dd/tests/fsm/run-test.sh000066400000000000000000000027001327610534100222140ustar00rootroot00000000000000#!/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.1+20180513git5d830dd/tests/io/000077500000000000000000000000001327610534100177225ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/io/.gitignore000066400000000000000000000000151327610534100217060ustar00rootroot00000000000000*.txt out-*.varachne-pnr-0.1+20180513git5d830dd/tests/io/inout_chain.blif000066400000000000000000000001641327610534100230610ustar00rootroot00000000000000.model top .inputs a b c .outputs a b .names $false .names $true 1 .names $undef .names c a 1 1 .names a b 1 1 .end arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_chain.v000066400000000000000000000002261327610534100224110ustar00rootroot00000000000000 module chip (output io_0_3_0, output io_0_3_1, input io_0_4_0); wire io_0_3_0; assign io_0_3_1 = io_0_3_0; assign io_0_3_0 = io_0_4_0; endmodule arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_in.blif000066400000000000000000000001411327610534100224000ustar00rootroot00000000000000.model top .inputs a b .outputs a .names $false .names $true 1 .names $undef .names b a 1 1 .end arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_in.v000066400000000000000000000001561327610534100217370ustar00rootroot00000000000000 module chip (output io_11_0_0, input io_11_0_1); wire io_11_0_0; assign io_11_0_0 = io_11_0_1; endmodule arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_inout.blif000066400000000000000000000001641327610534100231350ustar00rootroot00000000000000.model top .inputs a b c .outputs a b .names $false .names $true 1 .names $undef .names c a 1 1 .names c b 1 1 .end arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_inout.v000066400000000000000000000002261327610534100224650ustar00rootroot00000000000000 module chip (output io_0_3_0, output io_0_3_1, input io_0_4_0); wire io_0_3_0; assign io_0_3_1 = io_0_3_0; assign io_0_3_0 = io_0_4_0; endmodule arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_out.blif000066400000000000000000000001411327610534100226010ustar00rootroot00000000000000.model top .inputs a .outputs a b .names $false .names $true 1 .names $undef .names a b 1 1 .end arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_out.v000066400000000000000000000001561327610534100221400ustar00rootroot00000000000000 module chip (input io_11_0_0, output io_11_0_1); wire io_11_0_0; assign io_11_0_1 = io_11_0_0; endmodule arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_tbuf.blif000066400000000000000000000001561327610534100227400ustar00rootroot00000000000000.model top .inputs y a e .outputs y .names $false .names $true 1 .names $undef .gate $_TBUF_ A=a E=e Y=y .end arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_tbuf.v000066400000000000000000000002771327610534100222750ustar00rootroot00000000000000 module chip (input io_0_13_1, input io_0_12_1, output io_0_13_0); wire io_0_13_1, io_0_12_1, io_0_13_0; // IO Cell (0, 13, 0) assign io_0_13_0 = io_0_12_1 ? io_0_13_1 : 1'bz; endmodule arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_z.blif000066400000000000000000000001201327610534100222400ustar00rootroot00000000000000.model top .inputs a .outputs a .names $false .names $true 1 .names $undef .end arachne-pnr-0.1+20180513git5d830dd/tests/io/inout_z.v000066400000000000000000000000371327610534100216000ustar00rootroot00000000000000 module chip (); endmodule arachne-pnr-0.1+20180513git5d830dd/tests/io/run-test.sh000077500000000000000000000004611327610534100220430ustar00rootroot00000000000000#!/bin/bash set -ex arachne_pnr=../../bin/arachne-pnr tests='tri inout_in inout_out inout_z inout_inout inout_chain inout_tbuf' for t in $tests; do $arachne_pnr $t.blif -o $t.txt icebox_vlog -s $t.txt >out-$t.v if [ -e $t.v ]; then diff -u $t.v out-$t.v else cp out-$t.v $t.v fi done arachne-pnr-0.1+20180513git5d830dd/tests/io/tri.blif000066400000000000000000000010741327610534100213600ustar00rootroot00000000000000# Generated by Yosys 0.5+ 284 (git sha1 f40d1b7, clang 6.1.0 -fPIC -Os) .model test .inputs s1 s2 a1 a2 b .outputs y .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=s1 I1=s2 I2=$false I3=$false O=$auto$rtlil.cc:1564:ReduceOr$9 .attr src "/usr/local/bin/../share/yosys/ice40/cells_map.v:43" .param LUT_INIT 1011 .gate SB_LUT4 I0=a1 I1=a2 I2=s2 I3=$false O=$auto$rtlil.cc:1633:Pmux$6 .attr src "/usr/local/bin/../share/yosys/ice40/cells_map.v:47" .param LUT_INIT 10101100 .gate $_TBUF_ A=$auto$rtlil.cc:1633:Pmux$6 E=$auto$rtlil.cc:1564:ReduceOr$9 Y=y .end arachne-pnr-0.1+20180513git5d830dd/tests/io/tri.v000066400000000000000000000010121327610534100207010ustar00rootroot00000000000000 module chip (input io_0_8_0, input io_0_9_0, output io_0_9_1, input io_0_10_0, input io_0_10_1); wire io_0_8_0, n2, io_0_9_0, n4, io_0_9_1, io_0_10_0, io_0_10_1, n8, n9; // IO Cell (0, 9, 1) assign io_0_9_1 = n4 ? n2 : 1'bz; assign n8 = /* LUT 1 9 3 */ 1'b0 ? 1'b0 : io_0_10_1 ? io_0_8_0 ? 1'b1 : 1'b0 : io_0_9_0 ? 1'b1 : 1'b0; assign n9 = /* LUT 1 10 5 */ 1'b0 ? 1'b0 : 1'b0 ? 1'b0 : io_0_10_1 ? io_0_10_0 ? 1'b1 : 1'b0 : 1'b1; /* FF 1 9 3 */ assign n2 = n8; /* FF 1 10 5 */ assign n4 = n9; endmodule arachne-pnr-0.1+20180513git5d830dd/tests/regression/000077500000000000000000000000001327610534100214735ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/regression/.gitignore000066400000000000000000000000141327610534100234560ustar00rootroot00000000000000*.txt *.bin arachne-pnr-0.1+20180513git5d830dd/tests/regression/bram1.blif000066400000000000000000000026651327610534100233440ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/regression/c3demo.blif000066400000000000000000000014371327610534100235100ustar00rootroot00000000000000.model c3demo .inputs CLK12MHZ .outputs CLKOUT .names $false .names $true 1 .names $undef .gate SB_LUT4 I0=$false I1=$true I2=divided_clock[0] I3=$false O=$0\divided_clock[7:0][0] .attr src "/usr/local/bin/../share/yosys/ice40/arith_map.v:53" .param LUT_INIT 0110100110010110 .gate SB_DFF C=CLK12MHZ D=$0\divided_clock[7:0][0] Q=divided_clock[0] .attr src "c3demo.v:61|/usr/local/bin/../share/yosys/ice40/cells_map.v:2" .gate SB_GB GLOBAL_BUFFER_OUTPUT=clk USER_SIGNAL_TO_GLOBAL_BUFFER=divided_clock[0] .attr src "c3demo.v:64" .names clk CLKOUT 1 1 .names $undef divided_clock[1] 1 1 .names $undef divided_clock[2] 1 1 .names $undef divided_clock[3] 1 1 .names $undef divided_clock[4] 1 1 .names $undef divided_clock[5] 1 1 .names $undef divided_clock[6] 1 1 .names $undef divided_clock[7] 1 1 .end arachne-pnr-0.1+20180513git5d830dd/tests/regression/carry_pack_fail1.blif000066400000000000000000000043231327610534100255250ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/regression/carry_route_fail1.blif000066400000000000000000000042641327610534100257510ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/regression/carry_route_fail1.v000066400000000000000000000010211327610534100252660ustar00rootroot00000000000000module 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.1+20180513git5d830dd/tests/regression/j1a_gb_fail.blif000066400000000000000000000314701327610534100244540ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/regression/j1a_gb_fail.v000066400000000000000000000006361327610534100240050ustar00rootroot00000000000000`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.1+20180513git5d830dd/tests/regression/pin_type_fail.blif000066400000000000000000000020201327610534100251450ustar00rootroot00000000000000.model c3demo .inputs CLK12MHZ .outputs CLKOUT .names $false .names $true 1 .names $undef .gate SB_PLL40_CORE BYPASS=$false DYNAMICDELAY[0]=$false DYNAMICDELAY[1]=$false DYNAMICDELAY[2]=$false DYNAMICDELAY[3]=$false DYNAMICDELAY[4]=$false DYNAMICDELAY[5]=$false DYNAMICDELAY[6]=$false DYNAMICDELAY[7]=$false EXTFEEDBACK=$false LATCHINPUTVALUE=$false LOCK=pll_lock PLLOUTCORE=PLLOUTCORE PLLOUTGLOBAL=clk REFERENCECLK=CLK12MHZ RESETB=$true .attr src "c3demo.v:34" .param DELAY_ADJUSTMENT_MODE_FEEDBACK "FIXED" .param DELAY_ADJUSTMENT_MODE_RELATIVE "FIXED" .param DIVF 00000000000000000000000000000000 .param DIVQ 00000000000000000000000000000001 .param DIVR 00000000000000000000000000001010 .param ENABLE_ICEGATE 00000000000000000000000000000000 .param FDA_FEEDBACK 00000000000000000000000000000000 .param FDA_RELATIVE 00000000000000000000000000000000 .param FEEDBACK_PATH "SIMPLE" .param FILTER_RANGE 00000000000000000000000000000000 .param PLLOUT_SELECT "GENCLK" .param TEST_MODE 00000000000000000000000000000000 .names clk CLKOUT 1 1 .end arachne-pnr-0.1+20180513git5d830dd/tests/regression/pin_type_fail.pcf000066400000000000000000000000451327610534100250060ustar00rootroot00000000000000set_io CLK12MHZ R9 set_io CLKOUT P14 arachne-pnr-0.1+20180513git5d830dd/tests/regression/run-test.sh000066400000000000000000000025231327610534100236120ustar00rootroot00000000000000#!/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 $arachne_pnr -d $d c3demo.blif -o $d/c3demo.txt icepack $d/c3demo.txt $d/c3demo.bin done $arachne_pnr -d 8k -p pin_type_fail.pcf pin_type_fail.blif -o /dev/null arachne-pnr-0.1+20180513git5d830dd/tests/regression/test1.blif000066400000000000000000000044171327610534100233770ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/regression/test2.blif000066400000000000000000000102641327610534100233750ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/000077500000000000000000000000001327610534100206045ustar00rootroot00000000000000arachne-pnr-0.1+20180513git5d830dd/tests/simple/.gitignore000066400000000000000000000000541327610534100225730ustar00rootroot00000000000000*.txt *.bin sb_up3down5_packed.blif txt.sum arachne-pnr-0.1+20180513git5d830dd/tests/simple/bram.blif000066400000000000000000000140761327610534100223730ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/carry.blif000066400000000000000000000222471327610534100225710ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/run-test.sh000077500000000000000000000032311327610534100227230ustar00rootroot00000000000000#!/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.1+20180513git5d830dd/tests/simple/run-valgrind-test.sh000066400000000000000000000002661327610534100245310ustar00rootroot00000000000000#!/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.1+20180513git5d830dd/tests/simple/sb_gb_io.1k.pcf000066400000000000000000000001451327610534100233530ustar00rootroot00000000000000set_io inclk 50 set_io outclk 52 set_io out[0] 56 set_io out[1] 58 set_io out[2] 60 set_io out[3] 61 arachne-pnr-0.1+20180513git5d830dd/tests/simple/sb_gb_io.8k.pcf000066400000000000000000000001451327610534100233620ustar00rootroot00000000000000set_io inclk F7 set_io outclk T1 set_io out[0] P4 set_io out[1] R2 set_io out[2] N5 set_io out[3] T2 arachne-pnr-0.1+20180513git5d830dd/tests/simple/sb_gb_io.blif000066400000000000000000000035511327610534100232110ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/sb_gb_io.v000066400000000000000000000004751327610534100225440ustar00rootroot00000000000000 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.1+20180513git5d830dd/tests/simple/sb_pll40_2_pad.blif000066400000000000000000000025251327610534100241320ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/sb_pll40_2_pad.v000066400000000000000000000042011327610534100234540ustar00rootroot00000000000000module 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.1+20180513git5d830dd/tests/simple/sb_pll40_2f_core.blif000066400000000000000000000026031327610534100244610ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/sb_pll40_2f_core.v000066400000000000000000000045431327610534100240170ustar00rootroot00000000000000module 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.1+20180513git5d830dd/tests/simple/sb_pll40_2f_pad.blif000066400000000000000000000025731327610534100243030ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/sb_pll40_2f_pad.v000066400000000000000000000045401327610534100236300ustar00rootroot00000000000000module 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.1+20180513git5d830dd/tests/simple/sb_pll40_core.blif000066400000000000000000000023131327610534100240700ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/sb_pll40_core.v000066400000000000000000000037051327610534100234270ustar00rootroot00000000000000module 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.1+20180513git5d830dd/tests/simple/sb_pll40_pad.blif000066400000000000000000000023031327610534100237030ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/simple/sb_pll40_pad.v000066400000000000000000000037031327610534100232410ustar00rootroot00000000000000module 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.1+20180513git5d830dd/tests/simple/sb_up3down5.blif000066400000000000000000000227651327610534100236260ustar00rootroot00000000000000# 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.1+20180513git5d830dd/tests/test_bv.cc000066400000000000000000000021121327610534100212640ustar00rootroot00000000000000 #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.1+20180513git5d830dd/tests/test_us.cc000066400000000000000000000017731327610534100213200ustar00rootroot00000000000000 #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); }