mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into xaig_dff
This commit is contained in:
		
						commit
						8f5710c464
					
				
					 174 changed files with 26477 additions and 2398 deletions
				
			
		
							
								
								
									
										2
									
								
								Brewfile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Brewfile
									
										
									
									
									
								
							|  | @ -6,3 +6,5 @@ brew "git" | |||
| brew "graphviz" | ||||
| brew "pkg-config" | ||||
| brew "python3" | ||||
| brew "tcl-tk" | ||||
| brew "xdot" | ||||
|  |  | |||
							
								
								
									
										130
									
								
								CHANGELOG
									
										
									
									
									
								
							
							
						
						
									
										130
									
								
								CHANGELOG
									
										
									
									
									
								
							|  | @ -12,7 +12,10 @@ Yosys 0.9 .. Yosys 0.9-dev | |||
|     - Added "synth_xilinx -abc9" (experimental) | ||||
|     - Added "synth_ice40 -abc9" (experimental) | ||||
|     - Added "synth -abc9" (experimental) | ||||
|     - Added "script -scriptwire | ||||
|     - Added "script -scriptwire" | ||||
|     - Added "synth_xilinx -nocarry" | ||||
|     - Added "synth_xilinx -nowidelut" | ||||
|     - Added "synth_ecp5 -nowidelut" | ||||
|     - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable) | ||||
|     - Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram) | ||||
|     - Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram) | ||||
|  | @ -23,37 +26,142 @@ Yosys 0.9 .. Yosys 0.9-dev | |||
|     - Added automatic gzip compression (based on filename extension) for backends | ||||
|     - Improve attribute and parameter encoding in JSON to avoid ambiguities between | ||||
|       bit vectors and strings containing [01xz]* | ||||
|     - Added "clkbufmap" pass | ||||
|     - Added "extractinv" pass and "invertible_pin" attribute | ||||
|     - Added "synth_xilinx -family xc6s" for Spartan 6 support (experimental) | ||||
|     - Added "synth_xilinx -ise" (experimental) | ||||
|     - Added "synth_xilinx -iopad" | ||||
|     - "synth_xilinx" now automatically inserts clock buffers (add -noclkbuf to disable) | ||||
|     - Improvements in pmgen: subpattern and recursive matches | ||||
|     - Added "opt_share" pass, run as part of "opt -full" | ||||
|     - Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping | ||||
|     - Removed "ice40_unlut" | ||||
|     - Improvements in pmgen: slices, choices, define, generate | ||||
|     - Added "xilinx_srl" for Xilinx shift register extraction | ||||
|     - Removed "shregmap -tech xilinx" (superseded by "xilinx_srl") | ||||
|     - Added "_TECHMAP_WIREINIT_*_" attribute and "_TECHMAP_REMOVEINIT_*_" wire for "techmap" pass | ||||
|     - Added "-match-init" option to "dff2dffs" pass | ||||
|     - Added "techmap_autopurge" support to techmap | ||||
|     - Added "add -mod <modname[s]>" | ||||
| 
 | ||||
| Yosys 0.8 .. Yosys 0.8-dev | ||||
| -------------------------- | ||||
| Yosys 0.8 .. Yosys 0.9 | ||||
| ---------------------- | ||||
| 
 | ||||
|  * Various | ||||
|     - Added $changed support to read_verilog | ||||
|     - Many bugfixes and small improvements | ||||
|     - Added support for SystemVerilog interfaces and modports | ||||
|     - Added "write_edif -attrprop" | ||||
|     - Added "ice40_unlut" pass | ||||
|     - Added "opt_lut" pass | ||||
|     - Added "synth_ice40 -relut" | ||||
|     - Added "synth_ice40 -noabc" | ||||
|     - Added "gate2lut.v" techmap rule | ||||
|     - Added "rename -src" | ||||
|     - Added "equiv_opt" pass | ||||
|     - Added "shregmap -tech xilinx" | ||||
|     - Added "flowmap" LUT mapping pass | ||||
|     - Added "rename -wire" to rename cells based on the wires they drive | ||||
|     - Added "bugpoint" for creating minimised testcases | ||||
|     - Added "write_edif -gndvccy" | ||||
|     - "write_verilog" to escape Verilog keywords | ||||
|     - Fixed sign handling of real constants | ||||
|     - "write_verilog" to write initial statement for initial flop state | ||||
|     - Added pmgen pattern matcher generator | ||||
|     - Fixed opt_rmdff handling of $_DFFSR_???_ and $_DLATCHSR_???_ | ||||
|     - Added "setundef -params" to replace undefined cell parameters | ||||
|     - Renamed "yosys -D" to "yosys -U", added "yosys -D" to set Verilog defines | ||||
|     - Fixed handling of defparam when default_nettype is none | ||||
|     - Fixed "wreduce" flipflop handling | ||||
|     - Fixed FIRRTL to Verilog process instance subfield assignment | ||||
|     - Added "write_verilog -siminit" | ||||
|     - Several fixes and improvements for mem2reg memories | ||||
|     - Fixed handling of task output ports in clocked always blocks | ||||
|     - Improved handling of and-with-1 and or-with-0 in "opt_expr" | ||||
|     - Added "read_aiger" frontend | ||||
|     - Added "mutate" pass | ||||
|     - Added "hdlname" attribute | ||||
|     - Added "rename -output" | ||||
|     - Added "read_ilang -lib" | ||||
|     - Improved "proc" full_case detection and handling | ||||
|     - Added "whitebox" and "lib_whitebox" attributes | ||||
|     - Added "read_verilog -nowb", "flatten -wb" and "wbflip" | ||||
|     - Added Python bindings and support for Python plug-ins | ||||
|     - Added "pmux2shiftx" | ||||
|     - Added log_debug framework for reduced default verbosity | ||||
|     - Improved "opt_expr" and "opt_clean" handling of (partially) undriven and/or unused wires | ||||
|     - Added "peepopt" peephole optimisation pass using pmgen | ||||
|     - Added approximate support for SystemVerilog "var" keyword | ||||
|     - Added parsing of "specify" blocks into $specrule and $specify[23] | ||||
|     - Added support for attributes on parameters and localparams | ||||
|     - Added support for parsing attributes on port connections | ||||
|     - Added "wreduce -keepdc" | ||||
|     - Added support for optimising $dffe and $_DFFE_* cells in "opt_rmdff" | ||||
|     - Added Verilog wand/wor wire type support | ||||
|     - Added support for elaboration system tasks | ||||
|     - Added "muxcover -mux{4,8,16}=<cost>" | ||||
|     - Added "muxcover -dmux=<cost>" | ||||
|     - Added "muxcover -nopartial" | ||||
|     - Added "muxpack" pass | ||||
|     - Added "pmux2shiftx -norange" | ||||
|     - Added support for "~" in filename parsing | ||||
|     - Added "read_verilog -pwires" feature to turn parameters into wires | ||||
|     - Fixed sign extension of unsized constants with 'bx and 'bz MSB | ||||
|     - Fixed genvar to be a signed type | ||||
|     - Added support for attributes on case rules | ||||
|     - Added "upto" and "offset" to JSON frontend and backend | ||||
|     - Several liberty file parser improvements | ||||
|     - Fixed handling of more complex BRAM patterns | ||||
|     - Add "write_aiger -I -O -B" | ||||
| 
 | ||||
|  * Formal Verification | ||||
|     - Added $changed support to read_verilog | ||||
|     - Added "read_verilog -noassert -noassume -assert-assumes" | ||||
|     - Added btor ops for $mul, $div, $mod and $concat | ||||
|     - Added yosys-smtbmc support for btor witnesses | ||||
|     - Added "supercover" pass | ||||
|     - Fixed $global_clock handling vs autowire | ||||
|     - Added $dffsr support to "async2sync" | ||||
|     - Added "fmcombine" pass | ||||
|     - Added memory init support in "write_btor" | ||||
|     - Added "cutpoint" pass | ||||
|     - Changed "ne" to "neq" in btor2 output | ||||
|     - Added support for SVA "final" keyword | ||||
|     - Added "fmcombine -initeq -anyeq" | ||||
|     - Added timescale and generated-by header to yosys-smtbmc vcd output | ||||
|     - Improved BTOR2 handling of undriven wires | ||||
| 
 | ||||
|  * Verific support | ||||
|     - Enabled Verific flags vhdl_support_variable_slice and veri_elaborate_top_level_modules_having_interface_ports | ||||
|     - Improved support for asymmetric memories | ||||
|     - Added "verific -chparam" | ||||
|     - Fixed "verific -extnets" for more complex situations | ||||
|     - Added "read -verific" and "read -noverific" | ||||
|     - Added "hierarchy -chparam" | ||||
| 
 | ||||
|  * New back-ends | ||||
|     - Added initial Anlogic support | ||||
|     - Added initial SmartFusion2 and IGLOO2 support | ||||
| 
 | ||||
|  * ECP5 support | ||||
|     - Added "synth_ecp5 -nowidelut" | ||||
|     - Added BRAM inference support to "synth_ecp5" | ||||
|     - Added support for transforming Diamond IO and flipflop primitives | ||||
| 
 | ||||
|  * iCE40 support | ||||
|     - Added "ice40_unlut" pass | ||||
|     - Added "synth_ice40 -relut" | ||||
|     - Added "synth_ice40 -noabc" | ||||
|     - Added "synth_ice40 -dffe_min_ce_use" | ||||
|     - Added DSP inference support using pmgen | ||||
|     - Added support for initialising BRAM primitives from a file | ||||
|     - Added iCE40 Ultra RGB LED driver cells | ||||
| 
 | ||||
|  * Xilinx support | ||||
|     - Use "write_edif -pvector bra" for Xilinx EDIF files | ||||
|     - Fixes for VPR place and route support with "synth_xilinx" | ||||
|     - Added more cell simulation models | ||||
|     - Added "synth_xilinx -family" | ||||
|     - Added "stat -tech xilinx" to estimate logic cell usage | ||||
|     - Added "synth_xilinx -nocarry" | ||||
|     - Added "synth_xilinx -nowidelut" | ||||
|     - Added "synth_ecp5 -nowidelut" | ||||
|     - "synth_xilinx" to now infer hard shift registers (-nosrl to disable) | ||||
|     - Fixed sign extension of unsized constants with 'bx and 'bz MSB | ||||
| 
 | ||||
|     - Added support for mapping RAM32X1D | ||||
| 
 | ||||
| Yosys 0.7 .. Yosys 0.8 | ||||
| ---------------------- | ||||
|  |  | |||
							
								
								
									
										2
									
								
								COPYING
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								COPYING
									
										
									
									
									
								
							|  | @ -1,4 +1,4 @@ | |||
| Copyright (C) 2012 - 2018  Clifford Wolf <clifford@clifford.at> | ||||
| Copyright (C) 2012 - 2019  Clifford Wolf <clifford@clifford.at> | ||||
| 
 | ||||
| Permission to use, copy, modify, and/or distribute this software for any | ||||
| purpose with or without fee is hereby granted, provided that the above | ||||
|  |  | |||
|  | @ -390,6 +390,7 @@ Finally run all tests with "make config-{clang,gcc,gcc-4.8}": | |||
| Release: | ||||
| 
 | ||||
| 	- set YOSYS_VER to x.y.z in Makefile | ||||
| 	- remove "bumpversion" target from Makefile | ||||
| 	- update version string in CHANGELOG | ||||
| 	git commit -am "Yosys x.y.z" | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										14
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -88,11 +88,13 @@ ifeq ($(OS), Darwin) | |||
| PLUGIN_LDFLAGS += -undefined dynamic_lookup | ||||
| 
 | ||||
| # homebrew search paths
 | ||||
| ifneq ($(shell which brew),) | ||||
| ifneq ($(shell :; command -v brew),) | ||||
| BREW_PREFIX := $(shell brew --prefix)/opt | ||||
| $(info $$BREW_PREFIX is [${BREW_PREFIX}]) | ||||
| ifeq ($(ENABLE_PYOSYS),1) | ||||
| CXXFLAGS += -I$(BREW_PREFIX)/boost/include/boost | ||||
| LDFLAGS += -L$(BREW_PREFIX)/boost/lib | ||||
| endif | ||||
| CXXFLAGS += -I$(BREW_PREFIX)/readline/include | ||||
| LDFLAGS += -L$(BREW_PREFIX)/readline/lib | ||||
| PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH) | ||||
|  | @ -100,8 +102,8 @@ PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) | |||
| export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) | ||||
| 
 | ||||
| # macports search paths
 | ||||
| else ifneq ($(shell which port),) | ||||
| PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port)) | ||||
| else ifneq ($(shell :; command -v port),) | ||||
| PORT_PREFIX := $(patsubst %/bin/port,%,$(shell :; command -v port)) | ||||
| CXXFLAGS += -I$(PORT_PREFIX)/include | ||||
| LDFLAGS += -L$(PORT_PREFIX)/lib | ||||
| PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH) | ||||
|  | @ -113,10 +115,13 @@ LDFLAGS += -rdynamic | |||
| LDLIBS += -lrt | ||||
| endif | ||||
| 
 | ||||
| YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; }) | ||||
| YOSYS_VER := 0.9+431 | ||||
| GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) | ||||
| OBJS = kernel/version_$(GIT_REV).o | ||||
| 
 | ||||
| bumpversion: | ||||
| 	sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 8a4c6e6.. | wc -l`/;" Makefile | ||||
| 
 | ||||
| # set 'ABCREV = default' to use abc/ as it is
 | ||||
| #
 | ||||
| # Note: If you do ABC development, make sure that 'abc' in this directory
 | ||||
|  | @ -704,6 +709,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) | |||
| 	+cd tests/opt && bash run-test.sh | ||||
| 	+cd tests/aiger && bash run-test.sh $(ABCOPT) | ||||
| 	+cd tests/arch && bash run-test.sh | ||||
| 	+cd tests/ice40 && bash run-test.sh $(SEEDOPT) | ||||
| 	@echo "" | ||||
| 	@echo "  Passed \"make test\"." | ||||
| 	@echo "" | ||||
|  |  | |||
							
								
								
									
										59
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,7 +1,7 @@ | |||
| ``` | ||||
| yosys -- Yosys Open SYnthesis Suite | ||||
| 
 | ||||
| Copyright (C) 2012 - 2018  Clifford Wolf <clifford@clifford.at> | ||||
| Copyright (C) 2012 - 2019  Clifford Wolf <clifford@clifford.at> | ||||
| 
 | ||||
| Permission to use, copy, modify, and/or distribute this software for any | ||||
| purpose with or without fee is hereby granted, provided that the above | ||||
|  | @ -69,11 +69,14 @@ prerequisites for building yosys: | |||
| 		graphviz xdot pkg-config python3 libboost-system-dev \ | ||||
| 		libboost-python-dev libboost-filesystem-dev zlib1g-dev | ||||
| 
 | ||||
| Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: | ||||
| Similarily, on Mac OS X Homebrew can be used to install dependencies: | ||||
| 
 | ||||
| 	$ brew tap Homebrew/bundle && brew bundle | ||||
| 
 | ||||
| or MacPorts: | ||||
| 
 | ||||
| 	$ sudo port install bison flex readline gawk libffi \ | ||||
| 		git graphviz pkgconfig python36 boost zlib | ||||
| 		git graphviz pkgconfig python36 boost zlib tcl | ||||
| 
 | ||||
| On FreeBSD use the following command to install all prerequisites: | ||||
| 
 | ||||
|  | @ -327,7 +330,46 @@ Verilog Attributes and non-standard features | |||
| 
 | ||||
| - The ``parameter`` and ``localparam`` attributes are used to mark wires | ||||
|   that represent module parameters or localparams (when the HDL front-end | ||||
|   is run in -pwires mode). | ||||
|   is run in ``-pwires`` mode). | ||||
| 
 | ||||
| - Wires marked with the ``hierconn`` attribute are connected to wires with the | ||||
|   same name (format ``cell_name.identifier``) when they are imported from | ||||
|   sub-modules by ``flatten``. | ||||
| 
 | ||||
| - The ``clkbuf_driver`` attribute can be set on an output port of a blackbox | ||||
|   module to mark it as a clock buffer output, and thus prevent ``clkbufmap`` | ||||
|   from inserting another clock buffer on a net driven by such output. | ||||
| 
 | ||||
| - The ``clkbuf_sink`` attribute can be set on an input port of a module to | ||||
|   request clock buffer insertion by the ``clkbufmap`` pass. | ||||
| 
 | ||||
| - The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent | ||||
|   automatic clock buffer insertion by ``clkbufmap``. This behaviour can be | ||||
|   overridden by providing a custom selection to ``clkbufmap``. | ||||
| 
 | ||||
| - The ``invertible_pin`` attribute can be set on a port to mark it as | ||||
|   invertible via a cell parameter.  The name of the inversion parameter | ||||
|   is specified as the value of this attribute.  The value of the inversion | ||||
|   parameter must be of the same width as the port, with 1 indicating | ||||
|   an inverted bit and 0 indicating a non-inverted bit. | ||||
| 
 | ||||
| - The ``iopad_external_pin`` attribute on a blackbox module's port marks | ||||
|   it as the external-facing pin of an I/O pad, and prevents ``iopadmap`` | ||||
|   from inserting another pad cell on it. | ||||
| 
 | ||||
| - The module attribute ``abc_box_id`` specifies a positive integer linking a | ||||
|   blackbox or whitebox definition to a corresponding entry in a `abc9` | ||||
|   box-file. | ||||
| 
 | ||||
| - The port attribute ``abc_carry`` marks the carry-in (if an input port) and | ||||
|   carry-out (if output port) ports of a box. This information is necessary for | ||||
|   `abc9` to preserve the integrity of carry-chains. Specifying this attribute | ||||
|   onto a bus port will affect only its most significant bit. | ||||
| 
 | ||||
| - The port attribute ``abc_arrival`` specifies an integer (for output ports | ||||
|   only) to be used as the arrival time of this sequential port. It can be used, | ||||
|   for example, to specify the clk-to-Q delay of a flip-flop for consideration | ||||
|   during techmapping. | ||||
| 
 | ||||
| - In addition to the ``(* ... *)`` attribute syntax, Yosys supports | ||||
|   the non-standard ``{* ... *}`` attribute syntax to set default attributes | ||||
|  | @ -405,15 +447,6 @@ Verilog Attributes and non-standard features | |||
|   blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this | ||||
|   functionality. (By default specify .. endspecify blocks are ignored.) | ||||
| 
 | ||||
| - The module attribute ``abc_box_id`` specifies a positive integer linking a | ||||
|   blackbox or whitebox definition to a corresponding entry in a `abc9` | ||||
|   box-file. | ||||
| 
 | ||||
| - The port attribute ``abc_carry`` marks the carry-in (if an input port) and | ||||
|   carry-out (if output port) ports of a box. This information is necessary for | ||||
|   `abc9` to preserve the integrity of carry-chains. Specifying this attribute | ||||
|   onto a bus port will affect only its most significant bit. | ||||
| 
 | ||||
| 
 | ||||
| Non-standard or SystemVerilog features for formal verification | ||||
| ============================================================== | ||||
|  |  | |||
|  | @ -101,7 +101,7 @@ struct AigerWriter | |||
| 		return a; | ||||
| 	} | ||||
| 
 | ||||
| 	AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module) | ||||
| 	AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module) | ||||
| 	{ | ||||
| 		pool<SigBit> undriven_bits; | ||||
| 		pool<SigBit> unused_bits; | ||||
|  | @ -367,6 +367,12 @@ struct AigerWriter | |||
| 				aig_latchin.push_back(a); | ||||
| 		} | ||||
| 
 | ||||
| 		if (lmode && aig_l == 0) { | ||||
| 			aig_m++, aig_l++; | ||||
| 			aig_latchinit.push_back(0); | ||||
| 			aig_latchin.push_back(0); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!initstate_bits.empty() || !init_inputs.empty()) | ||||
| 			aig_latchin.push_back(1); | ||||
| 
 | ||||
|  | @ -704,9 +710,9 @@ struct AigerBackend : public Backend { | |||
| 		log("    -vmap <filename>\n"); | ||||
| 		log("        like -map, but more verbose\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -I, -O, -B\n"); | ||||
| 		log("        If the design contains no input/output/assert then create one\n"); | ||||
| 		log("        dummy input/output/bad_state pin to make the tools reading the\n"); | ||||
| 		log("    -I, -O, -B, -L\n"); | ||||
| 		log("        If the design contains no input/output/assert/flip-flop then create one\n"); | ||||
| 		log("        dummy input/output/bad_state-pin or latch to make the tools reading the\n"); | ||||
| 		log("        AIGER file happy.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
|  | @ -720,6 +726,7 @@ struct AigerBackend : public Backend { | |||
| 		bool imode = false; | ||||
| 		bool omode = false; | ||||
| 		bool bmode = false; | ||||
| 		bool lmode = false; | ||||
| 		std::string map_filename; | ||||
| 
 | ||||
| 		log_header(design, "Executing AIGER backend.\n"); | ||||
|  | @ -764,6 +771,10 @@ struct AigerBackend : public Backend { | |||
| 				bmode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-L") { | ||||
| 				lmode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(f, filename, args, argidx); | ||||
|  | @ -773,7 +784,7 @@ struct AigerBackend : public Backend { | |||
| 		if (top_module == nullptr) | ||||
| 			log_error("Can't find top module in current design!\n"); | ||||
| 
 | ||||
| 		AigerWriter writer(top_module, zinit_mode, imode, omode, bmode); | ||||
| 		AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode); | ||||
| 		writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); | ||||
| 
 | ||||
| 		if (!map_filename.empty()) { | ||||
|  |  | |||
|  | @ -345,12 +345,12 @@ struct XAigerWriter | |||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				bool cell_known = inst_module; | ||||
| 				bool cell_known = inst_module || cell->known(); | ||||
| 				for (const auto &c : cell->connections()) { | ||||
| 					if (c.second.is_fully_const()) continue; | ||||
| 					auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr; | ||||
| 					auto is_input = !cell_known || port_wire->port_input; | ||||
| 					auto is_output = !cell_known || port_wire->port_output; | ||||
| 					auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first); | ||||
| 					auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first); | ||||
| 					if (!is_input && !is_output) | ||||
| 						log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); | ||||
| 
 | ||||
|  | @ -653,6 +653,11 @@ struct XAigerWriter | |||
| 			aig_outputs.push_back(bit2aig(bit)); | ||||
| 		} | ||||
| 
 | ||||
| 		if (output_bits.empty()) { | ||||
| 			output_bits.insert(State::S0); | ||||
| 			omode = true; | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto bit : output_bits) { | ||||
| 			ordered_outputs[bit] = aig_o++; | ||||
| 			aig_outputs.push_back(bit2aig(bit)); | ||||
|  | @ -749,6 +754,7 @@ struct XAigerWriter | |||
| 
 | ||||
| 		f << "c"; | ||||
| 
 | ||||
| 		log_assert(!output_bits.empty()); | ||||
| 		auto write_buffer = [](std::stringstream &buffer, int i32) { | ||||
| 			int32_t i32_be = to_big_endian(i32); | ||||
| 			buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); | ||||
|  | @ -1024,6 +1030,8 @@ struct XAigerWriter | |||
| 			f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); | ||||
| 
 | ||||
| 		output_lines.sort(); | ||||
| 		if (omode) | ||||
| 			output_lines[State::S0] = "output 0 0 $__dummy__\n"; | ||||
| 		for (auto &it : output_lines) | ||||
| 			f << it.second; | ||||
| 		log_assert(output_lines.size() == output_bits.size()); | ||||
|  |  | |||
|  | @ -685,7 +685,7 @@ struct BtorWorker | |||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					int nid_init_val = next_nid++; | ||||
| 					nid_init_val = next_nid++; | ||||
| 					btorf("%d state %d\n", nid_init_val, sid); | ||||
| 
 | ||||
| 					for (int i = 0; i < nwords; i++) { | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ yosys-smtbmc-script.py: backends/smt2/smtbmc.py | |||
| 		-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ | ||||
| 
 | ||||
| yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py | ||||
| 	$(P) gcc -DGUI=0 -O -s -o $@ $< | ||||
| 	$(P) $(CXX) -DGUI=0 -O -s -o $@ $< | ||||
| # Other targets
 | ||||
| else | ||||
| TARGETS += yosys-smtbmc | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| read_verilog example.v | ||||
| synth_xilinx -top example -family xc6s | ||||
| iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I | ||||
| synth_xilinx -top example -family xc6s -ise | ||||
| write_edif -pvector bra example.edif | ||||
|  |  | |||
|  | @ -158,6 +158,11 @@ std::string AST::type2str(AstNodeType type) | |||
| 	X(AST_POSEDGE) | ||||
| 	X(AST_NEGEDGE) | ||||
| 	X(AST_EDGE) | ||||
| 	X(AST_INTERFACE) | ||||
| 	X(AST_INTERFACEPORT) | ||||
| 	X(AST_INTERFACEPORTTYPE) | ||||
| 	X(AST_MODPORT) | ||||
| 	X(AST_MODPORTMEMBER) | ||||
| 	X(AST_PACKAGE) | ||||
| #undef X | ||||
| 	default: | ||||
|  | @ -1099,6 +1104,13 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 
 | ||||
| 		ignoreThisSignalsInInitial = RTLIL::SigSpec(); | ||||
| 	} | ||||
| 	else { | ||||
| 		for (auto &attr : ast->attributes) { | ||||
| 			if (attr.second->type != AST_CONSTANT) | ||||
| 				continue; | ||||
| 			current_module->attributes[attr.first] = attr.second->asAttrConst(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ast->type == AST_INTERFACE) | ||||
| 		current_module->set_bool_attribute("\\is_interface"); | ||||
|  | @ -1284,6 +1296,8 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule | |||
| // from AST. The interface members are copied into the AST module with the prefix of the interface.
 | ||||
| void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces) | ||||
| { | ||||
| 	loadconfig(); | ||||
| 
 | ||||
| 	bool is_top = false; | ||||
| 	AstNode *new_ast = ast->clone(); | ||||
| 	for (auto &intf : local_interfaces) { | ||||
|  | @ -1467,24 +1481,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString | |||
| 		stripped_name = stripped_name.substr(9); | ||||
| 
 | ||||
| 	log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); | ||||
| 
 | ||||
| 	current_ast = NULL; | ||||
| 	flag_dump_ast1 = false; | ||||
| 	flag_dump_ast2 = false; | ||||
| 	flag_dump_vlog1 = false; | ||||
| 	flag_dump_vlog2 = false; | ||||
| 	flag_nolatches = nolatches; | ||||
| 	flag_nomeminit = nomeminit; | ||||
| 	flag_nomem2reg = nomem2reg; | ||||
| 	flag_mem2reg = mem2reg; | ||||
| 	flag_noblackbox = noblackbox; | ||||
| 	flag_lib = lib; | ||||
| 	flag_nowb = nowb; | ||||
| 	flag_noopt = noopt; | ||||
| 	flag_icells = icells; | ||||
| 	flag_pwires = pwires; | ||||
| 	flag_autowire = autowire; | ||||
| 	use_internal_line_num(); | ||||
| 	loadconfig(); | ||||
| 
 | ||||
| 	std::string para_info; | ||||
| 	AstNode *new_ast = ast->clone(); | ||||
|  | @ -1565,6 +1562,27 @@ RTLIL::Module *AstModule::clone() const | |||
| 	return new_mod; | ||||
| } | ||||
| 
 | ||||
| void AstModule::loadconfig() const | ||||
| { | ||||
| 	current_ast = NULL; | ||||
| 	flag_dump_ast1 = false; | ||||
| 	flag_dump_ast2 = false; | ||||
| 	flag_dump_vlog1 = false; | ||||
| 	flag_dump_vlog2 = false; | ||||
| 	flag_nolatches = nolatches; | ||||
| 	flag_nomeminit = nomeminit; | ||||
| 	flag_nomem2reg = nomem2reg; | ||||
| 	flag_mem2reg = mem2reg; | ||||
| 	flag_noblackbox = noblackbox; | ||||
| 	flag_lib = lib; | ||||
| 	flag_nowb = nowb; | ||||
| 	flag_noopt = noopt; | ||||
| 	flag_icells = icells; | ||||
| 	flag_pwires = pwires; | ||||
| 	flag_autowire = autowire; | ||||
| 	use_internal_line_num(); | ||||
| } | ||||
| 
 | ||||
| // internal dummy line number callbacks
 | ||||
| namespace { | ||||
| 	int internal_line_num; | ||||
|  |  | |||
|  | @ -299,6 +299,7 @@ namespace AST | |||
| 		std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail); | ||||
| 		void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE; | ||||
| 		RTLIL::Module *clone() const YS_OVERRIDE; | ||||
| 		void loadconfig() const; | ||||
| 	}; | ||||
| 
 | ||||
| 	// this must be set by the language frontend before parsing the sources
 | ||||
|  |  | |||
|  | @ -150,6 +150,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | |||
| 					reg->str = stringf("%s[%d]", node->str.c_str(), i); | ||||
| 					reg->is_reg = true; | ||||
| 					reg->is_signed = node->is_signed; | ||||
| 					for (auto &it : node->attributes) | ||||
| 						if (it.first != ID(mem2reg)) | ||||
| 							reg->attributes.emplace(it.first, it.second->clone()); | ||||
| 					reg->filename = node->filename; | ||||
| 					reg->linenum = node->linenum; | ||||
| 					children.push_back(reg); | ||||
| 					while (reg->simplify(true, false, false, 1, -1, false, false)) { } | ||||
| 				} | ||||
|  | @ -1525,10 +1530,16 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 		current_scope[wire_en->str] = wire_en; | ||||
| 		while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } | ||||
| 
 | ||||
| 		AstNode *check_defval; | ||||
| 		if (type == AST_LIVE || type == AST_FAIR) { | ||||
| 			check_defval = new AstNode(AST_REDUCE_BOOL, children[0]->clone()); | ||||
| 		} else { | ||||
| 			std::vector<RTLIL::State> x_bit; | ||||
| 			x_bit.push_back(RTLIL::State::Sx); | ||||
| 			check_defval = mkconst_bits(x_bit, false); | ||||
| 		} | ||||
| 
 | ||||
| 		AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); | ||||
| 		AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), check_defval); | ||||
| 		assign_check->children[0]->str = id_check; | ||||
| 		assign_check->children[0]->was_checked = true; | ||||
| 
 | ||||
|  | @ -1541,9 +1552,13 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 		default_signals->children.push_back(assign_en); | ||||
| 		current_top_block->children.insert(current_top_block->children.begin(), default_signals); | ||||
| 
 | ||||
| 		if (type == AST_LIVE || type == AST_FAIR) { | ||||
| 			assign_check = nullptr; | ||||
| 		} else { | ||||
| 			assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); | ||||
| 			assign_check->children[0]->str = id_check; | ||||
| 			assign_check->children[0]->was_checked = true; | ||||
| 		} | ||||
| 
 | ||||
| 		if (current_always == nullptr || current_always->type != AST_INITIAL) { | ||||
| 			assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); | ||||
|  | @ -1555,6 +1570,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 		assign_en->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		newNode = new AstNode(AST_BLOCK); | ||||
| 		if (assign_check != nullptr) | ||||
| 			newNode->children.push_back(assign_check); | ||||
| 		newNode->children.push_back(assign_en); | ||||
| 
 | ||||
|  | @ -2879,8 +2895,15 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m | |||
| void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map) | ||||
| { | ||||
| 	if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) { | ||||
| 		if (children.empty()) { | ||||
| 			current_scope[index_var]->children[0]->cloneInto(this); | ||||
| 		return; | ||||
| 		} else { | ||||
| 			AstNode *p = new AstNode(AST_LOCALPARAM, current_scope[index_var]->children[0]->clone()); | ||||
| 			p->str = stringf("$genval$%d", autoidx++); | ||||
| 			current_ast_mod->children.push_back(p); | ||||
| 			str = p->str; | ||||
| 			id2ast = p; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) | ||||
|  |  | |||
|  | @ -85,10 +85,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le | |||
| 			digits.push_back(10 + *str - 'A'); | ||||
| 		else if (*str == 'x' || *str == 'X') | ||||
| 			digits.push_back(0xf0); | ||||
| 		else if (*str == 'z' || *str == 'Z') | ||||
| 		else if (*str == 'z' || *str == 'Z' || *str == '?') | ||||
| 			digits.push_back(0xf1); | ||||
| 		else if (*str == '?') | ||||
| 			digits.push_back(0xf2); | ||||
| 		str++; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -112,8 +110,6 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le | |||
| 					data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); | ||||
| 				else if (*it == 0xf1) | ||||
| 					data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); | ||||
| 				else if (*it == 0xf2) | ||||
| 					data.push_back(RTLIL::Sa); | ||||
| 				else | ||||
| 					data.push_back((*it & bitmask) ? State::S1 : State::S0); | ||||
| 			} | ||||
|  | @ -199,13 +195,13 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn | |||
| 	if (str == endptr) | ||||
| 		len_in_bits = -1; | ||||
| 
 | ||||
| 	// The "<bits>'s?[bodhBODH]<digits>" syntax
 | ||||
| 	// The "<bits>'[sS]?[bodhBODH]<digits>" syntax
 | ||||
| 	if (*endptr == '\'') | ||||
| 	{ | ||||
| 		std::vector<RTLIL::State> data; | ||||
| 		bool is_signed = false; | ||||
| 		bool is_unsized = len_in_bits < 0; | ||||
| 		if (*(endptr+1) == 's') { | ||||
| 		if (*(endptr+1) == 's' || *(endptr+1) == 'S') { | ||||
| 			is_signed = true; | ||||
| 			endptr++; | ||||
| 		} | ||||
|  |  | |||
|  | @ -239,7 +239,7 @@ YOSYS_NAMESPACE_END | |||
| 	return TOK_CONSTVAL; | ||||
| } | ||||
| 
 | ||||
| [0-9]*[ \t]*\'s?[bodhBODH]*[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { | ||||
| [0-9]*[ \t]*\'[sS]?[bodhBODH]?[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { | ||||
| 	frontend_verilog_yylval.string = new std::string(yytext); | ||||
| 	return TOK_CONSTVAL; | ||||
| } | ||||
|  |  | |||
|  | @ -48,7 +48,7 @@ using zlib to write gzip-compressed data every time the stream is flushed. | |||
| */ | ||||
| class gzip_ostream : public std::ostream  { | ||||
| public: | ||||
| 	gzip_ostream() | ||||
| 	gzip_ostream() : std::ostream(nullptr) | ||||
| 	{ | ||||
| 		rdbuf(&outbuf); | ||||
| 	} | ||||
|  | @ -71,7 +71,7 @@ private: | |||
| 			str(""); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		~gzip_streambuf() | ||||
| 		virtual ~gzip_streambuf() | ||||
| 		{ | ||||
| 			sync(); | ||||
| 			gzclose(gzf); | ||||
|  | @ -498,7 +498,15 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s | |||
| 			if (f != NULL) { | ||||
| 				// Check for gzip magic
 | ||||
| 				unsigned char magic[3]; | ||||
| 				int n = readsome(*ff, reinterpret_cast<char*>(magic), 3); | ||||
| 				int n = 0; | ||||
| 				while (n < 3) | ||||
| 				{ | ||||
| 					int c = ff->get(); | ||||
| 					if (c != EOF) { | ||||
| 						magic[n] = (unsigned char) c; | ||||
| 					} | ||||
| 					n++; | ||||
| 				} | ||||
| 				if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { | ||||
| 	#ifdef YOSYS_ENABLE_ZLIB | ||||
| 					log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); | ||||
|  |  | |||
|  | @ -135,9 +135,11 @@ struct SigPool | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| template <typename T, class Compare = std::less<T>> | ||||
| template <typename T, class Compare = void> | ||||
| struct SigSet | ||||
| { | ||||
| 	static_assert(!std::is_same<Compare,void>::value, "Default value for `Compare' class not found for SigSet<T>. Please specify."); | ||||
| 
 | ||||
| 	struct bitDef_t : public std::pair<RTLIL::Wire*, int> { | ||||
| 		bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } | ||||
| 		bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } | ||||
|  | @ -220,6 +222,13 @@ struct SigSet | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| template<typename T> | ||||
| class SigSet<T, typename std::enable_if<!std::is_pointer<T>::value>::type> : public SigSet<T, std::less<T>> {}; | ||||
| template<typename T> | ||||
| using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell*>::value>::type; | ||||
| template<typename T> | ||||
| class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {}; | ||||
| 
 | ||||
| struct SigMap | ||||
| { | ||||
| 	mfp<SigBit> database; | ||||
|  |  | |||
|  | @ -129,7 +129,7 @@ void yosys_banner() | |||
| 	log(" |                                                                            |\n"); | ||||
| 	log(" |  yosys -- Yosys Open SYnthesis Suite                                       |\n"); | ||||
| 	log(" |                                                                            |\n"); | ||||
| 	log(" |  Copyright (C) 2012 - 2018  Clifford Wolf <clifford@clifford.at>           |\n"); | ||||
| 	log(" |  Copyright (C) 2012 - 2019  Clifford Wolf <clifford@clifford.at>           |\n"); | ||||
| 	log(" |                                                                            |\n"); | ||||
| 	log(" |  Permission to use, copy, modify, and/or distribute this software for any  |\n"); | ||||
| 	log(" |  purpose with or without fee is hereby granted, provided that the above    |\n"); | ||||
|  |  | |||
|  | @ -65,7 +65,7 @@ SOFTWARE. */ | |||
| 
 | ||||
| int child_pid=0; | ||||
| 
 | ||||
| int fail(char *format, char *data) { | ||||
| int fail(const char *format, const char *data) { | ||||
|     /* Print error message to stderr and return 2 */ | ||||
|     fprintf(stderr, format, data); | ||||
|     return 2; | ||||
|  | @ -76,7 +76,7 @@ char *quoted(char *data) { | |||
| 
 | ||||
|     /* We allocate twice as much space as needed to deal with worse-case
 | ||||
|        of having to escape everything. */ | ||||
|     char *result = calloc(ln*2+3, sizeof(char)); | ||||
|     char *result = (char *)calloc(ln*2+3, sizeof(char)); | ||||
|     char *presult = result; | ||||
| 
 | ||||
|     *presult++ = '"'; | ||||
|  | @ -120,7 +120,7 @@ char *loadable_exe(char *exename) { | |||
|     if (!hPython) return NULL; */ | ||||
| 
 | ||||
|     /* Return the absolute filename for spawnv */ | ||||
|     result = calloc(MAX_PATH, sizeof(char)); | ||||
|     result = (char *)calloc(MAX_PATH, sizeof(char)); | ||||
|     strncpy(result, exename, MAX_PATH); | ||||
|     /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
 | ||||
| 
 | ||||
|  | @ -158,7 +158,7 @@ char **parse_argv(char *cmdline, int *argc) | |||
| { | ||||
|     /* Parse a command line in-place using MS C rules */ | ||||
| 
 | ||||
|     char **result = calloc(strlen(cmdline), sizeof(char *)); | ||||
|     char **result = (char **)calloc(strlen(cmdline), sizeof(char *)); | ||||
|     char *output = cmdline; | ||||
|     char c; | ||||
|     int nb = 0; | ||||
|  |  | |||
|  | @ -508,23 +508,17 @@ class TupleTranslator(PythonDictTranslator): | |||
| 	#Generate c++ code to translate to a boost::python::tuple | ||||
| 	@classmethod | ||||
| 	def translate_cpp(c, varname, types, prefix, ref): | ||||
| 		text  = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + varname + ".first, " + varname + ".second);" | ||||
| 		return text | ||||
| 		tmp_name = "tmp_" + str(Translator.tmp_cntr) | ||||
| 		Translator.tmp_cntr = Translator.tmp_cntr + 1 | ||||
| 		if ref: | ||||
| 			text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" | ||||
| 		# if the tuple is a pair of SigSpecs (aka SigSig), then we need | ||||
| 		# to call get_py_obj() on each item in the tuple | ||||
| 		if types[0].name in classnames: | ||||
| 			first_var = types[0].name + "::get_py_obj(" + varname + ".first)" | ||||
| 		else: | ||||
| 			text += prefix + "for(auto " + tmp_name + " : " + varname + ")" | ||||
| 		text += prefix + "{" | ||||
| 		if types[0].name.split(" ")[-1] in primitive_types or types[0].name in enum_names: | ||||
| 			text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");" | ||||
| 		elif types[0].name in known_containers: | ||||
| 			text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[1].attr_type == attr_types.star) | ||||
| 			text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "___tmp);" | ||||
| 		elif types[0].name in classnames: | ||||
| 			text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));" | ||||
| 		text += prefix + "}" | ||||
| 			first_var = varname + ".first" | ||||
| 		if types[1].name in classnames: | ||||
| 			second_var = types[1].name + "::get_py_obj(" + varname + ".second)" | ||||
| 		else: | ||||
| 			second_var = varname + ".second" | ||||
| 		text  = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");" | ||||
| 		return text | ||||
| 
 | ||||
| #Associate the Translators with their c++ type | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ OBJS += passes/cmds/plugin.o | |||
| OBJS += passes/cmds/check.o | ||||
| OBJS += passes/cmds/qwp.o | ||||
| OBJS += passes/cmds/edgetypes.o | ||||
| OBJS += passes/cmds/portlist.o | ||||
| OBJS += passes/cmds/chformal.o | ||||
| OBJS += passes/cmds/chtype.o | ||||
| OBJS += passes/cmds/blackbox.o | ||||
|  |  | |||
|  | @ -105,6 +105,11 @@ struct AddPass : public Pass { | |||
| 		log("Like 'add -input', but also connect the signal between instances of the\n"); | ||||
| 		log("selected modules.\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("    add -mod <name[s]>\n"); | ||||
| 		log("\n"); | ||||
| 		log("Add module[s] with the specified name[s].\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
|  | @ -113,6 +118,7 @@ struct AddPass : public Pass { | |||
| 		bool arg_flag_input = false; | ||||
| 		bool arg_flag_output = false; | ||||
| 		bool arg_flag_global = false; | ||||
| 		bool mod_mode = false; | ||||
| 		int arg_width = 0; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
|  | @ -133,8 +139,20 @@ struct AddPass : public Pass { | |||
| 				arg_width = atoi(args[++argidx].c_str()); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-mod") { | ||||
| 				mod_mode = true; | ||||
| 				argidx++; | ||||
| 				break; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (mod_mode) { | ||||
| 			for (; argidx < args.size(); argidx++) | ||||
| 				design->addModule(RTLIL::escape_id(args[argidx])); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (auto &mod : design->modules_) | ||||
|  |  | |||
							
								
								
									
										93
									
								
								passes/cmds/portlist.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								passes/cmds/portlist.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,93 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct PortlistPass : public Pass { | ||||
| 	PortlistPass() : Pass("portlist", "list (top-level) ports") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    portlist [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This command lists all module ports found in the selected modules.\n"); | ||||
| 		log("\n"); | ||||
| 		log("If no selection is provided then it lists the ports on the top module.\n"); | ||||
| 		log("\n"); | ||||
| 		log("  -m\n"); | ||||
| 		log("    print verilog blackbox module definitions instead of port lists\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		bool m_mode = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||
| 			if (args[argidx] == "-m") { | ||||
| 				m_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		bool first_module = true; | ||||
| 
 | ||||
| 		auto handle_module = [&](RTLIL::Module *module) { | ||||
| 			vector<string> ports; | ||||
| 			if (first_module) | ||||
| 				first_module = false; | ||||
| 			else | ||||
| 				log("\n"); | ||||
| 			for (auto port : module->ports) { | ||||
| 				auto *w = module->wire(port); | ||||
| 				ports.push_back(stringf("%s [%d:%d] %s", w->port_input ? w->port_output ? "inout" : "input" : "output", | ||||
| 						w->upto ? w->start_offset : w->start_offset + w->width - 1, | ||||
| 						w->upto ? w->start_offset + w->width - 1 : w->start_offset, | ||||
| 						log_id(w))); | ||||
| 			} | ||||
| 			log("module %s%s\n", log_id(module), m_mode ? " (" : ""); | ||||
| 			for (int i = 0; i < GetSize(ports); i++) | ||||
| 				log("%s%s\n", ports[i].c_str(), m_mode && i+1 < GetSize(ports) ? "," : ""); | ||||
| 			if (m_mode) | ||||
| 				log(");\nendmodule\n"); | ||||
| 		}; | ||||
| 
 | ||||
| 		if (argidx == args.size()) | ||||
| 		{ | ||||
| 			auto *top = design->top_module(); | ||||
| 			if (top == nullptr) | ||||
| 				log_cmd_error("Can't find top module in current design!\n"); | ||||
| 			handle_module(top); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			extra_args(args, argidx, design); | ||||
| 			for (auto module : design->selected_modules()) | ||||
| 				handle_module(module); | ||||
| 		} | ||||
| 	} | ||||
| } PortlistPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -664,7 +664,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg) | |||
| 		} else | ||||
| 		if (arg == "%D") { | ||||
| 			if (work_stack.size() < 2) | ||||
| 				log_cmd_error("Must have at least two elements on the stack for operator %%d.\n"); | ||||
| 				log_cmd_error("Must have at least two elements on the stack for operator %%D.\n"); | ||||
| 			select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]); | ||||
| 			work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1]; | ||||
| 			work_stack.pop_back(); | ||||
|  | @ -693,7 +693,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg) | |||
| 		} else | ||||
| 		if (arg == "%C") { | ||||
| 			if (work_stack.size() < 1) | ||||
| 				log_cmd_error("Must have at least one element on the stack for operator %%M.\n"); | ||||
| 				log_cmd_error("Must have at least one element on the stack for operator %%C.\n"); | ||||
| 			select_op_module_to_cells(design, work_stack[work_stack.size()-1]); | ||||
| 		} else | ||||
| 		if (arg == "%c") { | ||||
|  |  | |||
|  | @ -26,6 +26,10 @@ | |||
| #  include <dirent.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __APPLE__ | ||||
| #  include <unistd.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef YOSYS_ENABLE_READLINE | ||||
| #  include <readline/readline.h> | ||||
| #endif | ||||
|  | @ -866,7 +870,11 @@ struct ShowPass : public Pass { | |||
| 				log_cmd_error("Shell command failed!\n"); | ||||
| 		} else | ||||
| 		if (format.empty()) { | ||||
| 			#ifdef __APPLE__ | ||||
| 			std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str()); | ||||
| 			#else | ||||
| 			std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str()); | ||||
| 			#endif | ||||
| 			log("Exec: %s\n", cmd.c_str()); | ||||
| 			if (run_command(cmd) != 0) | ||||
| 				log_cmd_error("Shell command failed!\n"); | ||||
|  |  | |||
|  | @ -532,10 +532,10 @@ struct EquivMakePass : public Pass { | |||
| 			log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str()); | ||||
| 
 | ||||
| 		if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes()) | ||||
| 			log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); | ||||
| 			log_cmd_error("Gold module contains memories or processes. Run 'memory' or 'proc' respectively.\n"); | ||||
| 
 | ||||
| 		if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes()) | ||||
| 			log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); | ||||
| 			log_cmd_error("Gate module contains memories or processes. Run 'memory' or 'proc' respectively.\n"); | ||||
| 
 | ||||
| 		worker.read_blacklists(); | ||||
| 		worker.read_encfiles(); | ||||
|  |  | |||
|  | @ -46,6 +46,9 @@ struct EquivOptPass:public ScriptPass | |||
| 		log("    -assert\n"); | ||||
| 		log("        produce an error if the circuits are not equivalent.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -multiclock\n"); | ||||
| 		log("        run clk2fflogic before equivalence checking.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -undef\n"); | ||||
| 		log("        enable modelling of undef states during equiv_induct.\n"); | ||||
| 		log("\n"); | ||||
|  | @ -55,7 +58,7 @@ struct EquivOptPass:public ScriptPass | |||
| 	} | ||||
| 
 | ||||
| 	std::string command, techmap_opts; | ||||
| 	bool assert, undef; | ||||
| 	bool assert, undef, multiclock; | ||||
| 
 | ||||
| 	void clear_flags() YS_OVERRIDE | ||||
| 	{ | ||||
|  | @ -63,6 +66,7 @@ struct EquivOptPass:public ScriptPass | |||
| 		techmap_opts = ""; | ||||
| 		assert = false; | ||||
| 		undef = false; | ||||
| 		multiclock = false; | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE | ||||
|  | @ -92,6 +96,10 @@ struct EquivOptPass:public ScriptPass | |||
| 				undef = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-multiclock") { | ||||
| 				multiclock = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
|  | @ -146,6 +154,8 @@ struct EquivOptPass:public ScriptPass | |||
| 		} | ||||
| 
 | ||||
| 		if (check_label("prove")) { | ||||
| 			if (multiclock || help_mode) | ||||
| 				run("clk2fflogic", "(only with -multiclock)"); | ||||
| 			run("equiv_make gold gate equiv"); | ||||
| 			if (help_mode) | ||||
| 				run("equiv_induct [-undef] equiv"); | ||||
|  |  | |||
|  | @ -808,6 +808,30 @@ struct HierarchyPass : public Pass { | |||
| 				if (mod_it.second->get_bool_attribute("\\top")) | ||||
| 					top_mod = mod_it.second; | ||||
| 
 | ||||
| 		if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) { | ||||
| 			IdString top_name = top_mod->name.substr(strlen("$abstract")); | ||||
| 
 | ||||
| 			dict<RTLIL::IdString, RTLIL::Const> top_parameters; | ||||
| 			for (auto ¶ : parameters) { | ||||
| 				SigSpec sig_value; | ||||
| 				if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) | ||||
| 					log_cmd_error("Can't decode value '%s'!\n", para.second.c_str()); | ||||
| 				top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); | ||||
| 			} | ||||
| 
 | ||||
| 			top_mod = design->module(top_mod->derive(design, top_parameters)); | ||||
| 
 | ||||
| 			if (top_mod != nullptr && top_mod->name != top_name) { | ||||
| 				Module *m = top_mod->clone(); | ||||
| 				m->name = top_name; | ||||
| 				Module *old_mod = design->module(top_name); | ||||
| 				if (old_mod) | ||||
| 					design->remove(old_mod); | ||||
| 				design->add(m); | ||||
| 				top_mod = m; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (top_mod == nullptr && auto_top_mode) { | ||||
| 			log_header(design, "Finding top of design hierarchy..\n"); | ||||
| 			dict<Module*, int> db; | ||||
|  |  | |||
|  | @ -369,7 +369,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | |||
| 	for (auto cell : module->cells()) | ||||
| 		if (design->selected(module, cell) && cell->type[0] == '$') { | ||||
| 			if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && | ||||
| 					cell->getPort(ID::A).size() == 1 && cell->getPort(ID::Y).size() == 1) | ||||
| 					GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1) | ||||
| 				invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A)); | ||||
| 			if (cell->type.in(ID($mux), ID($_MUX_)) && | ||||
| 					cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0)) | ||||
|  | @ -740,12 +740,34 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | |||
| 				if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) | ||||
| 					replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); | ||||
| 				else | ||||
| 					replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort(ID::Y).size())); | ||||
| 					replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y)))); | ||||
| 				goto next_cell; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && cell->getPort(ID::Y).size() == 1 && | ||||
| 		if (cell->type.in(ID($shiftx), ID($shift))) { | ||||
| 			SigSpec sig_a = assign_map(cell->getPort(ID::A)); | ||||
| 			int width; | ||||
| 			bool trim_x = cell->type == ID($shiftx) || !keepdc; | ||||
| 			bool trim_0 = cell->type == ID($shift); | ||||
| 			for (width = GetSize(sig_a); width > 1; width--) { | ||||
| 				if ((trim_x && sig_a[width-1] == State::Sx) || | ||||
| 					(trim_0 && sig_a[width-1] == State::S0)) | ||||
| 					continue; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			if (width < GetSize(sig_a)) { | ||||
| 				cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str()); | ||||
| 				sig_a.remove(width, GetSize(sig_a)-width); | ||||
| 				cell->setPort(ID::A, sig_a); | ||||
| 				cell->setParam(ID(A_WIDTH), width); | ||||
| 				did_something = true; | ||||
| 				goto next_cell; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 && | ||||
| 				invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { | ||||
| 			cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); | ||||
| 			replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); | ||||
|  | @ -931,6 +953,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | |||
| 			} | ||||
| 
 | ||||
| 			if (b.is_fully_const()) { | ||||
| 				if (b.is_fully_undef()) { | ||||
| 					RTLIL::SigSpec input = b; | ||||
| 					ACTION_DO(ID::Y, Const(State::Sx, GetSize(cell->getPort(ID::Y)))); | ||||
| 				} else | ||||
| 				if (b.as_bool() == (cell->type == ID($eq))) { | ||||
| 					RTLIL::SigSpec input = b; | ||||
| 					ACTION_DO(ID::Y, cell->getPort(ID::A)); | ||||
|  | @ -1142,7 +1168,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons | |||
| 
 | ||||
| 		if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { | ||||
| 			RTLIL::SigSpec new_a, new_b, new_s; | ||||
| 			int width = cell->getPort(ID::A).size(); | ||||
| 			int width = GetSize(cell->getPort(ID::A)); | ||||
| 			if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || | ||||
| 					cell->getPort(ID(S)).is_fully_undef()) { | ||||
| 				cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); | ||||
|  |  | |||
|  | @ -108,12 +108,13 @@ bool cell_supported(RTLIL::Cell *cell) | |||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| std::map<IdString, IdString> mergeable_type_map{ | ||||
|   {ID($sub), ID($add)}, | ||||
| }; | ||||
| std::map<IdString, IdString> mergeable_type_map; | ||||
| 
 | ||||
| bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b) | ||||
| { | ||||
| 	if (mergeable_type_map.empty()) { | ||||
| 		mergeable_type_map.insert({ID($sub), ID($add)}); | ||||
| 	} | ||||
| 	auto a_type = a->type; | ||||
| 	if (mergeable_type_map.count(a_type)) | ||||
| 		a_type = mergeable_type_map.at(a_type); | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| # --------------------------------------
 | ||||
| 
 | ||||
| OBJS += passes/pmgen/test_pmgen.o | ||||
| passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h | ||||
| passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h passes/pmgen/xilinx_srl_pm.h | ||||
| $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
|  | @ -17,7 +17,7 @@ $(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h)) | |||
| 
 | ||||
| OBJS += passes/pmgen/ice40_wrapcarry.o | ||||
| passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h | ||||
| $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) | ||||
| $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h)) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
|  | @ -27,6 +27,13 @@ $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) | |||
| 
 | ||||
| PEEPOPT_PATTERN  = passes/pmgen/peepopt_shiftmul.pmg | ||||
| PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg | ||||
| PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg | ||||
| 
 | ||||
| passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) | ||||
| 	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| OBJS += passes/pmgen/xilinx_srl.o | ||||
| passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h | ||||
| $(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h)) | ||||
|  |  | |||
|  | @ -178,6 +178,45 @@ evaluates to `false`. | |||
| The `semioptional` statement marks matches that must match if at least one | ||||
| matching cell exists, but if no matching cell exists it is set to `nullptr`. | ||||
| 
 | ||||
| Slices and choices | ||||
| ------------------ | ||||
| 
 | ||||
| Cell matches can contain "slices" and "choices". Slices can be used to | ||||
| create matches for different sections of a cell. For example: | ||||
| 
 | ||||
|     state <int> pmux_slice | ||||
| 
 | ||||
|     match pmux | ||||
|         select pmux->type == $pmux | ||||
|         slice idx GetSize(port(pmux, \S)) | ||||
|         index <SigBit> port(pmux, \S)[idx] === port(eq, \Y) | ||||
| 	set pmux_slice idx | ||||
|     endmatch | ||||
| 
 | ||||
| The first argument to `slice` is the local variable name used to identify the | ||||
| slice. The second argument is the number of slices that should be created for | ||||
| this cell. The `set` statement can be used to copy that index into a state | ||||
| variable so that later matches and/or code blocks can refer to it. | ||||
| 
 | ||||
| A similar mechanism is "choices", where a list of options is given as | ||||
| second argument, and the matcher will iterate over those options: | ||||
| 
 | ||||
|     state <SigSpec> foo bar | ||||
|     state <IdString> eq_ab eq_ba | ||||
| 
 | ||||
|     match eq | ||||
|         select eq->type == $eq | ||||
|         choice <IdString> AB {\A, \B} | ||||
|         define <IdString> BA (AB == \A ? \B : \A) | ||||
|         index <SigSpec> port(eq, AB) === foo | ||||
|         index <SigSpec> port(eq, BA) === bar | ||||
|         set eq_ab AB | ||||
|         set eq_ba BA | ||||
|     generate | ||||
| 
 | ||||
| Notice how `define` can be used to define additional local variables similar | ||||
| to the loop variables defined by `slice` and `choice`. | ||||
| 
 | ||||
| Additional code | ||||
| --------------- | ||||
| 
 | ||||
|  | @ -313,7 +352,7 @@ state variables used to pass arguments. | |||
|     subpattern tail | ||||
|     ... | ||||
| 
 | ||||
| Subpatterns cann be called recursively. | ||||
| Subpatterns can be called recursively. | ||||
| 
 | ||||
| If a `subpattern` statement is preceded by a `fallthrough` statement, this is | ||||
| equivalent to calling the subpattern at the end of the preceding block. | ||||
|  | @ -326,7 +365,7 @@ test-case generation. For example: | |||
| 
 | ||||
|     match mul | ||||
|         ... | ||||
|     generate 10 | ||||
|     generate 10 0 | ||||
|         SigSpec Y = port(ff, \D); | ||||
|         SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); | ||||
|         SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); | ||||
|  | @ -335,8 +374,11 @@ test-case generation. For example: | |||
| 
 | ||||
| The expression `rng(n)` returns a non-negative integer less than `n`. | ||||
| 
 | ||||
| The argument to `generate` is the chance of this generate block being executed | ||||
| when the match block did not match anything, in percent. | ||||
| The first argument to `generate` is the chance of this generate block being | ||||
| executed when the match block did not match anything, in percent. | ||||
| 
 | ||||
| The second argument to `generate` is the chance of this generate block being | ||||
| executed when the match block did match something, in percent. | ||||
| 
 | ||||
| The special statement `finish` can be used within generate blocks to terminate | ||||
| the current pattern matcher run. | ||||
|  |  | |||
|  | @ -64,11 +64,6 @@ void create_ice40_dsp(ice40_dsp_pm &pm) | |||
| 
 | ||||
| 	bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool(); | ||||
| 
 | ||||
| 	if (mul_signed) { | ||||
| 		log("  inference of signed iCE40 DSP arithmetic is currently not supported.\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	log("  replacing $mul with SB_MAC16 cell.\n"); | ||||
| 
 | ||||
| 	Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); | ||||
|  |  | |||
|  | @ -60,6 +60,7 @@ struct PeepoptPass : public Pass { | |||
| 				peepopt_pm pm(module, module->selected_cells()); | ||||
| 				pm.run_shiftmul(); | ||||
| 				pm.run_muldiv(); | ||||
| 				pm.run_dffmux(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										113
									
								
								passes/pmgen/peepopt_dffmux.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								passes/pmgen/peepopt_dffmux.pmg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | |||
| pattern dffmux | ||||
| 
 | ||||
| state <IdString> cemuxAB rstmuxBA | ||||
| state <SigSpec> sigD | ||||
| 
 | ||||
| match dff | ||||
| 	select dff->type == $dff | ||||
| 	select GetSize(port(dff, \D)) > 1 | ||||
| endmatch | ||||
| 
 | ||||
| match rstmux | ||||
| 	select rstmux->type == $mux | ||||
| 	select GetSize(port(rstmux, \Y)) > 1 | ||||
| 	index <SigSpec> port(rstmux, \Y) === port(dff, \D) | ||||
| 	choice <IdString> BA {\B, \A} | ||||
| 	select port(rstmux, BA).is_fully_const() | ||||
| 	set rstmuxBA BA | ||||
| 	optional | ||||
| endmatch | ||||
| 
 | ||||
| code sigD | ||||
| 	if (rstmux) | ||||
| 		sigD = port(rstmux, rstmuxBA == \B ? \A : \B); | ||||
| 	else | ||||
| 		sigD = port(dff, \D); | ||||
| endcode | ||||
| 
 | ||||
| match cemux | ||||
| 	select cemux->type == $mux | ||||
| 	select GetSize(port(cemux, \Y)) > 1 | ||||
| 	index <SigSpec> port(cemux, \Y) === sigD | ||||
| 	choice <IdString> AB {\A, \B} | ||||
| 	index <SigSpec> port(cemux, AB) === port(dff, \Q) | ||||
| 	set cemuxAB AB | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	SigSpec D = port(cemux, cemuxAB == \A ? \B : \A); | ||||
| 	SigSpec Q = port(dff, \Q); | ||||
| 	Const rst; | ||||
| 	if (rstmux) | ||||
| 		rst = port(rstmux, rstmuxBA).as_const(); | ||||
| 	int width = GetSize(D); | ||||
| 
 | ||||
| 	SigSpec &ceA = cemux->connections_.at(\A); | ||||
| 	SigSpec &ceB = cemux->connections_.at(\B); | ||||
| 	SigSpec &ceY = cemux->connections_.at(\Y); | ||||
| 	SigSpec &dffD = dff->connections_.at(\D); | ||||
| 	SigSpec &dffQ = dff->connections_.at(\Q); | ||||
| 
 | ||||
| 	if (D[width-1] == D[width-2]) { | ||||
| 		did_something = true; | ||||
| 
 | ||||
| 		SigBit sign = D[width-1]; | ||||
| 		bool is_signed = sign.wire; | ||||
| 		int i; | ||||
| 		for (i = width-1; i >= 2; i--) { | ||||
| 			if (!is_signed) { | ||||
| 				module->connect(Q[i], sign); | ||||
| 				if (D[i-1] != sign || (rst.size() && rst[i-1] != rst[width-1])) | ||||
| 					break; | ||||
| 			} | ||||
| 			else { | ||||
| 				module->connect(Q[i], Q[i-1]); | ||||
| 				if (D[i-2] != sign || (rst.size() && rst[i-1] != rst[width-1])) | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		ceA.remove(i, width-i); | ||||
| 		ceB.remove(i, width-i); | ||||
| 		ceY.remove(i, width-i); | ||||
| 		cemux->fixup_parameters(); | ||||
| 		dffD.remove(i, width-i); | ||||
| 		dffQ.remove(i, width-i); | ||||
| 		dff->fixup_parameters(); | ||||
| 
 | ||||
| 		log("dffcemux pattern in %s: dff=%s, cemux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux), width-i); | ||||
| 		accept; | ||||
| 	} | ||||
| 	else { | ||||
| 		int count = 0; | ||||
| 		for (int i = width-1; i >= 0; i--) { | ||||
| 			if (D[i].wire) | ||||
| 				continue; | ||||
| 			Wire *w = Q[i].wire; | ||||
| 			auto it = w->attributes.find(\init); | ||||
| 			State init; | ||||
| 			if (it != w->attributes.end()) | ||||
| 				init = it->second[Q[i].offset]; | ||||
| 			else | ||||
| 				init = State::Sx; | ||||
| 
 | ||||
| 			if (init == State::Sx || init == D[i].data) { | ||||
| 				count++; | ||||
| 				module->connect(Q[i], D[i]); | ||||
| 				ceA.remove(i); | ||||
| 				ceB.remove(i); | ||||
| 				ceY.remove(i); | ||||
| 				dffD.remove(i); | ||||
| 				dffQ.remove(i); | ||||
| 			} | ||||
| 		} | ||||
| 		if (count > 0) { | ||||
| 			did_something = true; | ||||
| 			cemux->fixup_parameters(); | ||||
| 			dff->fixup_parameters(); | ||||
| 			log("dffcemux pattern in %s: dff=%s, cemux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), count); | ||||
| 		} | ||||
| 
 | ||||
| 		accept; | ||||
| 	} | ||||
| endcode | ||||
|  | @ -207,9 +207,10 @@ def process_pmgfile(f, filename): | |||
|             state_types[current_pattern][line[1]] = "Cell*"; | ||||
| 
 | ||||
|             block["if"] = list() | ||||
|             block["select"] = list() | ||||
|             block["setup"] = list() | ||||
|             block["index"] = list() | ||||
|             block["filter"] = list() | ||||
|             block["sets"] = list() | ||||
|             block["optional"] = False | ||||
|             block["semioptional"] = False | ||||
| 
 | ||||
|  | @ -228,7 +229,22 @@ def process_pmgfile(f, filename): | |||
| 
 | ||||
|                 if a[0] == "select": | ||||
|                     b = l.lstrip()[6:] | ||||
|                     block["select"].append(rewrite_cpp(b.strip())) | ||||
|                     block["setup"].append(("select", rewrite_cpp(b.strip()))) | ||||
|                     continue | ||||
| 
 | ||||
|                 if a[0] == "slice": | ||||
|                     m = re.match(r"^\s*slice\s+(\S+)\s+(.*?)\s*$", l) | ||||
|                     block["setup"].append(("slice", m.group(1), rewrite_cpp(m.group(2)))) | ||||
|                     continue | ||||
| 
 | ||||
|                 if a[0] == "choice": | ||||
|                     m = re.match(r"^\s*choice\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l) | ||||
|                     block["setup"].append(("choice", m.group(1), m.group(2), rewrite_cpp(m.group(3)))) | ||||
|                     continue | ||||
| 
 | ||||
|                 if a[0] == "define": | ||||
|                     m = re.match(r"^\s*define\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l) | ||||
|                     block["setup"].append(("define", m.group(1), m.group(2), rewrite_cpp(m.group(3)))) | ||||
|                     continue | ||||
| 
 | ||||
|                 if a[0] == "index": | ||||
|  | @ -242,6 +258,11 @@ def process_pmgfile(f, filename): | |||
|                     block["filter"].append(rewrite_cpp(b.strip())) | ||||
|                     continue | ||||
| 
 | ||||
|                 if a[0] == "set": | ||||
|                     m = re.match(r"^\s*set\s+(\S+)\s+(.*?)\s*$", l) | ||||
|                     block["sets"].append((m.group(1), rewrite_cpp(m.group(2)))) | ||||
|                     continue | ||||
| 
 | ||||
|                 if a[0] == "optional": | ||||
|                     block["optional"] = True | ||||
|                     continue | ||||
|  | @ -252,14 +273,16 @@ def process_pmgfile(f, filename): | |||
| 
 | ||||
|                 if a[0] == "generate": | ||||
|                     block["genargs"] = list([int(s) for s in a[1:]]) | ||||
|                     if len(block["genargs"]) == 0: block["genargs"].append(100) | ||||
|                     if len(block["genargs"]) == 1: block["genargs"].append(0) | ||||
|                     assert len(block["genargs"]) == 2 | ||||
|                     block["gencode"] = list() | ||||
|                     assert len(block["genargs"]) < 2 | ||||
|                     while True: | ||||
|                         linenr += 1 | ||||
|                         l = f.readline() | ||||
|                         assert l != "" | ||||
|                         a = l.split() | ||||
|                         if a[0] == "endmatch": break | ||||
|                         if len(a) == 1 and a[0] == "endmatch": break | ||||
|                         block["gencode"].append(rewrite_cpp(l.rstrip())) | ||||
|                     break | ||||
| 
 | ||||
|  | @ -357,8 +380,17 @@ with open(outfile, "w") as f: | |||
|             index_types = list() | ||||
|             for entry in block["index"]: | ||||
|                 index_types.append(entry[0]) | ||||
|             value_types = ["Cell*"] | ||||
|             for entry in block["setup"]: | ||||
|                 if entry[0] == "slice": | ||||
|                     value_types.append("int") | ||||
|                 if entry[0] == "choice": | ||||
|                     value_types.append(entry[1]) | ||||
|                 if entry[0] == "define": | ||||
|                     value_types.append(entry[1]) | ||||
|             print("  typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) | ||||
|             print("  dict<index_{}_key_type, vector<Cell*>> index_{};".format(index, index), file=f) | ||||
|             print("  typedef std::tuple<{}> index_{}_value_type;".format(", ".join(value_types), index), file=f) | ||||
|             print("  dict<index_{}_key_type, vector<index_{}_value_type>> index_{};".format(index, index, index), file=f) | ||||
|     print("  dict<SigBit, pool<Cell*>> sigusers;", file=f) | ||||
|     print("  pool<Cell*> blacklist_cells;", file=f) | ||||
|     print("  pool<Cell*> autoremove_cells;", file=f) | ||||
|  | @ -390,8 +422,6 @@ with open(outfile, "w") as f: | |||
|     print("  void add_siguser(const SigSpec &sig, Cell *cell) {", file=f) | ||||
|     print("    for (auto bit : sigmap(sig)) {", file=f) | ||||
|     print("      if (bit.wire == nullptr) continue;", file=f) | ||||
|     print("      if (sigusers.count(bit) == 0 && bit.wire->port_id)", file=f) | ||||
|     print("        sigusers[bit].insert(nullptr);", file=f) | ||||
|     print("      sigusers[bit].insert(cell);", file=f) | ||||
|     print("    }", file=f) | ||||
|     print("  }", file=f) | ||||
|  | @ -446,10 +476,11 @@ with open(outfile, "w") as f: | |||
|             else: | ||||
|                 print("    ud_{}.{} = {}();".format(current_pattern, s, t), file=f) | ||||
|     current_pattern = None | ||||
|     print("    for (auto cell : module->cells()) {", file=f) | ||||
|     print("    for (auto port : module->ports)", file=f) | ||||
|     print("      add_siguser(module->wire(port), nullptr);", file=f) | ||||
|     print("    for (auto cell : module->cells())", file=f) | ||||
|     print("      for (auto &conn : cell->connections())", file=f) | ||||
|     print("        add_siguser(conn.second, cell);", file=f) | ||||
|     print("    }", file=f) | ||||
|     print("    for (auto cell : cells) {", file=f) | ||||
| 
 | ||||
|     for index in range(len(blocks)): | ||||
|  | @ -457,12 +488,34 @@ with open(outfile, "w") as f: | |||
|         if block["type"] == "match": | ||||
|             print("      do {", file=f) | ||||
|             print("        Cell *{} = cell;".format(block["cell"]), file=f) | ||||
|             for expr in block["select"]: | ||||
|                 print("        if (!({})) break;".format(expr), file=f) | ||||
|             print("        index_{}_value_type value;".format(index), file=f) | ||||
|             print("        std::get<0>(value) = cell;", file=f) | ||||
|             loopcnt = 0 | ||||
|             valueidx = 1 | ||||
|             for item in block["setup"]: | ||||
|                 if item[0] == "select": | ||||
|                     print("        if (!({})) continue;".format(item[1]), file=f) | ||||
|                 if item[0] == "slice": | ||||
|                     print("        int &{} = std::get<{}>(value);".format(item[1], valueidx), file=f) | ||||
|                     print("        for ({} = 0; {} < {}; {}++) {{".format(item[1], item[1], item[2], item[1]), file=f) | ||||
|                     valueidx += 1 | ||||
|                     loopcnt += 1 | ||||
|                 if item[0] == "choice": | ||||
|                     print("        vector<{}> _pmg_choices_{} = {};".format(item[1], item[2], item[3]), file=f) | ||||
|                     print("        for (const {} &{} : _pmg_choices_{}) {{".format(item[1], item[2], item[2]), file=f) | ||||
|                     print("        std::get<{}>(value) = {};".format(valueidx, item[2]), file=f) | ||||
|                     valueidx += 1 | ||||
|                     loopcnt += 1 | ||||
|                 if item[0] == "define": | ||||
|                     print("        {} &{} = std::get<{}>(value);".format(item[1], item[2], valueidx), file=f) | ||||
|                     print("        {} = {};".format(item[2], item[3]), file=f) | ||||
|                     valueidx += 1 | ||||
|             print("        index_{}_key_type key;".format(index), file=f) | ||||
|             for field, entry in enumerate(block["index"]): | ||||
|                 print("        std::get<{}>(key) = {};".format(field, entry[1]), file=f) | ||||
|             print("        index_{}[key].push_back(cell);".format(index), file=f) | ||||
|             print("        index_{}[key].push_back(value);".format(index), file=f) | ||||
|             for i in range(loopcnt): | ||||
|                 print("        }", file=f) | ||||
|             print("      } while (0);", file=f) | ||||
| 
 | ||||
|     print("    }", file=f) | ||||
|  | @ -535,6 +588,8 @@ with open(outfile, "w") as f: | |||
|                     const_st.add(s) | ||||
|             elif blocks[i]["type"] == "match": | ||||
|                 const_st.add(blocks[i]["cell"]) | ||||
|                 for item in blocks[i]["sets"]: | ||||
|                     const_st.add(item[0]) | ||||
|             else: | ||||
|                 assert False | ||||
| 
 | ||||
|  | @ -548,6 +603,10 @@ with open(outfile, "w") as f: | |||
|             s = block["cell"] | ||||
|             assert s not in const_st | ||||
|             nonconst_st.add(s) | ||||
|             for item in block["sets"]: | ||||
|                 if item[0] in const_st: | ||||
|                     const_st.remove(item[0]) | ||||
|                 nonconst_st.add(item[0]) | ||||
|         else: | ||||
|             assert False | ||||
| 
 | ||||
|  | @ -570,7 +629,7 @@ with open(outfile, "w") as f: | |||
|             print("", file=f) | ||||
|             for s in sorted(restore_st): | ||||
|                 t = state_types[current_pattern][s] | ||||
|                 print("    {} backup_{} = {};".format(t, s, s), file=f) | ||||
|                 print("    {} _pmg_backup_{} = {};".format(t, s, s), file=f) | ||||
| 
 | ||||
|         if block["type"] == "code": | ||||
|             print("", file=f) | ||||
|  | @ -610,7 +669,7 @@ with open(outfile, "w") as f: | |||
|                 print("", file=f) | ||||
|                 for s in sorted(restore_st): | ||||
|                     t = state_types[current_pattern][s] | ||||
|                     print("    {} = backup_{};".format(s, s), file=f) | ||||
|                     print("    {} = _pmg_backup_{};".format(s, s), file=f) | ||||
|                 for s in sorted(nonconst_st): | ||||
|                     if s not in restore_st: | ||||
|                         t = state_types[current_pattern][s] | ||||
|  | @ -622,7 +681,7 @@ with open(outfile, "w") as f: | |||
|         elif block["type"] == "match": | ||||
|             assert len(restore_st) == 0 | ||||
| 
 | ||||
|             print("    Cell* backup_{} = {};".format(block["cell"], block["cell"]), file=f) | ||||
|             print("    Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f) | ||||
| 
 | ||||
|             if len(block["if"]): | ||||
|                 for expr in block["if"]: | ||||
|  | @ -630,7 +689,7 @@ with open(outfile, "w") as f: | |||
|                     print("    if (!({})) {{".format(expr), file=f) | ||||
|                     print("      {} = nullptr;".format(block["cell"]), file=f) | ||||
|                     print("      block_{}(recursion+1);".format(index+1), file=f) | ||||
|                     print("      {} = backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|                     print("      {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|                     print("      return;", file=f) | ||||
|                     print("    }", file=f) | ||||
| 
 | ||||
|  | @ -645,21 +704,37 @@ with open(outfile, "w") as f: | |||
| 
 | ||||
|             print("", file=f) | ||||
|             print("    if (cells_ptr != index_{}.end()) {{".format(index), file=f) | ||||
|             print("      const vector<Cell*> &cells = cells_ptr->second;".format(index), file=f) | ||||
|             print("      for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) | ||||
|             print("        {} = cells[idx];".format(block["cell"]), file=f) | ||||
|             print("      const vector<index_{}_value_type> &cells = cells_ptr->second;".format(index), file=f) | ||||
|             print("      for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", file=f) | ||||
|             print("        {} = std::get<0>(cells[_pmg_idx]);".format(block["cell"]), file=f) | ||||
|             valueidx = 1 | ||||
|             for item in block["setup"]: | ||||
|                 if item[0] == "slice": | ||||
|                     print("        const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f) | ||||
|                     valueidx += 1 | ||||
|                 if item[0] == "choice": | ||||
|                     print("        const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f) | ||||
|                     valueidx += 1 | ||||
|                 if item[0] == "define": | ||||
|                     print("        const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f) | ||||
|                     valueidx += 1 | ||||
|             print("        if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) | ||||
|             for expr in block["filter"]: | ||||
|                 print("        if (!({})) continue;".format(expr), file=f) | ||||
|             if block["semioptional"] or block["genargs"] is not None: | ||||
|                 print("        found_any_match = true;", file=f) | ||||
|             print("        auto rollback_ptr = rollback_cache.insert(make_pair(cells[idx], recursion));", file=f) | ||||
|             for item in block["sets"]: | ||||
|                 print("        auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f) | ||||
|                 print("        {} = {};".format(item[0], item[1]), file=f) | ||||
|             print("        auto rollback_ptr = rollback_cache.insert(make_pair(std::get<0>(cells[_pmg_idx]), recursion));", file=f) | ||||
|             print("        block_{}(recursion+1);".format(index+1), file=f) | ||||
|             for item in block["sets"]: | ||||
|                 print("        {} = _pmg_backup_{};".format(item[0], item[0]), file=f) | ||||
|             print("        if (rollback_ptr.second)", file=f) | ||||
|             print("          rollback_cache.erase(rollback_ptr.first);", file=f) | ||||
|             print("        if (rollback) {", file=f) | ||||
|             print("          if (rollback != recursion) {{".format(index+1), file=f) | ||||
|             print("            {} = backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|             print("            {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|             print("            return;", file=f) | ||||
|             print("          }", file=f) | ||||
|             print("          rollback = 0;", file=f) | ||||
|  | @ -676,13 +751,11 @@ with open(outfile, "w") as f: | |||
|             if block["semioptional"]: | ||||
|                 print("    if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f) | ||||
| 
 | ||||
|             print("    {} = backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|             print("    {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
| 
 | ||||
|             if block["genargs"] is not None: | ||||
|                 print("#define finish do { rollback = -1; return; } while(0)", file=f) | ||||
|                 print("    if (generate_mode && !found_any_match) {", file=f) | ||||
|                 if len(block["genargs"]) == 1: | ||||
|                     print("    if (rng(100) >= {}) return;".format(block["genargs"][0]), file=f) | ||||
|                 print("    if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f) | ||||
|                 for line in block["gencode"]: | ||||
|                     print("      " + line, file=f) | ||||
|                 print("    }", file=f) | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ bool did_something; | |||
| 
 | ||||
| #include "passes/pmgen/test_pmgen_pm.h" | ||||
| #include "passes/pmgen/ice40_dsp_pm.h" | ||||
| #include "passes/pmgen/xilinx_srl_pm.h" | ||||
| #include "passes/pmgen/peepopt_pm.h" | ||||
| 
 | ||||
| void reduce_chain(test_pmgen_pm &pm) | ||||
|  | @ -99,6 +100,24 @@ void reduce_tree(test_pmgen_pm &pm) | |||
| 	log("    -> %s (%s)\n", log_id(c), log_id(c->type)); | ||||
| } | ||||
| 
 | ||||
| void opt_eqpmux(test_pmgen_pm &pm) | ||||
| { | ||||
| 	auto &st = pm.st_eqpmux; | ||||
| 
 | ||||
| 	SigSpec Y = st.pmux->getPort(ID::Y); | ||||
| 	int width = GetSize(Y); | ||||
| 
 | ||||
| 	SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width); | ||||
| 	SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width); | ||||
| 
 | ||||
| 	log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n", | ||||
| 			log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux)); | ||||
| 
 | ||||
| 	pm.autoremove(st.pmux); | ||||
| 	Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y); | ||||
| 	log("    -> %s (%s)\n", log_id(c), log_id(c->type)); | ||||
| } | ||||
| 
 | ||||
| #define GENERATE_PATTERN(pmclass, pattern) \ | ||||
| 	generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design) | ||||
| 
 | ||||
|  | @ -149,19 +168,20 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const | |||
| 	log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass); | ||||
| 
 | ||||
| 	int modcnt = 0; | ||||
| 	int maxmodcnt = 100; | ||||
| 	int maxsubcnt = 4; | ||||
| 	int timeout = 0; | ||||
| 	vector<Module*> mods; | ||||
| 
 | ||||
| 	while (modcnt < 100) | ||||
| 	while (modcnt < maxmodcnt) | ||||
| 	{ | ||||
| 		int submodcnt = 0, itercnt = 0, cellcnt = 0; | ||||
| 		Module *mod = design->addModule(NEW_ID); | ||||
| 
 | ||||
| 		while (modcnt < 100 && submodcnt < maxsubcnt && itercnt++ < 1000) | ||||
| 		while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000) | ||||
| 		{ | ||||
| 			if (timeout++ > 10000) | ||||
| 				log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n"); | ||||
| 				log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n"); | ||||
| 
 | ||||
| 			pm matcher(mod, mod->cells()); | ||||
| 
 | ||||
|  | @ -197,7 +217,7 @@ void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const | |||
| 			run(matcher, [](){}); | ||||
| 		} | ||||
| 
 | ||||
| 		if (submodcnt) | ||||
| 		if (submodcnt && maxsubcnt < (1 << 16)) | ||||
| 			maxsubcnt *= 2; | ||||
| 
 | ||||
| 		design->remove(mod); | ||||
|  | @ -232,6 +252,12 @@ struct TestPmgenPass : public Pass { | |||
| 		log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n"); | ||||
| 		log("\n"); | ||||
| 
 | ||||
| 		log("\n"); | ||||
| 		log("    test_pmgen -eqpmux [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n"); | ||||
| 		log("\n"); | ||||
| 
 | ||||
| 		log("\n"); | ||||
| 		log("    test_pmgen -generate [options] <pattern_name>\n"); | ||||
| 		log("\n"); | ||||
|  | @ -277,6 +303,25 @@ struct TestPmgenPass : public Pass { | |||
| 			test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design) | ||||
| 	{ | ||||
| 		log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n"); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 2; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			// if (args[argidx] == "-singleton") {
 | ||||
| 			// 	singleton_mode = true;
 | ||||
| 			// 	continue;
 | ||||
| 			// }
 | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 			test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute_generate(std::vector<std::string> args, RTLIL::Design *design) | ||||
| 	{ | ||||
| 		log_header(design, "Executing TEST_PMGEN pass (-generate).\n"); | ||||
|  | @ -299,16 +344,24 @@ struct TestPmgenPass : public Pass { | |||
| 		if (pattern == "reduce") | ||||
| 			return GENERATE_PATTERN(test_pmgen_pm, reduce); | ||||
| 
 | ||||
| 		if (pattern == "eqpmux") | ||||
| 			return GENERATE_PATTERN(test_pmgen_pm, eqpmux); | ||||
| 
 | ||||
| 		if (pattern == "ice40_dsp") | ||||
| 			return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp); | ||||
| 
 | ||||
| 		if (pattern == "xilinx_srl.fixed") | ||||
| 			return GENERATE_PATTERN(xilinx_srl_pm, fixed); | ||||
| 		if (pattern == "xilinx_srl.variable") | ||||
| 			return GENERATE_PATTERN(xilinx_srl_pm, variable); | ||||
| 
 | ||||
| 		if (pattern == "peepopt-muldiv") | ||||
| 			return GENERATE_PATTERN(peepopt_pm, muldiv); | ||||
| 
 | ||||
| 		if (pattern == "peepopt-shiftmul") | ||||
| 			return GENERATE_PATTERN(peepopt_pm, shiftmul); | ||||
| 
 | ||||
| 		log_cmd_error("Unkown pattern: %s\n", pattern.c_str()); | ||||
| 		log_cmd_error("Unknown pattern: %s\n", pattern.c_str()); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
|  | @ -319,6 +372,8 @@ struct TestPmgenPass : public Pass { | |||
| 				return execute_reduce_chain(args, design); | ||||
| 			if (args[1] == "-reduce_tree") | ||||
| 				return execute_reduce_tree(args, design); | ||||
| 			if (args[1] == "-eqpmux") | ||||
| 				return execute_eqpmux(args, design); | ||||
| 			if (args[1] == "-generate") | ||||
| 				return execute_generate(args, design); | ||||
| 		} | ||||
|  |  | |||
|  | @ -60,8 +60,8 @@ code portname | |||
| endcode | ||||
| 
 | ||||
| match next | ||||
| 	select nusers(port(next, \Y)) == 2 | ||||
| 	select next->type.in($_AND_, $_OR_, $_XOR_) | ||||
| 	select nusers(port(next, \Y)) == 2 | ||||
| 	index <IdString> next->type === first->type | ||||
| 	index <SigSpec> port(next, \Y) === port(first, portname) | ||||
| endmatch | ||||
|  | @ -77,8 +77,8 @@ arg first | |||
| 
 | ||||
| match next | ||||
| 	semioptional | ||||
| 	select nusers(port(next, \Y)) == 2 | ||||
| 	select next->type.in($_AND_, $_OR_, $_XOR_) | ||||
| 	select nusers(port(next, \Y)) == 2 | ||||
| 	index <IdString> next->type === chain.back().first->type | ||||
| 	index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second) | ||||
| generate 10 | ||||
|  | @ -104,3 +104,86 @@ finally | |||
| 	if (next) | ||||
| 		chain.pop_back(); | ||||
| endcode | ||||
| 
 | ||||
| // ================================================================== | ||||
| 
 | ||||
| pattern eqpmux | ||||
| 
 | ||||
| state <bool> eq_ne_signed | ||||
| state <SigSpec> eq_inA eq_inB | ||||
| state <int> pmux_slice_eq pmux_slice_ne | ||||
| 
 | ||||
| match eq | ||||
| 	select eq->type == $eq | ||||
| 	choice <IdString> AB {\A, \B} | ||||
| 	define <IdString> BA AB == \A ? \B : \A | ||||
| 	set eq_inA port(eq, \A) | ||||
| 	set eq_inB port(eq, \B) | ||||
| 	set eq_ne_signed param(eq, \A_SIGNED).as_bool() | ||||
| generate 100 10 | ||||
| 	SigSpec A = module->addWire(NEW_ID, rng(7)+1); | ||||
| 	SigSpec B = module->addWire(NEW_ID, rng(7)+1); | ||||
| 	SigSpec Y = module->addWire(NEW_ID); | ||||
| 	module->addEq(NEW_ID, A, B, Y, rng(2)); | ||||
| endmatch | ||||
| 
 | ||||
| match pmux | ||||
| 	select pmux->type == $pmux | ||||
| 	slice idx GetSize(port(pmux, \S)) | ||||
| 	index <SigBit> port(pmux, \S)[idx] === port(eq, \Y) | ||||
| 	set pmux_slice_eq idx | ||||
| generate 100 10 | ||||
| 	int width = rng(7) + 1; | ||||
| 	int numsel = rng(4) + 1; | ||||
| 	int idx = rng(numsel); | ||||
| 
 | ||||
| 	SigSpec A = module->addWire(NEW_ID, width); | ||||
| 	SigSpec Y = module->addWire(NEW_ID, width); | ||||
| 
 | ||||
| 	SigSpec B, S; | ||||
| 	for (int i = 0; i < numsel; i++) { | ||||
| 		B.append(module->addWire(NEW_ID, width)); | ||||
| 		S.append(i == idx ? port(eq, \Y) : module->addWire(NEW_ID)); | ||||
| 	} | ||||
| 
 | ||||
| 	module->addPmux(NEW_ID, A, B, S, Y); | ||||
| endmatch | ||||
| 
 | ||||
| match ne | ||||
| 	select ne->type == $ne | ||||
| 	choice <IdString> AB {\A, \B} | ||||
| 	define <IdString> BA (AB == \A ? \B : \A) | ||||
| 	index <SigSpec> port(ne, AB) === eq_inA | ||||
| 	index <SigSpec> port(ne, BA) === eq_inB | ||||
| 	index <int> param(ne, \A_SIGNED).as_bool() === eq_ne_signed | ||||
| generate 100 10 | ||||
| 	SigSpec A = eq_inA, B = eq_inB, Y; | ||||
| 	if (rng(2)) { | ||||
| 		std::swap(A, B); | ||||
| 	} | ||||
| 	if (rng(2)) { | ||||
| 		for (auto bit : port(pmux, \S)) { | ||||
| 			if (nusers(bit) < 2) | ||||
| 				Y.append(bit); | ||||
| 		} | ||||
| 		if (GetSize(Y)) | ||||
| 			Y = Y[rng(GetSize(Y))]; | ||||
| 		else | ||||
| 			Y = module->addWire(NEW_ID); | ||||
| 	} else { | ||||
| 		Y = module->addWire(NEW_ID); | ||||
| 	} | ||||
| 	module->addNe(NEW_ID, A, B, Y, rng(2)); | ||||
| endmatch | ||||
| 
 | ||||
| match pmux2 | ||||
| 	select pmux2->type == $pmux | ||||
| 	slice idx GetSize(port(pmux2, \S)) | ||||
| 	index <Cell*> pmux2 === pmux | ||||
| 	index <SigBit> port(pmux2, \S)[idx] === port(ne, \Y) | ||||
| 	set pmux_slice_ne idx | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	accept; | ||||
| endcode | ||||
|  |  | |||
							
								
								
									
										258
									
								
								passes/pmgen/xilinx_srl.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								passes/pmgen/xilinx_srl.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,258 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *            (C) 2019  Eddie Hung    <eddie@fpgeh.com> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| #include "passes/pmgen/xilinx_srl_pm.h" | ||||
| 
 | ||||
| void run_fixed(xilinx_srl_pm &pm) | ||||
| { | ||||
| 	auto &st = pm.st_fixed; | ||||
| 	auto &ud = pm.ud_fixed; | ||||
| 	log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type)); | ||||
| 
 | ||||
| 	SigSpec initval; | ||||
| 	for (auto cell : ud.longest_chain) { | ||||
| 		log_debug("    %s\n", log_id(cell)); | ||||
| 		if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) { | ||||
| 			SigBit Q = cell->getPort(ID(Q)); | ||||
| 			log_assert(Q.wire); | ||||
| 			auto it = Q.wire->attributes.find(ID(init)); | ||||
| 			if (it != Q.wire->attributes.end()) { | ||||
| 				auto &i = it->second[Q.offset]; | ||||
| 				initval.append(i); | ||||
| 				i = State::Sx; | ||||
| 			} | ||||
| 			else | ||||
| 				initval.append(State::Sx); | ||||
| 		} | ||||
| 		else if (cell->type.in(ID(FDRE), ID(FDRE_1))) { | ||||
| 			if (cell->parameters.at(ID(INIT), State::S0).as_bool()) | ||||
| 				initval.append(State::S1); | ||||
| 			else | ||||
| 				initval.append(State::S0); | ||||
| 		} | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 		pm.autoremove(cell); | ||||
| 	} | ||||
| 
 | ||||
| 	auto first_cell = ud.longest_chain.back(); | ||||
| 	auto last_cell = ud.longest_chain.front(); | ||||
| 	Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_)); | ||||
| 	pm.module->swap_names(c, first_cell); | ||||
| 
 | ||||
| 	if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) { | ||||
| 		c->setParam(ID(DEPTH), GetSize(ud.longest_chain)); | ||||
| 		c->setParam(ID(INIT), initval.as_const()); | ||||
| 		if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_))) | ||||
| 			c->setParam(ID(CLKPOL), 1); | ||||
| 		else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1))) | ||||
| 			c->setParam(ID(CLKPOL), 0); | ||||
| 		else if (first_cell->type.in(ID(FDRE))) { | ||||
| 			if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool()) | ||||
| 				c->setParam(ID(CLKPOL), 1); | ||||
| 			else | ||||
| 				c->setParam(ID(CLKPOL), 0); | ||||
| 		} | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 		if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_))) | ||||
| 			c->setParam(ID(ENPOL), 1); | ||||
| 		else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_))) | ||||
| 			c->setParam(ID(ENPOL), 0); | ||||
| 		else | ||||
| 			c->setParam(ID(ENPOL), 2); | ||||
| 
 | ||||
| 		c->setPort(ID(C), first_cell->getPort(ID(C))); | ||||
| 		c->setPort(ID(D), first_cell->getPort(ID(D))); | ||||
| 		c->setPort(ID(Q), last_cell->getPort(ID(Q))); | ||||
| 		c->setPort(ID(L), GetSize(ud.longest_chain)-1); | ||||
| 		if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) | ||||
| 			c->setPort(ID(E), State::S1); | ||||
| 		else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) | ||||
| 			c->setPort(ID(E), first_cell->getPort(ID(E))); | ||||
| 		else if (first_cell->type.in(ID(FDRE), ID(FDRE_1))) | ||||
| 			c->setPort(ID(E), first_cell->getPort(ID(CE))); | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 	} | ||||
| 	else | ||||
| 		log_abort(); | ||||
| 
 | ||||
| 	log("    -> %s (%s)\n", log_id(c), log_id(c->type)); | ||||
| } | ||||
| 
 | ||||
| void run_variable(xilinx_srl_pm &pm) | ||||
| { | ||||
| 	auto &st = pm.st_variable; | ||||
| 	auto &ud = pm.ud_variable; | ||||
| 
 | ||||
| 	log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type)); | ||||
| 
 | ||||
| 	SigSpec initval; | ||||
| 	for (const auto &i : ud.chain) { | ||||
| 		auto cell = i.first; | ||||
| 		auto slice = i.second; | ||||
| 		log_debug("    %s\n", log_id(cell)); | ||||
| 		if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) { | ||||
| 			SigBit Q = cell->getPort(ID(Q))[slice]; | ||||
| 			log_assert(Q.wire); | ||||
| 			auto it = Q.wire->attributes.find(ID(init)); | ||||
| 			if (it != Q.wire->attributes.end()) { | ||||
| 				auto &i = it->second[Q.offset]; | ||||
| 				initval.append(i); | ||||
| 				i = State::Sx; | ||||
| 			} | ||||
| 			else | ||||
| 				initval.append(State::Sx); | ||||
| 		} | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 	} | ||||
| 	pm.autoremove(st.shiftx); | ||||
| 
 | ||||
| 	auto first_cell = ud.chain.back().first; | ||||
| 	auto first_slice = ud.chain.back().second; | ||||
| 
 | ||||
| 	Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_)); | ||||
| 	pm.module->swap_names(c, first_cell); | ||||
| 
 | ||||
| 	if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) { | ||||
| 		c->setParam(ID(DEPTH), GetSize(ud.chain)); | ||||
| 		c->setParam(ID(INIT), initval.as_const()); | ||||
| 		Const clkpol, enpol; | ||||
| 		if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_))) | ||||
| 			clkpol = 1; | ||||
| 		else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_))) | ||||
| 			clkpol = 0; | ||||
| 		else if (first_cell->type.in(ID($dff), ID($dffe))) | ||||
| 			clkpol = first_cell->getParam(ID(CLK_POLARITY)); | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 		if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_))) | ||||
| 			enpol = 1; | ||||
| 		else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_))) | ||||
| 			enpol = 0; | ||||
| 		else if (first_cell->type.in(ID($dffe))) | ||||
| 			enpol = first_cell->getParam(ID(EN_POLARITY)); | ||||
| 		else | ||||
| 			enpol = 2; | ||||
| 		c->setParam(ID(CLKPOL), clkpol); | ||||
| 		c->setParam(ID(ENPOL), enpol); | ||||
| 
 | ||||
| 		if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) | ||||
| 			c->setPort(ID(C), first_cell->getPort(ID(C))); | ||||
| 		else if (first_cell->type.in(ID($dff), ID($dffe))) | ||||
| 			c->setPort(ID(C), first_cell->getPort(ID(CLK))); | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 		c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]); | ||||
| 		c->setPort(ID(Q), st.shiftx->getPort(ID(Y))); | ||||
| 		c->setPort(ID(L), st.shiftx->getPort(ID(B))); | ||||
| 		if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff))) | ||||
| 			c->setPort(ID(E), State::S1); | ||||
| 		else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) | ||||
| 			c->setPort(ID(E), first_cell->getPort(ID(E))); | ||||
| 		else if (first_cell->type.in(ID($dffe))) | ||||
| 			c->setPort(ID(E), first_cell->getPort(ID(EN))); | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 	} | ||||
| 	else | ||||
| 		log_abort(); | ||||
| 
 | ||||
| 	log("    -> %s (%s)\n", log_id(c), log_id(c->type)); | ||||
| } | ||||
| 
 | ||||
| struct XilinxSrlPass : public Pass { | ||||
| 	XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    xilinx_srl [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n"); | ||||
| 		log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n"); | ||||
| 		log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n"); | ||||
| 		log("enable, and enable polarity (where relevant).\n"); | ||||
| 		log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred."); | ||||
| 		log("\n"); | ||||
| 		log("    -minlen N\n"); | ||||
| 		log("        min length of shift register (default = 3)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -fixed\n"); | ||||
| 		log("        infer fixed-length shift registers.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -variable\n"); | ||||
| 		log("        infer variable-length shift registers (i.e. fixed-length shifts where\n"); | ||||
| 		log("        each element also fans-out to a $shiftx cell).\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n"); | ||||
| 
 | ||||
| 		bool fixed = false; | ||||
| 		bool variable = false; | ||||
| 		int minlen = 3; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			if (args[argidx] == "-minlen" && argidx+1 < args.size()) { | ||||
| 				minlen = atoi(args[++argidx].c_str()); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-fixed") { | ||||
| 				fixed = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-variable") { | ||||
| 				variable = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (!fixed && !variable) | ||||
| 			log_cmd_error("'-fixed' and/or '-variable' must be specified.\n"); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) { | ||||
| 			auto pm = xilinx_srl_pm(module, module->selected_cells()); | ||||
| 			pm.ud_fixed.minlen = minlen; | ||||
| 			pm.ud_variable.minlen = minlen; | ||||
| 
 | ||||
| 			if (fixed) | ||||
| 				pm.run_fixed(run_fixed); | ||||
| 			if (variable) | ||||
| 				pm.run_variable(run_variable); | ||||
| 		} | ||||
| 	} | ||||
| } XilinxSrlPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										326
									
								
								passes/pmgen/xilinx_srl.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								passes/pmgen/xilinx_srl.pmg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,326 @@ | |||
| pattern fixed | ||||
| 
 | ||||
| state <IdString> clk_port en_port | ||||
| udata <vector<Cell*>> chain longest_chain | ||||
| udata <pool<Cell*>> non_first_cells | ||||
| udata <int> minlen | ||||
| 
 | ||||
| code | ||||
| 	non_first_cells.clear(); | ||||
| 	subpattern(setup); | ||||
| endcode | ||||
| 
 | ||||
| match first | ||||
| 	select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) | ||||
| 	select !first->has_keep_attr() | ||||
| 	select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() | ||||
| 	select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() | ||||
| 	select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero() | ||||
| 	filter !non_first_cells.count(first) | ||||
| generate | ||||
| 	SigSpec C = module->addWire(NEW_ID); | ||||
| 	SigSpec D = module->addWire(NEW_ID); | ||||
| 	SigSpec Q = module->addWire(NEW_ID); | ||||
| 	auto r = rng(8); | ||||
| 	Cell* cell; | ||||
| 	switch (r) | ||||
| 	{ | ||||
| 	case 0: | ||||
| 	case 1: | ||||
| 		cell = module->addCell(NEW_ID, \FDRE); | ||||
| 		cell->setPort(\C, C); | ||||
| 		cell->setPort(\D, D); | ||||
| 		cell->setPort(\Q, Q); | ||||
| 		cell->setPort(\CE, module->addWire(NEW_ID)); | ||||
| 		if (r & 1) | ||||
| 			cell->setPort(\R, module->addWire(NEW_ID)); | ||||
| 		else { | ||||
| 			if (rng(2) == 0) | ||||
| 				cell->setPort(\R, State::S0); | ||||
| 		} | ||||
| 		break; | ||||
| 	case 2: | ||||
| 	case 3: | ||||
| 		cell = module->addDffGate(NEW_ID, C, D, Q, r & 1); | ||||
| 		break; | ||||
| 	case 4: | ||||
| 	case 5: | ||||
| 	case 6: | ||||
| 	case 7: | ||||
| 		cell = module->addDffeGate(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 2); | ||||
| 		break; | ||||
| 	default: log_abort(); | ||||
| 	} | ||||
| endmatch | ||||
| 
 | ||||
| code clk_port en_port | ||||
| 	if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)) | ||||
| 		clk_port = \C; | ||||
| 	else log_abort(); | ||||
| 	if (first->type.in($_DFF_N_, $_DFF_P_)) | ||||
| 		en_port = IdString(); | ||||
| 	else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) | ||||
| 		en_port = \E; | ||||
| 	else if (first->type.in(\FDRE, \FDRE_1)) | ||||
| 		en_port = \CE; | ||||
| 	else log_abort(); | ||||
| 
 | ||||
| 	longest_chain.clear(); | ||||
| 	chain.push_back(first); | ||||
| 	subpattern(tail); | ||||
| finally | ||||
| 	chain.pop_back(); | ||||
| 	log_assert(chain.empty()); | ||||
| 	if (GetSize(longest_chain) >= minlen) | ||||
| 		accept; | ||||
| endcode | ||||
| 
 | ||||
| // ------------------------------------------------------------------ | ||||
| 
 | ||||
| subpattern setup | ||||
| arg clk_port | ||||
| arg en_port | ||||
| 
 | ||||
| match first | ||||
| 	select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) | ||||
| 	select !first->has_keep_attr() | ||||
| 	select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() | ||||
| 	select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() | ||||
| 	select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero() | ||||
| endmatch | ||||
| 
 | ||||
| code clk_port en_port | ||||
| 	if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)) | ||||
| 		clk_port = \C; | ||||
| 	else log_abort(); | ||||
| 	if (first->type.in($_DFF_N_, $_DFF_P_)) | ||||
| 		en_port = IdString(); | ||||
| 	else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) | ||||
| 		en_port = \E; | ||||
| 	else if (first->type.in(\FDRE, \FDRE_1)) | ||||
| 		en_port = \CE; | ||||
| 	else log_abort(); | ||||
| endcode | ||||
| 
 | ||||
| match next | ||||
| 	select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) | ||||
| 	select !next->has_keep_attr() | ||||
| 	select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) | ||||
| 	select nusers(port(next, \Q)) == 2 | ||||
| 	index <IdString> next->type === first->type | ||||
| 	index <SigBit> port(next, \Q) === port(first, \D) | ||||
| 	filter port(next, clk_port) == port(first, clk_port) | ||||
| 	filter en_port == IdString() || port(next, en_port) == port(first, en_port) | ||||
| 	filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool() | ||||
| 	filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() | ||||
| 	filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() | ||||
| 	filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero() | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	non_first_cells.insert(next); | ||||
| endcode | ||||
| 
 | ||||
| // ------------------------------------------------------------------ | ||||
| 
 | ||||
| subpattern tail | ||||
| arg first | ||||
| arg clk_port | ||||
| arg en_port | ||||
| 
 | ||||
| match next | ||||
| 	semioptional | ||||
| 	select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) | ||||
| 	select !next->has_keep_attr() | ||||
| 	select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) | ||||
| 	select nusers(port(next, \Q)) == 2 | ||||
| 	index <IdString> next->type === chain.back()->type | ||||
| 	index <SigBit> port(next, \Q) === port(chain.back(), \D) | ||||
| 	filter port(next, clk_port) == port(first, clk_port) | ||||
| 	filter en_port == IdString() || port(next, en_port) == port(first, en_port) | ||||
| 	filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool() | ||||
| 	filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() | ||||
| 	filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() | ||||
| 	filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero() | ||||
| generate | ||||
| 	Cell *cell = module->addCell(NEW_ID, chain.back()->type); | ||||
| 	cell->setPort(\C, chain.back()->getPort(\C)); | ||||
| 	cell->setPort(\D, module->addWire(NEW_ID)); | ||||
| 	cell->setPort(\Q, chain.back()->getPort(\D)); | ||||
| 	if (cell->type == \FDRE) { | ||||
| 		if (rng(2) == 0) | ||||
| 			cell->setPort(\R, chain.back()->connections_.at(\R, State::S0)); | ||||
| 		cell->setPort(\CE, chain.back()->getPort(\CE)); | ||||
| 	} | ||||
| 	else if (cell->type.begins_with("$_DFFE_")) | ||||
| 		cell->setPort(\E, chain.back()->getPort(\E)); | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	if (next) { | ||||
| 		chain.push_back(next); | ||||
| 		subpattern(tail); | ||||
| 	} else { | ||||
| 		if (GetSize(chain) > GetSize(longest_chain)) | ||||
| 			longest_chain = chain; | ||||
| 	} | ||||
| finally | ||||
| 	if (next) | ||||
| 		chain.pop_back(); | ||||
| endcode | ||||
| 
 | ||||
| // ----------- | ||||
| 
 | ||||
| pattern variable | ||||
| 
 | ||||
| state <IdString> clk_port en_port | ||||
| state <int> shiftx_width | ||||
| state <int> slice | ||||
| udata <int> minlen | ||||
| udata <vector<pair<Cell*,int>>> chain | ||||
| udata <pool<SigBit>> chain_bits | ||||
| 
 | ||||
| code | ||||
| 	chain_bits.clear(); | ||||
| endcode | ||||
| 
 | ||||
| match shiftx | ||||
| 	select shiftx->type.in($shiftx) | ||||
| 	select !shiftx->has_keep_attr() | ||||
| 	select param(shiftx, \Y_WIDTH).as_int() == 1 | ||||
| 	filter param(shiftx, \A_WIDTH).as_int() >= minlen | ||||
| generate | ||||
| 	minlen = 3; | ||||
| 	module->addShiftx(NEW_ID, module->addWire(NEW_ID, rng(6)+minlen), module->addWire(NEW_ID, 3), module->addWire(NEW_ID)); | ||||
| endmatch | ||||
| 
 | ||||
| code shiftx_width | ||||
| 	shiftx_width = param(shiftx, \A_WIDTH).as_int(); | ||||
| endcode | ||||
| 
 | ||||
| match first | ||||
| 	select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe) | ||||
| 	select !first->has_keep_attr() | ||||
| 	select port(first, \Q)[0].wire && !port(first, \Q)[0].wire->get_bool_attribute(\keep) | ||||
| 	slice idx GetSize(port(first, \Q)) | ||||
| 	select nusers(port(first, \Q)[idx]) <= 2 | ||||
| 	index <SigBit> port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1] | ||||
| 	set slice idx | ||||
| generate | ||||
| 	SigSpec C = module->addWire(NEW_ID); | ||||
| 	auto WIDTH = rng(3)+1; | ||||
| 	SigSpec D = module->addWire(NEW_ID, WIDTH); | ||||
| 	SigSpec Q = module->addWire(NEW_ID, WIDTH); | ||||
| 	auto r = rng(8); | ||||
| 	Cell *cell = nullptr; | ||||
| 	switch (r) | ||||
| 	{ | ||||
| 	case 0: | ||||
| 	case 1: | ||||
| 		cell = module->addDff(NEW_ID, C, D, Q, r & 1); | ||||
| 		break; | ||||
| 	case 2: | ||||
| 	case 3: | ||||
| 	case 4: | ||||
| 	case 5: | ||||
| 		//cell = module->addDffe(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 4); | ||||
| 		//break; | ||||
| 	case 6: | ||||
| 	case 7: | ||||
| 		WIDTH = 1; | ||||
| 		cell = module->addDffGate(NEW_ID, C, D[0], Q[0], r & 1); | ||||
| 		break; | ||||
| 	default: log_abort(); | ||||
| 	} | ||||
| 	shiftx->connections_.at(\A)[shiftx_width-1] = port(cell, \Q)[rng(WIDTH)]; | ||||
| endmatch | ||||
| 
 | ||||
| code clk_port en_port | ||||
| 	if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) | ||||
| 		clk_port = \C; | ||||
| 	else if (first->type.in($dff, $dffe)) | ||||
| 		clk_port = \CLK; | ||||
| 	else log_abort(); | ||||
| 	if (first->type.in($_DFF_N_, $_DFF_P_, $dff)) | ||||
| 		en_port = IdString(); | ||||
| 	else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) | ||||
| 		en_port = \E; | ||||
| 	else if (first->type.in($dffe)) | ||||
| 		en_port = \EN; | ||||
| 	else log_abort(); | ||||
| 
 | ||||
| 	chain_bits.insert(port(first, \Q)[slice]); | ||||
| 	chain.emplace_back(first, slice); | ||||
| 	subpattern(tail); | ||||
| finally | ||||
| 	if (GetSize(chain) == shiftx_width) | ||||
| 		accept; | ||||
| 	chain.clear(); | ||||
| endcode | ||||
| 
 | ||||
| // ------------------------------------------------------------------ | ||||
| 
 | ||||
| subpattern tail | ||||
| arg first | ||||
| arg shiftx | ||||
| arg shiftx_width | ||||
| arg slice | ||||
| arg clk_port | ||||
| arg en_port | ||||
| 
 | ||||
| match next | ||||
| 	semioptional | ||||
| 	select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe) | ||||
| 	select !next->has_keep_attr() | ||||
| 	select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) | ||||
| 	slice idx GetSize(port(next, \Q)) | ||||
| 	select nusers(port(next, \Q)[idx]) <= 3 | ||||
| 	index <IdString> next->type === chain.back().first->type | ||||
| 	index <SigBit> port(next, \Q)[idx] === port(chain.back().first, \D)[chain.back().second] | ||||
| 	index <SigBit> port(next, \Q)[idx] === port(shiftx, \A)[shiftx_width-1-GetSize(chain)] | ||||
| 	filter port(next, clk_port) == port(first, clk_port) | ||||
| 	filter en_port == IdString() || port(next, en_port) == port(first, en_port) | ||||
| 	filter !next->type.in($dff, $dffe) || param(next, \CLK_POLARITY).as_bool() == param(first, \CLK_POLARITY).as_bool() | ||||
| 	filter !next->type.in($dffe) || param(next, \EN_POLARITY).as_bool() == param(first, \EN_POLARITY).as_bool() | ||||
| 	filter !chain_bits.count(port(next, \D)[idx]) | ||||
| 	set slice idx | ||||
| generate | ||||
| 	if (GetSize(chain) < shiftx_width) { | ||||
| 		auto back = chain.back().first; | ||||
| 		auto slice = chain.back().second; | ||||
| 		if (back->type.in($dff, $dffe)) { | ||||
| 			auto WIDTH = GetSize(port(back, \D)); | ||||
| 			if (rng(2) == 0 && slice < WIDTH-1) { | ||||
| 				auto new_slice = slice + rng(WIDTH-1-slice); | ||||
| 				back->connections_.at(\D)[slice] = port(back, \Q)[new_slice]; | ||||
| 			} | ||||
| 			else { | ||||
| 				auto D = module->addWire(NEW_ID, WIDTH); | ||||
| 				if (back->type == $dff) | ||||
| 					module->addDff(NEW_ID, port(back, \CLK), D, port(back, \D), param(back, \CLK_POLARITY).as_bool()); | ||||
| 				else if (back->type == $dffe) | ||||
| 					module->addDffe(NEW_ID, port(back, \CLK), port(back, \EN), D, port(back, \D), param(back, \CLK_POLARITY).as_bool(), param(back, \EN_POLARITY).as_bool()); | ||||
| 				else | ||||
| 					log_abort(); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (back->type.begins_with("$_DFF_")) { | ||||
| 			Cell *cell = module->addCell(NEW_ID, back->type); | ||||
| 			cell->setPort(\C, back->getPort(\C)); | ||||
| 			cell->setPort(\D, module->addWire(NEW_ID)); | ||||
| 			cell->setPort(\Q, back->getPort(\D)); | ||||
| 		} | ||||
| 		else | ||||
| 			log_abort(); | ||||
| 		shiftx->connections_.at(\A)[shiftx_width-1-GetSize(chain)] = port(back, \D)[slice]; | ||||
| 	} | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	if (next) { | ||||
| 		chain_bits.insert(port(next, \Q)[slice]); | ||||
| 		chain.emplace_back(next, slice); | ||||
| 		if (GetSize(chain) < shiftx_width) | ||||
| 			subpattern(tail); | ||||
| 	} | ||||
| endcode | ||||
|  | @ -39,7 +39,7 @@ struct Async2syncPass : public Pass { | |||
| 		log("reset value in the next cycle regardless of the data-in value at the time of\n"); | ||||
| 		log("the clock edge.\n"); | ||||
| 		log("\n"); | ||||
| 		log("Currently only $adff and $dffsr cells are supported by this pass.\n"); | ||||
| 		log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
|  | @ -169,6 +169,41 @@ struct Async2syncPass : public Pass { | |||
| 					cell->type = "$dff"; | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				if (cell->type.in("$dlatch")) | ||||
| 				{ | ||||
| 					bool en_pol = cell->parameters["\\EN_POLARITY"].as_bool(); | ||||
| 
 | ||||
| 					SigSpec sig_en = cell->getPort("\\EN"); | ||||
| 					SigSpec sig_d = cell->getPort("\\D"); | ||||
| 					SigSpec sig_q = cell->getPort("\\Q"); | ||||
| 
 | ||||
| 					log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n", | ||||
| 							log_id(module), log_id(cell), log_id(cell->type), | ||||
| 							log_signal(sig_en), log_signal(sig_d), log_signal(sig_q)); | ||||
| 
 | ||||
| 					Const init_val; | ||||
| 					for (int i = 0; i < GetSize(sig_q); i++) { | ||||
| 						SigBit bit = sigmap(sig_q[i]); | ||||
| 						init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); | ||||
| 						del_initbits.insert(bit); | ||||
| 					} | ||||
| 
 | ||||
| 					Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); | ||||
| 					new_q->attributes["\\init"] = init_val; | ||||
| 
 | ||||
| 					if (en_pol) { | ||||
| 						module->addMux(NEW_ID, new_q, sig_d, sig_en, sig_q); | ||||
| 					} else { | ||||
| 						module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q); | ||||
| 					} | ||||
| 
 | ||||
| 					cell->setPort("\\Q", new_q); | ||||
| 					cell->unsetPort("\\EN"); | ||||
| 					cell->unsetParam("\\EN_POLARITY"); | ||||
| 					cell->type = "$ff"; | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			for (auto wire : module->wires()) | ||||
|  |  | |||
|  | @ -268,7 +268,7 @@ struct SatHelper | |||
| 				RTLIL::SigSpec removed_bits; | ||||
| 				for (int i = 0; i < lhs.size(); i++) { | ||||
| 					RTLIL::SigSpec bit = lhs.extract(i, 1); | ||||
| 					if (!satgen.initial_state.check_all(bit)) { | ||||
| 					if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) { | ||||
| 						removed_bits.append(bit); | ||||
| 						lhs.remove(i, 1); | ||||
| 						rhs.remove(i, 1); | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ endif | |||
| 
 | ||||
| ifneq ($(SMALL),1) | ||||
| OBJS += passes/techmap/iopadmap.o | ||||
| OBJS += passes/techmap/clkbufmap.o | ||||
| OBJS += passes/techmap/hilomap.o | ||||
| OBJS += passes/techmap/extract.o | ||||
| OBJS += passes/techmap/extract_fa.o | ||||
|  | @ -39,6 +40,7 @@ OBJS += passes/techmap/attrmap.o | |||
| OBJS += passes/techmap/zinit.o | ||||
| OBJS += passes/techmap/dff2dffs.o | ||||
| OBJS += passes/techmap/flowmap.o | ||||
| OBJS += passes/techmap/extractinv.o | ||||
| endif | ||||
| 
 | ||||
| GENFILES += passes/techmap/techmap.inc | ||||
|  |  | |||
|  | @ -76,8 +76,7 @@ inline std::string remap_name(RTLIL::IdString abc_name) | |||
| 	return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); | ||||
| } | ||||
| 
 | ||||
| void handle_loops(RTLIL::Design *design, | ||||
| 		const dict<IdString,pool<IdString>> &scc_break_inputs) | ||||
| void handle_loops(RTLIL::Design *design) | ||||
| { | ||||
| 	Pass::call(design, "scc -set_attr abc_scc_id {}"); | ||||
| 
 | ||||
|  | @ -85,7 +84,7 @@ void handle_loops(RTLIL::Design *design, | |||
| 	// cell in the component, and select (and mark) all its output
 | ||||
| 	// wires
 | ||||
| 	pool<RTLIL::Const> ids_seen; | ||||
| 	for (auto cell : module->selected_cells()) { | ||||
| 	for (auto cell : module->cells()) { | ||||
| 		auto it = cell->attributes.find(ID(abc_scc_id)); | ||||
| 		if (it != cell->attributes.end()) { | ||||
| 			auto r = ids_seen.insert(it->second); | ||||
|  | @ -114,30 +113,6 @@ void handle_loops(RTLIL::Design *design, | |||
| 			} | ||||
| 			cell->attributes.erase(it); | ||||
| 		} | ||||
| 
 | ||||
| 		auto jt = scc_break_inputs.find(cell->type); | ||||
| 		if (jt != scc_break_inputs.end()) | ||||
| 			for (auto port_name : jt->second) { | ||||
| 				RTLIL::SigSpec sig; | ||||
| 				auto &rhs = cell->connections_.at(port_name); | ||||
| 				for (auto b : rhs) { | ||||
| 					Wire *w = b.wire; | ||||
| 					if (!w) continue; | ||||
| 					w->port_output = true; | ||||
| 					w->set_bool_attribute(ID(abc_scc_break)); | ||||
| 					w = module->wire(stringf("%s.abci", w->name.c_str())); | ||||
| 					if (!w) { | ||||
| 						w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire)); | ||||
| 						w->port_input = true; | ||||
| 					} | ||||
| 					else { | ||||
| 						log_assert(b.offset < GetSize(w)); | ||||
| 						log_assert(w->port_input); | ||||
| 					} | ||||
| 					sig.append(RTLIL::SigBit(w, b.offset)); | ||||
| 				} | ||||
| 				rhs = sig; | ||||
| 			} | ||||
| 	} | ||||
| 
 | ||||
| 	module->fixup_ports(); | ||||
|  | @ -269,11 +244,10 @@ struct abc_output_filter | |||
| }; | ||||
| 
 | ||||
| void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, | ||||
| 		bool cleanup, vector<int> lut_costs, bool /*dff_mode*/, std::string clk_str, | ||||
| 		bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, | ||||
| 		bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, | ||||
| 		bool show_tempdir, std::string box_file, std::string lut_file, | ||||
| 		std::string wire_delay, const dict<int,IdString> &box_lookup, | ||||
| 		const dict<IdString,pool<IdString>> &scc_break_inputs | ||||
| 		std::string wire_delay, const dict<int,IdString> &box_lookup | ||||
| ) | ||||
| { | ||||
| 	module = current_module; | ||||
|  | @ -309,8 +283,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 			clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); | ||||
| 	} | ||||
| 
 | ||||
| 	//if (dff_mode && clk_sig.empty())
 | ||||
| 	//	log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
 | ||||
| 	if (dff_mode && clk_sig.empty()) | ||||
| 		log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); | ||||
| 
 | ||||
| 	std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; | ||||
| 	if (!cleanup) | ||||
|  | @ -383,7 +357,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 	fprintf(f, "%s\n", abc_script.c_str()); | ||||
| 	fclose(f); | ||||
| 
 | ||||
| 	if (/*dff_mode ||*/ !clk_str.empty()) | ||||
| 	if (dff_mode || !clk_str.empty()) | ||||
| 	{ | ||||
| 		if (clk_sig.size() == 0) | ||||
| 			log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); | ||||
|  | @ -413,16 +387,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 		RTLIL::Selection& sel = design->selection_stack.back(); | ||||
| 		sel.select(module); | ||||
| 
 | ||||
| 		handle_loops(design, scc_break_inputs); | ||||
| 		handle_loops(design); | ||||
| 
 | ||||
| 		Pass::call(design, "aigmap"); | ||||
| 
 | ||||
| 		//log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
 | ||||
| 		//		count_gates, GetSize(signal_list), count_input, count_output);
 | ||||
| 
 | ||||
| #if 0 | ||||
| 		Pass::call(design, stringf("write_verilog -noexpr -norename %s/before.v", tempdir_name.c_str())); | ||||
| #endif | ||||
| 		Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); | ||||
| 
 | ||||
| 		std::string buffer; | ||||
|  | @ -531,12 +502,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 				for (int i = 0; i < GetSize(w); i++) | ||||
| 					output_bits.insert({wire, i}); | ||||
| 			} | ||||
| 
 | ||||
| 			auto jt = w->attributes.find("\\init"); | ||||
| 			if (jt != w->attributes.end()) { | ||||
| 				auto r = remap_wire->attributes.insert(std::make_pair("\\init", jt->second)); | ||||
| 				log_assert(r.second); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto &it : module->connections_) { | ||||
|  | @ -578,6 +543,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 			if (mapped_cell->type == ID($_NOT_)) { | ||||
| 				RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); | ||||
| 				RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); | ||||
| 				bit_users[a_bit].insert(mapped_cell->name); | ||||
| 				bit_drivers[y_bit].insert(mapped_cell->name); | ||||
| 
 | ||||
| 				if (!a_bit.wire) { | ||||
| 					mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); | ||||
|  | @ -585,8 +552,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 					log_assert(wire); | ||||
| 					module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); | ||||
| 				} | ||||
| 				else { | ||||
| 					RTLIL::Cell* driving_lut = nullptr; | ||||
| 				else if (!lut_costs.empty() || !lut_file.empty()) { | ||||
| 					RTLIL::Cell* driver_lut = nullptr; | ||||
| 					// ABC can return NOT gates that drive POs
 | ||||
| 					if (!a_bit.wire->port_input) { | ||||
| 						// If it's not a NOT gate that that comes from a PI directly,
 | ||||
|  | @ -598,10 +565,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 							driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); | ||||
| 						else | ||||
| 							driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); | ||||
| 						driving_lut = mapped_mod->cell(driver_name); | ||||
| 						driver_lut = mapped_mod->cell(driver_name); | ||||
| 					} | ||||
| 
 | ||||
| 					if (!driving_lut) { | ||||
| 					if (!driver_lut) { | ||||
| 						// If a driver couldn't be found (could be from PI or box CI)
 | ||||
| 						// then implement using a LUT
 | ||||
| 						cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), | ||||
|  | @ -610,13 +577,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 								RTLIL::Const::from_string("01")); | ||||
| 						bit2sinks[cell->getPort(ID::A)].push_back(cell); | ||||
| 						cell_stats[ID($lut)]++; | ||||
| 						bit_users[a_bit].insert(mapped_cell->name); | ||||
| 						bit_drivers[y_bit].insert(mapped_cell->name); | ||||
| 					} | ||||
| 					else | ||||
| 						not2drivers[mapped_cell] = driving_lut; | ||||
| 						not2drivers[mapped_cell] = driver_lut; | ||||
| 					continue; | ||||
| 				} | ||||
| 				else | ||||
| 					log_abort(); | ||||
| 				if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; | ||||
| 				continue; | ||||
| 			} | ||||
|  | @ -700,32 +667,31 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 		} | ||||
| 
 | ||||
| 		for (auto &it : cell_stats) | ||||
| 			log("ABC RESULTS:   %15s cells: %8d\n", log_id(it.first), it.second); | ||||
| 			log("ABC RESULTS:   %15s cells: %8d\n", it.first.c_str(), it.second); | ||||
| 		int in_wires = 0, out_wires = 0; | ||||
| 
 | ||||
| 		// Stitch in mapped_mod's inputs/outputs into module
 | ||||
| 		for (auto port_name : mapped_mod->ports) { | ||||
| 			RTLIL::Wire *port = mapped_mod->wire(port_name); | ||||
| 			log_assert(port); | ||||
| 			RTLIL::Wire *wire = module->wire(port->name); | ||||
| 		for (auto port : mapped_mod->ports) { | ||||
| 			RTLIL::Wire *w = mapped_mod->wire(port); | ||||
| 			RTLIL::Wire *wire = module->wire(port); | ||||
| 			log_assert(wire); | ||||
| 			RTLIL::Wire *remap_wire = module->wire(remap_name(port->name)); | ||||
| 			RTLIL::Wire *remap_wire = module->wire(remap_name(port)); | ||||
| 			RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); | ||||
| 			log_assert(GetSize(signal) >= GetSize(remap_wire)); | ||||
| 
 | ||||
| 			RTLIL::SigSig conn; | ||||
| 			if (port->port_input) { | ||||
| 				conn.first = remap_wire; | ||||
| 				conn.second = signal; | ||||
| 				in_wires++; | ||||
| 				module->connect(conn); | ||||
| 			} | ||||
| 			if (port->port_output) { | ||||
| 			if (w->port_output) { | ||||
| 				conn.first = signal; | ||||
| 				conn.second = remap_wire; | ||||
| 				out_wires++; | ||||
| 				module->connect(conn); | ||||
| 			} | ||||
| 			else if (w->port_input) { | ||||
| 				conn.first = remap_wire; | ||||
| 				conn.second = signal; | ||||
| 				in_wires++; | ||||
| 				module->connect(conn); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto &it : bit_users) | ||||
|  | @ -733,21 +699,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 				for (auto driver_cell : bit_drivers.at(it.first)) | ||||
| 				for (auto user_cell : it.second) | ||||
| 					toposort.edge(driver_cell, user_cell); | ||||
| #if 0 | ||||
| 		toposort.analyze_loops = true; | ||||
| #endif | ||||
| 		bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); | ||||
| #if 0 | ||||
| 		unsigned i = 0; | ||||
| 		for (auto &it : toposort.loops) { | ||||
| 			log("  loop %d\n", i++); | ||||
| 			for (auto cell_name : it) { | ||||
| 				auto cell = mapped_mod->cell(cell_name); | ||||
| 				log_assert(cell); | ||||
| 				log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); | ||||
| 			} | ||||
| 		} | ||||
| #endif | ||||
| 		log_assert(no_loops); | ||||
| 
 | ||||
| 		for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { | ||||
|  | @ -1048,7 +1000,7 @@ struct Abc9Pass : public Pass { | |||
| 				fast_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			//if (arg == "-retime") {
 | ||||
| 			//if (arg == "-dff") {
 | ||||
| 			//	dff_mode = true;
 | ||||
| 			//	continue;
 | ||||
| 			//}
 | ||||
|  | @ -1075,9 +1027,6 @@ struct Abc9Pass : public Pass { | |||
| 			} | ||||
| 			if (arg == "-box" && argidx+1 < args.size()) { | ||||
| 				box_file = args[++argidx]; | ||||
| 				rewrite_filename(box_file); | ||||
| 				if (!box_file.empty() && !is_absolute_path(box_file)) | ||||
| 					box_file = std::string(pwd) + "/" + box_file; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-W" && argidx+1 < args.size()) { | ||||
|  | @ -1088,11 +1037,15 @@ struct Abc9Pass : public Pass { | |||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (lut_costs.empty() && lut_file.empty()) | ||||
| 			log_cmd_error("abc9 must be called with '-lut' or '-luts'\n"); | ||||
| 		// ABC expects a box file for XAIG
 | ||||
| 		if (box_file.empty()) | ||||
| 		    box_file = "+/dummy.box"; | ||||
| 
 | ||||
| 		rewrite_filename(box_file); | ||||
| 		if (!box_file.empty() && !is_absolute_path(box_file)) | ||||
| 		    box_file = std::string(pwd) + "/" + box_file; | ||||
| 
 | ||||
| 		dict<int,IdString> box_lookup; | ||||
| 		dict<IdString,pool<IdString>> scc_break_inputs; | ||||
| 		for (auto m : design->modules()) { | ||||
| 			auto it = m->attributes.find(ID(abc_box_id)); | ||||
| 			if (it == m->attributes.end()) | ||||
|  | @ -1110,17 +1063,13 @@ struct Abc9Pass : public Pass { | |||
| 			for (auto p : m->ports) { | ||||
| 				auto w = m->wire(p); | ||||
| 				log_assert(w); | ||||
| 				if (w->port_input) { | ||||
| 					if (w->attributes.count(ID(abc_scc_break))) | ||||
| 						scc_break_inputs[m->name].insert(p); | ||||
| 				if (w->attributes.count(ID(abc_carry))) { | ||||
| 					if (w->port_input) { | ||||
| 						if (carry_in) | ||||
| 							log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); | ||||
| 						carry_in = w; | ||||
| 					} | ||||
| 				} | ||||
| 				if (w->port_output) { | ||||
| 					if (w->attributes.count(ID(abc_carry))) { | ||||
| 					else if (w->port_output) { | ||||
| 						if (carry_out) | ||||
| 							log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); | ||||
| 						carry_out = w; | ||||
|  | @ -1177,7 +1126,8 @@ struct Abc9Pass : public Pass { | |||
| 
 | ||||
| 				abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, false, clk_str, keepff, | ||||
| 						delay_target, lutin_shared, fast_mode, show_tempdir, | ||||
| 						box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); | ||||
| 						box_file, lut_file, wire_delay, box_lookup); | ||||
| 
 | ||||
| 				design->selection_stack.pop_back(); | ||||
| 				continue; | ||||
| 			} | ||||
|  | @ -1361,36 +1311,20 @@ struct Abc9Pass : public Pass { | |||
| 						std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), | ||||
| 						std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); | ||||
| 
 | ||||
| 			design->selection_stack.emplace_back(false); | ||||
| 
 | ||||
| 			for (auto &it : assigned_cells) { | ||||
| 				// FIXME: abc9_module calls below can delete cells,
 | ||||
| 				//        leaving a dangling pointer here...
 | ||||
| 				clk_polarity = std::get<0>(it.first); | ||||
| 				clk_sig = assign_map(std::get<1>(it.first)); | ||||
| 				en_polarity = std::get<2>(it.first); | ||||
| 				en_sig = assign_map(std::get<3>(it.first)); | ||||
| 
 | ||||
| 				pool<RTLIL::IdString> assigned_names; | ||||
| 				for (auto i : it.second) | ||||
| 					assigned_names.insert(i->name); | ||||
| 				RTLIL::Selection& sel = design->selection_stack.back(); | ||||
| 				sel.selected_members[mod->name] = std::move(assigned_names); | ||||
| 
 | ||||
| 				abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", | ||||
| 						keepff, delay_target, lutin_shared, fast_mode, show_tempdir, | ||||
| 						box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); | ||||
| 						box_file, lut_file, wire_delay, box_lookup); | ||||
| 				assign_map.set(mod); | ||||
| 			} | ||||
| 
 | ||||
| 			design->selection_stack.pop_back(); | ||||
| 		} | ||||
| 
 | ||||
| 		assign_map.clear(); | ||||
| 
 | ||||
| 		// The "clean" pass also contains a design->check() call
 | ||||
| 		Pass::call(design, "clean"); | ||||
| 
 | ||||
| 		log_pop(); | ||||
| 	} | ||||
| } Abc9Pass; | ||||
|  |  | |||
|  | @ -48,14 +48,25 @@ struct AlumaccWorker | |||
| 		RTLIL::SigSpec cached_cf, cached_of, cached_sf; | ||||
| 
 | ||||
| 		RTLIL::SigSpec get_lt() { | ||||
| 			if (GetSize(cached_lt) == 0) | ||||
| 				cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf(); | ||||
| 			if (GetSize(cached_lt) == 0) { | ||||
| 				if (is_signed) { | ||||
| 					get_of(); | ||||
| 					get_sf(); | ||||
| 					cached_lt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); | ||||
| 				} | ||||
| 				else | ||||
| 					cached_lt = get_cf(); | ||||
| 			} | ||||
| 			return cached_lt; | ||||
| 		} | ||||
| 
 | ||||
| 		RTLIL::SigSpec get_gt() { | ||||
| 			if (GetSize(cached_gt) == 0) | ||||
| 				cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()), false, alu_cell->get_src_attribute()); | ||||
| 			if (GetSize(cached_gt) == 0) { | ||||
| 				get_lt(); | ||||
| 				get_eq(); | ||||
| 				SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); | ||||
| 				cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); | ||||
| 			} | ||||
| 			return cached_gt; | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -143,17 +143,8 @@ void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actio | |||
| 	attributes.swap(new_attributes); | ||||
| } | ||||
| 
 | ||||
| struct AttrmapPass : public Pass { | ||||
| 	AttrmapPass() : Pass("attrmap", "renaming attributes") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| void log_attrmap_paramap_options() | ||||
| { | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    attrmap [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This command renames attributes and/or mapps key/value pairs to\n"); | ||||
| 		log("other key/value pairs.\n"); | ||||
| 		log("\n"); | ||||
| 	log("    -tocase <name>\n"); | ||||
| 	log("        Match attribute names case-insensitively and set it to the specified\n"); | ||||
| 	log("        name.\n"); | ||||
|  | @ -170,39 +161,23 @@ struct AttrmapPass : public Pass { | |||
| 	log("\n"); | ||||
| 	log("    -remove <name>=<value>\n"); | ||||
| 	log("        Remove attributes matching this pattern.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -modattr\n"); | ||||
| 		log("        Operate on module attributes instead of attributes on wires and cells.\n"); | ||||
| 		log("\n"); | ||||
| 		log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n"); | ||||
| 		log("\n"); | ||||
| 		log("    attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n"); | ||||
| 		log("            -imap keep=\"false\" keep=0 -remove keep=0\n"); | ||||
| 		log("\n"); | ||||
| } | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n"); | ||||
| 
 | ||||
| 		bool modattr_mode = false; | ||||
| 		vector<std::unique_ptr<AttrmapAction>> actions; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| bool parse_attrmap_paramap_options(size_t &argidx, std::vector<std::string> &args, vector<std::unique_ptr<AttrmapAction>> &actions) | ||||
| { | ||||
| 	std::string arg = args[argidx]; | ||||
| 	if (arg == "-tocase" && argidx+1 < args.size()) { | ||||
| 		auto action = new AttrmapTocase; | ||||
| 		action->name = args[++argidx]; | ||||
| 		actions.push_back(std::unique_ptr<AttrmapAction>(action)); | ||||
| 				continue; | ||||
| 		return true; | ||||
| 	} | ||||
| 	if (arg == "-rename" && argidx+2 < args.size()) { | ||||
| 		auto action = new AttrmapRename; | ||||
| 		action->old_name = args[++argidx]; | ||||
| 		action->new_name = args[++argidx]; | ||||
| 		actions.push_back(std::unique_ptr<AttrmapAction>(action)); | ||||
| 				continue; | ||||
| 		return true; | ||||
| 	} | ||||
| 	if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) { | ||||
| 		string arg1 = args[++argidx]; | ||||
|  | @ -225,7 +200,7 @@ struct AttrmapPass : public Pass { | |||
| 		action->old_value = val1; | ||||
| 		action->new_value = val2; | ||||
| 		actions.push_back(std::unique_ptr<AttrmapAction>(action)); | ||||
| 				continue; | ||||
| 		return true; | ||||
| 	} | ||||
| 	if (arg == "-remove" && argidx+1 < args.size()) { | ||||
| 		string arg1 = args[++argidx], val1; | ||||
|  | @ -239,9 +214,46 @@ struct AttrmapPass : public Pass { | |||
| 		action->has_value = (p != string::npos); | ||||
| 		action->value = val1; | ||||
| 		actions.push_back(std::unique_ptr<AttrmapAction>(action)); | ||||
| 				continue; | ||||
| 		return true; | ||||
| 	} | ||||
| 			if (arg == "-modattr") { | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| struct AttrmapPass : public Pass { | ||||
| 	AttrmapPass() : Pass("attrmap", "renaming attributes") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    attrmap [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This command renames attributes and/or maps key/value pairs to\n"); | ||||
| 		log("other key/value pairs.\n"); | ||||
| 		log("\n"); | ||||
| 		log_attrmap_paramap_options(); | ||||
| 		log("\n"); | ||||
| 		log("    -modattr\n"); | ||||
| 		log("        Operate on module attributes instead of attributes on wires and cells.\n"); | ||||
| 		log("\n"); | ||||
| 		log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n"); | ||||
| 		log("\n"); | ||||
| 		log("    attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n"); | ||||
| 		log("            -imap keep=\"false\" keep=0 -remove keep=0\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n"); | ||||
| 
 | ||||
| 		bool modattr_mode = false; | ||||
| 		vector<std::unique_ptr<AttrmapAction>> actions; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			if (parse_attrmap_paramap_options(argidx, args, actions)) | ||||
| 				continue; | ||||
| 			if (args[argidx] == "-modattr") { | ||||
| 				modattr_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
|  | @ -287,4 +299,43 @@ struct AttrmapPass : public Pass { | |||
| 	} | ||||
| } AttrmapPass; | ||||
| 
 | ||||
| struct ParamapPass : public Pass { | ||||
| 	ParamapPass() : Pass("paramap", "renaming cell parameters") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    paramap [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This command renames cell parameters and/or maps key/value pairs to\n"); | ||||
| 		log("other key/value pairs.\n"); | ||||
| 		log("\n"); | ||||
| 		log_attrmap_paramap_options(); | ||||
| 		log("\n"); | ||||
| 		log("For example, mapping Diamond-style ECP5 \"init\" attributes to Yosys-style:\n"); | ||||
| 		log("\n"); | ||||
| 		log("    paramap -tocase INIT t:LUT4\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n"); | ||||
| 
 | ||||
| 		vector<std::unique_ptr<AttrmapAction>> actions; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			if (parse_attrmap_paramap_options(argidx, args, actions)) | ||||
| 				continue; | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		for (auto cell : module->selected_cells()) | ||||
| 			attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->parameters); | ||||
| 	} | ||||
| } ParamapPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  |  | |||
							
								
								
									
										298
									
								
								passes/techmap/clkbufmap.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								passes/techmap/clkbufmap.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,298 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *  Copyright (C) 2019  Marcin Kościelnicki <mwk@0x04.net> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| void split_portname_pair(std::string &port1, std::string &port2) | ||||
| { | ||||
| 	size_t pos = port1.find_first_of(':'); | ||||
| 	if (pos != std::string::npos) { | ||||
| 		port2 = port1.substr(pos+1); | ||||
| 		port1 = port1.substr(0, pos); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct ClkbufmapPass : public Pass { | ||||
| 	ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    clkbufmap [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); | ||||
| 		log("\n"); | ||||
| 		log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); | ||||
| 		log("attribute will be considered for global buffer insertion.\n"); | ||||
| 		log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); | ||||
| 		log("'none' or 'bufr' one would specify:\n"); | ||||
| 		log("  'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); | ||||
| 		log("as the selection.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -buf <celltype> <portname_out>:<portname_in>\n"); | ||||
| 		log("        Specifies the cell type to use for the global buffers\n"); | ||||
| 		log("        and its port names.  The first port will be connected to\n"); | ||||
| 		log("        the clock network sinks, and the second will be connected\n"); | ||||
| 		log("        to the actual clock source.  This option is required.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -inpad <celltype> <portname_out>:<portname_in>\n"); | ||||
| 		log("        If specified, a PAD cell of the given type is inserted on\n"); | ||||
| 		log("        clock nets that are also top module's inputs (in addition\n"); | ||||
| 		log("        to the global buffer).\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) { | ||||
| 		if (modules_processed.count(module)) | ||||
| 			return; | ||||
| 		for (auto cell : module->cells()) { | ||||
| 			Module *submodule = design->module(cell->type); | ||||
| 			if (!submodule) | ||||
| 				continue; | ||||
| 			module_queue(design, submodule, modules_sorted, modules_processed); | ||||
| 		} | ||||
| 		modules_sorted.push_back(module); | ||||
| 		modules_processed.insert(module); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); | ||||
| 
 | ||||
| 		std::string buf_celltype, buf_portname, buf_portname2; | ||||
| 		std::string inpad_celltype, inpad_portname, inpad_portname2; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			std::string arg = args[argidx]; | ||||
| 			if (arg == "-buf" && argidx+2 < args.size()) { | ||||
| 				buf_celltype = args[++argidx]; | ||||
| 				buf_portname = args[++argidx]; | ||||
| 				split_portname_pair(buf_portname, buf_portname2); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-inpad" && argidx+2 < args.size()) { | ||||
| 				inpad_celltype = args[++argidx]; | ||||
| 				inpad_portname = args[++argidx]; | ||||
| 				split_portname_pair(inpad_portname, inpad_portname2); | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		bool select = false; | ||||
| 		if (argidx < args.size()) { | ||||
| 			if (args[argidx].compare(0, 1, "-") != 0) | ||||
| 				select = true; | ||||
| 			extra_args(args, argidx, design); | ||||
| 		} | ||||
| 
 | ||||
| 		if (buf_celltype.empty()) | ||||
| 			log_error("The -buf option is required.\n"); | ||||
| 
 | ||||
| 		// Cell type, port name, bit index.
 | ||||
| 		pool<pair<IdString, pair<IdString, int>>> sink_ports; | ||||
| 		pool<pair<IdString, pair<IdString, int>>> buf_ports; | ||||
| 
 | ||||
| 		// Process submodules before module using them.
 | ||||
| 		std::vector<Module *> modules_sorted; | ||||
| 		pool<Module *> modules_processed; | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 			module_queue(design, module, modules_sorted, modules_processed); | ||||
| 
 | ||||
| 		for (auto module : modules_sorted) | ||||
| 		{ | ||||
| 			if (module->get_blackbox_attribute()) { | ||||
| 				for (auto port : module->ports) { | ||||
| 					auto wire = module->wire(port); | ||||
| 					if (wire->get_bool_attribute("\\clkbuf_driver")) | ||||
| 						for (int i = 0; i < GetSize(wire); i++) | ||||
| 							buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); | ||||
| 					if (wire->get_bool_attribute("\\clkbuf_sink")) | ||||
| 						for (int i = 0; i < GetSize(wire); i++) | ||||
| 							sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); | ||||
| 				} | ||||
| 				continue; | ||||
| 			} | ||||
| 			pool<SigBit> sink_wire_bits; | ||||
| 			pool<SigBit> buf_wire_bits; | ||||
| 			pool<SigBit> driven_wire_bits; | ||||
| 			SigMap sigmap(module); | ||||
| 			// bit -> (buffer, buffer's input)
 | ||||
| 			dict<SigBit, pair<Cell *, Wire *>> buffered_bits; | ||||
| 
 | ||||
| 			// First, collect nets that could use a clock buffer.
 | ||||
| 			for (auto cell : module->cells()) | ||||
| 			for (auto port : cell->connections()) | ||||
| 			for (int i = 0; i < port.second.size(); i++) | ||||
| 				if (sink_ports.count(make_pair(cell->type, make_pair(port.first, i)))) | ||||
| 					sink_wire_bits.insert(sigmap(port.second[i])); | ||||
| 
 | ||||
| 			// Second, collect ones that already have a clock buffer.
 | ||||
| 			for (auto cell : module->cells()) | ||||
| 			for (auto port : cell->connections()) | ||||
| 			for (int i = 0; i < port.second.size(); i++) | ||||
| 				if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i)))) | ||||
| 					buf_wire_bits.insert(sigmap(port.second[i])); | ||||
| 
 | ||||
| 			// Collect all driven bits.
 | ||||
| 			for (auto cell : module->cells()) | ||||
| 			for (auto port : cell->connections()) | ||||
| 				if (cell->output(port.first)) | ||||
| 					for (int i = 0; i < port.second.size(); i++) | ||||
| 						driven_wire_bits.insert(port.second[i]); | ||||
| 
 | ||||
| 			// Insert buffers.
 | ||||
| 			std::vector<pair<Wire *, Wire *>> input_queue; | ||||
| 			// Copy current wire list, as we will be adding new ones during iteration.
 | ||||
| 			std::vector<Wire *> wires(module->wires()); | ||||
| 			for (auto wire : wires) | ||||
| 			{ | ||||
| 				// Should not happen.
 | ||||
| 				if (wire->port_input && wire->port_output) | ||||
| 					continue; | ||||
| 				bool process_wire = module->selected(wire); | ||||
| 				if (!select && wire->get_bool_attribute("\\clkbuf_inhibit")) | ||||
| 					process_wire = false; | ||||
| 				if (!process_wire) { | ||||
| 					// This wire is supposed to be bypassed, so make sure we don't buffer it in
 | ||||
| 					// some buffer higher up in the hierarchy.
 | ||||
| 					if (wire->port_output) | ||||
| 						for (int i = 0; i < GetSize(wire); i++) | ||||
| 							buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				pool<int> input_bits; | ||||
| 
 | ||||
| 				for (int i = 0; i < GetSize(wire); i++) | ||||
| 				{ | ||||
| 					SigBit wire_bit(wire, i); | ||||
| 					SigBit mapped_wire_bit = sigmap(wire_bit); | ||||
| 					if (buf_wire_bits.count(mapped_wire_bit)) { | ||||
| 						// Already buffered downstream.  If this is an output, mark it.
 | ||||
| 						if (wire->port_output) | ||||
| 							buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); | ||||
| 					} else if (!sink_wire_bits.count(mapped_wire_bit)) { | ||||
| 						// Nothing to do.
 | ||||
| 					} else if (driven_wire_bits.count(wire_bit) || (wire->port_input && module->get_bool_attribute("\\top"))) { | ||||
| 						// Clock network not yet buffered, driven by one of
 | ||||
| 						// our cells or a top-level input -- buffer it.
 | ||||
| 
 | ||||
| 						log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); | ||||
| 						RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); | ||||
| 						Wire *iwire = module->addWire(NEW_ID); | ||||
| 						cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); | ||||
| 						cell->setPort(RTLIL::escape_id(buf_portname2), iwire); | ||||
| 						if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute("\\top")) { | ||||
| 							log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); | ||||
| 							RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); | ||||
| 							cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); | ||||
| 							iwire = module->addWire(NEW_ID); | ||||
| 							cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); | ||||
| 						} | ||||
| 						buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); | ||||
| 
 | ||||
| 						if (wire->port_input) { | ||||
| 							input_bits.insert(i); | ||||
| 						} | ||||
| 					} else if (wire->port_input) { | ||||
| 						// A clock input in a submodule -- mark it, let higher level
 | ||||
| 						// worry about it.
 | ||||
| 						if (wire->port_input) | ||||
| 							sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); | ||||
| 					} | ||||
| 				} | ||||
| 				if (!input_bits.empty()) { | ||||
| 					// This is an input port and some buffers were inserted -- we need
 | ||||
| 					// to create a new input wire and transfer attributes.
 | ||||
| 					Wire *new_wire = module->addWire(NEW_ID, wire); | ||||
| 
 | ||||
| 					for (int i = 0; i < wire->width; i++) { | ||||
| 						SigBit wire_bit(wire, i); | ||||
| 						SigBit mapped_wire_bit = sigmap(wire_bit); | ||||
| 						auto it = buffered_bits.find(mapped_wire_bit); | ||||
| 						if (it != buffered_bits.end()) { | ||||
| 
 | ||||
| 							module->connect(it->second.second, SigSpec(new_wire, i)); | ||||
| 						} else { | ||||
| 							module->connect(SigSpec(wire, i), SigSpec(new_wire, i)); | ||||
| 						} | ||||
| 					} | ||||
| 					input_queue.push_back(make_pair(wire, new_wire)); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Mark any newly-buffered output ports as such.
 | ||||
| 			for (auto wire : module->selected_wires()) { | ||||
| 				if (wire->port_input || !wire->port_output) | ||||
| 					continue; | ||||
| 				for (int i = 0; i < GetSize(wire); i++) | ||||
| 				{ | ||||
| 					SigBit wire_bit(wire, i); | ||||
| 					SigBit mapped_wire_bit = sigmap(wire_bit); | ||||
| 					if (buffered_bits.count(mapped_wire_bit)) | ||||
| 						buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Reconnect the drivers to buffer inputs.
 | ||||
| 			for (auto cell : module->cells()) | ||||
| 			for (auto port : cell->connections()) { | ||||
| 				if (!cell->output(port.first)) | ||||
| 					continue; | ||||
| 				SigSpec sig = port.second; | ||||
| 				bool newsig = false; | ||||
| 				for (auto &bit : sig) { | ||||
| 					const auto it = buffered_bits.find(sigmap(bit)); | ||||
| 					if (it == buffered_bits.end()) | ||||
| 						continue; | ||||
| 					// Avoid substituting buffer's own output pin.
 | ||||
| 					if (cell == it->second.first) | ||||
| 						continue; | ||||
| 					bit = it->second.second; | ||||
| 					newsig = true; | ||||
| 				} | ||||
| 				if (newsig) | ||||
| 					cell->setPort(port.first, sig); | ||||
| 			} | ||||
| 
 | ||||
| 			// This has to be done last, to avoid upsetting sigmap before the port reconnections.
 | ||||
| 			for (auto &it : input_queue) { | ||||
| 				Wire *wire = it.first; | ||||
| 				Wire *new_wire = it.second; | ||||
| 				module->swap_names(new_wire, wire); | ||||
| 				wire->attributes.clear(); | ||||
| 				wire->port_id = 0; | ||||
| 				wire->port_input = false; | ||||
| 				wire->port_output = false; | ||||
| 			} | ||||
| 
 | ||||
| 			module->fixup_ports(); | ||||
| 		} | ||||
| 	} | ||||
| } ClkbufmapPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -34,11 +34,16 @@ struct Dff2dffsPass : public Pass { | |||
| 		log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n"); | ||||
| 		log("dff2dffe for SR over CE priority.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -match-init\n"); | ||||
| 		log("        Disallow merging synchronous set/reset that has polarity opposite of the\n"); | ||||
| 		log("        output wire's init attribute (if any).\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n"); | ||||
| 
 | ||||
| 		bool match_init = false; | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
|  | @ -46,6 +51,10 @@ struct Dff2dffsPass : public Pass { | |||
| 			// 	singleton_mode = true;
 | ||||
| 			// 	continue;
 | ||||
| 			// }
 | ||||
| 			if (args[argidx] == "-match-init") { | ||||
| 				match_init = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
|  | @ -96,9 +105,6 @@ struct Dff2dffsPass : public Pass { | |||
| 				SigBit bit_b = sigmap(mux_cell->getPort(ID::B)); | ||||
| 				SigBit bit_s = sigmap(mux_cell->getPort(ID(S))); | ||||
| 
 | ||||
| 				log("  Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell), | ||||
| 						log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type)); | ||||
| 
 | ||||
| 				SigBit sr_val, sr_sig; | ||||
| 				bool invert_sr; | ||||
| 				sr_sig = bit_s; | ||||
|  | @ -113,6 +119,23 @@ struct Dff2dffsPass : public Pass { | |||
| 					invert_sr = false; | ||||
| 				} | ||||
| 
 | ||||
| 				if (match_init) { | ||||
| 					SigBit bit_q = cell->getPort(ID(Q)); | ||||
| 					if (bit_q.wire) { | ||||
| 						auto it = bit_q.wire->attributes.find(ID(init)); | ||||
| 						if (it != bit_q.wire->attributes.end()) { | ||||
| 							auto init_val = it->second[bit_q.offset]; | ||||
| 							if (init_val == State::S1 && sr_val != State::S1) | ||||
| 								continue; | ||||
| 							if (init_val == State::S0 && sr_val != State::S0) | ||||
| 								continue; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				log("  Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell), | ||||
| 						log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type)); | ||||
| 
 | ||||
| 				if (sr_val == State::S1) { | ||||
| 					if (cell->type == ID($_DFF_N_)) { | ||||
| 						if (invert_sr) cell->type = ID($__DFFS_NN1_); | ||||
|  |  | |||
							
								
								
									
										123
									
								
								passes/techmap/extractinv.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								passes/techmap/extractinv.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,123 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *  Copyright (C) 2019  Marcin Kościelnicki <mwk@0x04.net> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| void split_portname_pair(std::string &port1, std::string &port2) | ||||
| { | ||||
| 	size_t pos = port1.find_first_of(':'); | ||||
| 	if (pos != std::string::npos) { | ||||
| 		port2 = port1.substr(pos+1); | ||||
| 		port1 = port1.substr(0, pos); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct ExtractinvPass : public Pass { | ||||
| 	ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    extractinv [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Searches the design for all cells with invertible pins controlled by a cell\n"); | ||||
| 		log("parameter (eg. IS_CLK_INVERTED on many Xilinx cells) and removes the parameter.\n"); | ||||
| 		log("If the parameter was set to 1, inserts an explicit inverter cell in front of\n"); | ||||
| 		log("the pin instead.  Normally used for output to ISE, which does not support the\n"); | ||||
| 		log("inversion parameters.\n"); | ||||
| 		log("\n"); | ||||
| 		log("To mark a cell port as invertible, use (* invertible_pin = \"param_name\" *)\n"); | ||||
| 		log("on the wire in the blackbox module.  The parameter value should have\n"); | ||||
| 		log("the same width as the port, and will be effectively XORed with it.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -inv <celltype> <portname_out>:<portname_in>\n"); | ||||
| 		log("        Specifies the cell type to use for the inverters and its port names.\n"); | ||||
| 		log("        This option is required.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n"); | ||||
| 
 | ||||
| 		std::string inv_celltype, inv_portname, inv_portname2; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			std::string arg = args[argidx]; | ||||
| 			if (arg == "-inv" && argidx+2 < args.size()) { | ||||
| 				inv_celltype = args[++argidx]; | ||||
| 				inv_portname = args[++argidx]; | ||||
| 				split_portname_pair(inv_portname, inv_portname2); | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (inv_celltype.empty()) | ||||
| 			log_error("The -inv option is required.\n"); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		{ | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			for (auto port : cell->connections()) { | ||||
| 				auto cell_module = design->module(cell->type); | ||||
| 				if (!cell_module) | ||||
| 					continue; | ||||
| 				auto cell_wire = cell_module->wire(port.first); | ||||
| 				if (!cell_wire) | ||||
| 					continue; | ||||
| 				auto it = cell_wire->attributes.find("\\invertible_pin"); | ||||
| 				if (it == cell_wire->attributes.end()) | ||||
| 					continue; | ||||
| 				IdString param_name = RTLIL::escape_id(it->second.decode_string()); | ||||
| 				auto it2 = cell->parameters.find(param_name); | ||||
| 				// Inversion not used -- skip.
 | ||||
| 				if (it2 == cell->parameters.end()) | ||||
| 					continue; | ||||
| 				SigSpec sig = port.second; | ||||
| 				if (it2->second.size() != sig.size()) | ||||
| 					log_error("The inversion parameter needs to be the same width as the port (%s.%s port %s parameter %s)", log_id(module->name), log_id(cell->type), log_id(port.first), log_id(param_name)); | ||||
| 				RTLIL::Const invmask = it2->second; | ||||
| 				cell->parameters.erase(param_name); | ||||
| 				if (invmask.is_fully_zero()) | ||||
| 					continue; | ||||
| 				Wire *iwire = module->addWire(NEW_ID, sig.size()); | ||||
| 				for (int i = 0; i < sig.size(); i++) | ||||
| 					if (invmask[i] == State::S1) { | ||||
| 						RTLIL::Cell *icell = module->addCell(NEW_ID, RTLIL::escape_id(inv_celltype)); | ||||
| 						icell->setPort(RTLIL::escape_id(inv_portname), SigSpec(iwire, i)); | ||||
| 						icell->setPort(RTLIL::escape_id(inv_portname2), sig[i]); | ||||
| 						log("Inserting %s on %s.%s.%s[%d].\n", inv_celltype.c_str(), log_id(module), log_id(cell->type), log_id(port.first), i); | ||||
| 						sig[i] = SigBit(iwire, i); | ||||
| 					} | ||||
| 				cell->setPort(port.first, sig); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } ExtractinvPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -64,6 +64,11 @@ struct IopadmapPass : public Pass { | |||
| 		log("        of the tristate driver and the 2nd portname is the internal output\n"); | ||||
| 		log("        buffering the external signal.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -ignore <celltype> <portname>[:<portname>]*\n"); | ||||
| 		log("        Skips mapping inputs/outputs that are already connected to given\n"); | ||||
| 		log("        ports of the given cell.  Can be used multiple times.  This is in\n"); | ||||
| 		log("        addition to the cells specified as mapping targets.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -widthparam <param_name>\n"); | ||||
| 		log("        Use the specified parameter name to set the port width.\n"); | ||||
| 		log("\n"); | ||||
|  | @ -88,6 +93,7 @@ struct IopadmapPass : public Pass { | |||
| 		std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3; | ||||
| 		std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4; | ||||
| 		std::string widthparam, nameparam; | ||||
| 		pool<pair<IdString, IdString>> ignore; | ||||
| 		bool flag_bits = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
|  | @ -127,6 +133,18 @@ struct IopadmapPass : public Pass { | |||
| 				split_portname_pair(tinoutpad_portname3, tinoutpad_portname4); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-ignore" && argidx+2 < args.size()) { | ||||
| 				std::string ignore_celltype = args[++argidx]; | ||||
| 				std::string ignore_portname = args[++argidx]; | ||||
| 				std::string ignore_portname2; | ||||
| 				while (!ignore_portname.empty()) { | ||||
| 					split_portname_pair(ignore_portname, ignore_portname2); | ||||
| 					ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname))); | ||||
| 
 | ||||
| 					ignore_portname = ignore_portname2; | ||||
| 				} | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-widthparam" && argidx+1 < args.size()) { | ||||
| 				widthparam = args[++argidx]; | ||||
| 				continue; | ||||
|  | @ -143,6 +161,23 @@ struct IopadmapPass : public Pass { | |||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (!inpad_portname2.empty()) | ||||
| 			ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2))); | ||||
| 		if (!outpad_portname2.empty()) | ||||
| 			ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2))); | ||||
| 		if (!inoutpad_portname2.empty()) | ||||
| 			ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2))); | ||||
| 		if (!toutpad_portname3.empty()) | ||||
| 			ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3))); | ||||
| 		if (!tinoutpad_portname4.empty()) | ||||
| 			ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4))); | ||||
| 
 | ||||
| 		for (auto module : design->modules()) | ||||
| 			if (module->get_blackbox_attribute()) | ||||
| 				for (auto wire : module->wires()) | ||||
| 					if (wire->get_bool_attribute("\\iopad_external_pin")) | ||||
| 						ignore.insert(make_pair(module->name, wire->name)); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		{ | ||||
| 			dict<IdString, pool<int>> skip_wires; | ||||
|  | @ -150,28 +185,11 @@ struct IopadmapPass : public Pass { | |||
| 			SigMap sigmap(module); | ||||
| 
 | ||||
| 			for (auto cell : module->cells()) | ||||
| 			{ | ||||
| 				if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2))) | ||||
| 					for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2)))) | ||||
| 			for (auto port : cell->connections()) | ||||
| 				if (ignore.count(make_pair(cell->type, port.first))) | ||||
| 					for (auto bit : sigmap(port.second)) | ||||
| 						skip_wire_bits.insert(bit); | ||||
| 
 | ||||
| 				if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2))) | ||||
| 					for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2)))) | ||||
| 						skip_wire_bits.insert(bit); | ||||
| 
 | ||||
| 				if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2))) | ||||
| 					for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2)))) | ||||
| 						skip_wire_bits.insert(bit); | ||||
| 
 | ||||
| 				if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3))) | ||||
| 					for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3)))) | ||||
| 						skip_wire_bits.insert(bit); | ||||
| 
 | ||||
| 				if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4))) | ||||
| 					for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4)))) | ||||
| 						skip_wire_bits.insert(bit); | ||||
| 			} | ||||
| 
 | ||||
| 			if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) | ||||
| 			{ | ||||
| 				dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits; | ||||
|  |  | |||
|  | @ -26,9 +26,7 @@ PRIVATE_NAMESPACE_BEGIN | |||
| struct ShregmapTech | ||||
| { | ||||
| 	virtual ~ShregmapTech() { } | ||||
| 	virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {} | ||||
| 	virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {} | ||||
| 	virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0; | ||||
| 	virtual bool analyze(vector<int> &taps) = 0; | ||||
| 	virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0; | ||||
| }; | ||||
| 
 | ||||
|  | @ -56,7 +54,7 @@ struct ShregmapOptions | |||
| 
 | ||||
| struct ShregmapTechGreenpak4 : ShregmapTech | ||||
| { | ||||
| 	bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/) | ||||
| 	bool analyze(vector<int> &taps) | ||||
| 	{ | ||||
| 		if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { | ||||
| 			taps.clear(); | ||||
|  | @ -93,155 +91,6 @@ struct ShregmapTechGreenpak4 : ShregmapTech | |||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct ShregmapTechXilinx7 : ShregmapTech | ||||
| { | ||||
| 	dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset; | ||||
| 	const ShregmapOptions &opts; | ||||
| 
 | ||||
| 	ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} | ||||
| 
 | ||||
| 	virtual void init(const Module* module, const SigMap &sigmap) override | ||||
| 	{ | ||||
| 		for (const auto &i : module->cells_) { | ||||
| 			auto cell = i.second; | ||||
| 			if (cell->type == ID($shiftx)) { | ||||
| 				if (cell->getParam(ID(Y_WIDTH)) != 1) continue; | ||||
| 				int j = 0; | ||||
| 				for (auto bit : sigmap(cell->getPort(ID::A))) | ||||
| 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0); | ||||
| 				log_assert(j == cell->getParam(ID(A_WIDTH)).as_int()); | ||||
| 			} | ||||
| 			else if (cell->type == ID($mux)) { | ||||
| 				int j = 0; | ||||
| 				for (auto bit : sigmap(cell->getPort(ID::A))) | ||||
| 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); | ||||
| 				j = 0; | ||||
| 				for (auto bit : sigmap(cell->getPort(ID::B))) | ||||
| 					sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override | ||||
| 	{ | ||||
| 		auto it = sigbit_to_shiftx_offset.find(bit); | ||||
| 		if (it == sigbit_to_shiftx_offset.end()) | ||||
| 			return; | ||||
| 		if (cell) { | ||||
| 			if (cell->type == ID($shiftx) && port == ID::A) | ||||
| 				return; | ||||
| 			if (cell->type == ID($mux) && port.in(ID::A, ID::B)) | ||||
| 				return; | ||||
| 		} | ||||
| 		sigbit_to_shiftx_offset.erase(it); | ||||
| 	} | ||||
| 
 | ||||
| 	virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override | ||||
| 	{ | ||||
| 		if (GetSize(taps) == 1) | ||||
| 			return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]); | ||||
| 
 | ||||
| 		if (taps.back() < opts.minlen-1) | ||||
| 			return false; | ||||
| 
 | ||||
| 		Cell *shiftx = nullptr; | ||||
| 		int group = 0; | ||||
| 		for (int i = 0; i < GetSize(taps); ++i) { | ||||
| 			auto it = sigbit_to_shiftx_offset.find(qbits[i]); | ||||
| 			if (it == sigbit_to_shiftx_offset.end()) | ||||
| 				return false; | ||||
| 
 | ||||
| 			// Check taps are sequential
 | ||||
| 			if (i != taps[i]) | ||||
| 				return false; | ||||
| 			// Check taps are not connected to a shift register,
 | ||||
| 			// or sequential to the same shift register
 | ||||
| 			if (i == 0) { | ||||
| 				int offset; | ||||
| 				std::tie(shiftx,offset,group) = it->second; | ||||
| 				if (offset != i) | ||||
| 					return false; | ||||
| 			} | ||||
| 			else { | ||||
| 				Cell *shiftx_ = std::get<0>(it->second); | ||||
| 				if (shiftx_ != shiftx) | ||||
| 					return false; | ||||
| 				int offset = std::get<1>(it->second); | ||||
| 				if (offset != i) | ||||
| 					return false; | ||||
| 				int group_ = std::get<2>(it->second); | ||||
| 				if (group_ != group) | ||||
| 					return false; | ||||
| 			} | ||||
| 		} | ||||
| 		log_assert(shiftx); | ||||
| 
 | ||||
| 		// Only map if $shiftx exclusively covers the shift register
 | ||||
| 		if (shiftx->type == ID($shiftx)) { | ||||
| 			if (GetSize(taps) > shiftx->getParam(ID(A_WIDTH)).as_int()) | ||||
| 				return false; | ||||
| 			// Due to padding the most significant bits of A may be 1'bx,
 | ||||
| 			//   and if so, discount them
 | ||||
| 			if (GetSize(taps) < shiftx->getParam(ID(A_WIDTH)).as_int()) { | ||||
| 				const SigSpec A = shiftx->getPort(ID::A); | ||||
| 				const int A_width = shiftx->getParam(ID(A_WIDTH)).as_int(); | ||||
| 				for (int i = GetSize(taps); i < A_width; ++i) | ||||
| 					if (A[i] != RTLIL::Sx) return false; | ||||
| 			} | ||||
| 			else if (GetSize(taps) != shiftx->getParam(ID(A_WIDTH)).as_int()) | ||||
| 				return false; | ||||
| 		} | ||||
| 		else if (shiftx->type == ID($mux)) { | ||||
| 			if (GetSize(taps) != 2) | ||||
| 				return false; | ||||
| 		} | ||||
| 		else log_abort(); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override | ||||
| 	{ | ||||
| 		const auto &tap = *taps.begin(); | ||||
| 		auto bit = tap.second; | ||||
| 
 | ||||
| 		auto it = sigbit_to_shiftx_offset.find(bit); | ||||
| 		log_assert(it != sigbit_to_shiftx_offset.end()); | ||||
| 
 | ||||
| 		auto newcell = cell->module->addCell(NEW_ID, ID($__XILINX_SHREG_)); | ||||
| 		newcell->set_src_attribute(cell->get_src_attribute()); | ||||
| 		newcell->setParam(ID(DEPTH), cell->getParam(ID(DEPTH))); | ||||
| 		newcell->setParam(ID(INIT), cell->getParam(ID(INIT))); | ||||
| 		newcell->setParam(ID(CLKPOL), cell->getParam(ID(CLKPOL))); | ||||
| 		newcell->setParam(ID(ENPOL), cell->getParam(ID(ENPOL))); | ||||
| 
 | ||||
| 		newcell->setPort(ID(C), cell->getPort(ID(C))); | ||||
| 		newcell->setPort(ID(D), cell->getPort(ID(D))); | ||||
| 		if (cell->hasPort(ID(E))) | ||||
| 			newcell->setPort(ID(E), cell->getPort(ID(E))); | ||||
| 
 | ||||
| 		Cell* shiftx = std::get<0>(it->second); | ||||
| 		RTLIL::SigSpec l_wire, q_wire; | ||||
| 		if (shiftx->type == ID($shiftx)) { | ||||
| 			l_wire = shiftx->getPort(ID::B); | ||||
| 			q_wire = shiftx->getPort(ID::Y); | ||||
| 			shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID)); | ||||
| 		} | ||||
| 		else if (shiftx->type == ID($mux)) { | ||||
| 			l_wire = shiftx->getPort(ID(S)); | ||||
| 			q_wire = shiftx->getPort(ID::Y); | ||||
| 			shiftx->setPort(ID::Y, cell->module->addWire(NEW_ID)); | ||||
| 		} | ||||
| 		else log_abort(); | ||||
| 
 | ||||
| 		newcell->setPort(ID(Q), q_wire); | ||||
| 		newcell->setPort(ID(L), l_wire); | ||||
| 
 | ||||
| 		return false; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct ShregmapWorker | ||||
| { | ||||
| 	Module *module; | ||||
|  | @ -264,10 +113,8 @@ struct ShregmapWorker | |||
| 		for (auto wire : module->wires()) | ||||
| 		{ | ||||
| 			if (wire->port_output || wire->get_bool_attribute(ID::keep)) { | ||||
| 				for (auto bit : sigmap(wire)) { | ||||
| 				for (auto bit : sigmap(wire)) | ||||
| 					sigbit_with_non_chain_users.insert(bit); | ||||
| 					if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {}); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (wire->attributes.count(ID(init))) { | ||||
|  | @ -317,10 +164,8 @@ struct ShregmapWorker | |||
| 
 | ||||
| 			for (auto conn : cell->connections()) | ||||
| 				if (cell->input(conn.first)) | ||||
| 					for (auto bit : sigmap(conn.second)) { | ||||
| 					for (auto bit : sigmap(conn.second)) | ||||
| 						sigbit_with_non_chain_users.insert(bit); | ||||
| 						if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first); | ||||
| 					} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -346,7 +191,7 @@ struct ShregmapWorker | |||
| 				IdString q_port = opts.ffcells.at(c1->type).second; | ||||
| 
 | ||||
| 				auto c1_conn = c1->connections(); | ||||
| 				auto c2_conn = c1->connections(); | ||||
| 				auto c2_conn = c2->connections(); | ||||
| 
 | ||||
| 				c1_conn.erase(d_port); | ||||
| 				c1_conn.erase(q_port); | ||||
|  | @ -425,7 +270,7 @@ struct ShregmapWorker | |||
| 					if (taps.empty() || taps.back() < depth-1) | ||||
| 						taps.push_back(depth-1); | ||||
| 
 | ||||
| 					if (opts.tech->analyze(taps, qbits)) | ||||
| 					if (opts.tech->analyze(taps)) | ||||
| 						break; | ||||
| 
 | ||||
| 					taps.pop_back(); | ||||
|  | @ -544,9 +389,6 @@ struct ShregmapWorker | |||
| 	ShregmapWorker(Module *module, const ShregmapOptions &opts) : | ||||
| 			module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) | ||||
| 	{ | ||||
| 		if (opts.tech) | ||||
| 			opts.tech->init(module, sigmap); | ||||
| 
 | ||||
| 		make_sigbit_chain_next_prev(); | ||||
| 		find_chain_start_cells(); | ||||
| 
 | ||||
|  | @ -617,11 +459,6 @@ struct ShregmapPass : public Pass { | |||
| 		log("\n"); | ||||
| 		log("    -tech greenpak4\n"); | ||||
| 		log("        map to greenpak4 shift registers.\n"); | ||||
| 		log("        this option also implies -clkpol pos -zinit\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -tech xilinx\n"); | ||||
| 		log("        map to xilinx dynamic-length shift registers.\n"); | ||||
| 		log("        this option also implies -params -init\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
|  | @ -676,12 +513,6 @@ struct ShregmapPass : public Pass { | |||
| 					clkpol = "pos"; | ||||
| 					opts.zinit = true; | ||||
| 					opts.tech = new ShregmapTechGreenpak4; | ||||
| 				} | ||||
| 				else if (tech == "xilinx") { | ||||
| 					opts.init = true; | ||||
| 					opts.params = true; | ||||
| 					enpol = "any_or_none"; | ||||
| 					opts.tech = new ShregmapTechXilinx7(opts); | ||||
| 				} else { | ||||
| 					argidx--; | ||||
| 					break; | ||||
|  |  | |||
|  | @ -205,20 +205,57 @@ struct TechmapWorker | |||
| 		} | ||||
| 
 | ||||
| 		std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; | ||||
| 		dict<Wire*, IdString> temp_renamed_wires; | ||||
| 		pool<SigBit> autopurge_tpl_bits; | ||||
| 
 | ||||
| 		for (auto &it : tpl->wires_) { | ||||
| 		for (auto &it : tpl->wires_) | ||||
| 		{ | ||||
| 			if (it.second->port_id > 0) | ||||
| 				positional_ports[stringf("$%d", it.second->port_id)] = it.first; | ||||
| 			{ | ||||
| 				IdString posportname = stringf("$%d", it.second->port_id); | ||||
| 				positional_ports[posportname] = it.first; | ||||
| 
 | ||||
| 				if (!flatten_mode && it.second->get_bool_attribute(ID(techmap_autopurge)) && | ||||
| 						(!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) && | ||||
| 						(!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) | ||||
| 				{ | ||||
| 					if (sigmaps.count(tpl) == 0) | ||||
| 						sigmaps[tpl].set(tpl); | ||||
| 
 | ||||
| 					for (auto bit : sigmaps.at(tpl)(it.second)) | ||||
| 						if (bit.wire != nullptr) | ||||
| 							autopurge_tpl_bits.insert(bit); | ||||
| 				} | ||||
| 			} | ||||
| 			IdString w_name = it.second->name; | ||||
| 			apply_prefix(cell->name, w_name); | ||||
| 			RTLIL::Wire *w = module->addWire(w_name, it.second); | ||||
| 			RTLIL::Wire *w = module->wire(w_name); | ||||
| 			if (w != nullptr) { | ||||
| 				if (!flatten_mode || !w->get_bool_attribute(ID(hierconn))) { | ||||
| 					temp_renamed_wires[w] = w->name; | ||||
| 					module->rename(w, NEW_ID); | ||||
| 					w = nullptr; | ||||
| 				} else { | ||||
| 					w->attributes.erase(ID(hierconn)); | ||||
| 					if (GetSize(w) < GetSize(it.second)) { | ||||
| 						log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), | ||||
| 								log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); | ||||
| 						w->width = GetSize(it.second); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (w == nullptr) { | ||||
| 				w = module->addWire(w_name, it.second); | ||||
| 				w->port_input = false; | ||||
| 				w->port_output = false; | ||||
| 				w->port_id = 0; | ||||
| 				if (!flatten_mode) | ||||
| 					w->attributes.erase(ID(techmap_autopurge)); | ||||
| 				if (it.second->get_bool_attribute(ID(_techmap_special_))) | ||||
| 					w->attributes.clear(); | ||||
| 				if (w->attributes.count(ID(src))) | ||||
| 					w->add_strpool_attribute(ID(src), extra_src_attrs); | ||||
| 			} | ||||
| 			design->select(module, w); | ||||
| 		} | ||||
| 
 | ||||
|  | @ -322,6 +359,12 @@ struct TechmapWorker | |||
| 				for (auto &attr : w->attributes) { | ||||
| 					if (attr.first == ID(src)) | ||||
| 						continue; | ||||
| 					auto lhs = GetSize(extra_connect.first); | ||||
| 					auto rhs = GetSize(extra_connect.second); | ||||
| 					if (lhs > rhs) | ||||
| 						extra_connect.first.remove(rhs, lhs-rhs); | ||||
| 					else if (rhs > lhs) | ||||
| 						extra_connect.second.remove(lhs, rhs-lhs); | ||||
| 					module->connect(extra_connect); | ||||
| 					break; | ||||
| 				} | ||||
|  | @ -344,10 +387,30 @@ struct TechmapWorker | |||
| 			if (!flatten_mode && c->type.begins_with("\\$")) | ||||
| 				c->type = c->type.substr(1); | ||||
| 
 | ||||
| 			for (auto &it2 : c->connections_) { | ||||
| 			vector<IdString> autopurge_ports; | ||||
| 
 | ||||
| 			for (auto &it2 : c->connections_) | ||||
| 			{ | ||||
| 				bool autopurge = false; | ||||
| 				if (!autopurge_tpl_bits.empty()) { | ||||
| 					autopurge = GetSize(it2.second) != 0; | ||||
| 					for (auto &bit : sigmaps.at(tpl)(it2.second)) | ||||
| 						if (!autopurge_tpl_bits.count(bit)) { | ||||
| 							autopurge = false; | ||||
| 							break; | ||||
| 						} | ||||
| 				} | ||||
| 
 | ||||
| 				if (autopurge) { | ||||
| 					autopurge_ports.push_back(it2.first); | ||||
| 				} else { | ||||
| 					apply_prefix(cell->name, it2.second, module); | ||||
| 					port_signal_map.apply(it2.second); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			for (auto &it2 : autopurge_ports) | ||||
| 				c->unsetPort(it2); | ||||
| 
 | ||||
| 			if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { | ||||
| 				IdString memid = c->getParam(ID(MEMID)).decode_string(); | ||||
|  | @ -380,6 +443,16 @@ struct TechmapWorker | |||
| 		} | ||||
| 
 | ||||
| 		module->remove(cell); | ||||
| 
 | ||||
| 		for (auto &it : temp_renamed_wires) | ||||
| 		{ | ||||
| 			Wire *w = it.first; | ||||
| 			IdString name = it.second; | ||||
| 			IdString altname = module->uniquify(name); | ||||
| 			Wire *other_w = module->wire(name); | ||||
| 			module->rename(other_w, altname); | ||||
| 			module->rename(w, name); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, | ||||
|  | @ -396,6 +469,18 @@ struct TechmapWorker | |||
| 
 | ||||
| 		SigMap sigmap(module); | ||||
| 
 | ||||
| 		dict<SigBit, State> init_bits; | ||||
| 		pool<SigBit> remove_init_bits; | ||||
| 
 | ||||
| 		for (auto wire : module->wires()) { | ||||
| 			if (wire->attributes.count("\\init")) { | ||||
| 				Const value = wire->attributes.at("\\init"); | ||||
| 				for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) | ||||
| 					if (value[i] != State::Sx) | ||||
| 						init_bits[sigmap(SigBit(wire, i))] = value[i]; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells; | ||||
| 		std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit; | ||||
| 		std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell; | ||||
|  | @ -633,6 +718,17 @@ struct TechmapWorker | |||
| 									bit = RTLIL::SigBit(RTLIL::State::Sx); | ||||
| 							parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); | ||||
| 						} | ||||
| 						if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))) != 0) { | ||||
| 							auto sig = sigmap(conn.second); | ||||
| 							RTLIL::Const value(State::Sx, sig.size()); | ||||
| 							for (int i = 0; i < sig.size(); i++) { | ||||
| 								auto it = init_bits.find(sig[i]); | ||||
| 								if (it != init_bits.end()) { | ||||
| 									value[i] = it->second; | ||||
| 								} | ||||
| 							} | ||||
| 							parameters[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value; | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 					int unique_bit_id_counter = 0; | ||||
|  | @ -833,7 +929,7 @@ struct TechmapWorker | |||
| 
 | ||||
| 					TechmapWires twd = techmap_find_special_wires(tpl); | ||||
| 					for (auto &it : twd) { | ||||
| 						if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") | ||||
| 						if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") | ||||
| 							log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); | ||||
| 						if (techmap_do_cache[tpl]) | ||||
| 							for (auto &it2 : it.second) | ||||
|  | @ -864,6 +960,23 @@ struct TechmapWorker | |||
| 					mkdebug.off(); | ||||
| 				} | ||||
| 
 | ||||
| 				TechmapWires twd = techmap_find_special_wires(tpl); | ||||
| 				for (auto &it : twd) { | ||||
| 					if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_") { | ||||
| 						for (auto &it2 : it.second) { | ||||
| 							auto val = it2.value.as_const(); | ||||
| 							auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); | ||||
| 							auto it = cell->connections().find(wirename); | ||||
| 							if (it != cell->connections().end()) { | ||||
| 								auto sig = sigmap(it->second); | ||||
| 								for (int i = 0; i < sig.size(); i++) | ||||
| 									if (val[i] == State::S1) | ||||
| 										remove_init_bits.insert(sig[i]); | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				if (extern_mode && !in_recursion) | ||||
| 				{ | ||||
| 					std::string m_name = stringf("$extern:%s", log_id(tpl)); | ||||
|  | @ -907,6 +1020,25 @@ struct TechmapWorker | |||
| 			handled_cells.insert(cell); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!remove_init_bits.empty()) { | ||||
| 			for (auto wire : module->wires()) | ||||
| 				if (wire->attributes.count("\\init")) { | ||||
| 					Const &value = wire->attributes.at("\\init"); | ||||
| 					bool do_cleanup = true; | ||||
| 					for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { | ||||
| 						SigBit bit = sigmap(SigBit(wire, i)); | ||||
| 						if (remove_init_bits.count(bit)) | ||||
| 							value[i] = State::Sx; | ||||
| 						else if (value[i] != State::Sx) | ||||
| 							do_cleanup = false; | ||||
| 					} | ||||
| 					if (do_cleanup) { | ||||
| 						log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); | ||||
| 						wire->attributes.erase("\\init"); | ||||
| 					} | ||||
| 				} | ||||
| 		} | ||||
| 
 | ||||
| 		if (log_continue) { | ||||
| 			log_header(design, "Continuing TECHMAP pass.\n"); | ||||
| 			log_continue = false; | ||||
|  | @ -943,7 +1075,8 @@ struct TechmapPass : public Pass { | |||
| 		log("        instead of inlining them.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -max_iter <number>\n"); | ||||
| 		log("        only run the specified number of iterations.\n"); | ||||
| 		log("        only run the specified number of iterations on each module.\n"); | ||||
| 		log("        default: unlimited\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -recursive\n"); | ||||
| 		log("        instead of the iterative breadth-first algorithm use a recursive\n"); | ||||
|  | @ -980,6 +1113,11 @@ struct TechmapPass : public Pass { | |||
| 		log("will create a wrapper for the cell and then run the command string that the\n"); | ||||
| 		log("attribute is set to on the wrapper module.\n"); | ||||
| 		log("\n"); | ||||
| 		log("When a port on a module in the map file has the 'techmap_autopurge' attribute\n"); | ||||
| 		log("set, and that port is not connected in the instantiation that is mapped, then\n"); | ||||
| 		log("then a cell port connected only to such wires will be omitted in the mapped\n"); | ||||
| 		log("version of the circuit.\n"); | ||||
| 		log("\n"); | ||||
| 		log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n"); | ||||
| 		log("or *._TECHMAP_* are special wires that are used to pass instructions from\n"); | ||||
| 		log("the mapping module to the techmap command. At the moment the following special\n"); | ||||
|  | @ -1018,6 +1156,13 @@ struct TechmapPass : public Pass { | |||
| 		log("\n"); | ||||
| 		log("        It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    _TECHMAP_REMOVEINIT_<port-name>_\n"); | ||||
| 		log("        When this wire is set to a constant value, the init attribute of the wire(s)\n"); | ||||
| 		log("        connected to this port will be consumed.  This wire must have the same\n"); | ||||
| 		log("        width as the given port, and for every bit that is set to 1 in the value,\n"); | ||||
| 		log("        the corresponding init attribute bit will be changed to 1'bx.  If all\n"); | ||||
| 		log("        bits of an init attribute are left as x, it will be removed.\n"); | ||||
| 		log("\n"); | ||||
| 		log("In addition to this special wires, techmap also supports special parameters in\n"); | ||||
| 		log("modules in the map file:\n"); | ||||
| 		log("\n"); | ||||
|  | @ -1031,6 +1176,13 @@ struct TechmapPass : public Pass { | |||
| 		log("        former has a 1-bit for each constant input bit and the latter has the\n"); | ||||
| 		log("        value for this bit. The unused bits of the latter are set to undef (x).\n"); | ||||
| 		log("\n"); | ||||
| 		log("    _TECHMAP_WIREINIT_<port-name>_\n"); | ||||
| 		log("        When a parameter with this name exists, it will be set to the initial\n"); | ||||
| 		log("        value of the wire(s) connected to the given port, as specified by the init\n"); | ||||
| 		log("        attribute. If the attribute doesn't exist, x will be filled for the\n"); | ||||
| 		log("        missing bits.  To remove the init attribute bits used, use the\n"); | ||||
| 		log("        _TECHMAP_REMOVEINIT_*_ wires.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    _TECHMAP_BITS_CONNMAP_\n"); | ||||
| 		log("    _TECHMAP_CONNMAP_<port-name>_\n"); | ||||
| 		log("        For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n"); | ||||
|  | @ -1157,6 +1309,7 @@ struct TechmapPass : public Pass { | |||
| 			RTLIL::Module *module = *worker.module_queue.begin(); | ||||
| 			worker.module_queue.erase(module); | ||||
| 
 | ||||
| 			int module_max_iter = max_iter; | ||||
| 			bool did_something = true; | ||||
| 			std::set<RTLIL::Cell*> handled_cells; | ||||
| 			while (did_something) { | ||||
|  | @ -1165,7 +1318,7 @@ struct TechmapPass : public Pass { | |||
| 					did_something = true; | ||||
| 				if (did_something) | ||||
| 					module->check(); | ||||
| 				if (max_iter > 0 && --max_iter == 0) | ||||
| 				if (module_max_iter > 0 && --module_max_iter == 0) | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
|  | @ -345,6 +345,9 @@ struct TestAutotbBackend : public Backend { | |||
| 		log("value after initialization. This can e.g. be used to force a reset signal\n"); | ||||
| 		log("low in order to explore more inner states in a state machine.\n"); | ||||
| 		log("\n"); | ||||
| 		log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n"); | ||||
| 		log("generation.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -n <int>\n"); | ||||
| 		log("        number of iterations the test bench should run (default = 1000)\n"); | ||||
| 		log("\n"); | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| 
 | ||||
| OBJS += techlibs/anlogic/synth_anlogic.o | ||||
| OBJS += techlibs/anlogic/anlogic_eqn.o | ||||
| OBJS += techlibs/anlogic/anlogic_determine_init.o | ||||
| OBJS += techlibs/anlogic/anlogic_fixcarry.o | ||||
| 
 | ||||
| $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v)) | ||||
| $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v)) | ||||
|  |  | |||
|  | @ -1,72 +0,0 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct AnlogicDetermineInitPass : public Pass { | ||||
| 	AnlogicDetermineInitPass() : Pass("anlogic_determine_init", "Anlogic: Determine the init value of cells") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		log("\n"); | ||||
| 		log("    anlogic_determine_init [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Determine the init value of cells that doesn't allow unknown init value.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	Const determine_init(Const init) | ||||
| 	{ | ||||
| 		for (int i = 0; i < GetSize(init); i++) { | ||||
| 			if (init[i] != State::S0 && init[i] != State::S1) | ||||
| 				init[i] = State::S0; | ||||
| 		} | ||||
| 
 | ||||
| 		return init; | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing ANLOGIC_DETERMINE_INIT pass (determine init value for cells).\n"); | ||||
| 
 | ||||
| 		extra_args(args, args.size(), design); | ||||
| 
 | ||||
| 		int cnt = 0; | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		{ | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			{ | ||||
| 				if (cell->type == "\\EG_LOGIC_DRAM16X4") | ||||
| 				{ | ||||
| 					cell->setParam("\\INIT_D0", determine_init(cell->getParam("\\INIT_D0"))); | ||||
| 					cell->setParam("\\INIT_D1", determine_init(cell->getParam("\\INIT_D1"))); | ||||
| 					cell->setParam("\\INIT_D2", determine_init(cell->getParam("\\INIT_D2"))); | ||||
| 					cell->setParam("\\INIT_D3", determine_init(cell->getParam("\\INIT_D3"))); | ||||
| 					cnt++; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		log_header(design, "Updated %d cells with determined init value.\n", cnt); | ||||
| 	} | ||||
| } AnlogicDetermineInitPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										130
									
								
								techlibs/anlogic/anlogic_fixcarry.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								techlibs/anlogic/anlogic_fixcarry.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2019  Miodrag Milanovic <miodrag@symbioticeda.com> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| static SigBit get_bit_or_zero(const SigSpec &sig) | ||||
| { | ||||
| 	if (GetSize(sig) == 0) | ||||
| 		return State::S0; | ||||
| 	return sig[0]; | ||||
| } | ||||
| 
 | ||||
| static void fix_carry_chain(Module *module) | ||||
| { | ||||
| 	SigMap sigmap(module); | ||||
| 
 | ||||
| 	pool<SigBit> ci_bits; | ||||
| 	dict<SigBit, SigBit> mapping_bits; | ||||
| 
 | ||||
| 	for (auto cell : module->cells()) | ||||
| 	{ | ||||
| 		if (cell->type == "\\AL_MAP_ADDER") { | ||||
| 			if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue; | ||||
| 			SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a")); | ||||
| 			SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b")); | ||||
| 			if (bit_i0 == State::S0 && bit_i1== State::S0) { | ||||
| 				SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); | ||||
| 				SigSpec o = cell->getPort("\\o"); | ||||
| 				if (GetSize(o) == 2) { | ||||
| 					SigBit bit_o = o[0]; | ||||
| 					ci_bits.insert(bit_ci);				 | ||||
| 					mapping_bits[bit_ci] = bit_o;				 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	vector<Cell*> adders_to_fix_cells; | ||||
| 	for (auto cell : module->cells()) | ||||
| 	{ | ||||
| 		if (cell->type == "\\AL_MAP_ADDER") { | ||||
| 			if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue; | ||||
| 			SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); | ||||
| 			SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a")); | ||||
| 			SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b"));			 | ||||
| 			SigBit canonical_bit = sigmap(bit_ci); | ||||
| 			if (!ci_bits.count(canonical_bit)) | ||||
| 				continue;			 | ||||
| 			if (bit_i0 == State::S0 && bit_i1== State::S0)  | ||||
| 				continue; | ||||
| 
 | ||||
| 			adders_to_fix_cells.push_back(cell); | ||||
| 			log("Found %s cell named %s with invalid 'c' signal.\n", log_id(cell->type), log_id(cell)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto cell : adders_to_fix_cells) | ||||
| 	{ | ||||
| 		SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); | ||||
| 		SigBit canonical_bit = sigmap(bit_ci); | ||||
| 		auto bit = mapping_bits.at(canonical_bit); | ||||
| 		log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell)); | ||||
| 		Cell *c = module->addCell(NEW_ID, "\\AL_MAP_ADDER"); | ||||
| 		SigBit new_bit = module->addWire(NEW_ID); | ||||
| 		SigBit dummy_bit = module->addWire(NEW_ID); | ||||
| 		SigSpec bits; | ||||
| 		bits.append(dummy_bit); | ||||
| 		bits.append(new_bit); | ||||
| 		c->setParam("\\ALUTYPE", Const("ADD_CARRY")); | ||||
| 		c->setPort("\\a", bit); | ||||
| 		c->setPort("\\b", State::S0); | ||||
| 		c->setPort("\\c", State::S0); | ||||
| 		c->setPort("\\o", bits); | ||||
| 		 | ||||
| 		cell->setPort("\\c", new_bit); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| struct AnlogicCarryFixPass : public Pass { | ||||
| 	AnlogicCarryFixPass() : Pass("anlogic_fixcarry", "Anlogic: fix carry chain") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    anlogic_fixcarry [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Add Anlogic adders to fix carry chain if needed.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing anlogic_fixcarry pass (fix invalid carry chain).\n"); | ||||
| 		 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		Module *module = design->top_module(); | ||||
| 
 | ||||
| 		if (module == nullptr) | ||||
| 			log_cmd_error("No top module found.\n"); | ||||
| 
 | ||||
| 		fix_carry_chain(module);		 | ||||
| 	} | ||||
| } AnlogicCarryFixPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -31,7 +31,10 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); | |||
| 	output [Y_WIDTH-1:0] X, Y; | ||||
| 
 | ||||
| 	input CI, BI; | ||||
| 	output CO; | ||||
| 	output [Y_WIDTH-1:0] CO; | ||||
|     | ||||
| 	wire CIx; | ||||
| 	wire [Y_WIDTH-1:0] COx; | ||||
| 
 | ||||
| 	wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; | ||||
| 
 | ||||
|  | @ -41,15 +44,16 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); | |||
| 
 | ||||
| 	wire [Y_WIDTH-1:0] AA = A_buf; | ||||
| 	wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; | ||||
| 	wire [Y_WIDTH+1:0] COx; | ||||
| 	wire [Y_WIDTH+2:0] C = {COx, CI}; | ||||
| 	wire [Y_WIDTH-1:0] C = { COx, CIx }; | ||||
| 
 | ||||
|     wire dummy; | ||||
|     AL_MAP_ADDER #( | ||||
|     	.ALUTYPE("ADD_CARRY")) | ||||
|     adder_cin  ( | ||||
|         .a(C[0]), | ||||
|         .o({COx[0], dummy}) | ||||
|         .a(CI), | ||||
| 		.b(1'b0), | ||||
| 		.c(1'b0), | ||||
|         .o({CIx, dummy}) | ||||
| 	); | ||||
| 
 | ||||
| 	genvar i; | ||||
|  | @ -59,18 +63,22 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); | |||
|         ) adder_i ( | ||||
|             .a(AA[i]), | ||||
|             .b(BB[i]), | ||||
|             .c(C[i+1]), | ||||
|             .o({COx[i+1],Y[i]}) | ||||
|             .c(C[i]), | ||||
|             .o({COx[i],Y[i]}) | ||||
|         ); | ||||
| 	  end: slice | ||||
| 	endgenerate | ||||
| 	/* End implementation */ | ||||
| 
 | ||||
| 		wire cout; | ||||
| 		AL_MAP_ADDER #( | ||||
| 			.ALUTYPE("ADD")) | ||||
| 		adder_cout  ( | ||||
| 		.c(C[Y_WIDTH+1]), | ||||
| 		.o(COx[Y_WIDTH+1]) | ||||
| 			.a(1'b0), | ||||
| 			.b(1'b0), | ||||
| 			.c(COx[i]), | ||||
| 			.o({cout, CO[i]}) | ||||
| 		); | ||||
| 	assign CO = COx[Y_WIDTH+1]; | ||||
| 	  end: slice	   | ||||
| 	endgenerate | ||||
| 
 | ||||
|    /* End implementation */ | ||||
|    assign X = AA ^ BB; | ||||
| endmodule | ||||
|  | @ -1,5 +1,5 @@ | |||
| module AL_MAP_SEQ ( | ||||
| 	output q, | ||||
| 	output reg q, | ||||
| 	input ce, | ||||
| 	input clk, | ||||
| 	input sr, | ||||
|  | @ -9,6 +9,71 @@ module AL_MAP_SEQ ( | |||
| 	parameter REGSET = "RESET"; //RESET/SET | ||||
| 	parameter SRMUX = "SR"; //SR/INV | ||||
| 	parameter SRMODE = "SYNC"; //SYNC/ASYNC | ||||
| 
 | ||||
| 	wire clk_ce; | ||||
| 	assign clk_ce = ce ? clk : 1'b0; | ||||
| 
 | ||||
| 	wire srmux; | ||||
| 	generate | ||||
| 		case (SRMUX) | ||||
| 			"SR": assign srmux = sr; | ||||
| 			"INV": assign srmux = ~sr; | ||||
| 			default: assign srmux = sr; | ||||
| 		endcase | ||||
| 	endgenerate	 | ||||
| 
 | ||||
| 	wire regset; | ||||
| 	generate | ||||
| 		case (REGSET) | ||||
| 			"RESET": assign regset = 1'b0; | ||||
| 			"SET": assign regset = 1'b1; | ||||
| 			default: assign regset = 1'b0; | ||||
| 		endcase | ||||
| 	endgenerate | ||||
| 
 | ||||
| 	initial q = regset; | ||||
| 
 | ||||
| 	generate | ||||
|    		if (DFFMODE == "FF")  | ||||
| 		begin | ||||
| 			if (SRMODE == "ASYNC")  | ||||
| 			begin | ||||
| 				always @(posedge clk_ce, posedge srmux) | ||||
| 					if (srmux) | ||||
| 						q <= regset; | ||||
| 					else  | ||||
| 						q <= d;	 | ||||
| 			end  | ||||
| 			else | ||||
| 			begin | ||||
| 				always @(posedge clk_ce) | ||||
| 					if (srmux) | ||||
| 						q <= regset; | ||||
| 					else  | ||||
| 						q <= d;	 | ||||
| 			end | ||||
| 		end | ||||
| 		else | ||||
| 		begin | ||||
| 			// DFFMODE == "LATCH" | ||||
| 			if (SRMODE == "ASYNC")  | ||||
| 			begin | ||||
| 				always @(clk_ce, srmux) | ||||
| 					if (srmux) | ||||
| 						q <= regset; | ||||
| 					else  | ||||
| 						q <= d;	 | ||||
| 			end  | ||||
| 			else | ||||
| 			begin | ||||
| 				always @(clk_ce) | ||||
| 					if (srmux) | ||||
| 						q <= regset; | ||||
| 					else  | ||||
| 						q <= d;	 | ||||
| 			end | ||||
| 		end | ||||
|     endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module AL_MAP_LUT1 ( | ||||
|  | @ -17,7 +82,8 @@ module AL_MAP_LUT1 ( | |||
| ); | ||||
| 	parameter [1:0] INIT = 2'h0; | ||||
| 	parameter EQN = "(A)"; | ||||
| 	assign o = INIT >> a; | ||||
| 
 | ||||
| 	assign o = a ? INIT[1] : INIT[0];	 | ||||
| endmodule | ||||
| 
 | ||||
| module AL_MAP_LUT2 ( | ||||
|  | @ -27,7 +93,9 @@ module AL_MAP_LUT2 ( | |||
| ); | ||||
| 	parameter [3:0] INIT = 4'h0; | ||||
| 	parameter EQN = "(A)"; | ||||
| 	assign o = INIT >> {b, a}; | ||||
| 
 | ||||
| 	wire [1:0] s1 = b ? INIT[ 3:2] : INIT[1:0]; | ||||
| 	assign o = a ? s1[1] : s1[0];	 | ||||
| endmodule | ||||
| 
 | ||||
| module AL_MAP_LUT3 ( | ||||
|  | @ -38,7 +106,10 @@ module AL_MAP_LUT3 ( | |||
| ); | ||||
| 	parameter [7:0] INIT = 8'h0; | ||||
| 	parameter EQN = "(A)"; | ||||
| 	assign o = INIT >> {c, b, a}; | ||||
| 
 | ||||
| 	wire [3:0] s2 = c ? INIT[ 7:4] : INIT[3:0]; | ||||
| 	wire [1:0] s1 = b ?   s2[ 3:2] :   s2[1:0]; | ||||
| 	assign o = a ? s1[1] : s1[0];	 | ||||
| endmodule | ||||
| 
 | ||||
| module AL_MAP_LUT4 ( | ||||
|  | @ -50,7 +121,11 @@ module AL_MAP_LUT4 ( | |||
| ); | ||||
| 	parameter [15:0] INIT = 16'h0; | ||||
| 	parameter EQN = "(A)"; | ||||
| 	assign o = INIT >> {d, c, b, a}; | ||||
| 
 | ||||
| 	wire [7:0] s3 = d ? INIT[15:8] : INIT[7:0]; | ||||
| 	wire [3:0] s2 = c ?   s3[ 7:4] :   s3[3:0]; | ||||
| 	wire [1:0] s1 = b ?   s2[ 3:2] :   s2[1:0]; | ||||
| 	assign o = a ? s1[1] : s1[0];	 | ||||
| endmodule | ||||
| 
 | ||||
| module AL_MAP_LUT5 ( | ||||
|  | @ -100,4 +175,18 @@ module AL_MAP_ADDER ( | |||
|   output [1:0] o | ||||
| ); | ||||
| 	parameter ALUTYPE = "ADD"; | ||||
| 
 | ||||
| 	generate | ||||
| 		case (ALUTYPE) | ||||
| 			"ADD": 		 assign o = a + b + c; | ||||
| 			"SUB": 		 assign o = a - b - c; | ||||
| 			"A_LE_B":    assign o = a - b - c; | ||||
| 
 | ||||
| 			"ADD_CARRY":    assign o = {  a, 1'b0 }; | ||||
| 			"SUB_CARRY":    assign o = { ~a, 1'b0 }; | ||||
| 			"A_LE_B_CARRY": assign o = {  a, 1'b0 }; | ||||
| 			default: assign o = a + b + c; | ||||
| 		endcase | ||||
| 	endgenerate	 | ||||
| 
 | ||||
| endmodule | ||||
|  |  | |||
|  | @ -154,7 +154,7 @@ struct SynthAnlogicPass : public ScriptPass | |||
| 		{ | ||||
| 			run("memory_bram -rules +/anlogic/drams.txt"); | ||||
| 			run("techmap -map +/anlogic/drams_map.v"); | ||||
| 			run("anlogic_determine_init"); | ||||
| 			run("setundef -zero -params t:EG_LOGIC_DRAM16X4"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("fine")) | ||||
|  | @ -186,6 +186,11 @@ struct SynthAnlogicPass : public ScriptPass | |||
| 		{ | ||||
| 			run("techmap -map +/anlogic/cells_map.v"); | ||||
| 			run("clean"); | ||||
| 		} | ||||
| 		 | ||||
| 		if (check_label("map_anlogic")) | ||||
| 		{ | ||||
| 			run("anlogic_fixcarry"); | ||||
| 			run("anlogic_eqn"); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,3 +28,4 @@ $(eval $(call add_share_file,share,techlibs/common/dff2ff.v)) | |||
| $(eval $(call add_share_file,share,techlibs/common/gate2lut.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/cells.lib)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/dummy.box)) | ||||
|  |  | |||
							
								
								
									
										1
									
								
								techlibs/common/dummy.box
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								techlibs/common/dummy.box
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| (dummy) 1 0 0 0 | ||||
|  | @ -175,7 +175,7 @@ struct SynthPass : public ScriptPass | |||
| 			log_cmd_error("This command only operates on fully selected designs!\n"); | ||||
| 
 | ||||
| 		if (abc == "abc9" && !lut) | ||||
| 			log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)"); | ||||
| 			log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)\n"); | ||||
| 
 | ||||
| 		log_header(design, "Executing SYNTH pass.\n"); | ||||
| 		log_push(); | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| 
 | ||||
| OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o | ||||
| OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \ | ||||
|         techlibs/ecp5/ecp5_gsr.o | ||||
| 
 | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v)) | ||||
|  | @ -11,6 +14,9 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt)) | |||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) | ||||
| 
 | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_map.v)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_unmap.v)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_model.v)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut)) | ||||
| $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut)) | ||||
|  |  | |||
|  | @ -15,16 +15,16 @@ CCU2C   1      1   9      3 | |||
| 630  379  630  379  526   275  392  141  273 | ||||
| 516  516  516  516  412   412  278  278  43 | ||||
| 
 | ||||
| # Box 2 : TRELLIS_DPR16X4 (16x4 dist ram) | ||||
| # Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram) | ||||
| # Outputs: DO0, DO1, DO2, DO3 | ||||
| # name               ID  w/b   ins   outs | ||||
| TRELLIS_DPR16X4   2     0   14    4 | ||||
| $__ABC_DPR16X4_COMB  2     0   8    4 | ||||
| 
 | ||||
| #DI0   DI1   DI2   DI3   RAD0   RAD1   RAD2   RAD3   WAD0    WAD1   WAD2   WAD3  WCK   WRE | ||||
| -      -     -     -     141    379    275    379    -       -      -      -     -     - | ||||
| -      -     -     -     141    379    275    379    -       -      -      -     -     - | ||||
| -      -     -     -     141    379    275    379    -       -      -      -     -     - | ||||
| -      -     -     -     141    379    275    379    -       -      -      -     -     - | ||||
| #A0   A1   A2   A3   RAD0   RAD1   RAD2   RAD3 | ||||
| 0     0    0    0    141    379    275    379 | ||||
| 0     0    0    0    141    379    275    379 | ||||
| 0     0    0    0    141    379    275    379 | ||||
| 0     0    0    0    141    379    275    379 | ||||
| 
 | ||||
| # Box 3 : PFUMX (MUX2) | ||||
| # Outputs: Z | ||||
|  |  | |||
							
								
								
									
										24
									
								
								techlibs/ecp5/abc_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								techlibs/ecp5/abc_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| // --------------------------------------- | ||||
| 
 | ||||
| module TRELLIS_DPR16X4 ( | ||||
| 	input  [3:0] DI, | ||||
| 	input  [3:0] WAD, | ||||
| 	input        WRE, | ||||
| 	input        WCK, | ||||
| 	input  [3:0] RAD, | ||||
| 	output [3:0] DO | ||||
| ); | ||||
| 	parameter WCKMUX = "WCK"; | ||||
| 	parameter WREMUX = "WRE"; | ||||
| 	parameter [63:0] INITVAL = 64'h0000000000000000; | ||||
|     wire [3:0] \$DO ; | ||||
| 
 | ||||
|     TRELLIS_DPR16X4 #( | ||||
|       .WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL) | ||||
|     ) _TECHMAP_REPLACE_ ( | ||||
|       .DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK), | ||||
|       .RAD(RAD), .DO(\$DO ) | ||||
|     ); | ||||
| 
 | ||||
|     \$__ABC_DPR16X4_COMB do (.A(\$DO ), .S(RAD), .Y(DO)); | ||||
| endmodule | ||||
							
								
								
									
										5
									
								
								techlibs/ecp5/abc_model.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								techlibs/ecp5/abc_model.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| // --------------------------------------- | ||||
| 
 | ||||
| (* abc_box_id=2 *) | ||||
| module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); | ||||
| endmodule | ||||
							
								
								
									
										5
									
								
								techlibs/ecp5/abc_unmap.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								techlibs/ecp5/abc_unmap.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| // --------------------------------------- | ||||
| 
 | ||||
| module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); | ||||
|     assign Y = A; | ||||
| endmodule | ||||
|  | @ -33,7 +33,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | |||
| 			.CLKBMUX(CLKBMUX), | ||||
| 			.WRITEMODE_A(WRITEMODE_A), | ||||
| 			.WRITEMODE_B("READBEFOREWRITE"), | ||||
| 			.GSR("DISABLED") | ||||
| 			.GSR("AUTO") | ||||
| 		) _TECHMAP_REPLACE_ ( | ||||
| 			`include "bram_conn_1.vh" | ||||
| 			.CLKA(CLK2), .CLKB(CLK3), | ||||
|  | @ -50,7 +50,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | |||
| 			.CLKBMUX(CLKBMUX), | ||||
| 			.WRITEMODE_A(WRITEMODE_A), | ||||
| 			.WRITEMODE_B("READBEFOREWRITE"), | ||||
| 			.GSR("DISABLED") | ||||
| 			.GSR("AUTO") | ||||
| 		) _TECHMAP_REPLACE_ ( | ||||
| 			`include "bram_conn_2.vh" | ||||
| 			.CLKA(CLK2), .CLKB(CLK3), | ||||
|  | @ -67,7 +67,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | |||
| 			.CLKBMUX(CLKBMUX), | ||||
| 			.WRITEMODE_A(WRITEMODE_A), | ||||
| 			.WRITEMODE_B("READBEFOREWRITE"), | ||||
| 			.GSR("DISABLED") | ||||
| 			.GSR("AUTO") | ||||
| 		) _TECHMAP_REPLACE_ ( | ||||
| 			`include "bram_conn_4.vh" | ||||
| 			.CLKA(CLK2), .CLKB(CLK3), | ||||
|  | @ -84,7 +84,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | |||
| 			.CLKBMUX(CLKBMUX), | ||||
| 			.WRITEMODE_A(WRITEMODE_A), | ||||
| 			.WRITEMODE_B("READBEFOREWRITE"), | ||||
| 			.GSR("DISABLED") | ||||
| 			.GSR("AUTO") | ||||
| 		) _TECHMAP_REPLACE_ ( | ||||
| 			`include "bram_conn_9.vh" | ||||
| 			.CLKA(CLK2), .CLKB(CLK3), | ||||
|  | @ -101,7 +101,7 @@ module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | |||
| 			.CLKBMUX(CLKBMUX), | ||||
| 			.WRITEMODE_A(WRITEMODE_A), | ||||
| 			.WRITEMODE_B("READBEFOREWRITE"), | ||||
| 			.GSR("DISABLED") | ||||
| 			.GSR("AUTO") | ||||
| 		) _TECHMAP_REPLACE_ ( | ||||
| 			`include "bram_conn_18.vh" | ||||
| 			.CLKA(CLK2), .CLKB(CLK3), | ||||
|  |  | |||
|  | @ -664,3 +664,23 @@ module PCSCLKDIV ( | |||
| ); | ||||
| 	parameter GSR = "DISABLED"; | ||||
| endmodule | ||||
| 
 | ||||
| // Note: this module is not marked keep as we want it swept away in synth (sim use only) | ||||
| (* blackbox *) | ||||
| module PUR ( | ||||
| 	input PUR | ||||
| ); | ||||
| 	parameter RST_PULSE = 1; | ||||
| endmodule | ||||
| 
 | ||||
| (* blackbox, keep *) | ||||
| module GSR ( | ||||
| 	input GSR | ||||
| ); | ||||
| endmodule | ||||
| 
 | ||||
| (* blackbox, keep *) | ||||
| module SGSR ( | ||||
| 	input GSR, CLK | ||||
| ); | ||||
| endmodule | ||||
							
								
								
									
										40
									
								
								techlibs/ecp5/cells_ff.vh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								techlibs/ecp5/cells_ff.vh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| // Diamond flip-flops | ||||
| module FD1P3AX(input     D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0),  .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module FD1P3AY(input     D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0),  .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3AX(input     D,     CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"),  .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0),           .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3AY(input     D,     CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"),  .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0),           .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3BX(input PD, D,     CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"),  .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD),          .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3DX(input CD, D,     CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"),  .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))        _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD),          .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3IX(input CD, D,     CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"),  .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD),          .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3JX(input PD, D,     CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"),  .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD),          .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| // TODO: Diamond latches | ||||
| // module FL1P3AY(); endmodule | ||||
| // module FL1P3AZ(); endmodule | ||||
| // module FL1P3BX(); endmodule | ||||
| // module FL1P3DX(); endmodule | ||||
| // module FL1P3IY(); endmodule | ||||
| // module FL1P3JY(); endmodule | ||||
| // module FL1S3AX(); endmodule | ||||
| // module FL1S3AY(); endmodule | ||||
| 
 | ||||
| // Diamond I/O registers | ||||
| module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("ASYNC"))       _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))       _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("ASYNC"))       _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))       _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"),   .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| // TODO: Diamond I/O latches | ||||
| // module IFS1S1B(input PD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1D(input CD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1I(input PD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1J(input CD, D, SCLK, output Q); endmodule | ||||
							
								
								
									
										14
									
								
								techlibs/ecp5/cells_io.vh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								techlibs/ecp5/cells_io.vh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| // Diamond I/O buffers | ||||
| module IB   (input I,     output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT"))  _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule | ||||
| module IBPU (input I,     output O); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("INPUT"))  _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule | ||||
| module IBPD (input I,     output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT"))  _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule | ||||
| module OB   (input I,     output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule | ||||
| module OBZ  (input I, T,  output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBZPU(input I, T,  output O); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBZPD(input I, T,  output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBCO (input I,     output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule | ||||
| module BB   (input I, T,  output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module BBPU (input I, T,  output O, inout B); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module BBPD (input I, T,  output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module ILVDS(input A, AN, output Z    ); TRELLIS_IO #(.DIR("INPUT"))  _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule | ||||
| module OLVDS(input A,     output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule | ||||
|  | @ -1,105 +1,54 @@ | |||
| module  \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| module  \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| // TODO: Diamond flip-flops | ||||
| // module FD1P3AX(); endmodule | ||||
| // module FD1P3AY(); endmodule | ||||
| // module FD1P3BX(); endmodule | ||||
| // module FD1P3DX(); endmodule | ||||
| // module FD1P3IX(); endmodule | ||||
| // module FD1P3JX(); endmodule | ||||
| // module FD1S3AX(); endmodule | ||||
| // module FD1S3AY(); endmodule | ||||
| module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule | ||||
| // module FL1P3AY(); endmodule | ||||
| // module FL1P3AZ(); endmodule | ||||
| // module FL1P3BX(); endmodule | ||||
| // module FL1P3DX(); endmodule | ||||
| // module FL1P3IY(); endmodule | ||||
| // module FL1P3JY(); endmodule | ||||
| // module FL1S3AX(); endmodule | ||||
| // module FL1S3AY(); endmodule | ||||
| 
 | ||||
| // Diamond I/O buffers | ||||
| module IB   (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule | ||||
| module IBPU (input I, output O); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("INPUT"))   _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule | ||||
| module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule | ||||
| module OB   (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule | ||||
| module OBZ  (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBZPU(input I, T, output O); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("OUTPUT"))   _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule | ||||
| module BB   (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module BBPU (input I, T, output O, inout B); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("BIDIR"))   _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT"))  _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule | ||||
| module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule | ||||
| 
 | ||||
| // Diamond I/O registers | ||||
| module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| // TODO: Diamond I/O latches | ||||
| // module IFS1S1B(input PD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1D(input CD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1I(input PD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1J(input CD, D, SCLK, output Q); endmodule | ||||
| `include "cells_ff.vh" | ||||
| `include "cells_io.vh" | ||||
| 
 | ||||
| `ifndef NO_LUT | ||||
| module \$lut (A, Y); | ||||
|  |  | |||
|  | @ -17,10 +17,12 @@ endmodule | |||
| // --------------------------------------- | ||||
| (* abc_box_id=1, lib_whitebox *) | ||||
| module CCU2C( | ||||
| 	(* abc_carry *) input CIN, | ||||
| 	(* abc_carry *) | ||||
| 	input  CIN, | ||||
| 	input  A0, B0, C0, D0, A1, B1, C1, D1, | ||||
| 	output S0, S1, | ||||
| 	(* abc_carry *) output COUT | ||||
| 	(* abc_carry *) | ||||
| 	output COUT | ||||
| ); | ||||
| 	parameter [15:0] INIT0 = 16'h0000; | ||||
| 	parameter [15:0] INIT1 = 16'h0000; | ||||
|  | @ -107,13 +109,13 @@ module PFUMX (input ALUT, BLUT, C0, output Z); | |||
| endmodule | ||||
| 
 | ||||
| // --------------------------------------- | ||||
| //(* abc_box_id=2 *) | ||||
| module TRELLIS_DPR16X4 ( | ||||
| 	(* abc_scc_break *) input [3:0] DI, | ||||
| 	(* abc_scc_break *) input [3:0] WAD, | ||||
| 	(* abc_scc_break *) input       WRE, | ||||
| 	input  [3:0] DI, | ||||
| 	input  [3:0] WAD, | ||||
| 	input        WRE, | ||||
| 	input        WCK, | ||||
| 	input  [3:0] RAD, | ||||
| 	/* (* abc_arrival=<TODO> *) */ | ||||
| 	output [3:0] DO | ||||
| ); | ||||
| 	parameter WCKMUX = "WCK"; | ||||
|  | @ -224,14 +226,15 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); | |||
| 	parameter REGSET = "RESET"; | ||||
| 	parameter [127:0] LSRMODE = "LSR"; | ||||
| 
 | ||||
| 	reg muxce; | ||||
| 	always @(*) | ||||
| 	wire muxce; | ||||
| 	generate | ||||
| 		case (CEMUX) | ||||
| 			"1": muxce = 1'b1; | ||||
| 			"0": muxce = 1'b0; | ||||
| 			"INV": muxce = ~CE; | ||||
| 			default: muxce = CE; | ||||
| 			"1": assign muxce = 1'b1; | ||||
| 			"0": assign muxce = 1'b0; | ||||
| 			"INV": assign muxce = ~CE; | ||||
| 			default: assign muxce = CE; | ||||
| 		endcase | ||||
| 	endgenerate | ||||
| 
 | ||||
| 	wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; | ||||
| 	wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; | ||||
|  | @ -688,56 +691,9 @@ module DP16KD( | |||
| 	parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; | ||||
| endmodule | ||||
| 
 | ||||
| // TODO: Diamond flip-flops | ||||
| // module FD1P3AX(); endmodule | ||||
| // module FD1P3AY(); endmodule | ||||
| // module FD1P3BX(); endmodule | ||||
| // module FD1P3DX(); endmodule | ||||
| // module FD1P3IX(); endmodule | ||||
| // module FD1P3JX(); endmodule | ||||
| // module FD1S3AX(); endmodule | ||||
| // module FD1S3AY(); endmodule | ||||
| module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule | ||||
| module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule | ||||
| // module FL1P3AY(); endmodule | ||||
| // module FL1P3AZ(); endmodule | ||||
| // module FL1P3BX(); endmodule | ||||
| // module FL1P3DX(); endmodule | ||||
| // module FL1P3IY(); endmodule | ||||
| // module FL1P3JY(); endmodule | ||||
| // module FL1S3AX(); endmodule | ||||
| // module FL1S3AY(); endmodule | ||||
| `ifndef NO_INCLUDES | ||||
| 
 | ||||
| // Diamond I/O buffers | ||||
| module IB   (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule | ||||
| module IBPU (input I, output O); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("INPUT"))   tio (.B(I), .O(O)); endmodule | ||||
| module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule | ||||
| module OB   (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule | ||||
| module OBZ  (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBZPU(input I, T, output O); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("OUTPUT"))   tio (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule | ||||
| module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule | ||||
| module BB   (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module BBPU (input I, T, output O, inout B); (* PULLMODE="UP"   *) TRELLIS_IO #(.DIR("BIDIR"))   tio (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule | ||||
| module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT"))  tio (.B(A), .O(Z)); endmodule | ||||
| module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule | ||||
| `include "cells_ff.vh" | ||||
| `include "cells_io.vh" | ||||
| 
 | ||||
| // Diamond I/O registers | ||||
| module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC"))  tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC"))  tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE"))  tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE"))  tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule | ||||
| 
 | ||||
| // TODO: Diamond I/O latches | ||||
| // module IFS1S1B(input PD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1D(input CD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1I(input PD, D, SCLK, output Q); endmodule | ||||
| // module IFS1S1J(input CD, D, SCLK, output Q); endmodule | ||||
| `endif | ||||
|  |  | |||
							
								
								
									
										135
									
								
								techlibs/ecp5/ecp5_gsr.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								techlibs/ecp5/ecp5_gsr.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *  Copyright (C) 2019  David Shah <david@symbioticeda.com> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct Ecp5GsrPass : public Pass { | ||||
| 	Ecp5GsrPass() : Pass("ecp5_gsr", "ECP5: handle GSR") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    ecp5_gsr [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Trim active low async resets connected to GSR and resolve GSR parameter,\n"); | ||||
| 		log("if a GSR or SGSR primitive is used in the design.\n"); | ||||
| 		log("\n"); | ||||
| 		log("If any cell has the GSR parameter set to \"AUTO\", this will be resolved\n"); | ||||
| 		log("to \"ENABLED\" if a GSR primitive is present and the (* nogsr *) attribute\n"); | ||||
| 		log("is not set, otherwise it will be resolved to \"DISABLED\".\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing ECP5_GSR pass (implement FF init values).\n"); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			// if (args[argidx] == "-singleton") {
 | ||||
| 			// 	singleton_mode = true;
 | ||||
| 			// 	continue;
 | ||||
| 			// }
 | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		{ | ||||
| 			log("Handling GSR in %s.\n", log_id(module)); | ||||
| 
 | ||||
| 			SigMap sigmap(module); | ||||
| 
 | ||||
| 			SigBit gsr; | ||||
| 			bool found_gsr = false; | ||||
| 
 | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			{ | ||||
| 				if (cell->type != ID(GSR) && cell->type != ID(SGSR)) | ||||
| 					continue; | ||||
| 				if (found_gsr) | ||||
| 					log_error("Found more than one GSR or SGSR cell in module %s.\n", log_id(module)); | ||||
| 				found_gsr = true; | ||||
| 				SigSpec sig_gsr = cell->getPort(ID(GSR)); | ||||
| 				if (GetSize(sig_gsr) < 1) | ||||
| 					log_error("GSR cell %s has disconnected GSR input.\n", log_id(cell)); | ||||
| 				gsr = sigmap(sig_gsr[0]); | ||||
| 			} | ||||
| 
 | ||||
| 			// Resolve GSR parameter
 | ||||
| 
 | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			{ | ||||
| 				if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "AUTO") | ||||
| 					continue; | ||||
| 				 | ||||
| 				bool gsren = found_gsr; | ||||
| 				if (cell->get_bool_attribute("\\nogsr")) | ||||
| 					gsren = false; | ||||
| 				cell->setParam(ID(GSR), gsren ? Const("ENABLED") : Const("DISABLED")); | ||||
| 				 | ||||
| 			} | ||||
| 
 | ||||
| 			if (!found_gsr) | ||||
| 				continue; | ||||
| 
 | ||||
| 			// For finding active low FF inputs
 | ||||
| 			pool<SigBit> inverted_gsr; | ||||
| 
 | ||||
| 			log_debug("GSR net in module %s is %s.\n", log_id(module), log_signal(gsr)); | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			{ | ||||
| 				if (cell->type != ID($_NOT_)) | ||||
| 					continue; | ||||
| 				SigSpec sig_a = cell->getPort(ID(A)), sig_y = cell->getPort(ID(Y)); | ||||
| 				if (GetSize(sig_a) < 1 || GetSize(sig_y) < 1) | ||||
| 					continue; | ||||
| 				SigBit a = sigmap(sig_a[0]); | ||||
| 				if (a == gsr) | ||||
| 					inverted_gsr.insert(sigmap(sig_y[0])); | ||||
| 			} | ||||
| 
 | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			{ | ||||
| 				if (cell->type != ID(TRELLIS_FF)) | ||||
| 					continue; | ||||
| 				if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "ENABLED") | ||||
| 					continue; | ||||
| 				if (!cell->hasParam(ID(SRMODE)) || cell->getParam(ID(SRMODE)).decode_string() != "ASYNC") | ||||
| 					continue; | ||||
| 				SigSpec sig_lsr = cell->getPort(ID(LSR)); | ||||
| 				if (GetSize(sig_lsr) < 1) | ||||
| 					continue; | ||||
| 				SigBit lsr = sigmap(sig_lsr[0]); | ||||
| 				if (!inverted_gsr.count(lsr)) | ||||
| 					continue; | ||||
| 				cell->setParam(ID(SRMODE), Const("LSR_OVER_CE")); | ||||
| 				cell->unsetPort(ID(LSR)); | ||||
| 			} | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| } Ecp5GsrPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -271,6 +271,8 @@ struct SynthEcp5Pass : public ScriptPass | |||
| 			run("opt_expr -undriven -mux_undef"); | ||||
| 			run("simplemap"); | ||||
| 			run("ecp5_ffinit"); | ||||
| 			run("ecp5_gsr"); | ||||
| 			run("opt_clean"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_luts")) | ||||
|  | @ -278,12 +280,17 @@ struct SynthEcp5Pass : public ScriptPass | |||
| 			if (abc2 || help_mode) { | ||||
| 				run("abc", "      (only if -abc2)"); | ||||
| 			} | ||||
| 			run("techmap -map +/ecp5/latches_map.v"); | ||||
| 			std::string techmap_args = "-map +/ecp5/latches_map.v"; | ||||
| 			if (abc9) | ||||
| 				techmap_args += " -map +/ecp5/abc_map.v -max_iter 1"; | ||||
| 			run("techmap " + techmap_args); | ||||
| 
 | ||||
| 			if (abc9) { | ||||
| 				if (nowidelut) | ||||
| 					run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200"); | ||||
| 				else | ||||
| 					run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200"); | ||||
| 				run("techmap -map +/ecp5/abc_unmap.v"); | ||||
| 			} else { | ||||
| 				if (nowidelut) | ||||
| 					run("abc -lut 4 -dress"); | ||||
|  |  | |||
							
								
								
									
										1
									
								
								techlibs/ecp5/tests/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								techlibs/ecp5/tests/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| work_* | ||||
							
								
								
									
										82
									
								
								techlibs/ecp5/tests/test_diamond_ffs.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								techlibs/ecp5/tests/test_diamond_ffs.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| import os | ||||
| import subprocess | ||||
| 
 | ||||
| if not os.path.exists("work_ff"): | ||||
| 	os.mkdir("work_ff") | ||||
| 
 | ||||
| modules = [] | ||||
| 
 | ||||
| with open("../cells_ff.vh", "r") as f: | ||||
| 	with open("work_ff/cells_ff_gate.v", "w") as g: | ||||
| 		for line in f: | ||||
| 			if not line.startswith("module"): | ||||
| 				g.write(line) | ||||
| 				continue | ||||
| 			else: | ||||
| 				spidx = line.find(" ") | ||||
| 				bridx = line.find("(") | ||||
| 				modname = line[spidx+1 : bridx] | ||||
| 				g.write("module %s_gate" % modname) | ||||
| 				g.write(line[bridx:]) | ||||
| 				inpidx = line.find("input ") | ||||
| 				outpidx = line.find(", output") | ||||
| 				modules.append((modname, [x.strip() for x in line[inpidx+6:outpidx].split(",")])) | ||||
| 
 | ||||
| with open("work_ff/testbench.v", "w") as f: | ||||
| 	print(""" | ||||
| `timescale 1ns/ 1ps | ||||
| 
 | ||||
| module testbench; | ||||
| reg pur = 0, clk, rst, cen, d; | ||||
| 
 | ||||
| // Needed for Diamond sim models | ||||
| GSR GSR_INST (.GSR(1'b1)); | ||||
| PUR PUR_INST (.PUR(pur)); | ||||
| 
 | ||||
| 
 | ||||
| initial begin | ||||
| 	$dumpfile("work_ff/ffs.vcd"); | ||||
| 	$dumpvars(0, testbench); | ||||
| 	#5; | ||||
| 	pur = 1; | ||||
| 	#95; | ||||
| 	repeat (2500) begin | ||||
| 		{clk, rst, cen, d} = $random; | ||||
| 		#10; | ||||
| 		check_outputs; | ||||
| 		#1; | ||||
| 	end | ||||
| 	$finish; | ||||
| end | ||||
| 	""", file=f) | ||||
| 
 | ||||
| 	for modname, inputs in modules: | ||||
| 		print("    wire %s_gold_q, %s_gate_q;"  % (modname, modname), file=f) | ||||
| 		portconns = [] | ||||
| 		for inp in inputs: | ||||
| 			if inp in ("SCLK", "CK"): | ||||
| 				portconns.append(".%s(clk)" % inp) | ||||
| 			elif inp in ("CD", "PD"): | ||||
| 				portconns.append(".%s(rst)" % inp) | ||||
| 			elif inp == "SP": | ||||
| 				portconns.append(".%s(cen)" % inp) | ||||
| 			elif inp == "D": | ||||
| 				portconns.append(".%s(d)" % inp) | ||||
| 			else: | ||||
| 				assert False | ||||
| 		portconns.append(".Q(%s_gold_q)" % modname) | ||||
| 		print("    %s %s_gold_i (%s);" % (modname, modname, ", ".join(portconns)), file=f) | ||||
| 		portconns[-1] = (".Q(%s_gate_q)" % modname) | ||||
| 		print("    %s_gate %s_gate_i (%s);" % (modname, modname, ", ".join(portconns)), file=f) | ||||
| 		print("", file=f) | ||||
| 	print("    task check_outputs;", file=f) | ||||
| 	print("        begin", file=f) | ||||
| 	print("             if (%s_gold_q != %s_gate_q) $display(\"MISMATCH at %%1t:  %s_gold_q=%%b, %s_gate_q=%%b\", $time, %s_gold_q, %s_gate_q);" % | ||||
| 			(modname, modname, modname, modname, modname, modname), file=f) | ||||
| 	print("        end", file=f) | ||||
| 	print("    endtask", file=f) | ||||
| 	print("endmodule", file=f) | ||||
| 
 | ||||
| diamond_models = "/usr/local/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u" | ||||
| subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim.v", "work_ff/testbench.v"]) | ||||
| subprocess.call(["vvp", "work_ff/testbench"]) | ||||
							
								
								
									
										10
									
								
								techlibs/efinix/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								techlibs/efinix/Makefile.inc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| 
 | ||||
| OBJS += techlibs/efinix/synth_efinix.o | ||||
| OBJS += techlibs/efinix/efinix_gbuf.o | ||||
| OBJS += techlibs/efinix/efinix_fixcarry.o | ||||
| 
 | ||||
| $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v)) | ||||
| $(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v)) | ||||
| $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v)) | ||||
| $(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v)) | ||||
| $(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt)) | ||||
							
								
								
									
										79
									
								
								techlibs/efinix/arith_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								techlibs/efinix/arith_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | |||
| /* | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2018  Miodrag Milanovic <miodrag@symbioticeda.com> | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| (* techmap_celltype = "$alu" *) | ||||
| module _80_efinix_alu (A, B, CI, BI, X, Y, CO); | ||||
| 	parameter A_SIGNED = 0; | ||||
| 	parameter B_SIGNED = 0; | ||||
| 	parameter A_WIDTH  = 1; | ||||
| 	parameter B_WIDTH  = 1; | ||||
| 	parameter Y_WIDTH  = 1; | ||||
| 
 | ||||
| 	input [A_WIDTH-1:0] A; | ||||
| 	input [B_WIDTH-1:0] B; | ||||
| 	output [Y_WIDTH-1:0] X, Y; | ||||
| 
 | ||||
| 	input CI, BI; | ||||
| 	output [Y_WIDTH-1:0] CO; | ||||
|     | ||||
|     wire CIx; | ||||
|     wire [Y_WIDTH-1:0] COx; | ||||
| 
 | ||||
| 	wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; | ||||
| 
 | ||||
| 	wire [Y_WIDTH-1:0] A_buf, B_buf; | ||||
| 	\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); | ||||
| 	\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); | ||||
| 
 | ||||
| 	wire [Y_WIDTH-1:0] AA = A_buf; | ||||
| 	wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; | ||||
| 	wire [Y_WIDTH-1:0] C = { COx, CIx }; | ||||
| 
 | ||||
|     EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) | ||||
|     adder_cin  ( | ||||
|         .I0(CI), | ||||
|         .I1(1'b1), | ||||
|         .CI(1'b0), | ||||
|         .CO(CIx) | ||||
| 	); | ||||
| 
 | ||||
| 	genvar i; | ||||
| 	generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice | ||||
| 		EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) | ||||
| 		adder_i ( | ||||
| 			.I0(AA[i]), | ||||
| 			.I1(BB[i]), | ||||
| 			.CI(C[i]), | ||||
| 			.O(Y[i]), | ||||
| 			.CO(COx[i]) | ||||
| 		); | ||||
| 		EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1))				 | ||||
| 		adder_cout  ( | ||||
| 			.I0(1'b0), | ||||
| 			.I1(1'b0), | ||||
| 			.CI(COx[i]), | ||||
| 			.O(CO[i]) | ||||
| 		); | ||||
| 	  end: slice	   | ||||
| 	endgenerate | ||||
| 
 | ||||
|    /* End implementation */ | ||||
|    assign X = AA ^ BB; | ||||
| endmodule | ||||
							
								
								
									
										32
									
								
								techlibs/efinix/bram.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								techlibs/efinix/bram.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| bram $__EFINIX_5K | ||||
|   init 1 | ||||
| 
 | ||||
|   abits 8  @a8d16 | ||||
|   dbits 16 @a8d16 | ||||
|   abits 9  @a9d8 | ||||
|   dbits 8  @a9d8 | ||||
|   abits 10 @a10d4 | ||||
|   dbits 4  @a10d4 | ||||
|   abits 11 @a11d2 | ||||
|   dbits 2  @a11d2 | ||||
|   abits 12 @a12d1 | ||||
|   dbits 1  @a12d1 | ||||
|   abits 8  @a8d20 | ||||
|   dbits 20 @a8d20 | ||||
|   abits 9  @a9d10 | ||||
|   dbits 10 @a9d10 | ||||
| 
 | ||||
|   groups 2 | ||||
|   ports 1 1 | ||||
|   wrmode 1 0 | ||||
|   enable 1 1 | ||||
|   transp 0 2 | ||||
|   clocks 2 3 | ||||
|   clkpol 2 3 | ||||
| endbram | ||||
| 
 | ||||
| match $__EFINIX_5K | ||||
|   min bits 256 | ||||
|   min efficiency 5 | ||||
|   shuffle_enable B | ||||
| endmatch | ||||
							
								
								
									
										65
									
								
								techlibs/efinix/brams_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								techlibs/efinix/brams_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| module \$__EFINIX_5K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); | ||||
| 	parameter CFG_ABITS = 8; | ||||
| 	parameter CFG_DBITS = 20; | ||||
| 	parameter CFG_ENABLE_A = 1; | ||||
| 
 | ||||
| 	parameter CLKPOL2 = 1; | ||||
| 	parameter CLKPOL3 = 1; | ||||
| 	parameter [5119:0] INIT = 5119'bx; | ||||
| 	parameter TRANSP2 = 0; | ||||
| 
 | ||||
| 	input CLK2; | ||||
| 	input CLK3; | ||||
| 
 | ||||
| 	input [CFG_ABITS-1:0] A1ADDR; | ||||
| 	input [CFG_DBITS-1:0] A1DATA; | ||||
| 	input [CFG_ENABLE_A-1:0] A1EN; | ||||
| 
 | ||||
| 	input [CFG_ABITS-1:0] B1ADDR; | ||||
| 	output [CFG_DBITS-1:0] B1DATA; | ||||
| 	input B1EN; | ||||
| 
 | ||||
| 	localparam WRITEMODE_A = TRANSP2 ? "WRITE_FIRST" : "READ_FIRST"; | ||||
| 
 | ||||
| 	EFX_RAM_5K #( | ||||
|    		.READ_WIDTH(CFG_DBITS), | ||||
|    		.WRITE_WIDTH(CFG_DBITS), | ||||
|    		.OUTPUT_REG(1'b0), | ||||
|    		.RCLK_POLARITY(1'b1), | ||||
|    		.RE_POLARITY(1'b1), | ||||
|    		.WCLK_POLARITY(1'b1), | ||||
|    		.WE_POLARITY(1'b1), | ||||
|    		.WCLKE_POLARITY(1'b1), | ||||
|    		.WRITE_MODE(WRITEMODE_A), | ||||
| 		.INIT_0(INIT[ 0*256 +: 256]), | ||||
| 		.INIT_1(INIT[ 1*256 +: 256]), | ||||
| 		.INIT_2(INIT[ 2*256 +: 256]), | ||||
| 		.INIT_3(INIT[ 3*256 +: 256]), | ||||
| 		.INIT_4(INIT[ 4*256 +: 256]), | ||||
| 		.INIT_5(INIT[ 5*256 +: 256]), | ||||
| 		.INIT_6(INIT[ 6*256 +: 256]), | ||||
| 		.INIT_7(INIT[ 7*256 +: 256]), | ||||
| 		.INIT_8(INIT[ 8*256 +: 256]), | ||||
| 		.INIT_9(INIT[ 9*256 +: 256]), | ||||
| 		.INIT_A(INIT[10*256 +: 256]), | ||||
| 		.INIT_B(INIT[11*256 +: 256]), | ||||
| 		.INIT_C(INIT[12*256 +: 256]), | ||||
| 		.INIT_D(INIT[13*256 +: 256]), | ||||
| 		.INIT_E(INIT[14*256 +: 256]), | ||||
| 		.INIT_F(INIT[15*256 +: 256]), | ||||
| 		.INIT_10(INIT[16*256 +: 256]), | ||||
| 		.INIT_11(INIT[17*256 +: 256]), | ||||
| 		.INIT_12(INIT[18*256 +: 256]), | ||||
| 		.INIT_13(INIT[19*256 +: 256]) | ||||
| 	) _TECHMAP_REPLACE_ ( | ||||
|    		.WDATA(A1DATA), | ||||
|    		.WADDR(A1ADDR), | ||||
|    		.WE(A1EN), | ||||
|    		.WCLK(CLK2), | ||||
|    		.WCLKE(1'b1), | ||||
|    		.RDATA(B1DATA), | ||||
|    		.RADDR(B1ADDR), | ||||
|    		.RE(B1EN), | ||||
|    		.RCLK(CLK3) | ||||
| 	); | ||||
| endmodule | ||||
							
								
								
									
										45
									
								
								techlibs/efinix/cells_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								techlibs/efinix/cells_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| module  \$_DFF_N_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule | ||||
| module  \$_DFF_P_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFFE_NN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule | ||||
| module  \$_DFFE_NP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFFE_PN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule | ||||
| module  \$_DFFE_PP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| module  \$_DFF_NN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| module  \$_DFF_PN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| module  \$_DFF_PN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| 
 | ||||
| module  \$_DFF_NP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| module  \$_DFF_NP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| module  \$_DFF_PP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| module  \$_DFF_PP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule | ||||
| 
 | ||||
| `ifndef NO_LUT | ||||
| module \$lut (A, Y); | ||||
|   parameter WIDTH = 0; | ||||
|   parameter LUT = 0; | ||||
| 
 | ||||
|   input [WIDTH-1:0] A; | ||||
|   output Y; | ||||
| 
 | ||||
|   generate | ||||
|     if (WIDTH == 1) begin | ||||
|       EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0)); | ||||
|     end else | ||||
|     if (WIDTH == 2) begin | ||||
|       EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0)); | ||||
|     end else | ||||
|     if (WIDTH == 3) begin | ||||
|       EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0)); | ||||
|     end else | ||||
|     if (WIDTH == 4) begin | ||||
|       EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3])); | ||||
|     end else begin | ||||
|       wire _TECHMAP_FAIL_ = 1; | ||||
|     end | ||||
|   endgenerate | ||||
| endmodule | ||||
| `endif | ||||
							
								
								
									
										173
									
								
								techlibs/efinix/cells_sim.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								techlibs/efinix/cells_sim.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,173 @@ | |||
| module EFX_LUT4( | ||||
|    output O,  | ||||
|    input I0, | ||||
|    input I1, | ||||
|    input I2, | ||||
|    input I3 | ||||
| ); | ||||
| 	parameter LUTMASK = 16'h0000; | ||||
| 
 | ||||
| 	wire [7:0] s3 = I3 ? LUTMASK[15:8] : LUTMASK[7:0]; | ||||
| 	wire [3:0] s2 = I2 ?      s3[ 7:4] :      s3[3:0]; | ||||
| 	wire [1:0] s1 = I1 ?      s2[ 3:2] :      s2[1:0]; | ||||
| 	assign O = I0 ? s1[1] : s1[0];	    | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_ADD( | ||||
|    output O, | ||||
|    output CO, | ||||
|    input I0, | ||||
|    input I1, | ||||
|    input CI | ||||
| ); | ||||
|    parameter I0_POLARITY   = 1; | ||||
|    parameter I1_POLARITY   = 1; | ||||
| 
 | ||||
|    wire i0; | ||||
|    wire i1; | ||||
| 
 | ||||
|    assign i0 = I0_POLARITY ? I0 : ~I0; | ||||
|    assign i1 = I1_POLARITY ? I1 : ~I1; | ||||
| 
 | ||||
|    assign {CO, O} = i0 + i1 + CI; | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_FF( | ||||
|    output reg Q, | ||||
|    input D, | ||||
|    input CE, | ||||
|    input CLK, | ||||
|    input SR | ||||
| ); | ||||
|    parameter CLK_POLARITY = 1; | ||||
|    parameter CE_POLARITY = 1; | ||||
|    parameter SR_POLARITY = 1; | ||||
|    parameter SR_SYNC = 0; | ||||
|    parameter SR_VALUE = 0; | ||||
|    parameter SR_SYNC_PRIORITY = 0; | ||||
|    parameter D_POLARITY = 1; | ||||
| 
 | ||||
|    wire clk; | ||||
|    wire ce; | ||||
|    wire sr; | ||||
|    wire d; | ||||
|    wire prio; | ||||
|    wire sync; | ||||
|    wire async; | ||||
| 
 | ||||
|    assign clk = CLK_POLARITY ? CLK : ~CLK; | ||||
|    assign ce = CE_POLARITY ? CE : ~CE; | ||||
|    assign sr = SR_POLARITY ? SR : ~SR; | ||||
|    assign d = D_POLARITY ? D : ~D; | ||||
|    | ||||
|    generate | ||||
|    	if (SR_SYNC == 1)  | ||||
|       begin | ||||
|          if (SR_SYNC_PRIORITY == 1)  | ||||
|          begin | ||||
|             always @(posedge clk) | ||||
|                if (sr) | ||||
|                   Q <= SR_VALUE; | ||||
|                else if (ce) | ||||
|                   Q <= d; | ||||
|          end | ||||
|          else | ||||
|          begin | ||||
|             always @(posedge clk) | ||||
|                if (ce) | ||||
|                begin | ||||
|                   if (sr) | ||||
|                      Q <= SR_VALUE; | ||||
|                   else | ||||
|                      Q <= d; | ||||
|                end | ||||
|          end | ||||
|       end | ||||
|       else | ||||
|       begin | ||||
|          always @(posedge clk or posedge sr) | ||||
|             if (sr) | ||||
|                Q <= SR_VALUE; | ||||
|             else if (ce) | ||||
|                Q <= d; | ||||
|           | ||||
|       end | ||||
|    endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_GBUFCE( | ||||
|    input CE, | ||||
|    input I, | ||||
|    output O | ||||
| ); | ||||
|    parameter CE_POLARITY = 1'b1; | ||||
| 
 | ||||
|    wire ce; | ||||
|    assign ce = CE_POLARITY ? CE : ~CE; | ||||
|     | ||||
|    assign O = I & ce; | ||||
|     | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_RAM_5K( | ||||
|    input [WRITE_WIDTH-1:0] WDATA, | ||||
|    input [WRITE_ADDR_WIDTH-1:0] WADDR, | ||||
|    input WE,  | ||||
|    input WCLK, | ||||
|    input WCLKE,  | ||||
|    output [READ_WIDTH-1:0] RDATA,  | ||||
|    input [READ_ADDR_WIDTH-1:0] RADDR, | ||||
|    input RE,  | ||||
|    input RCLK | ||||
| ); | ||||
|    parameter READ_WIDTH = 20; | ||||
|    parameter WRITE_WIDTH = 20; | ||||
|    parameter OUTPUT_REG = 1'b0; | ||||
|    parameter RCLK_POLARITY  = 1'b1; | ||||
|    parameter RE_POLARITY    = 1'b1; | ||||
|    parameter WCLK_POLARITY  = 1'b1; | ||||
|    parameter WE_POLARITY    = 1'b1; | ||||
|    parameter WCLKE_POLARITY = 1'b1; | ||||
|    parameter WRITE_MODE = "READ_FIRST"; | ||||
|    parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|    parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
| 
 | ||||
|    localparam READ_ADDR_WIDTH =  | ||||
| 			    (READ_WIDTH == 16) ? 8 :  // 256x16 | ||||
| 			    (READ_WIDTH == 8)  ? 9 :  // 512x8 | ||||
| 			    (READ_WIDTH == 4)  ? 10 : // 1024x4 | ||||
| 			    (READ_WIDTH == 2)  ? 11 : // 2048x2 | ||||
| 			    (READ_WIDTH == 1)  ? 12 : // 4096x1 | ||||
| 			    (READ_WIDTH == 20) ? 8 :  // 256x20 | ||||
| 			    (READ_WIDTH == 10) ? 9 :  // 512x10 | ||||
| 			    (READ_WIDTH == 5)  ? 10 : -1; // 1024x5 | ||||
|     | ||||
|    localparam WRITE_ADDR_WIDTH =  | ||||
| 			    (WRITE_WIDTH == 16) ? 8 :  // 256x16 | ||||
| 			    (WRITE_WIDTH == 8)  ? 9 :  // 512x8 | ||||
| 			    (WRITE_WIDTH == 4)  ? 10 : // 1024x4 | ||||
| 			    (WRITE_WIDTH == 2)  ? 11 : // 2048x2 | ||||
| 			    (WRITE_WIDTH == 1)  ? 12 : // 4096x1 | ||||
| 			    (WRITE_WIDTH == 20) ? 8 :  // 256x20 | ||||
| 			    (WRITE_WIDTH == 10) ? 9 :  // 512x10 | ||||
| 			    (WRITE_WIDTH == 5)  ? 10 : -1; // 1024x5 | ||||
|     | ||||
| endmodule | ||||
							
								
								
									
										122
									
								
								techlibs/efinix/efinix_fixcarry.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								techlibs/efinix/efinix_fixcarry.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,122 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2019  Miodrag Milanovic <miodrag@symbioticeda.com> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| static SigBit get_bit_or_zero(const SigSpec &sig) | ||||
| { | ||||
| 	if (GetSize(sig) == 0) | ||||
| 		return State::S0; | ||||
| 	return sig[0]; | ||||
| } | ||||
| 
 | ||||
| static void fix_carry_chain(Module *module) | ||||
| { | ||||
| 	SigMap sigmap(module); | ||||
| 
 | ||||
| 	pool<SigBit> ci_bits; | ||||
| 	dict<SigBit, SigBit> mapping_bits; | ||||
| 
 | ||||
| 	for (auto cell : module->cells()) | ||||
| 	{ | ||||
| 		if (cell->type == "\\EFX_ADD") { | ||||
| 			SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0")); | ||||
| 			SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1")); | ||||
| 			if (bit_i0 == State::S0 && bit_i1== State::S0) { | ||||
| 				SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); | ||||
| 				SigBit bit_o = sigmap(cell->getPort("\\O")); | ||||
| 				ci_bits.insert(bit_ci);				 | ||||
| 				mapping_bits[bit_ci] = bit_o; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	vector<Cell*> adders_to_fix_cells; | ||||
| 	for (auto cell : module->cells()) | ||||
| 	{ | ||||
| 		if (cell->type == "\\EFX_ADD") { | ||||
| 			SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); | ||||
| 			SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0")); | ||||
| 			SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1"));			 | ||||
| 			SigBit canonical_bit = sigmap(bit_ci); | ||||
| 			if (!ci_bits.count(canonical_bit)) | ||||
| 				continue;			 | ||||
| 			if (bit_i0 == State::S0 && bit_i1== State::S0)  | ||||
| 				continue; | ||||
| 
 | ||||
| 			adders_to_fix_cells.push_back(cell); | ||||
| 			log("Found %s cell named %s with invalid CI signal.\n", log_id(cell->type), log_id(cell)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto cell : adders_to_fix_cells) | ||||
| 	{ | ||||
| 		SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); | ||||
| 		SigBit canonical_bit = sigmap(bit_ci); | ||||
| 		auto bit = mapping_bits.at(canonical_bit); | ||||
| 		log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell)); | ||||
| 		Cell *c = module->addCell(NEW_ID, "\\EFX_ADD"); | ||||
| 		SigBit new_bit = module->addWire(NEW_ID); | ||||
| 		c->setParam("\\I0_POLARITY", State::S1); | ||||
| 		c->setParam("\\I1_POLARITY", State::S1); | ||||
| 		c->setPort("\\I0", bit); | ||||
| 		c->setPort("\\I1", State::S1); | ||||
| 		c->setPort("\\CI", State::S0); | ||||
| 		c->setPort("\\CO", new_bit); | ||||
| 		 | ||||
| 		cell->setPort("\\CI", new_bit); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct EfinixCarryFixPass : public Pass { | ||||
| 	EfinixCarryFixPass() : Pass("efinix_fixcarry", "Efinix: fix carry chain") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    efinix_fixcarry [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Add Efinix adders to fix carry chain if needed.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing efinix_fixcarry pass (fix invalid carry chain).\n"); | ||||
| 		 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		Module *module = design->top_module(); | ||||
| 
 | ||||
| 		if (module == nullptr) | ||||
| 			log_cmd_error("No top module found.\n"); | ||||
| 
 | ||||
| 		fix_carry_chain(module);		 | ||||
| 	} | ||||
| } EfinixCarryFixPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										119
									
								
								techlibs/efinix/efinix_gbuf.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								techlibs/efinix/efinix_gbuf.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2019  Miodrag Milanovic <miodrag@symbioticeda.com> | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| static void handle_gbufs(Module *module) | ||||
| { | ||||
| 	SigMap sigmap(module); | ||||
| 
 | ||||
| 	pool<SigBit> clk_bits; | ||||
| 	dict<SigBit, SigBit> rewrite_bits; | ||||
| 	vector<pair<Cell*, SigBit>> pad_bits; | ||||
| 
 | ||||
| 	for (auto cell : module->cells()) | ||||
| 	{ | ||||
| 		if (cell->type == "\\EFX_FF") { | ||||
| 			for (auto bit : sigmap(cell->getPort("\\CLK"))) | ||||
| 				clk_bits.insert(bit); | ||||
| 		} | ||||
| 		if (cell->type == "\\EFX_RAM_5K") { | ||||
| 			for (auto bit : sigmap(cell->getPort("\\RCLK"))) | ||||
| 				clk_bits.insert(bit); | ||||
| 			for (auto bit : sigmap(cell->getPort("\\WCLK"))) | ||||
| 				clk_bits.insert(bit); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto wire : vector<Wire*>(module->wires())) | ||||
| 	{ | ||||
| 		if (!wire->port_input) | ||||
| 			continue; | ||||
| 
 | ||||
| 		for (int index = 0; index < GetSize(wire); index++) | ||||
| 		{ | ||||
| 			SigBit bit(wire, index); | ||||
| 			SigBit canonical_bit = sigmap(bit); | ||||
| 
 | ||||
| 			if (!clk_bits.count(canonical_bit)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			Cell *c = module->addCell(NEW_ID, "\\EFX_GBUFCE"); | ||||
| 			SigBit new_bit = module->addWire(NEW_ID); | ||||
| 			c->setParam("\\CE_POLARITY", State::S1); | ||||
| 			c->setPort("\\O", new_bit); | ||||
| 			c->setPort("\\CE", State::S1); | ||||
| 			pad_bits.push_back(make_pair(c, bit)); | ||||
| 			rewrite_bits[canonical_bit] = new_bit; | ||||
| 
 | ||||
| 			log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	auto rewrite_function = [&](SigSpec &s) { | ||||
| 		for (auto &bit : s) { | ||||
| 			SigBit canonical_bit = sigmap(bit); | ||||
| 			if (rewrite_bits.count(canonical_bit)) | ||||
| 				bit = rewrite_bits.at(canonical_bit); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	module->rewrite_sigspecs(rewrite_function); | ||||
| 
 | ||||
| 	for (auto &it : pad_bits) | ||||
| 		it.first->setPort("\\I", it.second); | ||||
| } | ||||
| 
 | ||||
| struct EfinixGbufPass : public Pass { | ||||
| 	EfinixGbufPass() : Pass("efinix_gbuf", "Efinix: insert global clock buffers") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    efinix_gbuf [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Add Efinix global clock buffers to top module as needed.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing efinix_gbuf pass (insert global clock buffers).\n"); | ||||
| 		 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		Module *module = design->top_module(); | ||||
| 
 | ||||
| 		if (module == nullptr) | ||||
| 			log_cmd_error("No top module found.\n"); | ||||
| 
 | ||||
| 		handle_gbufs(module);		 | ||||
| 	} | ||||
| } EfinixGbufPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										219
									
								
								techlibs/efinix/synth_efinix.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								techlibs/efinix/synth_efinix.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,219 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2019  Miodrag Milanovic <miodrag@symbioticeda.com> | ||||
|  *  Copyright (C) 2019  Clifford Wolf <clifford@clifford.at> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/register.h" | ||||
| #include "kernel/celltypes.h" | ||||
| #include "kernel/rtlil.h" | ||||
| #include "kernel/log.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct SynthEfinixPass : public ScriptPass | ||||
| { | ||||
| 	SynthEfinixPass() : ScriptPass("synth_efinix", "synthesis for Efinix FPGAs") { } | ||||
| 
 | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    synth_efinix [options]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This command runs synthesis for Efinix FPGAs.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -top <module>\n"); | ||||
| 		log("        use the specified module as top module\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -edif <file>\n"); | ||||
| 		log("        write the design to the specified EDIF file. writing of an output file\n"); | ||||
| 		log("        is omitted if this parameter is not specified.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -json <file>\n"); | ||||
| 		log("        write the design to the specified JSON file. writing of an output file\n"); | ||||
| 		log("        is omitted if this parameter is not specified.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -run <from_label>:<to_label>\n"); | ||||
| 		log("        only run the commands between the labels (see below). an empty\n"); | ||||
| 		log("        from label is synonymous to 'begin', and empty to label is\n"); | ||||
| 		log("        synonymous to the end of the command list.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noflatten\n"); | ||||
| 		log("        do not flatten design before synthesis\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -retime\n"); | ||||
| 		log("        run 'abc' with -dff option\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("The following commands are executed by this synthesis command:\n"); | ||||
| 		help_script(); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	string top_opt, edif_file, json_file; | ||||
| 	bool flatten, retime; | ||||
| 
 | ||||
| 	void clear_flags() YS_OVERRIDE | ||||
| 	{ | ||||
| 		top_opt = "-auto-top"; | ||||
| 		edif_file = ""; | ||||
| 		json_file = ""; | ||||
| 		flatten = true; | ||||
| 		retime = false; | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		string run_from, run_to; | ||||
| 		clear_flags(); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			if (args[argidx] == "-top" && argidx+1 < args.size()) { | ||||
| 				top_opt = "-top " + args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-edif" && argidx+1 < args.size()) { | ||||
| 				edif_file = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-json" && argidx+1 < args.size()) { | ||||
| 				json_file = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-run" && argidx+1 < args.size()) { | ||||
| 				size_t pos = args[argidx+1].find(':'); | ||||
| 				if (pos == std::string::npos) | ||||
| 					break; | ||||
| 				run_from = args[++argidx].substr(0, pos); | ||||
| 				run_to = args[argidx].substr(pos+1); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-noflatten") { | ||||
| 				flatten = false; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-retime") { | ||||
| 				retime = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (!design->full_selection()) | ||||
| 			log_cmd_error("This command only operates on fully selected designs!\n"); | ||||
| 
 | ||||
| 		log_header(design, "Executing SYNTH_EFINIX pass.\n"); | ||||
| 		log_push(); | ||||
| 
 | ||||
| 		run_script(design, run_from, run_to); | ||||
| 
 | ||||
| 		log_pop(); | ||||
| 	} | ||||
| 
 | ||||
| 	void script() YS_OVERRIDE | ||||
| 	{ | ||||
| 		if (check_label("begin")) | ||||
| 		{ | ||||
| 			run("read_verilog -lib +/efinix/cells_sim.v"); | ||||
| 			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); | ||||
| 		} | ||||
| 
 | ||||
| 		if (flatten && check_label("flatten", "(unless -noflatten)")) | ||||
| 		{ | ||||
| 			run("proc"); | ||||
| 			run("flatten"); | ||||
| 			run("tribuf -logic"); | ||||
| 			run("deminout"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("coarse")) | ||||
| 		{ | ||||
| 			run("synth -run coarse"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_bram", "(skip if -nobram)")) | ||||
| 		{ | ||||
| 			run("memory_bram -rules +/efinix/bram.txt"); | ||||
| 			run("techmap -map +/efinix/brams_map.v"); | ||||
| 			run("setundef -zero -params t:EFX_RAM_5K"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("fine")) | ||||
| 		{ | ||||
| 			run("opt -fast -mux_undef -undriven -fine"); | ||||
| 			run("memory_map"); | ||||
| 			run("opt -undriven -fine"); | ||||
| 			run("techmap -map +/techmap.v -map +/efinix/arith_map.v"); | ||||
| 			if (retime || help_mode) | ||||
| 				run("abc -dff", "(only if -retime)"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_ffs")) | ||||
| 		{ | ||||
| 			run("dffsr2dff"); | ||||
| 			run("techmap -D NO_LUT -map +/efinix/cells_map.v"); | ||||
| 			run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); | ||||
| 			run("opt_expr -mux_undef"); | ||||
| 			run("simplemap"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_luts")) | ||||
| 		{ | ||||
| 			run("abc -lut 4"); | ||||
| 			run("clean"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_cells")) | ||||
| 		{ | ||||
| 			run("techmap -map +/efinix/cells_map.v"); | ||||
| 			run("clean"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_gbuf")) | ||||
| 		{ | ||||
| 			run("efinix_gbuf"); | ||||
| 			run("efinix_fixcarry"); | ||||
| 			run("clean"); | ||||
| 		} | ||||
| 		 | ||||
| 		if (check_label("check")) | ||||
| 		{ | ||||
| 			run("hierarchy -check"); | ||||
| 			run("stat"); | ||||
| 			run("check -noinit"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("edif")) | ||||
| 		{ | ||||
| 			if (!edif_file.empty() || help_mode) | ||||
| 				run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str())); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("json")) | ||||
| 		{ | ||||
| 			if (!json_file.empty() || help_mode) | ||||
| 				run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str())); | ||||
| 		} | ||||
| 	} | ||||
| } SynthEfinixPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
|  | @ -3,11 +3,11 @@ | |||
| # NB: Inputs/Outputs must be ordered alphabetically | ||||
| #     (with exceptions for carry in/out) | ||||
| 
 | ||||
| # Inputs: A B CI | ||||
| # Inputs: A B I0 I3 CI | ||||
| # Outputs: O CO | ||||
| #   (NB: carry chain input/output must be last | ||||
| #        input/output and have been moved there | ||||
| #        overriding the alphabetical ordering) | ||||
| $__ICE40_FULL_ADDER 1 1 3 2 | ||||
| 400 379 316 | ||||
| 259 231 126 | ||||
| $__ICE40_CARRY_WRAPPER 1 1 5 2 | ||||
| 400 379 449 316 316 | ||||
| 259 231 -   -   126 | ||||
|  |  | |||
|  | @ -3,11 +3,11 @@ | |||
| # NB: Inputs/Outputs must be ordered alphabetically | ||||
| #     (with exceptions for carry in/out) | ||||
| 
 | ||||
| # Inputs: A B CI | ||||
| # Inputs: A B I0 I3 CI | ||||
| # Outputs: O CO | ||||
| #   (NB: carry chain input/output must be last | ||||
| #        input/output and have been moved there | ||||
| #        overriding the alphabetical ordering) | ||||
| $__ICE40_FULL_ADDER 1 1 3 2 | ||||
| 589 558 465 | ||||
| 675 609 186  | ||||
| $__ICE40_CARRY_WRAPPER 1 1 5 2 | ||||
| 589 558 661 465 465 | ||||
| 675 609 -   -   186 | ||||
|  |  | |||
|  | @ -3,11 +3,11 @@ | |||
| # NB: Inputs/Outputs must be ordered alphabetically | ||||
| #     (with exceptions for carry in/out) | ||||
| 
 | ||||
| # Inputs: A B CI | ||||
| # Inputs: A B I0 I3 CI | ||||
| # Outputs: O CO | ||||
| #   (NB: carry chain input/output must be last | ||||
| #        input/output and have been moved there | ||||
| #        overriding the alphabetical ordering) | ||||
| $__ICE40_FULL_ADDER 1 1 3 2 | ||||
| 1231 1205 874 | ||||
| 675  609  278 | ||||
| $__ICE40_CARRY_WRAPPER 1 1 5 2 | ||||
| 1231 1205 1285 874 874 | ||||
| 675  609  -    -   278 | ||||
|  |  | |||
|  | @ -2,6 +2,10 @@ | |||
| `define SB_DFF_REG reg Q = 0 | ||||
| // `define SB_DFF_REG reg Q | ||||
| 
 | ||||
| `define ABC_ARRIVAL_HX(TIME) `ifdef ICE40_HX (* abc_arrival=TIME *) `endif | ||||
| `define ABC_ARRIVAL_LP(TIME) `ifdef ICE40_LP (* abc_arrival=TIME *) `endif | ||||
| `define ABC_ARRIVAL_U(TIME)  `ifdef ICE40_U (* abc_arrival=TIME *) `endif | ||||
| 
 | ||||
| // SiliconBlue IO Cells | ||||
| 
 | ||||
| module SB_IO ( | ||||
|  | @ -142,13 +146,16 @@ module SB_CARRY (output CO, input I0, I1, CI); | |||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id = 1, lib_whitebox *) | ||||
| module \$__ICE40_FULL_ADDER ( | ||||
| 	(* abc_carry *) output CO, | ||||
| module \$__ICE40_CARRY_WRAPPER ( | ||||
| 	(* abc_carry *) | ||||
| 	output CO, | ||||
| 	output O, | ||||
| 	input A, | ||||
| 	input B, | ||||
| 	(* abc_carry *) input CI | ||||
| 	input A, B, | ||||
| 	(* abc_carry *) | ||||
| 	input CI, | ||||
| 	input I0, I3 | ||||
| ); | ||||
| 	parameter LUT = 0; | ||||
| 	SB_CARRY carry ( | ||||
| 		.I0(A), | ||||
| 		.I1(B), | ||||
|  | @ -156,34 +163,52 @@ module \$__ICE40_FULL_ADDER ( | |||
| 		.CO(CO) | ||||
| 	); | ||||
| 	SB_LUT4 #( | ||||
| 		//         I0: 1010 1010 1010 1010 | ||||
| 		//         I1: 1100 1100 1100 1100 | ||||
| 		//         I2: 1111 0000 1111 0000 | ||||
| 		//         I3: 1111 1111 0000 0000 | ||||
| 		.LUT_INIT(16'b 0110_1001_1001_0110) | ||||
| 		.LUT_INIT(LUT) | ||||
| 	) adder ( | ||||
| 		.I0(1'b0), | ||||
| 		.I0(I0), | ||||
| 		.I1(A), | ||||
| 		.I2(B), | ||||
| 		.I3(CI), | ||||
| 		.I3(I3), | ||||
| 		.O(O) | ||||
| 	); | ||||
| endmodule | ||||
| 
 | ||||
| // Max delay from: https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 | ||||
| //                 https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 | ||||
| //                 https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 | ||||
| 
 | ||||
| // Positive Edge SiliconBlue FF Cells | ||||
| 
 | ||||
| module SB_DFF (output `SB_DFF_REG, input C, D); | ||||
| module SB_DFF ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, D | ||||
| ); | ||||
| 	always @(posedge C) | ||||
| 		Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFE (output `SB_DFF_REG, input C, E, D); | ||||
| module SB_DFFE ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, D | ||||
| ); | ||||
| 	always @(posedge C) | ||||
| 		if (E) | ||||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFSR (output `SB_DFF_REG, input C, R, D); | ||||
| module SB_DFFSR ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, R, D | ||||
| ); | ||||
| 	always @(posedge C) | ||||
| 		if (R) | ||||
| 			Q <= 0; | ||||
|  | @ -191,7 +216,13 @@ module SB_DFFSR (output `SB_DFF_REG, input C, R, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFR (output `SB_DFF_REG, input C, R, D); | ||||
| module SB_DFFR ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, R, D | ||||
| ); | ||||
| 	always @(posedge C, posedge R) | ||||
| 		if (R) | ||||
| 			Q <= 0; | ||||
|  | @ -199,7 +230,13 @@ module SB_DFFR (output `SB_DFF_REG, input C, R, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFSS (output `SB_DFF_REG, input C, S, D); | ||||
| module SB_DFFSS ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, S, D | ||||
| ); | ||||
| 	always @(posedge C) | ||||
| 		if (S) | ||||
| 			Q <= 1; | ||||
|  | @ -207,7 +244,13 @@ module SB_DFFSS (output `SB_DFF_REG, input C, S, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFS (output `SB_DFF_REG, input C, S, D); | ||||
| module SB_DFFS ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, S, D | ||||
| ); | ||||
| 	always @(posedge C, posedge S) | ||||
| 		if (S) | ||||
| 			Q <= 1; | ||||
|  | @ -215,7 +258,13 @@ module SB_DFFS (output `SB_DFF_REG, input C, S, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); | ||||
| module SB_DFFESR ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, R, D | ||||
| ); | ||||
| 	always @(posedge C) | ||||
| 		if (E) begin | ||||
| 			if (R) | ||||
|  | @ -225,7 +274,13 @@ module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); | |||
| 		end | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); | ||||
| module SB_DFFER ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, R, D | ||||
| ); | ||||
| 	always @(posedge C, posedge R) | ||||
| 		if (R) | ||||
| 			Q <= 0; | ||||
|  | @ -233,7 +288,13 @@ module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); | ||||
| module SB_DFFESS ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, S, D | ||||
| ); | ||||
| 	always @(posedge C) | ||||
| 		if (E) begin | ||||
| 			if (S) | ||||
|  | @ -243,7 +304,13 @@ module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); | |||
| 		end | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFES (output `SB_DFF_REG, input C, E, S, D); | ||||
| module SB_DFFES ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, S, D | ||||
| ); | ||||
| 	always @(posedge C, posedge S) | ||||
| 		if (S) | ||||
| 			Q <= 1; | ||||
|  | @ -253,18 +320,36 @@ endmodule | |||
| 
 | ||||
| // Negative Edge SiliconBlue FF Cells | ||||
| 
 | ||||
| module SB_DFFN (output `SB_DFF_REG, input C, D); | ||||
| module SB_DFFN ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, D | ||||
| ); | ||||
| 	always @(negedge C) | ||||
| 		Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNE (output `SB_DFF_REG, input C, E, D); | ||||
| module SB_DFFNE ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, D | ||||
| ); | ||||
| 	always @(negedge C) | ||||
| 		if (E) | ||||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); | ||||
| module SB_DFFNSR ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, R, D | ||||
| ); | ||||
| 	always @(negedge C) | ||||
| 		if (R) | ||||
| 			Q <= 0; | ||||
|  | @ -272,7 +357,13 @@ module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNR (output `SB_DFF_REG, input C, R, D); | ||||
| module SB_DFFNR ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, R, D | ||||
| ); | ||||
| 	always @(negedge C, posedge R) | ||||
| 		if (R) | ||||
| 			Q <= 0; | ||||
|  | @ -280,7 +371,13 @@ module SB_DFFNR (output `SB_DFF_REG, input C, R, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); | ||||
| module SB_DFFNSS ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, S, D | ||||
| ); | ||||
| 	always @(negedge C) | ||||
| 		if (S) | ||||
| 			Q <= 1; | ||||
|  | @ -288,7 +385,13 @@ module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNS (output `SB_DFF_REG, input C, S, D); | ||||
| module SB_DFFNS ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, S, D | ||||
| ); | ||||
| 	always @(negedge C, posedge S) | ||||
| 		if (S) | ||||
| 			Q <= 1; | ||||
|  | @ -296,7 +399,13 @@ module SB_DFFNS (output `SB_DFF_REG, input C, S, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); | ||||
| module SB_DFFNESR ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, R, D | ||||
| ); | ||||
| 	always @(negedge C) | ||||
| 		if (E) begin | ||||
| 			if (R) | ||||
|  | @ -306,7 +415,13 @@ module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); | |||
| 		end | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); | ||||
| module SB_DFFNER ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, R, D | ||||
| ); | ||||
| 	always @(negedge C, posedge R) | ||||
| 		if (R) | ||||
| 			Q <= 0; | ||||
|  | @ -314,7 +429,13 @@ module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); | |||
| 			Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); | ||||
| module SB_DFFNESS ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, S, D | ||||
| ); | ||||
| 	always @(negedge C) | ||||
| 		if (E) begin | ||||
| 			if (S) | ||||
|  | @ -324,7 +445,13 @@ module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); | |||
| 		end | ||||
| endmodule | ||||
| 
 | ||||
| module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D); | ||||
| module SB_DFFNES ( | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output `SB_DFF_REG, | ||||
| 	input C, E, S, D | ||||
| ); | ||||
| 	always @(negedge C, posedge S) | ||||
| 		if (S) | ||||
| 			Q <= 1; | ||||
|  | @ -335,6 +462,9 @@ endmodule | |||
| // SiliconBlue RAM Cells | ||||
| 
 | ||||
| module SB_RAM40_4K ( | ||||
| 	`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_U(1179)  // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 | ||||
| 	output [15:0] RDATA, | ||||
| 	input         RCLK, RCLKE, RE, | ||||
| 	input  [10:0] RADDR, | ||||
|  | @ -503,6 +633,9 @@ module SB_RAM40_4K ( | |||
| endmodule | ||||
| 
 | ||||
| module SB_RAM40_4KNR ( | ||||
| 	`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_U(1179)  // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 | ||||
| 	output [15:0] RDATA, | ||||
| 	input         RCLKN, RCLKE, RE, | ||||
| 	input  [10:0] RADDR, | ||||
|  | @ -568,6 +701,9 @@ module SB_RAM40_4KNR ( | |||
| endmodule | ||||
| 
 | ||||
| module SB_RAM40_4KNW ( | ||||
| 	`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_U(1179)  // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 | ||||
| 	output [15:0] RDATA, | ||||
| 	input         RCLK, RCLKE, RE, | ||||
| 	input  [10:0] RADDR, | ||||
|  | @ -633,6 +769,9 @@ module SB_RAM40_4KNW ( | |||
| endmodule | ||||
| 
 | ||||
| module SB_RAM40_4KNRNW ( | ||||
| 	`ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 | ||||
| 	`ABC_ARRIVAL_U(1179)  // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 | ||||
| 	output [15:0] RDATA, | ||||
| 	input         RCLKN, RCLKE, RE, | ||||
| 	input  [10:0] RADDR, | ||||
|  | @ -701,7 +840,12 @@ endmodule | |||
| 
 | ||||
| module ICESTORM_LC ( | ||||
| 	input I0, I1, I2, I3, CIN, CLK, CEN, SR, | ||||
| 	output LO, O, COUT | ||||
| 	output LO, | ||||
| 	`ABC_ARRIVAL_HX(540) | ||||
| 	`ABC_ARRIVAL_LP(796) | ||||
| 	`ABC_ARRIVAL_U(1391) | ||||
| 	output O, | ||||
| 	output COUT | ||||
| ); | ||||
| 	parameter [15:0] LUT_INIT = 0; | ||||
| 
 | ||||
|  | @ -1301,6 +1445,7 @@ module SB_MAC16 ( | |||
| 	input ADDSUBTOP, ADDSUBBOT, | ||||
| 	input OHOLDTOP, OHOLDBOT, | ||||
| 	input CI, ACCUMCI, SIGNEXTIN, | ||||
| 	//`ABC_ARRIVAL_U(1984)  // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 | ||||
| 	output [31:0] O, | ||||
| 	output CO, ACCUMCO, SIGNEXTOUT | ||||
| ); | ||||
|  |  | |||
|  | @ -84,7 +84,7 @@ static void run_ice40_opts(Module *module) | |||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (cell->type == "$__ICE40_FULL_ADDER") | ||||
| 		if (cell->type == "$__ICE40_CARRY_WRAPPER") | ||||
| 		{ | ||||
| 			SigSpec non_const_inputs, replacement_output; | ||||
| 			int count_zeros = 0, count_ones = 0; | ||||
|  | @ -114,16 +114,17 @@ static void run_ice40_opts(Module *module) | |||
| 				optimized_co.insert(sigmap(cell->getPort("\\CO")[0])); | ||||
| 				module->connect(cell->getPort("\\CO")[0], replacement_output); | ||||
| 				module->design->scratchpad_set_bool("opt.did_something", true); | ||||
| 				log("Optimized $__ICE40_FULL_ADDER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n", | ||||
| 				log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n", | ||||
| 						log_id(module), log_id(cell), log_signal(replacement_output)); | ||||
| 				cell->type = "$lut"; | ||||
| 				cell->setPort("\\A", { State::S0, inbit[0], inbit[1], inbit[2] }); | ||||
| 				cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], cell->getPort("\\I3") }); | ||||
| 				cell->setPort("\\Y", cell->getPort("\\O")); | ||||
| 				cell->unsetPort("\\B"); | ||||
| 				cell->unsetPort("\\CI"); | ||||
| 				cell->unsetPort("\\I0"); | ||||
| 				cell->unsetPort("\\I3"); | ||||
| 				cell->unsetPort("\\CO"); | ||||
| 				cell->unsetPort("\\O"); | ||||
| 				cell->setParam("\\LUT", RTLIL::Const::from_string("0110100110010110")); | ||||
| 				cell->setParam("\\WIDTH", 4); | ||||
| 			} | ||||
| 			continue; | ||||
|  |  | |||
|  | @ -238,7 +238,14 @@ struct SynthIce40Pass : public ScriptPass | |||
| 	{ | ||||
| 		if (check_label("begin")) | ||||
| 		{ | ||||
| 			run("read_verilog -icells -lib +/ice40/cells_sim.v"); | ||||
| 			std::string define; | ||||
| 			if (device_opt == "lp") | ||||
| 				define = "-D ICE40_LP"; | ||||
| 			else if (device_opt == "u") | ||||
| 				define = "-D ICE40_U"; | ||||
| 			else | ||||
| 				define = "-D ICE40_HX"; | ||||
| 			run("read_verilog -icells " + define + " -lib +/ice40/cells_sim.v"); | ||||
| 			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); | ||||
| 			run("proc"); | ||||
| 		} | ||||
|  |  | |||
|  | @ -25,7 +25,10 @@ techlibs/xilinx/brams_init_8.vh: techlibs/xilinx/brams_init.mk | |||
| 
 | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_cells_xtra.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6v_cells_xtra.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_cells_xtra.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_cells_xtra.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v)) | ||||
|  | @ -35,7 +38,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v)) | |||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_ff_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_ff_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) | ||||
| 
 | ||||
|  |  | |||
|  | @ -128,7 +128,7 @@ module RAM32X1D ( | |||
|   parameter INIT = 32'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|   wire \$DPO , \$SPO ; | ||||
|   \$__ABC_RAM32X1D #( | ||||
|   RAM32X1D #( | ||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .DPO(\$DPO ), .SPO(\$SPO ), | ||||
|  | @ -136,8 +136,8 @@ module RAM32X1D ( | |||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), | ||||
|     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) | ||||
|   ); | ||||
|   \$__ABC_LUTMUX6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO)); | ||||
|   \$__ABC_LUTMUX6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO)); | ||||
|   \$__ABC_LUT6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO)); | ||||
|   \$__ABC_LUT6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO)); | ||||
| endmodule | ||||
| 
 | ||||
| module RAM64X1D ( | ||||
|  | @ -151,7 +151,7 @@ module RAM64X1D ( | |||
|   parameter INIT = 64'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|   wire \$DPO , \$SPO ; | ||||
|   \$__ABC_RAM64X1D #( | ||||
|   RAM64X1D #( | ||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .DPO(\$DPO ), .SPO(\$SPO ), | ||||
|  | @ -159,8 +159,8 @@ module RAM64X1D ( | |||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), | ||||
|     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) | ||||
|   ); | ||||
|   \$__ABC_LUTMUX6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO)); | ||||
|   \$__ABC_LUTMUX6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO)); | ||||
|   \$__ABC_LUT6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO)); | ||||
|   \$__ABC_LUT6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO)); | ||||
| endmodule | ||||
| 
 | ||||
| module RAM128X1D ( | ||||
|  | @ -173,7 +173,7 @@ module RAM128X1D ( | |||
|   parameter INIT = 128'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|   wire \$DPO , \$SPO ; | ||||
|   \$__ABC_RAM128X1D #( | ||||
|   RAM128X1D #( | ||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .DPO(\$DPO ), .SPO(\$SPO ), | ||||
|  | @ -181,8 +181,8 @@ module RAM128X1D ( | |||
|     .A(A), | ||||
|     .DPRA(DPRA) | ||||
|   ); | ||||
|   \$__ABC_LUTMUX7 dpo (.A(\$DPO ), .S(A), .Y(DPO)); | ||||
|   \$__ABC_LUTMUX7 spo (.A(\$SPO ), .S(A), .Y(SPO)); | ||||
|   \$__ABC_LUT7 dpo (.A(\$DPO ), .S(A), .Y(DPO)); | ||||
|   \$__ABC_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO)); | ||||
| endmodule | ||||
| 
 | ||||
| module SRL16E ( | ||||
|  | @ -192,14 +192,13 @@ module SRL16E ( | |||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|   wire \$Q ; | ||||
|   \$__ABC_SRL16E #( | ||||
|   SRL16E #( | ||||
|     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .Q(\$Q ), | ||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) | ||||
|   ); | ||||
|   // TODO: Check if SRL uses fast inputs or slow inputs | ||||
|   \$__ABC_LUTMUX6 q (.A(\$Q ), .S({A0, A1, A2, A3, 1'b0, 1'b0}), .Y(Q)); | ||||
|   \$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A0, A1, A2, A3, 1'b1}), .Y(Q)); | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC32E ( | ||||
|  | @ -211,12 +210,11 @@ module SRLC32E ( | |||
|   parameter [31:0] INIT = 32'h00000000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|   wire \$Q ; | ||||
|   \$__ABC_SRLC32E #( | ||||
|   SRLC32E #( | ||||
|     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .Q(\$Q ), .Q31(Q31), | ||||
|     .A(A), .CE(CE), .CLK(CLK), .D(D) | ||||
|   ); | ||||
|   // TODO: Check if SRL uses fast inputs or slow inputs | ||||
|   \$__ABC_LUTMUX6 q (.A(\$Q ), .S({A, 1'b0}), .Y(Q)); | ||||
|   \$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q)); | ||||
| endmodule | ||||
|  |  | |||
|  | @ -115,65 +115,8 @@ module \$__ABC_FDPE_1 ((* abc_flop_q, abc_arrival=303 *) output Q, | |||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id=2000 *) | ||||
| module \$__ABC_LUTMUX6 (input A, input [5:0] S, output Y); | ||||
| module \$__ABC_LUT6 (input A, input [5:0] S, output Y); | ||||
| endmodule | ||||
| (* abc_box_id=2001 *) | ||||
| module \$__ABC_LUTMUX7 (input A, input [6:0] S, output Y); | ||||
| endmodule | ||||
| 
 | ||||
| 
 | ||||
| module \$__ABC_RAM32X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   (* abc_arrival=1153 *) output DPO, SPO, | ||||
|   input  D, | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||
| ); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_RAM64X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   (* abc_arrival=1153 *) output DPO, SPO, | ||||
|   input  D, | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, A5, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||
| ); | ||||
|   parameter INIT = 64'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_RAM128X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   (* abc_arrival=1153 *) output DPO, SPO, | ||||
|   input        D, | ||||
|   input        WCLK, | ||||
|   input        WE, | ||||
|   input  [6:0] A, DPRA | ||||
| ); | ||||
|   parameter INIT = 128'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
| endmodule | ||||
| 
 | ||||
| module SRL16E ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 | ||||
|   (* abc_arrival=1472 *) output Q, | ||||
|   input A0, A1, A2, A3, CE, CLK, D | ||||
| ); | ||||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC32E ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 | ||||
|   (* abc_arrival=1472 *) output Q, | ||||
|   (* abc_arrival=1114 *) output Q31, | ||||
|   input [4:0] A, | ||||
|   input CE, CLK, D | ||||
| ); | ||||
|   parameter [31:0] INIT = 32'h00000000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| module \$__ABC_LUT7 (input A, input [6:0] S, output Y); | ||||
| endmodule | ||||
|  |  | |||
|  | @ -139,101 +139,9 @@ module \$__ABC_FDPE_1 (output Q, | |||
|   ); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_LUTMUX6 (input A, input [5:0] S, output Y); | ||||
| module \$__ABC_LUT6 (input A, input [5:0] S, output Y); | ||||
|   assign Y = A; | ||||
| endmodule | ||||
| module \$__ABC_LUTMUX7 (input A, input [6:0] S, output Y); | ||||
| module \$__ABC_LUT7 (input A, input [6:0] S, output Y); | ||||
|   assign Y = A; | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_RAM32X1D ( | ||||
|   output DPO, SPO, | ||||
|   input  D, | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||
| ); | ||||
|   parameter INIT = 32'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|   RAM32X1D #( | ||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .DPO(DPO), .SPO(SPO), | ||||
|     .D(D), .WCLK(WCLK), .WE(WE), | ||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), | ||||
|     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) | ||||
|   ); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_RAM64X1D ( | ||||
|   output DPO, SPO, | ||||
|   input  D, | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, A5, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||
| ); | ||||
|   parameter INIT = 64'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|   RAM64X1D #( | ||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .DPO(DPO), .SPO(SPO), | ||||
|     .D(D), .WCLK(WCLK), .WE(WE), | ||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), | ||||
|     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) | ||||
|   ); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_RAM128X1D ( | ||||
|   output DPO, SPO, | ||||
|   input  D, | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A, | ||||
|   input  DPRA, | ||||
| ); | ||||
|   parameter INIT = 128'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|   RAM128X1D #( | ||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .DPO(DPO), .SPO(SPO), | ||||
|     .D(D), .WCLK(WCLK), .WE(WE), | ||||
|     .A(A), | ||||
|     .DPRA(DPRA) | ||||
|   ); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_SRL16E ( | ||||
|   output Q, | ||||
|   input A0, A1, A2, A3, CE, CLK, D | ||||
| ); | ||||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| 
 | ||||
|   SRL16E #( | ||||
|     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .Q(Q), | ||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) | ||||
|   ); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__ABC_SRLC32E ( | ||||
|   output Q, | ||||
|   output Q31, | ||||
|   input [4:0] A, | ||||
|   input CE, CLK, D | ||||
| ); | ||||
|   parameter [31:0] INIT = 32'h00000000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| 
 | ||||
|   SRLC32E #( | ||||
|     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) | ||||
|   ) _TECHMAP_REPLACE_ ( | ||||
|     .Q(Q), .Q31(Q31), | ||||
|     .A(A), .CE(CE), .CLK(CLK), .D(D) | ||||
|   ); | ||||
| endmodule | ||||
|  |  | |||
|  | @ -15,7 +15,10 @@ F7MUX 1 1 3 1 | |||
| MUXF8 2 1 3 1 | ||||
| 104 94 273 | ||||
| 
 | ||||
| # Box containing MUXF7.[AB] + MUXF8 | ||||
| # Box containing MUXF7.[AB] + MUXF8, | ||||
| #   Necessary to make these an atomic unit so that | ||||
| #   ABC cannot optimise just one of the MUXF7 away | ||||
| #   and expect to save on its delay | ||||
| # Inputs: I0 I1 I2 I3 S0 S1 | ||||
| # Outputs: O | ||||
| $__MUXF78 3 1 6 1 | ||||
|  | @ -81,14 +84,19 @@ FDPE_1 1006 1 5 1 | |||
| 
 | ||||
| # SLICEM/A6LUT | ||||
| # Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} | ||||
| #   Necessary since RAMD* and SRL* have both combinatorial (i.e. | ||||
| #   same-cycle read operation) and sequential (write operation | ||||
| #   is only committed on the next clock edge). | ||||
| #   To model the combinatorial path, such cells have to be split | ||||
| #   into comb and seq parts, with this box modelling only the former. | ||||
| # Inputs: A S0 S1 S2 S3 S4 S5 | ||||
| # Outputs: Y | ||||
| $__ABC_LUTRAM6 2000 0 7 1 | ||||
| $__ABC_LUT6 2000 0 7 1 | ||||
| 0 642 631 472 407 238 127 | ||||
| 
 | ||||
| # SLICEM/A6LUT + F7BMUX | ||||
| # Box to emulate comb/seq behaviour of RAMD128 | ||||
| # Inputs: A S0 S1 S2 S3 S4 S5 S6 | ||||
| # Outputs: DPO SPO | ||||
| $__ABC_LUTRAM7 2001 0 8 1 | ||||
| $__ABC_LUT7 2001 0 8 1 | ||||
| 0 1047 1036 877 812 643 532 478 | ||||
|  |  | |||
|  | @ -29,29 +29,49 @@ module GND(output G); | |||
|   assign G = 0; | ||||
| endmodule | ||||
| 
 | ||||
| module IBUF(output O, input I); | ||||
| module IBUF( | ||||
|     output O, | ||||
|     (* iopad_external_pin *) | ||||
|     input I); | ||||
|   parameter IOSTANDARD = "default"; | ||||
|   parameter IBUF_LOW_PWR = 0; | ||||
|   assign O = I; | ||||
| endmodule | ||||
| 
 | ||||
| module OBUF(output O, input I); | ||||
| module OBUF( | ||||
|     (* iopad_external_pin *) | ||||
|     output O, | ||||
|     input I); | ||||
|   parameter IOSTANDARD = "default"; | ||||
|   parameter DRIVE = 12; | ||||
|   parameter SLEW = "SLOW"; | ||||
|   assign O = I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFG(output O, input I); | ||||
| module BUFG( | ||||
|     (* clkbuf_driver *) | ||||
|     output O, | ||||
|     input I); | ||||
| 
 | ||||
|   assign O = I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFGCTRL( | ||||
|     (* clkbuf_driver *) | ||||
|     output O, | ||||
|     input I0, input I1, | ||||
|     input S0, input S1, | ||||
|     input CE0, input CE1, | ||||
|     input IGNORE0, input IGNORE1); | ||||
|     (* invertible_pin = "IS_S0_INVERTED" *) | ||||
|     input S0, | ||||
|     (* invertible_pin = "IS_S1_INVERTED" *) | ||||
|     input S1, | ||||
|     (* invertible_pin = "IS_CE0_INVERTED" *) | ||||
|     input CE0, | ||||
|     (* invertible_pin = "IS_CE1_INVERTED" *) | ||||
|     input CE1, | ||||
|     (* invertible_pin = "IS_IGNORE0_INVERTED" *) | ||||
|     input IGNORE0, | ||||
|     (* invertible_pin = "IS_IGNORE1_INVERTED" *) | ||||
|     input IGNORE1); | ||||
| 
 | ||||
| parameter [0:0] INIT_OUT = 1'b0; | ||||
| parameter PRESELECT_I0 = "FALSE"; | ||||
|  | @ -72,7 +92,12 @@ assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT); | |||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| module BUFHCE(output O, input I, input CE); | ||||
| module BUFHCE( | ||||
|     (* clkbuf_driver *) | ||||
|     output O, | ||||
|     input I, | ||||
|     (* invertible_pin = "IS_CE_INVERTED" *) | ||||
|     input CE); | ||||
| 
 | ||||
| parameter [0:0] INIT_OUT = 1'b0; | ||||
| parameter CE_TYPE = "SYNC"; | ||||
|  | @ -175,9 +200,11 @@ endmodule | |||
| 
 | ||||
| (* abc_box_id = 4, lib_whitebox *) | ||||
| module CARRY4( | ||||
|   (* abc_carry *) output [3:0] CO, | ||||
|   (* abc_carry *) | ||||
|   output [3:0] CO, | ||||
|   output [3:0] O, | ||||
|   (* abc_carry *) input CI, | ||||
|   (* abc_carry *) | ||||
|   input        CI, | ||||
|   input        CYINIT, | ||||
|   input  [3:0] DI, S | ||||
| ); | ||||
|  | @ -211,7 +238,20 @@ endmodule | |||
| 
 | ||||
| `endif | ||||
| 
 | ||||
| module FDRE (output reg Q, input C, CE, D, R); | ||||
| // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250 | ||||
| 
 | ||||
| module FDRE ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_R_INVERTED" *) | ||||
|   input R | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -223,7 +263,18 @@ module FDRE (output reg Q, input C, CE, D, R); | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module FDSE (output reg Q, input C, CE, D, S); | ||||
| module FDSE ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_S_INVERTED" *) | ||||
|   input S | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -235,7 +286,18 @@ module FDSE (output reg Q, input C, CE, D, S); | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module FDCE (output reg Q, input C, CE, D, CLR); | ||||
| module FDCE ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_CLR_INVERTED" *) | ||||
|   input CLR | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -249,7 +311,18 @@ module FDCE (output reg Q, input C, CE, D, CLR); | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module FDPE (output reg Q, input C, CE, D, PRE); | ||||
| module FDPE ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_PRE_INVERTED" *) | ||||
|   input PRE | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -263,33 +336,61 @@ module FDPE (output reg Q, input C, CE, D, PRE); | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module FDRE_1 (output reg Q, input C, CE, D, R); | ||||
| module FDRE_1 ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, R | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   initial Q <= INIT; | ||||
|   always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module FDSE_1 (output reg Q, input C, CE, D, S); | ||||
| module FDSE_1 ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, S | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   initial Q <= INIT; | ||||
|   always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module FDCE_1 (output reg Q, input C, CE, D, CLR); | ||||
| module FDCE_1 ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, CLR | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   initial Q <= INIT; | ||||
|   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module FDPE_1 (output reg Q, input C, CE, D, PRE); | ||||
| module FDPE_1 ( | ||||
|   (* abc_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, PRE | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   initial Q <= INIT; | ||||
|   always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM32X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   (* abc_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, | ||||
|  | @ -307,8 +408,12 @@ module RAM32X1D ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM64X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   (* abc_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input  WCLK, | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, A5, | ||||
|  | @ -326,8 +431,12 @@ module RAM64X1D ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM128X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   (* abc_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   input        D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input        WCLK, | ||||
|   input        WE, | ||||
|   input  [6:0] A, DPRA | ||||
|  | @ -342,8 +451,14 @@ module RAM128X1D ( | |||
| endmodule | ||||
| 
 | ||||
| module SRL16E ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 | ||||
|   (* abc_arrival=1472 *) | ||||
|   output Q, | ||||
|   input A0, A1, A2, A3, CE, CLK, D | ||||
|   input A0, A1, A2, A3, CE, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_CLK_INVERTED" *) | ||||
|   input CLK, | ||||
|   input D | ||||
| ); | ||||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|  | @ -359,11 +474,42 @@ module SRL16E ( | |||
|   endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC32E ( | ||||
| module SRLC16E ( | ||||
|   output Q, | ||||
|   output Q15, | ||||
|   input A0, A1, A2, A3, CE, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_CLK_INVERTED" *) | ||||
|   input CLK, | ||||
|   input D | ||||
| ); | ||||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
| 
 | ||||
|   reg [15:0] r = INIT; | ||||
|   assign Q15 = r[15]; | ||||
|   assign Q = r[{A3,A2,A1,A0}]; | ||||
|   generate | ||||
|     if (IS_CLK_INVERTED) begin | ||||
|       always @(negedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|     end | ||||
|     else | ||||
|       always @(posedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|   endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC32E ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 | ||||
|   (* abc_arrival=1472 *) | ||||
|   output Q, | ||||
|   (* abc_arrival=1114 *) | ||||
|   output Q31, | ||||
|   input [4:0] A, | ||||
|   input CE, CLK, D | ||||
|   input CE, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_CLK_INVERTED" *) | ||||
|   input CLK, | ||||
|   input D | ||||
| ); | ||||
|   parameter [31:0] INIT = 32'h00000000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|  |  | |||
							
								
								
									
										708
									
								
								techlibs/xilinx/cells_xtra.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										708
									
								
								techlibs/xilinx/cells_xtra.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,708 @@ | |||
| #!/usr/bin/env python3 | ||||
| 
 | ||||
| from argparse import ArgumentParser | ||||
| from io import StringIO | ||||
| from enum import Enum, auto | ||||
| import os.path | ||||
| import sys | ||||
| import re | ||||
| 
 | ||||
| 
 | ||||
| class Cell: | ||||
|     def __init__(self, name, keep=False, port_attrs={}): | ||||
|         self.name = name | ||||
|         self.keep = keep | ||||
|         self.port_attrs = port_attrs | ||||
| 
 | ||||
| 
 | ||||
| XC6S_CELLS = [ | ||||
|     # Design elements types listed in Xilinx UG615. | ||||
| 
 | ||||
|     # Advanced. | ||||
|     Cell('MCB'), | ||||
|     Cell('PCIE_A1'), | ||||
| 
 | ||||
|     # Arithmetic functions. | ||||
|     Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Clock components. | ||||
|     # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFIO2', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}), | ||||
|     Cell('BUFIO2_2CLK', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}), | ||||
|     Cell('BUFIO2FB', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFPLL_MCB', port_attrs={'IOCLK0': ['clkbuf_driver'], 'IOCLK1': ['clkbuf_driver']}), | ||||
|     Cell('DCM_CLKGEN'), | ||||
|     Cell('DCM_SP'), | ||||
|     Cell('PLL_BASE'), | ||||
| 
 | ||||
|     # Config/BSCAN components. | ||||
|     Cell('BSCAN_SPARTAN6', keep=True), | ||||
|     Cell('DNA_PORT'), | ||||
|     Cell('ICAP_SPARTAN6', keep=True), | ||||
|     Cell('POST_CRC_INTERNAL'), | ||||
|     Cell('STARTUP_SPARTAN6', keep=True), | ||||
|     Cell('SUSPEND_SYNC', keep=True), | ||||
| 
 | ||||
|     # I/O components. | ||||
|     Cell('GTPA1_DUAL'), | ||||
|     # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IODELAY2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), | ||||
|     Cell('IODRP2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), | ||||
|     Cell('IODRP2_MCB', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), | ||||
|     Cell('ISERDES2', port_attrs={ | ||||
|         'CLK0': ['clkbuf_sink'], | ||||
|         'CLK1': ['clkbuf_sink'], | ||||
|         'CLKDIV': ['clkbuf_sink'], | ||||
|     }), | ||||
|     Cell('KEEPER'), | ||||
|     # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OSERDES2', port_attrs={ | ||||
|         'CLK0': ['clkbuf_sink'], | ||||
|         'CLK1': ['clkbuf_sink'], | ||||
|         'CLKDIV': ['clkbuf_sink'], | ||||
|     }), | ||||
|     Cell('PULLDOWN'), | ||||
|     Cell('PULLUP'), | ||||
| 
 | ||||
|     # RAM/ROM. | ||||
|     #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # NOTE: not in the official library guide! | ||||
|     Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # NOTE: not in the official library guide! | ||||
|     Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # Cell('RAMB8BWER', port_attrs={'CLKAWRCLK': ['clkbuf_sink'], 'CLKBRDCLK': ['clkbuf_sink']}), | ||||
|     # Cell('RAMB16BWER', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), | ||||
|     Cell('ROM128X1'), | ||||
|     Cell('ROM256X1'), | ||||
|     Cell('ROM32X1'), | ||||
|     Cell('ROM64X1'), | ||||
| 
 | ||||
|     # Registers/latches. | ||||
|     # Cell('FDCE'), | ||||
|     # Cell('FDPE'), | ||||
|     # Cell('FDRE'), | ||||
|     # Cell('FDSE'), | ||||
|     Cell('IDDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), | ||||
|     Cell('LDCE'), | ||||
|     Cell('LDPE'), | ||||
|     Cell('ODDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Slice/CLB primitives. | ||||
|     # Cell('CARRY4'), | ||||
|     Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('LUT1'), | ||||
|     # Cell('LUT2'), | ||||
|     # Cell('LUT3'), | ||||
|     # Cell('LUT4'), | ||||
|     # Cell('LUT5'), | ||||
|     # Cell('LUT6'), | ||||
|     # Cell('LUT6_2'), | ||||
|     # Cell('MUXF7'), | ||||
|     # Cell('MUXF8'), | ||||
|     # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| XC6V_CELLS = [ | ||||
|     # Design elements types listed in Xilinx UG623. | ||||
| 
 | ||||
|     # Advanced. | ||||
|     Cell('PCIE_2_0'), | ||||
|     Cell('SYSMON'), | ||||
| 
 | ||||
|     # Arithmetic functions. | ||||
|     Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Clock components. | ||||
|     # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     #Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFIODQS', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('IBUFDS_GTXE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('MMCM_ADV'), | ||||
|     Cell('MMCM_BASE'), | ||||
| 
 | ||||
|     # Config/BSCAN components. | ||||
|     Cell('BSCAN_VIRTEX6', keep=True), | ||||
|     Cell('CAPTURE_VIRTEX6', keep=True), | ||||
|     Cell('DNA_PORT'), | ||||
|     Cell('EFUSE_USR'), | ||||
|     Cell('FRAME_ECC_VIRTEX6'), | ||||
|     Cell('ICAP_VIRTEX6', keep=True), | ||||
|     Cell('STARTUP_VIRTEX6', keep=True), | ||||
|     Cell('USR_ACCESS_VIRTEX6'), | ||||
| 
 | ||||
|     # I/O components. | ||||
|     Cell('DCIRESET', keep=True), | ||||
|     Cell('GTHE1_QUAD'), | ||||
|     Cell('GTXE1'), | ||||
|     # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_GTHE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), | ||||
|     Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IODELAYE1', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     Cell('ISERDESE1', port_attrs={ | ||||
|         'CLK': ['clkbuf_sink'], | ||||
|         'CLKB': ['clkbuf_sink'], | ||||
|         'OCLK': ['clkbuf_sink'], | ||||
|         'CLKDIV': ['clkbuf_sink'], | ||||
|     }), | ||||
|     Cell('KEEPER'), | ||||
|     # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OSERDESE1', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), | ||||
|     Cell('PULLDOWN'), | ||||
|     Cell('PULLUP'), | ||||
|     Cell('TEMAC_SINGLE'), | ||||
| 
 | ||||
|     # RAM/ROM. | ||||
|     Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # NOTE: not in the official library guide! | ||||
|     Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), | ||||
|     # Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), | ||||
|     Cell('ROM128X1'), | ||||
|     Cell('ROM256X1'), | ||||
|     Cell('ROM32X1'), | ||||
|     Cell('ROM64X1'), | ||||
| 
 | ||||
|     # Registers/latches. | ||||
|     # Cell('FDCE'), | ||||
|     # Cell('FDPE'), | ||||
|     # Cell('FDRE'), | ||||
|     # Cell('FDSE'), | ||||
|     Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), | ||||
|     Cell('LDCE'), | ||||
|     Cell('LDPE'), | ||||
|     Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Slice/CLB primitives. | ||||
|     # Cell('CARRY4'), | ||||
|     Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('LUT1'), | ||||
|     # Cell('LUT2'), | ||||
|     # Cell('LUT3'), | ||||
|     # Cell('LUT4'), | ||||
|     # Cell('LUT5'), | ||||
|     # Cell('LUT6'), | ||||
|     # Cell('LUT6_2'), | ||||
|     # Cell('MUXF7'), | ||||
|     # Cell('MUXF8'), | ||||
|     # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| XC7_CELLS = [ | ||||
|     # Design elements types listed in Xilinx UG953. | ||||
| 
 | ||||
|     # Advanced. | ||||
|     Cell('GTHE2_CHANNEL'), | ||||
|     Cell('GTHE2_COMMON'), | ||||
|     Cell('GTPE2_CHANNEL'), | ||||
|     Cell('GTPE2_COMMON'), | ||||
|     Cell('GTXE2_CHANNEL'), | ||||
|     Cell('GTXE2_COMMON'), | ||||
|     Cell('PCIE_2_1'), | ||||
|     Cell('PCIE_3_0'), | ||||
|     Cell('XADC'), | ||||
| 
 | ||||
|     # Arithmetic functions. | ||||
|     Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Clock components. | ||||
|     # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     #Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFMR', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFMRCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('MMCME2_ADV'), | ||||
|     Cell('MMCME2_BASE'), | ||||
|     Cell('PLLE2_ADV'), | ||||
|     Cell('PLLE2_BASE'), | ||||
| 
 | ||||
|     # Config/BSCAN components. | ||||
|     Cell('BSCANE2', keep=True), | ||||
|     Cell('CAPTUREE2', keep=True), | ||||
|     Cell('DNA_PORT'), | ||||
|     Cell('EFUSE_USR'), | ||||
|     Cell('FRAME_ECCE2'), | ||||
|     Cell('ICAPE2', keep=True), | ||||
|     Cell('STARTUPE2', keep=True), | ||||
|     Cell('USR_ACCESSE2'), | ||||
| 
 | ||||
|     # I/O components. | ||||
|     Cell('DCIRESET', keep=True), | ||||
|     # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), | ||||
|     Cell('IDELAYE2', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     Cell('IN_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('ISERDESE2', port_attrs={ | ||||
|         'CLK': ['clkbuf_sink'], | ||||
|         'CLKB': ['clkbuf_sink'], | ||||
|         'OCLK': ['clkbuf_sink'], | ||||
|         'OCLKB': ['clkbuf_sink'], | ||||
|         'CLKDIV': ['clkbuf_sink'], | ||||
|         'CLKDIVP': ['clkbuf_sink'], | ||||
|     }), | ||||
|     Cell('KEEPER'), | ||||
|     # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('ODELAYE2', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     Cell('OSERDESE2', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), | ||||
|     Cell('OUT_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('PHASER_IN'), | ||||
|     Cell('PHASER_IN_PHY'), | ||||
|     Cell('PHASER_OUT'), | ||||
|     Cell('PHASER_OUT_PHY'), | ||||
|     Cell('PHASER_REF'), | ||||
|     Cell('PHY_CONTROL'), | ||||
|     Cell('PULLDOWN'), | ||||
|     Cell('PULLUP'), | ||||
| 
 | ||||
|     # RAM/ROM. | ||||
|     Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # NOTE: not in the official library guide! | ||||
|     Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     # Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), | ||||
|     # Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), | ||||
|     Cell('ROM128X1'), | ||||
|     Cell('ROM256X1'), | ||||
|     Cell('ROM32X1'), | ||||
|     Cell('ROM64X1'), | ||||
| 
 | ||||
|     # Registers/latches. | ||||
|     # Cell('FDCE'), | ||||
|     # Cell('FDPE'), | ||||
|     # Cell('FDRE'), | ||||
|     # Cell('FDSE'), | ||||
|     Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), | ||||
|     Cell('LDCE'), | ||||
|     Cell('LDPE'), | ||||
|     Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Slice/CLB primitives. | ||||
|     # Cell('CARRY4'), | ||||
|     Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('LUT1'), | ||||
|     # Cell('LUT2'), | ||||
|     # Cell('LUT3'), | ||||
|     # Cell('LUT4'), | ||||
|     # Cell('LUT5'), | ||||
|     # Cell('LUT6'), | ||||
|     # Cell('LUT6_2'), | ||||
|     # Cell('MUXF7'), | ||||
|     # Cell('MUXF8'), | ||||
|     # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # NOTE: not in the official library guide! | ||||
|     Cell('PS7', keep=True), | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| XCU_CELLS = [ | ||||
|     # Design elements types listed in Xilinx UG974. | ||||
| 
 | ||||
|     # Advanced. | ||||
|     Cell('CMAC'), | ||||
|     Cell('CMACE4'), | ||||
|     Cell('GTHE3_CHANNEL'), | ||||
|     Cell('GTHE3_COMMON'), | ||||
|     Cell('GTHE4_CHANNEL'), | ||||
|     Cell('GTHE4_COMMON'), | ||||
|     Cell('GTYE3_CHANNEL'), | ||||
|     Cell('GTYE3_COMMON'), | ||||
|     Cell('GTYE4_CHANNEL'), | ||||
|     Cell('GTYE4_COMMON'), | ||||
|     Cell('IBUFDS_GTE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_GTE4', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('ILKN'), | ||||
|     Cell('ILKNE4'), | ||||
|     Cell('OBUFDS_GTE3', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS_GTE3_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS_GTE4', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS_GTE4_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('PCIE40E4'), | ||||
|     Cell('PCIE_3_1'), | ||||
|     Cell('SYSMONE1'), | ||||
|     Cell('SYSMONE4'), | ||||
| 
 | ||||
|     # Arithmetic functions. | ||||
|     Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Blockram. | ||||
|     Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('FIFO36E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAMB18E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAMB36E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), | ||||
|     Cell('URAM288', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('URAM288_BASE', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # CLB. | ||||
|     # Cell('LUT6_2'), | ||||
|     #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM256X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32M16', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM512X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64M8', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), | ||||
|     Cell('AND2B1L'), | ||||
|     Cell('CARRY8'), | ||||
|     Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('LUT1'), | ||||
|     # Cell('LUT2'), | ||||
|     # Cell('LUT3'), | ||||
|     # Cell('LUT4'), | ||||
|     # Cell('LUT5'), | ||||
|     # Cell('LUT6'), | ||||
|     # Cell('MUXF7'), | ||||
|     # Cell('MUXF8'), | ||||
|     Cell('MUXF9'), | ||||
|     Cell('OR2L'), | ||||
|     # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # Clock. | ||||
|     # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFG_GT', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFG_GT_SYNC'), | ||||
|     Cell('BUFG_PS', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGCE_DIV', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), | ||||
|     Cell('MMCME3_ADV'), | ||||
|     Cell('MMCME3_BASE'), | ||||
|     Cell('MMCME4_ADV'), | ||||
|     Cell('MMCME4_BASE'), | ||||
|     Cell('PLLE3_ADV'), | ||||
|     Cell('PLLE3_BASE'), | ||||
|     Cell('PLLE4_ADV'), | ||||
|     Cell('PLLE4_BASE'), | ||||
| 
 | ||||
|     # Configuration. | ||||
|     Cell('BSCANE2', keep=True), | ||||
|     Cell('DNA_PORTE2'), | ||||
|     Cell('EFUSE_USR'), | ||||
|     Cell('FRAME_ECCE3'), | ||||
|     Cell('ICAPE3', keep=True), | ||||
|     Cell('MASTER_JTAG', keep=True), | ||||
|     Cell('STARTUPE3', keep=True), | ||||
|     Cell('USR_ACCESSE2'), | ||||
| 
 | ||||
|     # I/O. | ||||
|     Cell('BITSLICE_CONTROL', keep=True), | ||||
|     Cell('DCIRESET', keep=True), | ||||
|     Cell('HPIO_VREF'), | ||||
|     # XXX | ||||
|     # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUF_ANALOG', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_DPHY', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFDSE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), | ||||
|     Cell('IBUFE3', port_attrs={'I': ['iopad_external_pin']}), | ||||
|     Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), | ||||
|     Cell('IDELAYE3', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFDSE3', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('IOBUFE3', port_attrs={'IO': ['iopad_external_pin']}), | ||||
|     Cell('ISERDESE3', port_attrs={ | ||||
|         'CLK': ['clkbuf_sink'], | ||||
|         'CLK_B': ['clkbuf_sink'], | ||||
|         'FIFO_RD_CLK': ['clkbuf_sink'], | ||||
|         'CLKDIV': ['clkbuf_sink'], | ||||
|     }), | ||||
|     Cell('KEEPER'), | ||||
|     # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFDS_DPHY', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), | ||||
|     Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), | ||||
|     Cell('ODELAYE3', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('OSERDESE3', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), | ||||
|     Cell('PULLDOWN'), | ||||
|     Cell('PULLUP'), | ||||
|     Cell('RIU_OR'), | ||||
|     Cell('RX_BITSLICE'), | ||||
|     Cell('RXTX_BITSLICE'), | ||||
|     Cell('TX_BITSLICE'), | ||||
|     Cell('TX_BITSLICE_TRI'), | ||||
| 
 | ||||
|     # Registers. | ||||
|     # Cell('FDCE'), | ||||
|     # Cell('FDPE'), | ||||
|     # Cell('FDRE'), | ||||
|     # Cell('FDSE'), | ||||
|     Cell('HARD_SYNC', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('IDDRE1', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), | ||||
|     Cell('LDCE'), | ||||
|     Cell('LDPE'), | ||||
|     Cell('ODDRE1', port_attrs={'C': ['clkbuf_sink']}), | ||||
| 
 | ||||
|     # NOTE: not in the official library guide! | ||||
|     Cell('PS8', keep=True), | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| class State(Enum): | ||||
|     OUTSIDE = auto() | ||||
|     IN_MODULE = auto() | ||||
|     IN_OTHER_MODULE = auto() | ||||
|     IN_FUNCTION = auto() | ||||
|     IN_TASK = auto() | ||||
| 
 | ||||
| def xtract_cell_decl(cell, dirs, outf): | ||||
|     for dir in dirs: | ||||
|         fname = os.path.join(dir, cell.name + '.v') | ||||
|         try: | ||||
|             with open(fname) as f: | ||||
|                 state = State.OUTSIDE | ||||
|                 found = False | ||||
|                 # Probably the most horrible Verilog "parser" ever written. | ||||
|                 module_ports = [] | ||||
|                 invertible_ports = set() | ||||
|                 for l in f: | ||||
|                     l = l.partition('//')[0] | ||||
|                     l = l.strip() | ||||
|                     if l == 'module {}'.format(cell.name) or l.startswith('module {} '.format(cell.name)): | ||||
|                         if found: | ||||
|                             print('Multiple modules in {}.'.format(fname)) | ||||
|                             sys.exit(1) | ||||
|                         elif state != State.OUTSIDE: | ||||
|                             print('Nested modules in {}.'.format(fname)) | ||||
|                             sys.exit(1) | ||||
|                         found = True | ||||
|                         state = State.IN_MODULE | ||||
|                         if cell.keep: | ||||
|                             outf.write('(* keep *)\n') | ||||
|                         outf.write('module {} (...);\n'.format(cell.name)) | ||||
|                     elif l.startswith('module '): | ||||
|                         if state != State.OUTSIDE: | ||||
|                             print('Nested modules in {}.'.format(fname)) | ||||
|                             sys.exit(1) | ||||
|                         state = State.IN_OTHER_MODULE | ||||
|                     elif l.startswith('task '): | ||||
|                         if state == State.IN_MODULE: | ||||
|                             state = State.IN_TASK | ||||
|                     elif l.startswith('function '): | ||||
|                         if state == State.IN_MODULE: | ||||
|                             state = State.IN_FUNCTION | ||||
|                     elif l == 'endtask': | ||||
|                         if state == State.IN_TASK: | ||||
|                             state = State.IN_MODULE | ||||
|                     elif l == 'endfunction': | ||||
|                         if state == State.IN_FUNCTION: | ||||
|                             state = State.IN_MODULE | ||||
|                     elif l == 'endmodule': | ||||
|                         if state == State.IN_MODULE: | ||||
|                             for kind, rng, port in module_ports: | ||||
|                                 for attr in cell.port_attrs.get(port, []): | ||||
|                                     outf.write('    (* {} *)\n'.format(attr)) | ||||
|                                 if port in invertible_ports: | ||||
|                                     outf.write('    (* invertible_pin = "IS_{}_INVERTED" *)\n'.format(port)) | ||||
|                                 if rng is None: | ||||
|                                     outf.write('    {} {};\n'.format(kind, port)) | ||||
|                                 else: | ||||
|                                     outf.write('    {} {} {};\n'.format(kind, rng, port)) | ||||
|                             outf.write(l + '\n') | ||||
|                             outf.write('\n') | ||||
|                         elif state != State.IN_OTHER_MODULE: | ||||
|                             print('endmodule in weird place in {}.'.format(cell.name, fname)) | ||||
|                             sys.exit(1) | ||||
|                         state = State.OUTSIDE | ||||
|                     elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE: | ||||
|                         if l.endswith((';', ',')): | ||||
|                             l = l[:-1] | ||||
|                         if ';' in l: | ||||
|                             print('Weird port line in {} [{}].'.format(fname, l)) | ||||
|                             sys.exit(1) | ||||
|                         kind, _, ports = l.partition(' ') | ||||
|                         for port in ports.split(','): | ||||
|                             port = port.strip() | ||||
|                             if port.startswith('['): | ||||
|                                 rng, port = port.split() | ||||
|                             else: | ||||
|                                 rng = None | ||||
|                             module_ports.append((kind, rng, port)) | ||||
|                     elif l.startswith('parameter ') and state == State.IN_MODULE: | ||||
|                         if 'UNPLACED' in l: | ||||
|                             continue | ||||
|                         if l.endswith((';', ',')): | ||||
|                             l = l[:-1] | ||||
|                         while '  ' in l: | ||||
|                             l = l.replace('  ', ' ') | ||||
|                         if ';' in l: | ||||
|                             print('Weird parameter line in {} [{}].'.format(fname, l)) | ||||
|                             sys.exit(1) | ||||
|                         outf.write('    {};\n'.format(l)) | ||||
|                         match = re.search('IS_([a-zA-Z0-9_]+)_INVERTED', l) | ||||
|                         if match: | ||||
|                             invertible_ports.add(match[1]) | ||||
|                 if state != State.OUTSIDE: | ||||
|                     print('endmodule not found in {}.'.format(fname)) | ||||
|                     sys.exit(1) | ||||
|                 if not found: | ||||
|                     print('Cannot find module {} in {}.'.format(cell.name, fname)) | ||||
|                     sys.exit(1) | ||||
|             return | ||||
|         except FileNotFoundError: | ||||
|             continue | ||||
|     print('Cannot find {}.'.format(cell.name)) | ||||
|     sys.exit(1) | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     parser = ArgumentParser(description='Extract Xilinx blackbox cell definitions from ISE and Vivado.') | ||||
|     parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1') | ||||
|     parser.add_argument('ise_dir', nargs='?', default='/opt/Xilinx/ISE/14.7') | ||||
|     args = parser.parse_args() | ||||
| 
 | ||||
|     dirs = [ | ||||
|         os.path.join(args.vivado_dir, 'data/verilog/src/xeclib'), | ||||
|         os.path.join(args.vivado_dir, 'data/verilog/src/retarget'), | ||||
|         os.path.join(args.ise_dir, 'ISE_DS/ISE/verilog/xeclib/unisims'), | ||||
|     ] | ||||
|     for dir in dirs: | ||||
|         if not os.path.isdir(dir): | ||||
|             print('{} is not a directory'.format(dir)) | ||||
| 
 | ||||
|     for ofile, cells in [ | ||||
|         ('xc6s_cells_xtra.v', XC6S_CELLS), | ||||
|         ('xc6v_cells_xtra.v', XC6V_CELLS), | ||||
|         ('xc7_cells_xtra.v', XC7_CELLS), | ||||
|         ('xcu_cells_xtra.v', XCU_CELLS), | ||||
|     ]: | ||||
|         out = StringIO() | ||||
|         for cell in cells: | ||||
|             xtract_cell_decl(cell, dirs, out) | ||||
| 
 | ||||
|         with open(ofile, 'w') as f: | ||||
|             f.write('// Created by cells_xtra.py from Xilinx models\n') | ||||
|             f.write('\n') | ||||
|             f.write(out.getvalue()) | ||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue