mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/clifford/async2synclatch' into Sergey/tests_ice40
This commit is contained in:
		
						commit
						32eef26ee2
					
				
					 67 changed files with 3620 additions and 590 deletions
				
			
		
							
								
								
									
										1
									
								
								Brewfile
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								Brewfile
									
										
									
									
									
								
							|  | @ -6,3 +6,4 @@ brew "git" | |||
| brew "graphviz" | ||||
| brew "pkg-config" | ||||
| brew "python3" | ||||
| brew "tcl-tk" | ||||
|  |  | |||
							
								
								
									
										128
									
								
								CHANGELOG
									
										
									
									
									
								
							
							
						
						
									
										128
									
								
								CHANGELOG
									
										
									
									
									
								
							|  | @ -12,43 +12,149 @@ 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) | ||||
|     - Renamed labels in synth_intel (e.g. bram -> map_bram) | ||||
|     - Renamed labels/options in synth_xilinx (e.g. dram -> map_lutram; -nodram -> -nolutram) | ||||
|     - Added automatic gzip decompression for frontends | ||||
|     - Added $_NMUX_ cell type | ||||
|     - 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 "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 | ||||
| 
 | ||||
| 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" | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										12
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -91,8 +91,10 @@ PLUGIN_LDFLAGS += -undefined dynamic_lookup | |||
| ifneq ($(shell which 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) | ||||
|  | @ -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+1 | ||||
| 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
 | ||||
|  | @ -487,6 +492,11 @@ define add_include_file | |||
| $(eval $(call add_share_file,$(dir share/include/$(1)),$(1))) | ||||
| endef | ||||
| 
 | ||||
| define add_extra_objs | ||||
| EXTRA_OBJS += $(1) | ||||
| .SECONDARY: $(1) | ||||
| endef | ||||
| 
 | ||||
| ifeq ($(PRETTY), 1) | ||||
| P_STATUS = 0 | ||||
| P_OFFSET = 0 | ||||
|  |  | |||
							
								
								
									
										41
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										41
									
								
								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: | ||||
| 
 | ||||
|  | @ -329,6 +332,21 @@ Verilog Attributes and non-standard features | |||
|   that represent module parameters or localparams (when the HDL front-end | ||||
|   is run in -pwires mode). | ||||
| 
 | ||||
| - 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 ``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. | ||||
| 
 | ||||
| - In addition to the ``(* ... *)`` attribute syntax, Yosys supports | ||||
|   the non-standard ``{* ... *}`` attribute syntax to set default attributes | ||||
|   for everything that comes after the ``{* ... *}`` statement. (Reset | ||||
|  | @ -405,6 +423,23 @@ 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_scc_break`` indicates a module input port that will | ||||
|   be treated as a primary output during `abc9` techmapping. Doing so eliminates | ||||
|   the possibility of a strongly-connected component (i.e. a combinatorial loop) | ||||
|   existing. Typically, this is specified for sequential inputs on otherwise | ||||
|   combinatorial boxes -- for example, applying ``abc_scc_break`` onto the `D` | ||||
|   port of a LUTRAM cell prevents `abc9` from interpreting any `Q` -> `D` paths | ||||
|   as a combinatorial loop. | ||||
| 
 | ||||
| - 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 | ||||
| ============================================================== | ||||
|  |  | |||
|  | @ -326,7 +326,6 @@ struct XAigerWriter | |||
| #endif | ||||
| 			log_assert(no_loops); | ||||
| 
 | ||||
| 			pool<IdString> seen_boxes; | ||||
| 			for (auto cell_name : toposort.sorted) { | ||||
| 				RTLIL::Cell *cell = module->cell(cell_name); | ||||
| 				log_assert(cell); | ||||
|  | @ -335,47 +334,6 @@ struct XAigerWriter | |||
| 				if (!box_module || !box_module->attributes.count("\\abc_box_id")) | ||||
| 					continue; | ||||
| 
 | ||||
| 				if (seen_boxes.insert(cell->type).second) { | ||||
| 					auto it = box_module->attributes.find("\\abc_carry"); | ||||
| 					if (it != box_module->attributes.end()) { | ||||
| 						RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; | ||||
| 						auto carry_in_out = it->second.decode_string(); | ||||
| 						auto pos = carry_in_out.find(','); | ||||
| 						if (pos == std::string::npos) | ||||
| 							log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type)); | ||||
| 						auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos)); | ||||
| 						carry_in = box_module->wire(carry_in_name); | ||||
| 						if (!carry_in || !carry_in->port_input) | ||||
| 							log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str()); | ||||
| 
 | ||||
| 						auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1)); | ||||
| 						carry_out = box_module->wire(carry_out_name); | ||||
| 						if (!carry_out || !carry_out->port_output) | ||||
| 							log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str()); | ||||
| 
 | ||||
| 						auto &ports = box_module->ports; | ||||
| 						for (auto jt = ports.begin(); jt != ports.end(); ) { | ||||
| 							RTLIL::Wire* w = box_module->wire(*jt); | ||||
| 							log_assert(w); | ||||
| 							if (w == carry_in || w == carry_out) { | ||||
| 								jt = ports.erase(jt); | ||||
| 								continue; | ||||
| 							} | ||||
| 							if (w->port_id > carry_in->port_id) | ||||
| 								--w->port_id; | ||||
| 							if (w->port_id > carry_out->port_id) | ||||
| 								--w->port_id; | ||||
| 							log_assert(w->port_input || w->port_output); | ||||
| 							log_assert(ports[w->port_id-1] == w->name); | ||||
| 							++jt; | ||||
| 						} | ||||
| 						ports.push_back(carry_in->name); | ||||
| 						carry_in->port_id = ports.size(); | ||||
| 						ports.push_back(carry_out->name); | ||||
| 						carry_out->port_id = ports.size(); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				// Fully pad all unused input connections of this box cell with S0
 | ||||
| 				// Fully pad all undriven output connections of this box cell with anonymous wires
 | ||||
| 				// NB: Assume box_module->ports are sorted alphabetically
 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -1502,7 +1502,10 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString | |||
| 	rewrite_parameter: | ||||
| 			para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); | ||||
| 			delete child->children.at(0); | ||||
| 			if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0) | ||||
| 			if ((parameters[para_id].flags & RTLIL::CONST_FLAG_REAL) != 0) { | ||||
| 				child->children[0] = new AstNode(AST_REALVALUE); | ||||
| 				child->children[0]->realvalue = std::stod(parameters[para_id].decode_string()); | ||||
| 			} else if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0) | ||||
| 				child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string()); | ||||
| 			else | ||||
| 				child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0); | ||||
|  |  | |||
|  | @ -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)) { } | ||||
| 				} | ||||
|  |  | |||
|  | @ -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"); | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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)))); | ||||
|  | @ -1142,7 +1164,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()); | ||||
|  |  | |||
							
								
								
									
										2
									
								
								passes/pmgen/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								passes/pmgen/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +1 @@ | |||
| /*_pm.h | ||||
| /*_pm.h | ||||
|  | @ -1,30 +1,29 @@ | |||
| %_pm.h: passes/pmgen/pmgen.py %.pmg | ||||
| 	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| OBJS += passes/pmgen/test_pmgen.o | ||||
| passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h | ||||
| $(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| OBJS += passes/pmgen/ice40_dsp.o | ||||
| OBJS += passes/pmgen/ice40_wrapcarry.o | ||||
| OBJS += passes/pmgen/peepopt.o | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h | ||||
| EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h | ||||
| .SECONDARY: passes/pmgen/ice40_dsp_pm.h | ||||
| 
 | ||||
| passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg | ||||
| 	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^) | ||||
| $(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 | ||||
| EXTRA_OBJS += passes/pmgen/ice40_wrapcarry_pm.h | ||||
| .SECONDARY: passes/pmgen/ice40_wrapcarry_pm.h | ||||
| 
 | ||||
| passes/pmgen/ice40_wrapcarry_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_wrapcarry.pmg | ||||
| 	$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_wrapcarry $(filter-out $<,$^) | ||||
| $(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h)) | ||||
| 
 | ||||
| # --------------------------------------
 | ||||
| 
 | ||||
| OBJS += passes/pmgen/peepopt.o | ||||
| passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h | ||||
| EXTRA_OBJS += passes/pmgen/peepopt_pm.h | ||||
| .SECONDARY: passes/pmgen/peepopt_pm.h | ||||
| $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) | ||||
| 
 | ||||
| PEEPOPT_PATTERN  = passes/pmgen/peepopt_shiftmul.pmg | ||||
| PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg | ||||
|  |  | |||
|  | @ -45,9 +45,9 @@ of type `foobar_pm::state_<pattern_name>_t`.) | |||
| Similarly the `.pmg` file declares user data variables that become members of | ||||
| `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`. | ||||
| 
 | ||||
| There are four versions of the `run_<pattern_name>()` method: Without callback, | ||||
| callback without arguments, callback with reference to `pm`, and callback with | ||||
| reference to `pm.st_<pattern_name>`. | ||||
| There are three versions of the `run_<pattern_name>()` method: Without callback, | ||||
| callback without arguments, and callback with reference to `pm`. All versions | ||||
| of the `run_<pattern_name>()` method return the number of found matches. | ||||
| 
 | ||||
| 
 | ||||
| The .pmg File Format | ||||
|  | @ -118,8 +118,8 @@ write matchers: | |||
|   connected to any of the given signal bits, plus one if any of the signal | ||||
|   bits is also a primary input or primary output. | ||||
| 
 | ||||
| - In `code..endcode` blocks there exist `accept`, `reject`, and `branch` | ||||
|   statements. | ||||
| - In `code..endcode` blocks there exist `accept`, `reject`, `branch`, | ||||
|   `finish`, and `subpattern` statements. | ||||
| 
 | ||||
| - In `index` statements there is a special `===` operator for the index | ||||
|   lookup. | ||||
|  | @ -175,6 +175,48 @@ explore the case where `mul` is set to `nullptr`. Without the `optional` | |||
| statement a match may only be assigned nullptr when one of the `if` expressions | ||||
| 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 | ||||
| --------------- | ||||
| 
 | ||||
|  | @ -232,5 +274,111 @@ But in some cases it is more natural to utilize the implicit branch statement: | |||
|         portAB = \B; | ||||
|     endcode | ||||
| 
 | ||||
| There is an implicit `code..endcode` block at the end of each `.pmg` file | ||||
| that just accepts everything that gets all the way there. | ||||
| There is an implicit `code..endcode` block at the end of each (sub)pattern | ||||
| that just rejects. | ||||
| 
 | ||||
| A `code..finally..endcode` block executes the code after `finally` during | ||||
| back-tracking. This is useful for maintaining user data state or printing | ||||
| debug messages. For example: | ||||
| 
 | ||||
|     udata <vector<Cell*>> stack | ||||
| 
 | ||||
|     code | ||||
|         stack.push_back(addAB); | ||||
|         ... | ||||
|     finally | ||||
|         stack.pop_back(); | ||||
|     endcode | ||||
| 
 | ||||
| `accept` and `finish` statements can be used inside the `finally` section, | ||||
| but not `reject`, `branch`, or `subpattern`. | ||||
| 
 | ||||
| Declaring a subpattern | ||||
| ---------------------- | ||||
| 
 | ||||
| A subpattern starts with a line containing the `subpattern` keyword followed | ||||
| by the name of the subpattern. Subpatterns can be called from a `code` block | ||||
| using a `subpattern(<subpattern_name>);` C statement. | ||||
| 
 | ||||
| Arguments may be passed to subpattern via state variables. The `subpattern` | ||||
| line must be followed by a `arg <arg1> <arg2> ...` line that lists the | ||||
| state variables used to pass arguments. | ||||
| 
 | ||||
|     state <IdString> foobar_type | ||||
|     state <bool> foobar_state | ||||
| 
 | ||||
|     code foobar_type foobar_state | ||||
|         foobar_state = false; | ||||
|         foobar_type = $add; | ||||
|         subpattern(foo); | ||||
|         foobar_type = $sub; | ||||
|         subpattern(bar); | ||||
|     endcode | ||||
| 
 | ||||
|     subpattern foo | ||||
|     arg foobar_type foobar_state | ||||
| 
 | ||||
|     match addsub | ||||
|         index <IdString> addsub->type === foobar_type | ||||
|         ... | ||||
|     endmatch | ||||
| 
 | ||||
|     code | ||||
|         if (foobar_state) { | ||||
|             subpattern(tail); | ||||
|         } else { | ||||
|             foobar_state = true; | ||||
|             subpattern(bar); | ||||
|         } | ||||
|     endcode | ||||
| 
 | ||||
|     subpattern bar | ||||
|     arg foobar_type foobar_state | ||||
| 
 | ||||
|     match addsub | ||||
|         index <IdString> addsub->type === foobar_type | ||||
|         ... | ||||
|     endmatch | ||||
| 
 | ||||
|     code | ||||
|         if (foobar_state) { | ||||
|             subpattern(tail); | ||||
|         } else { | ||||
|             foobar_state = true; | ||||
|             subpattern(foo); | ||||
|         } | ||||
|     endcode | ||||
| 
 | ||||
|     subpattern tail | ||||
|     ... | ||||
| 
 | ||||
| Subpatterns cann 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. | ||||
| 
 | ||||
| Generate Blocks | ||||
| --------------- | ||||
| 
 | ||||
| Match blocks may contain an optional `generate` section that is used for automatic | ||||
| test-case generation. For example: | ||||
| 
 | ||||
|     match mul | ||||
|         ... | ||||
|     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)); | ||||
|         module->addMul(NEW_ID, A, B, Y, rng(2)); | ||||
|     endmatch | ||||
| 
 | ||||
| The expression `rng(n)` returns a non-negative integer less than `n`. | ||||
| 
 | ||||
| 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. | ||||
|  |  | |||
|  | @ -159,4 +159,5 @@ code clock clock_pol clock_vld | |||
| 		clock_pol = cp; | ||||
| 		clock_vld = true; | ||||
| 	} | ||||
| 	accept; | ||||
| endcode | ||||
|  |  | |||
|  | @ -32,5 +32,5 @@ code | |||
| 	log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); | ||||
| 	module->connect(div_y, val_y); | ||||
| 	autoremove(div); | ||||
| 	reject; | ||||
| 	accept; | ||||
| endcode | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ match mul | |||
| endmatch | ||||
| 
 | ||||
| code | ||||
| { | ||||
| 	IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; | ||||
| 	IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED; | ||||
| 	Const const_factor_cnst = port(mul, const_factor_port).as_const(); | ||||
|  | @ -90,5 +91,6 @@ code | |||
| 	shift->setParam(\B_WIDTH, GetSize(new_b)); | ||||
| 
 | ||||
| 	blacklist(shift); | ||||
| 	reject; | ||||
| 	accept; | ||||
| } | ||||
| endcode | ||||
|  |  | |||
|  | @ -38,7 +38,10 @@ for a in args: | |||
| assert prefix is not None | ||||
| 
 | ||||
| current_pattern = None | ||||
| current_subpattern = None | ||||
| patterns = dict() | ||||
| subpatterns = dict() | ||||
| subpattern_args = dict() | ||||
| state_types = dict() | ||||
| udata_types = dict() | ||||
| blocks = list() | ||||
|  | @ -104,9 +107,12 @@ def rewrite_cpp(s): | |||
| 
 | ||||
|     return "".join(t) | ||||
| 
 | ||||
| def process_pmgfile(f): | ||||
| def process_pmgfile(f, filename): | ||||
|     linenr = 0 | ||||
|     global current_pattern | ||||
|     global current_subpattern | ||||
|     while True: | ||||
|         linenr += 1 | ||||
|         line = f.readline() | ||||
|         if line == "": break | ||||
|         line = line.strip() | ||||
|  | @ -119,19 +125,52 @@ def process_pmgfile(f): | |||
|             if current_pattern is not None: | ||||
|                 block = dict() | ||||
|                 block["type"] = "final" | ||||
|                 block["pattern"] = current_pattern | ||||
|                 block["pattern"] = (current_pattern, current_subpattern) | ||||
|                 blocks.append(block) | ||||
|             line = line.split() | ||||
|             assert len(line) == 2 | ||||
|             assert line[1] not in patterns | ||||
|             current_pattern = line[1] | ||||
|             current_subpattern = "" | ||||
|             patterns[current_pattern] = len(blocks) | ||||
|             subpatterns[(current_pattern, current_subpattern)] = len(blocks) | ||||
|             subpattern_args[(current_pattern, current_subpattern)] = list() | ||||
|             state_types[current_pattern] = dict() | ||||
|             udata_types[current_pattern] = dict() | ||||
|             continue | ||||
| 
 | ||||
|         assert current_pattern is not None | ||||
| 
 | ||||
|         if cmd == "fallthrough": | ||||
|             block = dict() | ||||
|             block["type"] = "fallthrough" | ||||
|             blocks.append(block) | ||||
|             line = line.split() | ||||
|             assert len(line) == 1 | ||||
|             continue | ||||
| 
 | ||||
|         if cmd == "subpattern": | ||||
|             if len(blocks) == 0 or blocks[-1]["type"] != "fallthrough": | ||||
|                 block = dict() | ||||
|                 block["type"] = "final" | ||||
|                 block["pattern"] = (current_pattern, current_subpattern) | ||||
|                 blocks.append(block) | ||||
|             elif len(blocks) and blocks[-1]["type"] == "fallthrough": | ||||
|                 del blocks[-1] | ||||
|             line = line.split() | ||||
|             assert len(line) == 2 | ||||
|             current_subpattern = line[1] | ||||
|             subpattern_args[(current_pattern, current_subpattern)] = list() | ||||
|             assert (current_pattern, current_subpattern) not in subpatterns | ||||
|             subpatterns[(current_pattern, current_subpattern)] = len(blocks) | ||||
|             continue | ||||
| 
 | ||||
|         if cmd == "arg": | ||||
|             line = line.split() | ||||
|             assert len(line) > 1 | ||||
|             subpattern_args[(current_pattern, current_subpattern)] += line[1:] | ||||
|             continue | ||||
| 
 | ||||
|         if cmd == "state": | ||||
|             m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) | ||||
|             assert m | ||||
|  | @ -155,21 +194,28 @@ def process_pmgfile(f): | |||
|         if cmd == "match": | ||||
|             block = dict() | ||||
|             block["type"] = "match" | ||||
|             block["pattern"] = current_pattern | ||||
|             block["src"] = "%s:%d" % (filename, linenr) | ||||
|             block["pattern"] = (current_pattern, current_subpattern) | ||||
| 
 | ||||
|             block["genargs"] = None | ||||
|             block["gencode"] = None | ||||
| 
 | ||||
|             line = line.split() | ||||
|             assert len(line) == 2 | ||||
|             assert line[1] not in state_types[current_pattern] | ||||
|             assert (line[1] not in state_types[current_pattern]) or (state_types[current_pattern][line[1]] == "Cell*") | ||||
|             block["cell"] = line[1] | ||||
|             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 | ||||
| 
 | ||||
|             while True: | ||||
|                 linenr += 1 | ||||
|                 l = f.readline() | ||||
|                 assert l != "" | ||||
|                 a = l.split() | ||||
|  | @ -183,7 +229,22 @@ def process_pmgfile(f): | |||
| 
 | ||||
|                 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": | ||||
|  | @ -197,35 +258,71 @@ def process_pmgfile(f): | |||
|                     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 | ||||
| 
 | ||||
|                 if a[0] == "semioptional": | ||||
|                     block["semioptional"] = True | ||||
|                     continue | ||||
| 
 | ||||
|                 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() | ||||
|                     while True: | ||||
|                         linenr += 1 | ||||
|                         l = f.readline() | ||||
|                         assert l != "" | ||||
|                         a = l.split() | ||||
|                         if len(a) == 1 and a[0] == "endmatch": break | ||||
|                         block["gencode"].append(rewrite_cpp(l.rstrip())) | ||||
|                     break | ||||
| 
 | ||||
|                 assert False | ||||
| 
 | ||||
|             if block["optional"]: | ||||
|                 assert not block["semioptional"] | ||||
| 
 | ||||
|             blocks.append(block) | ||||
|             continue | ||||
| 
 | ||||
|         if cmd == "code": | ||||
|             block = dict() | ||||
|             block["type"] = "code" | ||||
|             block["pattern"] = current_pattern | ||||
|             block["src"] = "%s:%d" % (filename, linenr) | ||||
|             block["pattern"] = (current_pattern, current_subpattern) | ||||
| 
 | ||||
|             block["code"] = list() | ||||
|             block["fcode"] = list() | ||||
|             block["states"] = set() | ||||
| 
 | ||||
|             for s in line.split()[1:]: | ||||
|                 assert s in state_types[current_pattern] | ||||
|                 block["states"].add(s) | ||||
| 
 | ||||
|             codetype = "code" | ||||
| 
 | ||||
|             while True: | ||||
|                 linenr += 1 | ||||
|                 l = f.readline() | ||||
|                 assert l != "" | ||||
|                 a = l.split() | ||||
|                 if len(a) == 0: continue | ||||
|                 if a[0] == "endcode": break | ||||
| 
 | ||||
|                 block["code"].append(rewrite_cpp(l.rstrip())) | ||||
|                 if a[0] == "finally": | ||||
|                     codetype = "fcode" | ||||
|                     continue | ||||
| 
 | ||||
|                 block[codetype].append(rewrite_cpp(l.rstrip())) | ||||
| 
 | ||||
|             blocks.append(block) | ||||
|             continue | ||||
|  | @ -234,15 +331,16 @@ def process_pmgfile(f): | |||
| 
 | ||||
| for fn in pmgfiles: | ||||
|     with open(fn, "r") as f: | ||||
|         process_pmgfile(f) | ||||
|         process_pmgfile(f, fn) | ||||
| 
 | ||||
| if current_pattern is not None: | ||||
|     block = dict() | ||||
|     block["type"] = "final" | ||||
|     block["pattern"] = current_pattern | ||||
|     block["pattern"] = (current_pattern, current_subpattern) | ||||
|     blocks.append(block) | ||||
| 
 | ||||
| current_pattern = None | ||||
| current_subpattern = None | ||||
| 
 | ||||
| if debug: | ||||
|     pp.pprint(blocks) | ||||
|  | @ -262,7 +360,18 @@ with open(outfile, "w") as f: | |||
|     print("struct {}_pm {{".format(prefix), file=f) | ||||
|     print("  Module *module;", file=f) | ||||
|     print("  SigMap sigmap;", file=f) | ||||
|     print("  std::function<void()> on_accept;".format(prefix), file=f) | ||||
|     print("  std::function<void()> on_accept;", file=f) | ||||
|     print("  bool generate_mode;", file=f) | ||||
|     print("  int accept_cnt;", file=f) | ||||
|     print("", file=f) | ||||
| 
 | ||||
|     print("  uint32_t rngseed;", file=f) | ||||
|     print("  int rng(unsigned int n) {", file=f) | ||||
|     print("    rngseed ^= rngseed << 13;", file=f) | ||||
|     print("    rngseed ^= rngseed >> 17;", file=f) | ||||
|     print("    rngseed ^= rngseed << 5;", file=f) | ||||
|     print("    return rngseed % n;", file=f) | ||||
|     print("  }", file=f) | ||||
|     print("", file=f) | ||||
| 
 | ||||
|     for index in range(len(blocks)): | ||||
|  | @ -271,12 +380,21 @@ 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) | ||||
|     print("  bool blacklist_dirty;", file=f) | ||||
|     print("  dict<Cell*,int> rollback_cache;", file=f) | ||||
|     print("  int rollback;", file=f) | ||||
|     print("", file=f) | ||||
| 
 | ||||
|  | @ -304,47 +422,30 @@ 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) | ||||
|     print("", file=f) | ||||
| 
 | ||||
|     print("  void blacklist(Cell *cell) {", file=f) | ||||
|     print("    if (cell != nullptr) {", file=f) | ||||
|     print("      if (blacklist_cells.insert(cell).second)", file=f) | ||||
|     print("        blacklist_dirty = true;", file=f) | ||||
|     print("    if (cell != nullptr && blacklist_cells.insert(cell).second) {", file=f) | ||||
|     print("      auto ptr = rollback_cache.find(cell);", file=f) | ||||
|     print("      if (ptr == rollback_cache.end()) return;", file=f) | ||||
|     print("      int rb = ptr->second;", file=f) | ||||
|     print("      if (rollback == 0 || rollback > rb)", file=f) | ||||
|     print("        rollback = rb;", file=f) | ||||
|     print("    }", file=f) | ||||
|     print("  }", file=f) | ||||
|     print("", file=f) | ||||
| 
 | ||||
|     print("  void autoremove(Cell *cell) {", file=f) | ||||
|     print("    if (cell != nullptr) {", file=f) | ||||
|     print("      if (blacklist_cells.insert(cell).second)", file=f) | ||||
|     print("        blacklist_dirty = true;", file=f) | ||||
|     print("      autoremove_cells.insert(cell);", file=f) | ||||
|     print("      blacklist(cell);", file=f) | ||||
|     print("    }", file=f) | ||||
|     print("  }", file=f) | ||||
|     print("", file=f) | ||||
| 
 | ||||
|     for current_pattern in sorted(patterns.keys()): | ||||
|         print("  void check_blacklist_{}() {{".format(current_pattern), file=f) | ||||
|         print("    if (!blacklist_dirty)", file=f) | ||||
|         print("      return;", file=f) | ||||
|         print("    blacklist_dirty = false;", file=f) | ||||
|         for index in range(len(blocks)): | ||||
|             block = blocks[index] | ||||
|             if block["pattern"] != current_pattern: | ||||
|                 continue | ||||
|             if block["type"] == "match": | ||||
|                 print("    if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f) | ||||
|                 print("      rollback = {};".format(index+1), file=f) | ||||
|                 print("      return;", file=f) | ||||
|                 print("    }", file=f) | ||||
|         print("    rollback = 0;", file=f) | ||||
|         print("  }", file=f) | ||||
|         print("", file=f) | ||||
|     current_pattern = None | ||||
| 
 | ||||
|     print("  SigSpec port(Cell *cell, IdString portname) {", file=f) | ||||
|  | @ -367,7 +468,7 @@ with open(outfile, "w") as f: | |||
|     print("", file=f) | ||||
| 
 | ||||
|     print("  {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) | ||||
|     print("      module(module), sigmap(module) {", file=f) | ||||
|     print("      module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f) | ||||
|     for current_pattern in sorted(patterns.keys()): | ||||
|         for s, t in sorted(udata_types[current_pattern].items()): | ||||
|             if t.endswith("*"): | ||||
|  | @ -375,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)): | ||||
|  | @ -386,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) | ||||
|  | @ -405,41 +529,47 @@ with open(outfile, "w") as f: | |||
|     print("", file=f) | ||||
| 
 | ||||
|     for current_pattern in sorted(patterns.keys()): | ||||
|         print("  void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) | ||||
|         print("  int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) | ||||
|         print("    accept_cnt = 0;", file=f) | ||||
|         print("    on_accept = on_accept_f;", file=f) | ||||
|         print("    rollback = 0;", file=f) | ||||
|         print("    blacklist_dirty = false;", file=f) | ||||
|         for s, t in sorted(state_types[current_pattern].items()): | ||||
|             if t.endswith("*"): | ||||
|                 print("    st_{}.{} = nullptr;".format(current_pattern, s), file=f) | ||||
|             else: | ||||
|                 print("    st_{}.{} = {}();".format(current_pattern, s, t), file=f) | ||||
|         print("    block_{}();".format(patterns[current_pattern]), file=f) | ||||
|         print("    block_{}(1);".format(patterns[current_pattern]), file=f) | ||||
|         print("    log_assert(rollback_cache.empty());", file=f) | ||||
|         print("    return accept_cnt;", file=f) | ||||
|         print("  }", file=f) | ||||
|         print("", file=f) | ||||
|         print("  void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f) | ||||
|         print("    run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) | ||||
|         print("  int run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f) | ||||
|         print("    return run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) | ||||
|         print("  }", file=f) | ||||
|         print("", file=f) | ||||
|         print("  void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f) | ||||
|         print("    run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f) | ||||
|         print("  int run_{}() {{".format(current_pattern), file=f) | ||||
|         print("    return run_{}([](){{}});".format(current_pattern, current_pattern), file=f) | ||||
|         print("  }", file=f) | ||||
|         print("", file=f) | ||||
|         print("  void run_{}() {{".format(current_pattern), file=f) | ||||
|         print("    run_{}([](){{}});".format(current_pattern, current_pattern), file=f) | ||||
|         print("  }", file=f) | ||||
| 
 | ||||
|     if len(subpatterns): | ||||
|         for p, s in sorted(subpatterns.keys()): | ||||
|             print("  void block_subpattern_{}_{}(int recursion) {{ block_{}(recursion); }}".format(p, s, subpatterns[(p, s)]), file=f) | ||||
|         print("", file=f) | ||||
| 
 | ||||
|     current_pattern = None | ||||
|     current_subpattern = None | ||||
| 
 | ||||
|     for index in range(len(blocks)): | ||||
|         block = blocks[index] | ||||
| 
 | ||||
|         print("  void block_{}() {{".format(index), file=f) | ||||
|         current_pattern = block["pattern"] | ||||
|         if block["type"] in ("match", "code"): | ||||
|             print("  // {}".format(block["src"]), file=f) | ||||
| 
 | ||||
|         print("  void block_{}(int recursion YS_ATTRIBUTE(unused)) {{".format(index), file=f) | ||||
|         current_pattern, current_subpattern = block["pattern"] | ||||
| 
 | ||||
|         if block["type"] == "final": | ||||
|             print("    on_accept();", file=f) | ||||
|             print("    check_blacklist_{}();".format(current_pattern), file=f) | ||||
|             print("  }", file=f) | ||||
|             if index+1 != len(blocks): | ||||
|                 print("", file=f) | ||||
|  | @ -449,12 +579,17 @@ with open(outfile, "w") as f: | |||
|         nonconst_st = set() | ||||
|         restore_st = set() | ||||
| 
 | ||||
|         for i in range(patterns[current_pattern], index): | ||||
|         for s in subpattern_args[(current_pattern, current_subpattern)]: | ||||
|             const_st.add(s) | ||||
| 
 | ||||
|         for i in range(subpatterns[(current_pattern, current_subpattern)], index): | ||||
|             if blocks[i]["type"] == "code": | ||||
|                 for s in blocks[i]["states"]: | ||||
|                     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 | ||||
| 
 | ||||
|  | @ -468,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 | ||||
| 
 | ||||
|  | @ -482,37 +621,55 @@ with open(outfile, "w") as f: | |||
|             t = state_types[current_pattern][s] | ||||
|             print("    {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) | ||||
| 
 | ||||
|         for u in sorted(udata_types[current_pattern].keys()): | ||||
|             t = udata_types[current_pattern][u] | ||||
|             print("    {} &{} YS_ATTRIBUTE(unused) = ud_{}.{};".format(t, u, current_pattern, u), file=f) | ||||
| 
 | ||||
|         if len(restore_st): | ||||
|             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) | ||||
|             print("    do {", file=f) | ||||
|             print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f) | ||||
|             print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) | ||||
|             print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) | ||||
|             print("#define reject do { goto rollback_label; } while(0)", file=f) | ||||
|             print("#define accept do { accept_cnt++; on_accept(); if (rollback) goto rollback_label; } while(0)", file=f) | ||||
|             print("#define finish do { rollback = -1; goto rollback_label; } while(0)", file=f) | ||||
|             print("#define branch do {{ block_{}(recursion+1); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) | ||||
|             print("#define subpattern(pattern_name) do {{ block_subpattern_{}_ ## pattern_name (recursion+1); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) | ||||
| 
 | ||||
|             for line in block["code"]: | ||||
|                 print("    " + line, file=f) | ||||
|                 print("  " + line, file=f) | ||||
| 
 | ||||
|             print("", file=f) | ||||
|             print("      block_{}();".format(index+1), file=f) | ||||
|             print("    block_{}(recursion+1);".format(index+1), file=f) | ||||
| 
 | ||||
|             print("#undef reject", file=f) | ||||
|             print("#undef accept", file=f) | ||||
|             print("#undef finish", file=f) | ||||
|             print("#undef branch", file=f) | ||||
|             print("    } while (0);", file=f) | ||||
|             print("#undef subpattern", file=f) | ||||
| 
 | ||||
|             print("", file=f) | ||||
|             print("rollback_label:", file=f) | ||||
|             print("    YS_ATTRIBUTE(unused);", file=f) | ||||
| 
 | ||||
|             if len(block["fcode"]): | ||||
|                 print("#define accept do { accept_cnt++; on_accept(); } while(0)", file=f) | ||||
|                 print("#define finish do { rollback = -1; goto finish_label; } while(0)", file=f) | ||||
|                 for line in block["fcode"]: | ||||
|                     print("  " + line, file=f) | ||||
|                 print("finish_label:", file=f) | ||||
|                 print("    YS_ATTRIBUTE(unused);", file=f) | ||||
|                 print("#undef accept", file=f) | ||||
|                 print("#undef finish", file=f) | ||||
| 
 | ||||
|             if len(restore_st) or len(nonconst_st): | ||||
|                 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] | ||||
|  | @ -524,12 +681,15 @@ with open(outfile, "w") as f: | |||
|         elif block["type"] == "match": | ||||
|             assert len(restore_st) == 0 | ||||
| 
 | ||||
|             print("    Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f) | ||||
| 
 | ||||
|             if len(block["if"]): | ||||
|                 for expr in block["if"]: | ||||
|                     print("", file=f) | ||||
|                     print("    if (!({})) {{".format(expr), file=f) | ||||
|                     print("      {} = nullptr;".format(block["cell"]), file=f) | ||||
|                     print("      block_{}();".format(index+1), file=f) | ||||
|                     print("      block_{}(recursion+1);".format(index+1), file=f) | ||||
|                     print("      {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|                     print("      return;", file=f) | ||||
|                     print("    }", file=f) | ||||
| 
 | ||||
|  | @ -537,21 +697,48 @@ with open(outfile, "w") as f: | |||
|             print("    index_{}_key_type key;".format(index), file=f) | ||||
|             for field, entry in enumerate(block["index"]): | ||||
|                 print("    std::get<{}>(key) = {};".format(field, entry[2]), file=f) | ||||
|             print("    const vector<Cell*> &cells = index_{}[key];".format(index), file=f) | ||||
|             print("    auto cells_ptr = index_{}.find(key);".format(index), file=f) | ||||
| 
 | ||||
|             if block["semioptional"] or block["genargs"] is not None: | ||||
|                 print("    bool found_any_match = false;", file=f) | ||||
| 
 | ||||
|             print("", file=f) | ||||
|             print("    for (int idx = 0; idx < GetSize(cells); idx++) {", file=f) | ||||
|             print("      {} = cells[idx];".format(block["cell"]), file=f) | ||||
|             print("      if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) | ||||
|             print("    if (cells_ptr != index_{}.end()) {{".format(index), 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) | ||||
|             print("      block_{}();".format(index+1), file=f) | ||||
|             print("      if (rollback) {", file=f) | ||||
|             print("        if (rollback != {}) {{".format(index+1), file=f) | ||||
|             print("          {} = nullptr;".format(block["cell"]), file=f) | ||||
|             print("          return;", file=f) | ||||
|                 print("        if (!({})) continue;".format(expr), file=f) | ||||
|             if block["semioptional"] or block["genargs"] is not None: | ||||
|                 print("        found_any_match = true;", 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("            {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) | ||||
|             print("            return;", file=f) | ||||
|             print("          }", file=f) | ||||
|             print("          rollback = 0;", file=f) | ||||
|             print("        }", file=f) | ||||
|             print("        rollback = 0;", file=f) | ||||
|             print("      }", file=f) | ||||
|             print("    }", file=f) | ||||
| 
 | ||||
|  | @ -559,8 +746,20 @@ with open(outfile, "w") as f: | |||
|             print("    {} = nullptr;".format(block["cell"]), file=f) | ||||
| 
 | ||||
|             if block["optional"]: | ||||
|                 print("    block_{}();".format(index+1), file=f) | ||||
|                 print("    block_{}(recursion+1);".format(index+1), file=f) | ||||
| 
 | ||||
|             if block["semioptional"]: | ||||
|                 print("    if (!found_any_match) block_{}(recursion+1);".format(index+1), 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 && 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) | ||||
|                 print("#undef finish", file=f) | ||||
|         else: | ||||
|             assert False | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										379
									
								
								passes/pmgen/test_pmgen.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								passes/pmgen/test_pmgen.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,379 @@ | |||
| /*
 | ||||
|  *  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 | ||||
| 
 | ||||
| // for peepopt_pm
 | ||||
| bool did_something; | ||||
| 
 | ||||
| #include "passes/pmgen/test_pmgen_pm.h" | ||||
| #include "passes/pmgen/ice40_dsp_pm.h" | ||||
| #include "passes/pmgen/peepopt_pm.h" | ||||
| 
 | ||||
| void reduce_chain(test_pmgen_pm &pm) | ||||
| { | ||||
| 	auto &st = pm.st_reduce; | ||||
| 	auto &ud = pm.ud_reduce; | ||||
| 
 | ||||
| 	if (ud.longest_chain.empty()) | ||||
| 		return; | ||||
| 
 | ||||
| 	log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type)); | ||||
| 
 | ||||
| 	SigSpec A; | ||||
| 	SigSpec Y = ud.longest_chain.front().first->getPort(ID(Y)); | ||||
| 	auto last_cell = ud.longest_chain.back().first; | ||||
| 
 | ||||
| 	for (auto it : ud.longest_chain) { | ||||
| 		auto cell = it.first; | ||||
| 		if (cell == last_cell) { | ||||
| 			A.append(cell->getPort(ID(A))); | ||||
| 			A.append(cell->getPort(ID(B))); | ||||
| 		} else { | ||||
| 			A.append(cell->getPort(it.second == ID(A) ? ID(B) : ID(A))); | ||||
| 		} | ||||
| 		log("    %s\n", log_id(cell)); | ||||
| 		pm.autoremove(cell); | ||||
| 	} | ||||
| 
 | ||||
| 	Cell *c; | ||||
| 
 | ||||
| 	if (last_cell->type == ID($_AND_)) | ||||
| 		c = pm.module->addReduceAnd(NEW_ID, A, Y); | ||||
| 	else if (last_cell->type == ID($_OR_)) | ||||
| 		c = pm.module->addReduceOr(NEW_ID, A, Y); | ||||
| 	else if (last_cell->type == ID($_XOR_)) | ||||
| 		c = pm.module->addReduceXor(NEW_ID, A, Y); | ||||
| 	else | ||||
| 		log_abort(); | ||||
| 
 | ||||
| 	log("    -> %s (%s)\n", log_id(c), log_id(c->type)); | ||||
| } | ||||
| 
 | ||||
| void reduce_tree(test_pmgen_pm &pm) | ||||
| { | ||||
| 	auto &st = pm.st_reduce; | ||||
| 	auto &ud = pm.ud_reduce; | ||||
| 
 | ||||
| 	if (ud.longest_chain.empty()) | ||||
| 		return; | ||||
| 
 | ||||
| 	SigSpec A = ud.leaves; | ||||
| 	SigSpec Y = st.first->getPort(ID(Y)); | ||||
| 	pm.autoremove(st.first); | ||||
| 
 | ||||
| 	log("Found %s tree with %d leaves for %s (%s).\n", log_id(st.first->type), | ||||
| 			GetSize(A), log_signal(Y), log_id(st.first)); | ||||
| 
 | ||||
| 	Cell *c; | ||||
| 
 | ||||
| 	if (st.first->type == ID($_AND_)) | ||||
| 		c = pm.module->addReduceAnd(NEW_ID, A, Y); | ||||
| 	else if (st.first->type == ID($_OR_)) | ||||
| 		c = pm.module->addReduceOr(NEW_ID, A, Y); | ||||
| 	else if (st.first->type == ID($_XOR_)) | ||||
| 		c = pm.module->addReduceXor(NEW_ID, A, Y); | ||||
| 	else | ||||
| 		log_abort(); | ||||
| 
 | ||||
| 	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) | ||||
| 
 | ||||
| void pmtest_addports(Module *module) | ||||
| { | ||||
| 	pool<SigBit> driven_bits, used_bits; | ||||
| 	SigMap sigmap(module); | ||||
| 	int icnt = 0, ocnt = 0; | ||||
| 
 | ||||
| 	for (auto cell : module->cells()) | ||||
| 	for (auto conn : cell->connections()) | ||||
| 	{ | ||||
| 		if (cell->input(conn.first)) | ||||
| 			for (auto bit : sigmap(conn.second)) | ||||
| 				used_bits.insert(bit); | ||||
| 		if (cell->output(conn.first)) | ||||
| 			for (auto bit : sigmap(conn.second)) | ||||
| 				driven_bits.insert(bit); | ||||
| 	} | ||||
| 
 | ||||
| 	for (auto wire : vector<Wire*>(module->wires())) | ||||
| 	{ | ||||
| 		SigSpec ibits, obits; | ||||
| 		for (auto bit : sigmap(wire)) { | ||||
| 			if (!used_bits.count(bit)) | ||||
| 				obits.append(bit); | ||||
| 			if (!driven_bits.count(bit)) | ||||
| 				ibits.append(bit); | ||||
| 		} | ||||
| 		if (!ibits.empty()) { | ||||
| 			Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits)); | ||||
| 			w->port_input = true; | ||||
| 			module->connect(ibits, w); | ||||
| 		} | ||||
| 		if (!obits.empty()) { | ||||
| 			Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits)); | ||||
| 			w->port_output = true; | ||||
| 			module->connect(w, obits); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	module->fixup_ports(); | ||||
| } | ||||
| 
 | ||||
| template <class pm> | ||||
| void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design) | ||||
| { | ||||
| 	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 < maxmodcnt) | ||||
| 	{ | ||||
| 		int submodcnt = 0, itercnt = 0, cellcnt = 0; | ||||
| 		Module *mod = design->addModule(NEW_ID); | ||||
| 
 | ||||
| 		while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000) | ||||
| 		{ | ||||
| 			if (timeout++ > 10000) | ||||
| 				log_error("pmgen generator is stuck: 10000 iterations an no matching module generated.\n"); | ||||
| 
 | ||||
| 			pm matcher(mod, mod->cells()); | ||||
| 
 | ||||
| 			matcher.rng(1); | ||||
| 			matcher.rngseed += modcnt; | ||||
| 			matcher.rng(1); | ||||
| 			matcher.rngseed += submodcnt; | ||||
| 			matcher.rng(1); | ||||
| 			matcher.rngseed += itercnt; | ||||
| 			matcher.rng(1); | ||||
| 			matcher.rngseed += cellcnt; | ||||
| 			matcher.rng(1); | ||||
| 
 | ||||
| 			if (GetSize(mod->cells()) != cellcnt) | ||||
| 			{ | ||||
| 				bool found_match = false; | ||||
| 				run(matcher, [&](){ found_match = true; }); | ||||
| 				cellcnt = GetSize(mod->cells()); | ||||
| 
 | ||||
| 				if (found_match) { | ||||
| 					Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d", | ||||
| 							pmclass, pattern, modcnt++)); | ||||
| 					log("Creating module %s with %d cells.\n", log_id(m), cellcnt); | ||||
| 					mod->cloneInto(m); | ||||
| 					pmtest_addports(m); | ||||
| 					mods.push_back(m); | ||||
| 					submodcnt++; | ||||
| 					timeout = 0; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			matcher.generate_mode = true; | ||||
| 			run(matcher, [](){}); | ||||
| 		} | ||||
| 
 | ||||
| 		if (submodcnt) | ||||
| 			maxsubcnt *= 2; | ||||
| 
 | ||||
| 		design->remove(mod); | ||||
| 	} | ||||
| 
 | ||||
| 	Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern)); | ||||
| 	log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods)); | ||||
| 	for (auto mod : mods) { | ||||
| 		Cell *c = m->addCell(mod->name, mod->name); | ||||
| 		for (auto port : mod->ports) { | ||||
| 			Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port))); | ||||
| 			c->setPort(port, w); | ||||
| 		} | ||||
| 	} | ||||
| 	pmtest_addports(m); | ||||
| } | ||||
| 
 | ||||
| struct TestPmgenPass : public Pass { | ||||
| 	TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    test_pmgen -reduce_chain [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n"); | ||||
| 		log("\n"); | ||||
| 
 | ||||
| 		log("\n"); | ||||
| 		log("    test_pmgen -reduce_tree [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		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"); | ||||
| 		log("Create modules that match the specified pattern.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute_reduce_chain(std::vector<std::string> args, RTLIL::Design *design) | ||||
| 	{ | ||||
| 		log_header(design, "Executing TEST_PMGEN pass (-reduce_chain).\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()) | ||||
| 			while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {} | ||||
| 	} | ||||
| 
 | ||||
| 	void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design) | ||||
| 	{ | ||||
| 		log_header(design, "Executing TEST_PMGEN pass (-reduce_tree).\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_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"); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 2; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			// if (args[argidx] == "-singleton") {
 | ||||
| 			// 	singleton_mode = true;
 | ||||
| 			// 	continue;
 | ||||
| 			// }
 | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (argidx+1 != args.size()) | ||||
| 			log_cmd_error("Expected exactly one pattern.\n"); | ||||
| 
 | ||||
| 		string pattern = args[argidx]; | ||||
| 
 | ||||
| 		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 == "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()); | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		if (GetSize(args) > 1) | ||||
| 		{ | ||||
| 			if (args[1] == "-reduce_chain") | ||||
| 				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); | ||||
| 		} | ||||
| 		help(); | ||||
| 		log_cmd_error("Missing or unsupported mode parameter.\n"); | ||||
| 	} | ||||
| } TestPmgenPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										189
									
								
								passes/pmgen/test_pmgen.pmg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								passes/pmgen/test_pmgen.pmg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,189 @@ | |||
| pattern reduce | ||||
| 
 | ||||
| state <IdString> portname | ||||
| udata <vector<pair<Cell*, IdString>>> chain longest_chain | ||||
| udata <pool<Cell*>> non_first_cells | ||||
| udata <SigSpec> leaves | ||||
| 
 | ||||
| code | ||||
| 	non_first_cells.clear(); | ||||
| 	subpattern(setup); | ||||
| endcode | ||||
| 
 | ||||
| match first | ||||
| 	select first->type.in($_AND_, $_OR_, $_XOR_) | ||||
| 	filter !non_first_cells.count(first) | ||||
| generate | ||||
| 	SigSpec A = module->addWire(NEW_ID); | ||||
| 	SigSpec B = module->addWire(NEW_ID); | ||||
| 	SigSpec Y = module->addWire(NEW_ID); | ||||
| 	switch (rng(3)) | ||||
| 	{ | ||||
| 	case 0: | ||||
| 		module->addAndGate(NEW_ID, A, B, Y); | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		module->addOrGate(NEW_ID, A, B, Y); | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		module->addXorGate(NEW_ID, A, B, Y); | ||||
| 		break; | ||||
| 	} | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	leaves = SigSpec(); | ||||
| 	longest_chain.clear(); | ||||
| 	chain.push_back(make_pair(first, \A)); | ||||
| 	subpattern(tail); | ||||
| 	chain.back().second = \B; | ||||
| 	subpattern(tail); | ||||
| finally | ||||
| 	chain.pop_back(); | ||||
| 	log_assert(chain.empty()); | ||||
| 	if (GetSize(longest_chain) > 1) | ||||
| 		accept; | ||||
| endcode | ||||
| 
 | ||||
| // ------------------------------------------------------------------ | ||||
| 
 | ||||
| subpattern setup | ||||
| 
 | ||||
| match first | ||||
| 	select first->type.in($_AND_, $_OR_, $_XOR_) | ||||
| endmatch | ||||
| 
 | ||||
| code portname | ||||
| 	portname = \A; | ||||
| 	branch; | ||||
| 	portname = \B; | ||||
| endcode | ||||
| 
 | ||||
| match next | ||||
| 	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 | ||||
| 
 | ||||
| code | ||||
| 	non_first_cells.insert(next); | ||||
| endcode | ||||
| 
 | ||||
| // ------------------------------------------------------------------ | ||||
| 
 | ||||
| subpattern tail | ||||
| arg first | ||||
| 
 | ||||
| match next | ||||
| 	semioptional | ||||
| 	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 | ||||
| 	SigSpec A = module->addWire(NEW_ID); | ||||
| 	SigSpec B = module->addWire(NEW_ID); | ||||
| 	SigSpec Y = port(chain.back().first, chain.back().second); | ||||
| 	Cell *c = module->addAndGate(NEW_ID, A, B, Y); | ||||
| 	c->type = chain.back().first->type; | ||||
| endmatch | ||||
| 
 | ||||
| code | ||||
| 	if (next) { | ||||
| 		chain.push_back(make_pair(next, \A)); | ||||
| 		subpattern(tail); | ||||
| 		chain.back().second = \B; | ||||
| 		subpattern(tail); | ||||
| 	} else { | ||||
| 		if (GetSize(chain) > GetSize(longest_chain)) | ||||
| 			longest_chain = chain; | ||||
| 		leaves.append(port(chain.back().first, chain.back().second)); | ||||
| 	} | ||||
| 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 | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -76,12 +76,11 @@ 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) | ||||
| void handle_loops(RTLIL::Design *design, | ||||
| 		const dict<IdString,pool<IdString>> &scc_break_inputs) | ||||
| { | ||||
| 	Pass::call(design, "scc -set_attr abc_scc_id {}"); | ||||
| 
 | ||||
| 	dict<IdString, vector<IdString>> abc_scc_break; | ||||
| 
 | ||||
| 	// For every unique SCC found, (arbitrarily) find the first
 | ||||
| 	// cell in the component, and select (and mark) all its output
 | ||||
| 	// wires
 | ||||
|  | @ -116,44 +115,29 @@ void handle_loops(RTLIL::Design *design) | |||
| 			cell->attributes.erase(it); | ||||
| 		} | ||||
| 
 | ||||
| 		auto jt = abc_scc_break.find(cell->type); | ||||
| 		if (jt == abc_scc_break.end()) { | ||||
| 			std::vector<IdString> ports; | ||||
| 			RTLIL::Module* box_module = design->module(cell->type); | ||||
| 			if (box_module) { | ||||
| 				auto ports_csv = box_module->attributes.at(ID(abc_scc_break), RTLIL::Const::from_string("")).decode_string(); | ||||
| 				for (const auto &port_name : split_tokens(ports_csv, ",")) { | ||||
| 					auto port_id = RTLIL::escape_id(port_name); | ||||
| 					auto kt = cell->connections_.find(port_id); | ||||
| 					if (kt == cell->connections_.end()) | ||||
| 						log_error("abc_scc_break attribute value '%s' does not exist as port on module '%s'\n", port_name.c_str(), log_id(box_module)); | ||||
| 					ports.push_back(port_id); | ||||
| 		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; | ||||
| 			} | ||||
| 			jt = abc_scc_break.insert(std::make_pair(cell->type, std::move(ports))).first; | ||||
| 		} | ||||
| 
 | ||||
| 		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(); | ||||
|  | @ -288,7 +272,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | |||
| 		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) | ||||
| 		std::string wire_delay, const dict<int,IdString> &box_lookup, | ||||
| 		const dict<IdString,pool<IdString>> &scc_break_inputs | ||||
| ) | ||||
| { | ||||
| 	module = current_module; | ||||
| 	map_autoidx = autoidx++; | ||||
|  | @ -427,7 +413,7 @@ 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); | ||||
| 		handle_loops(design, scc_break_inputs); | ||||
| 
 | ||||
| 		Pass::call(design, "aigmap"); | ||||
| 
 | ||||
|  | @ -1081,6 +1067,7 @@ struct Abc9Pass : public Pass { | |||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		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()) | ||||
|  | @ -1093,6 +1080,56 @@ struct Abc9Pass : public Pass { | |||
| 				log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n", | ||||
| 						log_id(m), id, log_id(r.first->second)); | ||||
| 			log_assert(r.second); | ||||
| 
 | ||||
| 			RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; | ||||
| 			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 (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))) { | ||||
| 						if (carry_out) | ||||
| 							log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); | ||||
| 						carry_out = w; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (carry_in || carry_out) { | ||||
| 				if (carry_in && !carry_out) | ||||
| 					log_error("Module '%s' contains an 'abc_carry' input port but no output port.\n", log_id(m)); | ||||
| 				if (!carry_in && carry_out) | ||||
| 					log_error("Module '%s' contains an 'abc_carry' output port but no input port.\n", log_id(m)); | ||||
| 				// Make carry_in the last PI, and carry_out the last PO
 | ||||
| 				//   since ABC requires it this way
 | ||||
| 				auto &ports = m->ports; | ||||
| 				for (auto it = ports.begin(); it != ports.end(); ) { | ||||
| 					RTLIL::Wire* w = m->wire(*it); | ||||
| 					log_assert(w); | ||||
| 					if (w == carry_in || w == carry_out) { | ||||
| 						it = ports.erase(it); | ||||
| 						continue; | ||||
| 					} | ||||
| 					if (w->port_id > carry_in->port_id) | ||||
| 						--w->port_id; | ||||
| 					if (w->port_id > carry_out->port_id) | ||||
| 						--w->port_id; | ||||
| 					log_assert(w->port_input || w->port_output); | ||||
| 					log_assert(ports[w->port_id-1] == w->name); | ||||
| 					++it; | ||||
| 				} | ||||
| 				ports.push_back(carry_in->name); | ||||
| 				carry_in->port_id = ports.size(); | ||||
| 				ports.push_back(carry_out->name); | ||||
| 				carry_out->port_id = ports.size(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto mod : design->selected_modules()) | ||||
|  | @ -1110,7 +1147,7 @@ struct Abc9Pass : public Pass { | |||
| 			if (!dff_mode || !clk_str.empty()) { | ||||
| 				abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, | ||||
| 						delay_target, lutin_shared, fast_mode, show_tempdir, | ||||
| 						box_file, lut_file, wire_delay, box_lookup); | ||||
| 						box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
|  | @ -1256,7 +1293,7 @@ struct Abc9Pass : public Pass { | |||
| 				en_sig = assign_map(std::get<3>(it.first)); | ||||
| 				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); | ||||
| 						box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); | ||||
| 				assign_map.set(mod); | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
							
								
								
									
										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 | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -943,7 +943,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"); | ||||
|  | @ -1157,15 +1158,16 @@ 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) { | ||||
| 				did_something = false; | ||||
| 					if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) | ||||
| 						did_something = true; | ||||
| 				if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) | ||||
| 					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; | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
|  | @ -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 | ||||
| 
 | ||||
| 		wire cout; | ||||
| 		AL_MAP_ADDER #( | ||||
| 			.ALUTYPE("ADD")) | ||||
| 		adder_cout  ( | ||||
| 			.a(1'b0), | ||||
| 			.b(1'b0), | ||||
| 			.c(COx[i]), | ||||
| 			.o({cout, CO[i]}) | ||||
| 		); | ||||
| 	  end: slice	   | ||||
| 	endgenerate | ||||
| 	/* End implementation */ | ||||
| 	AL_MAP_ADDER #( | ||||
| 		.ALUTYPE("ADD")) | ||||
| 	adder_cout  ( | ||||
| 		.c(C[Y_WIDTH+1]), | ||||
| 		.o(COx[Y_WIDTH+1]) | ||||
| 	);				 | ||||
| 	assign CO = COx[Y_WIDTH+1]; | ||||
| 	assign X = AA ^ BB; | ||||
| endmodule | ||||
| 
 | ||||
|    /* End implementation */ | ||||
|    assign X = AA ^ BB; | ||||
| 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"); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -15,10 +15,15 @@ module L6MUX21 (input D0, D1, SD, output Z); | |||
| endmodule | ||||
| 
 | ||||
| // --------------------------------------- | ||||
| (* abc_box_id=1, abc_carry="CIN,COUT", lib_whitebox *) | ||||
| module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1, | ||||
| 	           output S0, S1, COUT); | ||||
| 
 | ||||
| (* abc_box_id=1, lib_whitebox *) | ||||
| module CCU2C( | ||||
| 	(* abc_carry *) | ||||
| 	input  CIN, | ||||
| 	input  A0, B0, C0, D0, A1, B1, C1, D1, | ||||
| 	output S0, S1, | ||||
| 	(* abc_carry *) | ||||
| 	output COUT | ||||
| ); | ||||
| 	parameter [15:0] INIT0 = 16'h0000; | ||||
| 	parameter [15:0] INIT1 = 16'h0000; | ||||
| 	parameter INJECT1_0 = "YES"; | ||||
|  | @ -104,12 +109,16 @@ module PFUMX (input ALUT, BLUT, C0, output Z); | |||
| endmodule | ||||
| 
 | ||||
| // --------------------------------------- | ||||
| //(* abc_box_id=2, abc_scc_break="DI,WAD,WRE" *) | ||||
| //(* abc_box_id=2 *) | ||||
| module TRELLIS_DPR16X4 ( | ||||
| 	input [3:0] DI, | ||||
| 	input [3:0] WAD, | ||||
| 	input WRE, WCK, | ||||
| 	input [3:0] RAD, | ||||
| 	(* abc_scc_break *) | ||||
| 	input  [3:0] DI, | ||||
| 	(* abc_scc_break *) | ||||
| 	input  [3:0] WAD, | ||||
| 	(* abc_scc_break *) | ||||
| 	input        WRE, | ||||
| 	input        WCK, | ||||
| 	input  [3:0] RAD, | ||||
| 	output [3:0] DO | ||||
| ); | ||||
| 	parameter WCKMUX = "WCK"; | ||||
|  |  | |||
							
								
								
									
										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 | ||||
							
								
								
									
										107
									
								
								techlibs/efinix/cells_sim.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								techlibs/efinix/cells_sim.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| module EFX_LUT4( | ||||
|    output O,  | ||||
|    input I0, | ||||
|    input I1, | ||||
|    input I2, | ||||
|    input I3 | ||||
| ); | ||||
|    parameter LUTMASK  = 16'h0000; | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_ADD( | ||||
|    output O, | ||||
|    output CO, | ||||
|    input I0, | ||||
|    input I1, | ||||
|    input CI | ||||
| ); | ||||
|    parameter I0_POLARITY   = 1; | ||||
|    parameter I1_POLARITY   = 1; | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_FF( | ||||
|    output 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; | ||||
| endmodule | ||||
| 
 | ||||
| module EFX_GBUFCE( | ||||
|    input CE, | ||||
|    input I, | ||||
|    output O | ||||
| ); | ||||
|    parameter CE_POLARITY = 1'b1; | ||||
| 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 | ||||
|  | @ -141,8 +141,16 @@ module SB_CARRY (output CO, input I0, I1, CI); | |||
| 	assign CO = (I0 && I1) || ((I0 || I1) && CI); | ||||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id = 1, abc_carry="CI,CO", lib_whitebox *) | ||||
| module \$__ICE40_FULL_ADDER (output CO, O, input A, B, CI); | ||||
| (* abc_box_id = 1, lib_whitebox *) | ||||
| module \$__ICE40_FULL_ADDER ( | ||||
| 	(* abc_carry *) | ||||
| 	output CO, | ||||
| 	output O, | ||||
| 	input A, | ||||
| 	input B, | ||||
| 	(* abc_carry *) | ||||
| 	input CI | ||||
| ); | ||||
| 	SB_CARRY carry ( | ||||
| 		.I0(A), | ||||
| 		.I1(B), | ||||
|  |  | |||
|  | @ -32,8 +32,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v)) | |||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams.txt)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt)) | ||||
| $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.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/lut_map.v)) | ||||
|  |  | |||
|  | @ -29,24 +29,35 @@ 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, | ||||
|  | @ -72,7 +83,11 @@ 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, | ||||
|     input CE); | ||||
| 
 | ||||
| parameter [0:0] INIT_OUT = 1'b0; | ||||
| parameter CE_TYPE = "SYNC"; | ||||
|  | @ -181,8 +196,16 @@ module XORCY(output O, input CI, LI); | |||
|   assign O = CI ^ LI; | ||||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id = 4, abc_carry="CI,CO", lib_whitebox *) | ||||
| module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); | ||||
| (* abc_box_id = 4, lib_whitebox *) | ||||
| module CARRY4( | ||||
|   (* abc_carry *) | ||||
|   output [3:0] CO, | ||||
|   output [3:0] O, | ||||
|   (* abc_carry *) | ||||
|   input        CI, | ||||
|   input        CYINIT, | ||||
|   input  [3:0] DI, S | ||||
| ); | ||||
|   assign O = S ^ {CO[2:0], CI | CYINIT}; | ||||
|   assign CO[0] = S[0] ? CI | CYINIT : DI[0]; | ||||
|   assign CO[1] = S[1] ? CO[0] : DI[1]; | ||||
|  | @ -213,7 +236,7 @@ endmodule | |||
| 
 | ||||
| `endif | ||||
| 
 | ||||
| module FDRE (output reg Q, input C, CE, D, R); | ||||
| module FDRE (output reg Q, (* clkbuf_sink *) input C, input CE, D, R); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -225,7 +248,7 @@ 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 (output reg Q, (* clkbuf_sink *) input C, input CE, D, S); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -237,7 +260,7 @@ 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 (output reg Q, (* clkbuf_sink *) input C, input CE, D, CLR); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -251,7 +274,7 @@ 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 (output reg Q, (* clkbuf_sink *) input C, input CE, D, PRE); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||
|   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||
|  | @ -265,34 +288,39 @@ 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 (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 (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 (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 (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 | ||||
| 
 | ||||
| (* abc_box_id = 5, abc_scc_break="D,WE" *) | ||||
| (* abc_box_id = 5 *) | ||||
| module RAM32X1D ( | ||||
|   output DPO, SPO, | ||||
|   input  D, WCLK, WE, | ||||
|   (* abc_scc_break *) | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   input  WCLK, | ||||
|   (* abc_scc_break *) | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||
| ); | ||||
|  | @ -307,10 +335,15 @@ module RAM32X1D ( | |||
|   always @(posedge clk) if (WE) mem[a] <= D; | ||||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id = 6, abc_scc_break="D,WE" *) | ||||
| (* abc_box_id = 6 *) | ||||
| module RAM64X1D ( | ||||
|   output DPO, SPO, | ||||
|   input  D, WCLK, WE, | ||||
|   (* abc_scc_break *) | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   input  WCLK, | ||||
|   (* abc_scc_break *) | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, A5, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||
| ); | ||||
|  | @ -325,10 +358,15 @@ module RAM64X1D ( | |||
|   always @(posedge clk) if (WE) mem[a] <= D; | ||||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id = 7, abc_scc_break="D,WE" *) | ||||
| (* abc_box_id = 7 *) | ||||
| module RAM128X1D ( | ||||
|   output       DPO, SPO, | ||||
|   input        D, WCLK, WE, | ||||
|   (* abc_scc_break *) | ||||
|   input        D, | ||||
|   (* clkbuf_sink *) | ||||
|   input        WCLK, | ||||
|   (* abc_scc_break *) | ||||
|   input        WE, | ||||
|   input  [6:0] A, DPRA | ||||
| ); | ||||
|   parameter INIT = 128'h0; | ||||
|  | @ -342,7 +380,9 @@ endmodule | |||
| 
 | ||||
| module SRL16E ( | ||||
|   output Q, | ||||
|   input A0, A1, A2, A3, CE, CLK, D | ||||
|   (* clkbuf_sink *) | ||||
|   input CLK, | ||||
|   input A0, A1, A2, A3, CE, D | ||||
| ); | ||||
|   parameter [15:0] INIT = 16'h0000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|  | @ -354,7 +394,27 @@ module SRL16E ( | |||
|       always @(negedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|     end | ||||
|     else | ||||
|         always @(posedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|       always @(posedge CLK) if (CE) r <= { r[14:0], D }; | ||||
|   endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module SRLC16E ( | ||||
|   output Q, | ||||
|   output Q15, | ||||
|   input A0, A1, A2, A3, CE, CLK, 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 | ||||
| 
 | ||||
|  | @ -362,7 +422,9 @@ module SRLC32E ( | |||
|   output Q, | ||||
|   output Q31, | ||||
|   input [4:0] A, | ||||
|   input CE, CLK, D | ||||
|   (* clkbuf_sink *) | ||||
|   input CLK, | ||||
|   input CE, D | ||||
| ); | ||||
|   parameter [31:0] INIT = 32'h00000000; | ||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||
|  |  | |||
							
								
								
									
										257
									
								
								techlibs/xilinx/cells_xtra.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								techlibs/xilinx/cells_xtra.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,257 @@ | |||
| #!/usr/bin/env python3 | ||||
| 
 | ||||
| from argparse import ArgumentParser | ||||
| from io import StringIO | ||||
| from enum import Enum, auto | ||||
| import os.path | ||||
| import sys | ||||
| 
 | ||||
| 
 | ||||
| class Cell: | ||||
|     def __init__(self, name, keep=False, port_attrs={}): | ||||
|         self.name = name | ||||
|         self.keep = keep | ||||
|         self.port_attrs = port_attrs | ||||
| 
 | ||||
| 
 | ||||
| CELLS = [ | ||||
|     # Design elements types listed in Xilinx UG953 | ||||
|     Cell('BSCANE2', keep=True), | ||||
|     # 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('CAPTUREE2', keep=True), | ||||
|     # Cell('CARRY4'), | ||||
|     Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('DCIRESET', keep=True), | ||||
|     Cell('DNA_PORT'), | ||||
|     Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('EFUSE_USR'), | ||||
|     # Cell('FDCE'), | ||||
|     # Cell('FDPE'), | ||||
|     # Cell('FDRE'), | ||||
|     # Cell('FDSE'), | ||||
|     Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|     Cell('FRAME_ECCE2'), | ||||
|     Cell('GTHE2_CHANNEL'), | ||||
|     Cell('GTHE2_COMMON'), | ||||
|     Cell('GTPE2_CHANNEL'), | ||||
|     Cell('GTPE2_COMMON'), | ||||
|     Cell('GTXE2_CHANNEL'), | ||||
|     Cell('GTXE2_COMMON'), | ||||
|     # 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('ICAPE2', keep=True), | ||||
|     Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), | ||||
|     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('ISERDESE2', port_attrs={ | ||||
|         'CLK': ['clkbuf_sink'], | ||||
|         'CLKB': ['clkbuf_sink'], | ||||
|         'OCLK': ['clkbuf_sink'], | ||||
|         'OCLKB': ['clkbuf_sink'], | ||||
|         'CLKDIV': ['clkbuf_sink'], | ||||
|         'CLKDIVP': ['clkbuf_sink'], | ||||
|     }), | ||||
|     Cell('KEEPER'), | ||||
|     Cell('LDCE'), | ||||
|     Cell('LDPE'), | ||||
|     # Cell('LUT1'), | ||||
|     # Cell('LUT2'), | ||||
|     # Cell('LUT3'), | ||||
|     # Cell('LUT4'), | ||||
|     # Cell('LUT5'), | ||||
|     # Cell('LUT6'), | ||||
|     #Cell('LUT6_2'), | ||||
|     Cell('MMCME2_ADV'), | ||||
|     Cell('MMCME2_BASE'), | ||||
|     # Cell('MUXF7'), | ||||
|     # Cell('MUXF8'), | ||||
|     # 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('ODDR', port_attrs={'C': ['clkbuf_sink']}), | ||||
|     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('PLLE2_ADV'), | ||||
|     Cell('PLLE2_BASE'), | ||||
|     Cell('PS7', keep=True), | ||||
|     Cell('PULLDOWN'), | ||||
|     Cell('PULLUP'), | ||||
|     #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']}), | ||||
|     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'), | ||||
|     #Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     #Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), | ||||
|     Cell('STARTUPE2', keep=True), | ||||
|     Cell('USR_ACCESSE2'), | ||||
|     Cell('XADC'), | ||||
| ] | ||||
| 
 | ||||
| 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. | ||||
|                 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: | ||||
|                             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() | ||||
|                             for attr in cell.port_attrs.get(port, []): | ||||
|                                 outf.write('    (* {} *)\n'.format(attr)) | ||||
|                             outf.write('    {} {};\n'.format(kind, 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)) | ||||
|                 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 Vivado.') | ||||
|     parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1') | ||||
|     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'), | ||||
|     ] | ||||
|     for dir in dirs: | ||||
|         if not os.path.isdir(dir): | ||||
|             print('{} is not a directory'.format(dir)) | ||||
| 
 | ||||
|     out = StringIO() | ||||
|     for cell in CELLS: | ||||
|         xtract_cell_decl(cell, dirs, out) | ||||
| 
 | ||||
|     with open('cells_xtra.v', 'w') as f: | ||||
|         f.write('// Created by cells_xtra.py from Xilinx models\n') | ||||
|         f.write('\n') | ||||
|         f.write(out.getvalue()) | ||||
|  | @ -1,147 +0,0 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| set -e | ||||
| libdir="/opt/Xilinx/Vivado/2018.1/data/verilog/src" | ||||
| 
 | ||||
| function xtract_cell_decl() | ||||
| { | ||||
| 	for dir in $libdir/xeclib $libdir/retarget; do | ||||
| 		[ -f $dir/$1.v ] || continue | ||||
| 		[ -z "$2" ] || echo $2 | ||||
| 		egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v | | ||||
| 			sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d; | ||||
| 			         s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; | ||||
| 			         s/\s+$//; s/,$/;/; /input|output|parameter/ s/[^;]$/&;/; s/\s+/ /g; | ||||
| 				 s/^ ((end)?module)/\1/; s/^ /    /; /module.*_bb/,/endmodule/ d;' | ||||
| 		echo; return | ||||
| 	done | ||||
| 	echo "Can't find $1." | ||||
| 	exit 1 | ||||
| } | ||||
| 
 | ||||
| { | ||||
| 	echo "// Created by cells_xtra.sh from Xilinx models" | ||||
| 	echo | ||||
| 
 | ||||
| 	# Design elements types listed in Xilinx UG953 | ||||
| 	xtract_cell_decl BSCANE2 | ||||
| 	# xtract_cell_decl BUFG | ||||
| 	xtract_cell_decl BUFGCE | ||||
| 	xtract_cell_decl BUFGCE_1 | ||||
| 	#xtract_cell_decl BUFGCTRL | ||||
| 	xtract_cell_decl BUFGMUX | ||||
| 	xtract_cell_decl BUFGMUX_1 | ||||
| 	xtract_cell_decl BUFGMUX_CTRL | ||||
| 	xtract_cell_decl BUFH | ||||
| 	#xtract_cell_decl BUFHCE | ||||
| 	xtract_cell_decl BUFIO | ||||
| 	xtract_cell_decl BUFMR | ||||
| 	xtract_cell_decl BUFMRCE | ||||
| 	xtract_cell_decl BUFR | ||||
| 	xtract_cell_decl CAPTUREE2 "(* keep *)" | ||||
| 	# xtract_cell_decl CARRY4 | ||||
| 	xtract_cell_decl CFGLUT5 | ||||
| 	xtract_cell_decl DCIRESET "(* keep *)" | ||||
| 	xtract_cell_decl DNA_PORT | ||||
| 	xtract_cell_decl DSP48E1 | ||||
| 	xtract_cell_decl EFUSE_USR | ||||
| 	# xtract_cell_decl FDCE | ||||
| 	# xtract_cell_decl FDPE | ||||
| 	# xtract_cell_decl FDRE | ||||
| 	# xtract_cell_decl FDSE | ||||
| 	xtract_cell_decl FIFO18E1 | ||||
| 	xtract_cell_decl FIFO36E1 | ||||
| 	xtract_cell_decl FRAME_ECCE2 | ||||
| 	xtract_cell_decl GTHE2_CHANNEL | ||||
| 	xtract_cell_decl GTHE2_COMMON | ||||
| 	xtract_cell_decl GTPE2_CHANNEL | ||||
| 	xtract_cell_decl GTPE2_COMMON | ||||
| 	xtract_cell_decl GTXE2_CHANNEL | ||||
| 	xtract_cell_decl GTXE2_COMMON | ||||
| 	# xtract_cell_decl IBUF | ||||
| 	xtract_cell_decl IBUF_IBUFDISABLE | ||||
| 	xtract_cell_decl IBUF_INTERMDISABLE | ||||
| 	xtract_cell_decl IBUFDS | ||||
| 	xtract_cell_decl IBUFDS_DIFF_OUT | ||||
| 	xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE | ||||
| 	xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE | ||||
| 	xtract_cell_decl IBUFDS_GTE2 | ||||
| 	xtract_cell_decl IBUFDS_IBUFDISABLE | ||||
| 	xtract_cell_decl IBUFDS_INTERMDISABLE | ||||
| 	xtract_cell_decl ICAPE2 "(* keep *)" | ||||
| 	xtract_cell_decl IDDR | ||||
| 	xtract_cell_decl IDDR_2CLK | ||||
| 	xtract_cell_decl IDELAYCTRL "(* keep *)" | ||||
| 	xtract_cell_decl IDELAYE2 | ||||
| 	xtract_cell_decl IN_FIFO | ||||
| 	xtract_cell_decl IOBUF | ||||
| 	xtract_cell_decl IOBUF_DCIEN | ||||
| 	xtract_cell_decl IOBUF_INTERMDISABLE | ||||
| 	xtract_cell_decl IOBUFDS | ||||
| 	xtract_cell_decl IOBUFDS_DCIEN | ||||
| 	xtract_cell_decl IOBUFDS_DIFF_OUT | ||||
| 	xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN | ||||
| 	xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE | ||||
| 	xtract_cell_decl ISERDESE2 | ||||
| 	xtract_cell_decl KEEPER | ||||
| 	xtract_cell_decl LDCE | ||||
| 	xtract_cell_decl LDPE | ||||
| 	# xtract_cell_decl LUT1 | ||||
| 	# xtract_cell_decl LUT2 | ||||
| 	# xtract_cell_decl LUT3 | ||||
| 	# xtract_cell_decl LUT4 | ||||
| 	# xtract_cell_decl LUT5 | ||||
| 	# xtract_cell_decl LUT6 | ||||
| 	#xtract_cell_decl LUT6_2 | ||||
| 	xtract_cell_decl MMCME2_ADV | ||||
| 	xtract_cell_decl MMCME2_BASE | ||||
| 	# xtract_cell_decl MUXF7 | ||||
| 	# xtract_cell_decl MUXF8 | ||||
| 	# xtract_cell_decl OBUF | ||||
| 	xtract_cell_decl OBUFDS | ||||
| 	xtract_cell_decl OBUFT | ||||
| 	xtract_cell_decl OBUFTDS | ||||
| 	xtract_cell_decl ODDR | ||||
| 	xtract_cell_decl ODELAYE2 | ||||
| 	xtract_cell_decl OSERDESE2 | ||||
| 	xtract_cell_decl OUT_FIFO | ||||
| 	xtract_cell_decl PHASER_IN | ||||
| 	xtract_cell_decl PHASER_IN_PHY | ||||
| 	xtract_cell_decl PHASER_OUT | ||||
| 	xtract_cell_decl PHASER_OUT_PHY | ||||
| 	xtract_cell_decl PHASER_REF | ||||
| 	xtract_cell_decl PHY_CONTROL | ||||
| 	xtract_cell_decl PLLE2_ADV | ||||
| 	xtract_cell_decl PLLE2_BASE | ||||
| 	xtract_cell_decl PS7 "(* keep *)" | ||||
| 	xtract_cell_decl PULLDOWN | ||||
| 	xtract_cell_decl PULLUP | ||||
| 	#xtract_cell_decl RAM128X1D | ||||
| 	xtract_cell_decl RAM128X1S | ||||
| 	xtract_cell_decl RAM256X1S | ||||
| 	xtract_cell_decl RAM32M | ||||
| 	#xtract_cell_decl RAM32X1D | ||||
| 	xtract_cell_decl RAM32X1S | ||||
| 	xtract_cell_decl RAM32X1S_1 | ||||
| 	xtract_cell_decl RAM32X2S | ||||
| 	xtract_cell_decl RAM64M | ||||
| 	#xtract_cell_decl RAM64X1D | ||||
| 	xtract_cell_decl RAM64X1S | ||||
| 	xtract_cell_decl RAM64X1S_1 | ||||
| 	xtract_cell_decl RAM64X2S | ||||
| 	# xtract_cell_decl RAMB18E1 | ||||
| 	# xtract_cell_decl RAMB36E1 | ||||
| 	xtract_cell_decl ROM128X1 | ||||
| 	xtract_cell_decl ROM256X1 | ||||
| 	xtract_cell_decl ROM32X1 | ||||
| 	xtract_cell_decl ROM64X1 | ||||
| 	#xtract_cell_decl SRL16E | ||||
| 	#xtract_cell_decl SRLC32E | ||||
| 	xtract_cell_decl STARTUPE2 "(* keep *)" | ||||
| 	xtract_cell_decl USR_ACCESSE2 | ||||
| 	xtract_cell_decl XADC | ||||
| } > cells_xtra.new | ||||
| 
 | ||||
| mv cells_xtra.new cells_xtra.v | ||||
| exit 0 | ||||
| 
 | ||||
|  | @ -1,5 +1,6 @@ | |||
| // Created by cells_xtra.sh from Xilinx models | ||||
| // Created by cells_xtra.py from Xilinx models | ||||
| 
 | ||||
| (* keep *) | ||||
| module BSCANE2 (...); | ||||
|     parameter DISABLE_JTAG = "FALSE"; | ||||
|     parameter integer JTAG_CHAIN = 1; | ||||
|  | @ -20,29 +21,39 @@ module BUFGCE (...); | |||
|     parameter CE_TYPE = "SYNC"; | ||||
|     parameter [0:0] IS_CE_INVERTED = 1'b0; | ||||
|     parameter [0:0] IS_I_INVERTED = 1'b0; | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input CE; | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFGCE_1 (...); | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input CE, I; | ||||
|     input CE; | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFGMUX (...); | ||||
|     parameter CLK_SEL_TYPE = "SYNC"; | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input I0, I1, S; | ||||
|     input I0; | ||||
|     input I1; | ||||
|     input S; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFGMUX_1 (...); | ||||
|     parameter CLK_SEL_TYPE = "SYNC"; | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input I0, I1, S; | ||||
|     input I0; | ||||
|     input I1; | ||||
|     input S; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFGMUX_CTRL (...); | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input I0; | ||||
|     input I1; | ||||
|  | @ -50,16 +61,19 @@ module BUFGMUX_CTRL (...); | |||
| endmodule | ||||
| 
 | ||||
| module BUFH (...); | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFIO (...); | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFMR (...); | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input I; | ||||
| endmodule | ||||
|  | @ -68,12 +82,14 @@ module BUFMRCE (...); | |||
|     parameter CE_TYPE = "SYNC"; | ||||
|     parameter integer INIT_OUT = 0; | ||||
|     parameter [0:0] IS_CE_INVERTED = 1'b0; | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input CE; | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
| module BUFR (...); | ||||
|     (* clkbuf_driver *) | ||||
|     output O; | ||||
|     input CE; | ||||
|     input CLR; | ||||
|  | @ -95,8 +111,15 @@ module CFGLUT5 (...); | |||
|     output CDO; | ||||
|     output O5; | ||||
|     output O6; | ||||
|     input I4, I3, I2, I1, I0; | ||||
|     input CDI, CE, CLK; | ||||
|     input I4; | ||||
|     input I3; | ||||
|     input I2; | ||||
|     input I1; | ||||
|     input I0; | ||||
|     input CDI; | ||||
|     input CE; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLK; | ||||
| endmodule | ||||
| 
 | ||||
| (* keep *) | ||||
|  | @ -108,7 +131,10 @@ endmodule | |||
| module DNA_PORT (...); | ||||
|     parameter [56:0] SIM_DNA_VALUE = 57'h0; | ||||
|     output DOUT; | ||||
|     input CLK, DIN, READ, SHIFT; | ||||
|     input CLK; | ||||
|     input DIN; | ||||
|     input READ; | ||||
|     input SHIFT; | ||||
| endmodule | ||||
| 
 | ||||
| module DSP48E1 (...); | ||||
|  | @ -175,6 +201,7 @@ module DSP48E1 (...); | |||
|     input CEINMODE; | ||||
|     input CEM; | ||||
|     input CEP; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLK; | ||||
|     input [24:0] D; | ||||
|     input [4:0] INMODE; | ||||
|  | @ -227,11 +254,13 @@ module FIFO18E1 (...); | |||
|     output WRERR; | ||||
|     input [31:0] DI; | ||||
|     input [3:0] DIP; | ||||
|     (* clkbuf_sink *) | ||||
|     input RDCLK; | ||||
|     input RDEN; | ||||
|     input REGCE; | ||||
|     input RST; | ||||
|     input RSTREG; | ||||
|     (* clkbuf_sink *) | ||||
|     input WRCLK; | ||||
|     input WREN; | ||||
| endmodule | ||||
|  | @ -272,11 +301,13 @@ module FIFO36E1 (...); | |||
|     input [7:0] DIP; | ||||
|     input INJECTDBITERR; | ||||
|     input INJECTSBITERR; | ||||
|     (* clkbuf_sink *) | ||||
|     input RDCLK; | ||||
|     input RDEN; | ||||
|     input REGCE; | ||||
|     input RST; | ||||
|     input RSTREG; | ||||
|     (* clkbuf_sink *) | ||||
|     input WRCLK; | ||||
|     input WREN; | ||||
| endmodule | ||||
|  | @ -1969,6 +2000,7 @@ module IBUF_IBUFDISABLE (...); | |||
|     parameter SIM_DEVICE = "7SERIES"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     input IBUFDISABLE; | ||||
| endmodule | ||||
|  | @ -1979,6 +2011,7 @@ module IBUF_INTERMDISABLE (...); | |||
|     parameter SIM_DEVICE = "7SERIES"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     input IBUFDISABLE; | ||||
|     input INTERMDISABLE; | ||||
|  | @ -1993,7 +2026,10 @@ module IBUFDS (...); | |||
|     parameter IFD_DELAY_VALUE = "AUTO"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     output O; | ||||
|     input I, IB; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
| endmodule | ||||
| 
 | ||||
| module IBUFDS_DIFF_OUT (...); | ||||
|  | @ -2001,8 +2037,12 @@ module IBUFDS_DIFF_OUT (...); | |||
|     parameter DQS_BIAS = "FALSE"; | ||||
|     parameter IBUF_LOW_PWR = "TRUE"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     output O, OB; | ||||
|     input I, IB; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
| endmodule | ||||
| 
 | ||||
| module IBUFDS_DIFF_OUT_IBUFDISABLE (...); | ||||
|  | @ -2014,7 +2054,9 @@ module IBUFDS_DIFF_OUT_IBUFDISABLE (...); | |||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
|     input IBUFDISABLE; | ||||
| endmodule | ||||
|  | @ -2028,7 +2070,9 @@ module IBUFDS_DIFF_OUT_INTERMDISABLE (...); | |||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
|     input IBUFDISABLE; | ||||
|     input INTERMDISABLE; | ||||
|  | @ -2041,7 +2085,9 @@ module IBUFDS_GTE2 (...); | |||
|     output O; | ||||
|     output ODIV2; | ||||
|     input CEB; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
| endmodule | ||||
| 
 | ||||
|  | @ -2053,7 +2099,9 @@ module IBUFDS_IBUFDISABLE (...); | |||
|     parameter SIM_DEVICE = "7SERIES"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
|     input IBUFDISABLE; | ||||
| endmodule | ||||
|  | @ -2066,12 +2114,50 @@ module IBUFDS_INTERMDISABLE (...); | |||
|     parameter SIM_DEVICE = "7SERIES"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
|     input IBUFDISABLE; | ||||
|     input INTERMDISABLE; | ||||
| endmodule | ||||
| 
 | ||||
| module IBUFG (...); | ||||
|     parameter CAPACITANCE = "DONT_CARE"; | ||||
|     parameter IBUF_DELAY_VALUE = "0"; | ||||
|     parameter IBUF_LOW_PWR = "TRUE"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
| module IBUFGDS (...); | ||||
|     parameter CAPACITANCE = "DONT_CARE"; | ||||
|     parameter DIFF_TERM = "FALSE"; | ||||
|     parameter IBUF_DELAY_VALUE = "0"; | ||||
|     parameter IBUF_LOW_PWR = "TRUE"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
| endmodule | ||||
| 
 | ||||
| module IBUFGDS_DIFF_OUT (...); | ||||
|     parameter DIFF_TERM = "FALSE"; | ||||
|     parameter DQS_BIAS = "FALSE"; | ||||
|     parameter IBUF_LOW_PWR = "TRUE"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     input I; | ||||
|     (* iopad_external_pin *) | ||||
|     input IB; | ||||
| endmodule | ||||
| 
 | ||||
| (* keep *) | ||||
| module ICAPE2 (...); | ||||
|     parameter [31:0] DEVICE_ID = 32'h04244093; | ||||
|  | @ -2095,6 +2181,7 @@ module IDDR (...); | |||
|     parameter XON = "TRUE"; | ||||
|     output Q1; | ||||
|     output Q2; | ||||
|     (* clkbuf_sink *) | ||||
|     input C; | ||||
|     input CE; | ||||
|     input D; | ||||
|  | @ -2112,7 +2199,9 @@ module IDDR_2CLK (...); | |||
|     parameter SRTYPE = "SYNC"; | ||||
|     output Q1; | ||||
|     output Q2; | ||||
|     (* clkbuf_sink *) | ||||
|     input C; | ||||
|     (* clkbuf_sink *) | ||||
|     input CB; | ||||
|     input CE; | ||||
|     input D; | ||||
|  | @ -2124,6 +2213,7 @@ endmodule | |||
| module IDELAYCTRL (...); | ||||
|     parameter SIM_DEVICE = "7SERIES"; | ||||
|     output RDY; | ||||
|     (* clkbuf_sink *) | ||||
|     input REFCLK; | ||||
|     input RST; | ||||
| endmodule | ||||
|  | @ -2143,6 +2233,7 @@ module IDELAYE2 (...); | |||
|     parameter integer SIM_DELAY_D = 0; | ||||
|     output [4:0] CNTVALUEOUT; | ||||
|     output DATAOUT; | ||||
|     (* clkbuf_sink *) | ||||
|     input C; | ||||
|     input CE; | ||||
|     input CINVCTRL; | ||||
|  | @ -2174,9 +2265,11 @@ module IN_FIFO (...); | |||
|     output [7:0] Q7; | ||||
|     output [7:0] Q8; | ||||
|     output [7:0] Q9; | ||||
|     (* clkbuf_sink *) | ||||
|     input RDCLK; | ||||
|     input RDEN; | ||||
|     input RESET; | ||||
|     (* clkbuf_sink *) | ||||
|     input WRCLK; | ||||
|     input WREN; | ||||
|     input [3:0] D0; | ||||
|  | @ -2197,8 +2290,10 @@ module IOBUF (...); | |||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     parameter SLEW = "SLOW"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     input I, T; | ||||
|     input I; | ||||
|     input T; | ||||
| endmodule | ||||
| 
 | ||||
| module IOBUF_DCIEN (...); | ||||
|  | @ -2209,6 +2304,7 @@ module IOBUF_DCIEN (...); | |||
|     parameter SLEW = "SLOW"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     input DCITERMDISABLE; | ||||
|     input I; | ||||
|  | @ -2224,6 +2320,7 @@ module IOBUF_INTERMDISABLE (...); | |||
|     parameter SLEW = "SLOW"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     input I; | ||||
|     input IBUFDISABLE; | ||||
|  | @ -2238,8 +2335,11 @@ module IOBUFDS (...); | |||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     parameter SLEW = "SLOW"; | ||||
|     output O; | ||||
|     inout IO, IOB; | ||||
|     input I, T; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     inout IOB; | ||||
|     input I; | ||||
|     input T; | ||||
| endmodule | ||||
| 
 | ||||
| module IOBUFDS_DCIEN (...); | ||||
|  | @ -2251,7 +2351,9 @@ module IOBUFDS_DCIEN (...); | |||
|     parameter SLEW = "SLOW"; | ||||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IOB; | ||||
|     input DCITERMDISABLE; | ||||
|     input I; | ||||
|  | @ -2266,7 +2368,9 @@ module IOBUFDS_DIFF_OUT (...); | |||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IOB; | ||||
|     input I; | ||||
|     input TM; | ||||
|  | @ -2282,7 +2386,9 @@ module IOBUFDS_DIFF_OUT_DCIEN (...); | |||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IOB; | ||||
|     input DCITERMDISABLE; | ||||
|     input I; | ||||
|  | @ -2300,7 +2406,9 @@ module IOBUFDS_DIFF_OUT_INTERMDISABLE (...); | |||
|     parameter USE_IBUFDISABLE = "TRUE"; | ||||
|     output O; | ||||
|     output OB; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IO; | ||||
|     (* iopad_external_pin *) | ||||
|     inout IOB; | ||||
|     input I; | ||||
|     input IBUFDISABLE; | ||||
|  | @ -2348,15 +2456,21 @@ module ISERDESE2 (...); | |||
|     input BITSLIP; | ||||
|     input CE1; | ||||
|     input CE2; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLK; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLKB; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLKDIV; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLKDIVP; | ||||
|     input D; | ||||
|     input DDLY; | ||||
|     input DYNCLKDIVSEL; | ||||
|     input DYNCLKSEL; | ||||
|     (* clkbuf_sink *) | ||||
|     input OCLK; | ||||
|     (* clkbuf_sink *) | ||||
|     input OCLKB; | ||||
|     input OFB; | ||||
|     input RST; | ||||
|  | @ -2375,7 +2489,10 @@ module LDCE (...); | |||
|     parameter MSGON = "TRUE"; | ||||
|     parameter XON = "TRUE"; | ||||
|     output Q; | ||||
|     input CLR, D, G, GE; | ||||
|     input CLR; | ||||
|     input D; | ||||
|     input G; | ||||
|     input GE; | ||||
| endmodule | ||||
| 
 | ||||
| module LDPE (...); | ||||
|  | @ -2385,7 +2502,10 @@ module LDPE (...); | |||
|     parameter MSGON = "TRUE"; | ||||
|     parameter XON = "TRUE"; | ||||
|     output Q; | ||||
|     input D, G, GE, PRE; | ||||
|     input D; | ||||
|     input G; | ||||
|     input GE; | ||||
|     input PRE; | ||||
| endmodule | ||||
| 
 | ||||
| module MMCME2_ADV (...); | ||||
|  | @ -2533,7 +2653,10 @@ module OBUFDS (...); | |||
|     parameter CAPACITANCE = "DONT_CARE"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     parameter SLEW = "SLOW"; | ||||
|     output O, OB; | ||||
|     (* iopad_external_pin *) | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     output OB; | ||||
|     input I; | ||||
| endmodule | ||||
| 
 | ||||
|  | @ -2542,20 +2665,27 @@ module OBUFT (...); | |||
|     parameter integer DRIVE = 12; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     parameter SLEW = "SLOW"; | ||||
|     (* iopad_external_pin *) | ||||
|     output O; | ||||
|     input I, T; | ||||
|     input I; | ||||
|     input T; | ||||
| endmodule | ||||
| 
 | ||||
| module OBUFTDS (...); | ||||
|     parameter CAPACITANCE = "DONT_CARE"; | ||||
|     parameter IOSTANDARD = "DEFAULT"; | ||||
|     parameter SLEW = "SLOW"; | ||||
|     output O, OB; | ||||
|     input I, T; | ||||
|     (* iopad_external_pin *) | ||||
|     output O; | ||||
|     (* iopad_external_pin *) | ||||
|     output OB; | ||||
|     input I; | ||||
|     input T; | ||||
| endmodule | ||||
| 
 | ||||
| module ODDR (...); | ||||
|     output Q; | ||||
|     (* clkbuf_sink *) | ||||
|     input C; | ||||
|     input CE; | ||||
|     input D1; | ||||
|  | @ -2586,6 +2716,7 @@ module ODELAYE2 (...); | |||
|     parameter integer SIM_DELAY_D = 0; | ||||
|     output [4:0] CNTVALUEOUT; | ||||
|     output DATAOUT; | ||||
|     (* clkbuf_sink *) | ||||
|     input C; | ||||
|     input CE; | ||||
|     input CINVCTRL; | ||||
|  | @ -2631,7 +2762,9 @@ module OSERDESE2 (...); | |||
|     output TBYTEOUT; | ||||
|     output TFB; | ||||
|     output TQ; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLK; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLKDIV; | ||||
|     input D1; | ||||
|     input D2; | ||||
|  | @ -2673,9 +2806,11 @@ module OUT_FIFO (...); | |||
|     output [3:0] Q9; | ||||
|     output [7:0] Q5; | ||||
|     output [7:0] Q6; | ||||
|     (* clkbuf_sink *) | ||||
|     input RDCLK; | ||||
|     input RDEN; | ||||
|     input RESET; | ||||
|     (* clkbuf_sink *) | ||||
|     input WRCLK; | ||||
|     input WREN; | ||||
|     input [7:0] D0; | ||||
|  | @ -3659,7 +3794,17 @@ module RAM128X1S (...); | |||
|     parameter [127:0] INIT = 128'h00000000000000000000000000000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
|     input A6; | ||||
|     input D; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM256X1S (...); | ||||
|  | @ -3668,6 +3813,7 @@ module RAM256X1S (...); | |||
|     output O; | ||||
|     input [7:0] A; | ||||
|     input D; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
|  | @ -3690,6 +3836,7 @@ module RAM32M (...); | |||
|     input [1:0] DIB; | ||||
|     input [1:0] DIC; | ||||
|     input [1:0] DID; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
|  | @ -3698,22 +3845,48 @@ module RAM32X1S (...); | |||
|     parameter [31:0] INIT = 32'h00000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, D, WCLK, WE; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input D; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM32X1S_1 (...); | ||||
|     parameter [31:0] INIT = 32'h00000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, D, WCLK, WE; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input D; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM32X2S (...); | ||||
|     parameter [31:0] INIT_00 = 32'h00000000; | ||||
|     parameter [31:0] INIT_01 = 32'h00000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O0, O1; | ||||
|     input A0, A1, A2, A3, A4, D0, D1, WCLK, WE; | ||||
|     output O0; | ||||
|     output O1; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input D0; | ||||
|     input D1; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM64M (...); | ||||
|  | @ -3734,6 +3907,7 @@ module RAM64M (...); | |||
|     input DIB; | ||||
|     input DIC; | ||||
|     input DID; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
|  | @ -3742,46 +3916,97 @@ module RAM64X1S (...); | |||
|     parameter [63:0] INIT = 64'h0000000000000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, A5, D, WCLK, WE; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
|     input D; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM64X1S_1 (...); | ||||
|     parameter [63:0] INIT = 64'h0000000000000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, A5, D, WCLK, WE; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
|     input D; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module RAM64X2S (...); | ||||
|     parameter [63:0] INIT_00 = 64'h0000000000000000; | ||||
|     parameter [63:0] INIT_01 = 64'h0000000000000000; | ||||
|     parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||
|     output O0, O1; | ||||
|     input A0, A1, A2, A3, A4, A5, D0, D1, WCLK, WE; | ||||
|     output O0; | ||||
|     output O1; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
|     input D0; | ||||
|     input D1; | ||||
|     (* clkbuf_sink *) | ||||
|     input WCLK; | ||||
|     input WE; | ||||
| endmodule | ||||
| 
 | ||||
| module ROM128X1 (...); | ||||
|     parameter [127:0] INIT = 128'h00000000000000000000000000000000; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, A5, A6; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
|     input A6; | ||||
| endmodule | ||||
| 
 | ||||
| module ROM256X1 (...); | ||||
|     parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, A5, A6, A7; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
|     input A6; | ||||
|     input A7; | ||||
| endmodule | ||||
| 
 | ||||
| module ROM32X1 (...); | ||||
|     parameter [31:0] INIT = 32'h00000000; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
| endmodule | ||||
| 
 | ||||
| module ROM64X1 (...); | ||||
|     parameter [63:0] INIT = 64'h0000000000000000; | ||||
|     output O; | ||||
|     input A0, A1, A2, A3, A4, A5; | ||||
|     input A0; | ||||
|     input A1; | ||||
|     input A2; | ||||
|     input A3; | ||||
|     input A4; | ||||
|     input A5; | ||||
| endmodule | ||||
| 
 | ||||
| (* keep *) | ||||
|  |  | |||
|  | @ -63,14 +63,17 @@ struct SynthXilinxPass : public ScriptPass | |||
| 		log("        generate an output netlist (and BLIF file) suitable for VPR\n"); | ||||
| 		log("        (this feature is experimental and incomplete)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nobram\n"); | ||||
| 		log("        disable inference of block rams\n"); | ||||
| 		log("    -ise\n"); | ||||
| 		log("        generate an output netlist suitable for ISE (enables -iopad)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nodram\n"); | ||||
| 		log("        disable inference of distributed rams\n"); | ||||
| 		log("    -nobram\n"); | ||||
| 		log("        do not use block RAM cells in output netlist\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nolutram\n"); | ||||
| 		log("        do not use distributed RAM cells in output netlist\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nosrl\n"); | ||||
| 		log("        disable inference of shift registers\n"); | ||||
| 		log("        do not use distributed SRL cells in output netlist\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nocarry\n"); | ||||
| 		log("        do not use XORCY/MUXCY/CARRY4 cells in output netlist\n"); | ||||
|  | @ -78,6 +81,15 @@ struct SynthXilinxPass : public ScriptPass | |||
| 		log("    -nowidelut\n"); | ||||
| 		log("        do not use MUXF[78] resources to implement LUTs larger than LUT6s\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -iopad\n"); | ||||
| 		log("        enable I/O buffer insertion (selected automatically by -ise)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noiopad\n"); | ||||
| 		log("        disable I/O buffer insertion (only useful with -ise)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noclkbuf\n"); | ||||
| 		log("        disable automatic clock buffer insertion\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -widemux <int>\n"); | ||||
| 		log("        enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n"); | ||||
| 		log("        above this number of inputs (minimum value 2, recommended value >= 5).\n"); | ||||
|  | @ -104,7 +116,8 @@ struct SynthXilinxPass : public ScriptPass | |||
| 	} | ||||
| 
 | ||||
| 	std::string top_opt, edif_file, blif_file, family; | ||||
| 	bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9; | ||||
| 	bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9; | ||||
| 	bool flatten_before_abc; | ||||
| 	int widemux; | ||||
| 
 | ||||
| 	void clear_flags() YS_OVERRIDE | ||||
|  | @ -116,13 +129,18 @@ struct SynthXilinxPass : public ScriptPass | |||
| 		flatten = false; | ||||
| 		retime = false; | ||||
| 		vpr = false; | ||||
| 		ise = false; | ||||
| 		iopad = false; | ||||
| 		noiopad = false; | ||||
| 		noclkbuf = false; | ||||
| 		nocarry = false; | ||||
| 		nobram = false; | ||||
| 		nodram = false; | ||||
| 		nolutram = false; | ||||
| 		nosrl = false; | ||||
| 		nocarry = false; | ||||
| 		nowidelut = false; | ||||
| 		abc9 = false; | ||||
| 		flatten_before_abc = false; | ||||
| 		widemux = 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -162,6 +180,10 @@ struct SynthXilinxPass : public ScriptPass | |||
| 				flatten = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-flatten_before_abc") { | ||||
| 				flatten_before_abc = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-retime") { | ||||
| 				retime = true; | ||||
| 				continue; | ||||
|  | @ -178,6 +200,22 @@ struct SynthXilinxPass : public ScriptPass | |||
| 				vpr = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-ise") { | ||||
| 				ise = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-iopad") { | ||||
| 				iopad = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-noiopad") { | ||||
| 				noiopad = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-noclkbuf") { | ||||
| 				noclkbuf = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nocarry") { | ||||
| 				nocarry = true; | ||||
| 				continue; | ||||
|  | @ -186,8 +224,8 @@ struct SynthXilinxPass : public ScriptPass | |||
| 				nobram = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nodram") { | ||||
| 				nodram = true; | ||||
| 			if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { | ||||
| 				nolutram = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nosrl") { | ||||
|  | @ -284,7 +322,7 @@ struct SynthXilinxPass : public ScriptPass | |||
| 			run("opt_clean"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("bram", "(skip if '-nobram')")) { | ||||
| 		if (check_label("map_bram", "(skip if '-nobram')")) { | ||||
| 			if (help_mode) { | ||||
| 				run("memory_bram -rules +/xilinx/{family}_brams.txt"); | ||||
| 				run("techmap -map +/xilinx/{family}_brams_map.v"); | ||||
|  | @ -301,20 +339,23 @@ struct SynthXilinxPass : public ScriptPass | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("dram", "(skip if '-nodram')")) { | ||||
| 			if (!nodram || help_mode) { | ||||
| 				run("memory_bram -rules +/xilinx/drams.txt"); | ||||
| 				run("techmap -map +/xilinx/drams_map.v"); | ||||
| 		if (check_label("map_lutram", "(skip if '-nolutram')")) { | ||||
| 			if (!nolutram || help_mode) { | ||||
| 				run("memory_bram -rules +/xilinx/lutrams.txt"); | ||||
| 				run("techmap -map +/xilinx/lutrams_map.v"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("fine")) { | ||||
| 		if (check_label("map_ffram")) { | ||||
| 			if (widemux > 0) | ||||
| 				run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover
 | ||||
| 									    // performs less efficiently
 | ||||
| 			else | ||||
| 				run("opt -fast -full"); | ||||
| 			run("memory_map"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("fine")) { | ||||
| 			run("dffsr2dff"); | ||||
| 			run("dff2dffe"); | ||||
| 			if (help_mode) { | ||||
|  | @ -382,6 +423,8 @@ struct SynthXilinxPass : public ScriptPass | |||
| 
 | ||||
| 		if (check_label("map_luts")) { | ||||
| 			run("opt_expr -mux_undef"); | ||||
| 			if (flatten_before_abc) | ||||
| 				run("flatten"); | ||||
| 			if (help_mode) | ||||
| 				run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut', option for '-retime')"); | ||||
| 			else if (abc9) { | ||||
|  | @ -410,6 +453,18 @@ struct SynthXilinxPass : public ScriptPass | |||
| 			run("clean"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("finalize")) { | ||||
| 			bool do_iopad = iopad || (ise && !noiopad); | ||||
| 			if (help_mode || !noclkbuf) { | ||||
| 				if (help_mode || do_iopad) | ||||
| 					run("clkbufmap -buf BUFG O:I -inpad IBUFG O:I", "(skip if '-noclkbuf', '-inpad' passed if '-iopad' or '-ise' and not '-noiopad')"); | ||||
| 				else | ||||
| 					run("clkbufmap -buf BUFG O:I"); | ||||
| 			} | ||||
| 			if (do_iopad) | ||||
| 				run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopad' or '-ise' and not '-noiopad')"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("check")) { | ||||
| 			run("hierarchy -check"); | ||||
| 			run("stat -tech xilinx"); | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| module RAMB8BWER ( | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKAWRCLK, | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKBRDCLK, | ||||
| 	input ENAWREN, | ||||
| 	input ENBRDEN, | ||||
|  | @ -87,7 +89,9 @@ module RAMB8BWER ( | |||
| endmodule | ||||
| 
 | ||||
| module RAMB16BWER ( | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKA, | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKB, | ||||
| 	input ENA, | ||||
| 	input ENB, | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| module RAMB18E1 ( | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKARDCLK, | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKBWRCLK, | ||||
| 	input ENARDEN, | ||||
| 	input ENBWREN, | ||||
|  | @ -123,7 +125,9 @@ module RAMB18E1 ( | |||
| endmodule | ||||
| 
 | ||||
| module RAMB36E1 ( | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKARDCLK, | ||||
| 	(* clkbuf_sink *) | ||||
| 	input CLKBWRCLK, | ||||
| 	input ENARDEN, | ||||
| 	input ENBWREN, | ||||
|  |  | |||
|  | @ -221,3 +221,73 @@ check | |||
| equiv_opt opt_expr -fine | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i | ||||
| 
 | ||||
| ########### | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module opt_expr_shiftx_1bit(input [2:0] a, input [1:0] b, output y); | ||||
|     \$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shiftx (.A({1'bx,a}), .B(b), .Y(y)); | ||||
| endmodule | ||||
| EOT | ||||
| check | ||||
| 
 | ||||
| equiv_opt opt_expr | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$shiftx r:A_WIDTH=3 %i | ||||
| 
 | ||||
| ########### | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module opt_expr_shiftx_3bit(input [9:0] a, input [3:0] b, output [2:0] y); | ||||
|     \$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shiftx (.A({4'bxx00,a}), .B(b), .Y(y)); | ||||
| endmodule | ||||
| EOT | ||||
| check | ||||
| 
 | ||||
| equiv_opt opt_expr | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$shiftx r:A_WIDTH=12 %i | ||||
| 
 | ||||
| ########### | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module opt_expr_shift_1bit(input [2:0] a, input [1:0] b, output y); | ||||
|     \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shift (.A({1'b0,a}), .B(b), .Y(y)); | ||||
| endmodule | ||||
| EOT | ||||
| check | ||||
| 
 | ||||
| equiv_opt opt_expr | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$shift r:A_WIDTH=3 %i | ||||
| 
 | ||||
| ########### | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module opt_expr_shift_3bit(input [9:0] a, input [3:0] b, output [2:0] y); | ||||
|     \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y)); | ||||
| endmodule | ||||
| EOT | ||||
| check | ||||
| 
 | ||||
| equiv_opt opt_expr | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$shift r:A_WIDTH=10 %i | ||||
| 
 | ||||
| ########### | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module opt_expr_shift_3bit_keepdc(input [9:0] a, input [3:0] b, output [2:0] y); | ||||
|     \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y)); | ||||
| endmodule | ||||
| EOT | ||||
| check | ||||
| 
 | ||||
| equiv_opt opt_expr -keepdc | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$shift r:A_WIDTH=13 %i | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| module test(input clk, input [3:0] bar, output [3:0] foo); | ||||
| module test(input clk, input [3:0] bar, output [3:0] foo, asdf); | ||||
|   reg [3:0] foo = 0; | ||||
|   reg [3:0] last_bar = 0; | ||||
|   reg [3:0] asdf = 4'b1xxx; | ||||
| 
 | ||||
|   always @* | ||||
|     foo[1:0] <= bar[1:0]; | ||||
|  | @ -11,5 +12,10 @@ module test(input clk, input [3:0] bar, output [3:0] foo); | |||
|   always @(posedge clk) | ||||
|     last_bar <= bar; | ||||
| 
 | ||||
|   always @(posedge clk) | ||||
|     asdf[3] <= bar[3]; | ||||
|   always @* | ||||
|     asdf[2:0] = 3'b111; | ||||
| 
 | ||||
|   assert property (foo == {last_bar[3:2], bar[1:0]}); | ||||
| endmodule | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| 
 | ||||
| module demo_001(y1, y2, y3, y4); | ||||
| 	output [7:0] y1, y2, y3, y4; | ||||
| 
 | ||||
|  | @ -22,3 +21,13 @@ module demo_002(y0, y1, y2, y3); | |||
| 	assign y3 = 1 ? -1 : 'd0; | ||||
| endmodule | ||||
| 
 | ||||
| module demo_003(output A, B); | ||||
| 	parameter real p = 0; | ||||
| 	assign A = (p==1.0); | ||||
| 	assign B = (p!="1.000000"); | ||||
| endmodule | ||||
| 
 | ||||
| module demo_004(output A, B, C, D); | ||||
| 	demo_003 #(1.0) demo_real (A, B); | ||||
| 	demo_003 #(1) demo_int (C, D); | ||||
| endmodule | ||||
|  |  | |||
							
								
								
									
										1
									
								
								tests/techmap/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/techmap/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +1,2 @@ | |||
| *.log | ||||
| /*.mk | ||||
|  |  | |||
							
								
								
									
										96
									
								
								tests/techmap/clkbufmap.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								tests/techmap/clkbufmap.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| read_verilog <<EOT | ||||
| module clkbuf (input i, (* clkbuf_driver *) output o); endmodule | ||||
| module dff ((* clkbuf_sink *) input clk, input d, output q); endmodule | ||||
| module dffe ((* clkbuf_sink *) input c, input d, e, output q); endmodule | ||||
| module latch (input e, d, output q); endmodule | ||||
| module clkgen (output o); endmodule | ||||
| 
 | ||||
| module top(input clk1, clk2, clk3, d, e, output [4:0] q); | ||||
| wire clk4, clk5, clk6; | ||||
| dff s0 (.clk(clk1), .d(d), .q(q[0])); | ||||
| dffe s1 (.c(clk2), .d(d), .e(e), .q(q[1])); | ||||
| latch s2 (.e(clk3), .d(d), .q(q[2])); | ||||
| sub s3 (.sclk4(clk4), .sclk5(clk5), .sclk6(clk6), .sd(d), .sq(q[3])); | ||||
| dff s4 (.clk(clk4), .d(d), .q(q[4])); | ||||
| dff s5 (.clk(clk5), .d(d), .q(q[4])); | ||||
| dff s6 (.clk(clk6), .d(d), .q(q[4])); | ||||
| endmodule | ||||
| 
 | ||||
| module sub(output sclk4, output sclk5, output sclk6, input sd, output sq); | ||||
| wire tmp; | ||||
| clkgen s7(.o(sclk4)); | ||||
| clkgen s8(.o(sclk5)); | ||||
| clkgen s9(.o(tmp)); | ||||
| clkbuf s10(.i(tmp), .o(sclk6)); | ||||
| dff s11(.clk(sclk4), .d(sd), .q(sq)); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| hierarchy -auto-top | ||||
| design -save ref | ||||
| 
 | ||||
| # ---------------------- | ||||
| 
 | ||||
| design -load ref | ||||
| clkbufmap -buf clkbuf o:i | ||||
| select -assert-count 3 top/t:clkbuf | ||||
| select -assert-count 2 sub/t:clkbuf | ||||
| select -set clk1 w:clk1 %a %co t:clkbuf %i          # Find 'clk1' fanouts that are 'clkbuf' | ||||
| select -assert-count 1 @clk1                        # Check there is one such fanout | ||||
| select -assert-count 1 @clk1 %x:+[o] %co c:s* %i    # Check that the 'o' of that clkbuf drives one fanout | ||||
| select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i    # And that one fanout is 's0' | ||||
| select -set clk2 w:clk2 %a %co t:clkbuf %i | ||||
| select -assert-count 1 @clk2 | ||||
| select -assert-count 1 @clk2 %x:+[o] %co c:s* %i | ||||
| select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i | ||||
| select -set clk5 w:clk5 %a %ci t:clkbuf %i | ||||
| select -assert-count 1 @clk5 | ||||
| select -assert-count 1 @clk5 %x:+[o] %co c:s5 %i | ||||
| select -assert-count 1 @clk5 %x:+[i] %ci c:s3 %i | ||||
| select -set sclk4 w:sclk4 %a %ci t:clkbuf %i | ||||
| select -assert-count 1 @sclk4 | ||||
| select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i | ||||
| select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i | ||||
| 
 | ||||
| # ---------------------- | ||||
| 
 | ||||
| design -load ref | ||||
| setattr -set clkbuf_inhibit 0 w:clk1 | ||||
| setattr -set clkbuf_inhibit 1 w:clk2 | ||||
| clkbufmap -buf clkbuf o:i | ||||
| select -assert-count 2 top/t:clkbuf | ||||
| select -set clk1 w:clk1 %a %co t:clkbuf %i          # Find 'clk1' fanouts that are 'clkbuf' | ||||
| select -assert-count 1 @clk1                        # Check there is one such fanout | ||||
| select -assert-count 1 @clk1 %x:+[o] %co c:s* %i    # Check that the 'o' of that clkbuf drives one fanout | ||||
| select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i    # And that one fanout is 's0' | ||||
| select -assert-count 0 w:clk2 %a %co t:clkbuf %i | ||||
| 
 | ||||
| # ---------------------- | ||||
| 
 | ||||
| design -load ref | ||||
| setattr -set clkbuf_inhibit 1 w:clk1 | ||||
| setattr -set buffer_type "bufg" w:clk2 | ||||
| clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d | ||||
| select -assert-count 3 top/t:clkbuf | ||||
| select -assert-count 2 sub/t:clkbuf | ||||
| select -set clk1 w:clk1 %a %co t:clkbuf %i          # Find 'clk1' fanouts that are 'clkbuf' | ||||
| select -assert-count 1 @clk1                        # Check there is one such fanout | ||||
| select -assert-count 1 @clk1 %x:+[o] %co c:s* %i    # Check that the 'o' of that clkbuf drives one fanout | ||||
| select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i    # And that one fanout is 's0' | ||||
| select -set clk2 w:clk2 %a %co t:clkbuf %i          # Find 'clk1' fanouts that are 'clkbuf' | ||||
| select -assert-count 1 @clk2                        # Check there is one such fanout | ||||
| select -assert-count 1 @clk2 %x:+[o] %co c:s* %i    # Check that the 'o' of that clkbuf drives one fanout | ||||
| select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i    # And that one fanout is 's0' | ||||
| 
 | ||||
| # ---------------------- | ||||
| 
 | ||||
| design -load ref | ||||
| setattr -set buffer_type "none" w:clk1 | ||||
| setattr -set buffer_type "bufr" w:clk2 | ||||
| setattr -set buffer_type "bufr" w:sclk4 | ||||
| setattr -set buffer_type "bufr" w:sclk5 | ||||
| clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d | ||||
| select -assert-count 0 w:clk1 %a %co t:clkbuf %i | ||||
| select -assert-count 0 w:clk2 %a %co t:clkbuf %i | ||||
| select -assert-count 0 top/t:clkbuf | ||||
| select -assert-count 1 sub/t:clkbuf | ||||
							
								
								
									
										8
									
								
								tests/techmap/recursive.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/techmap/recursive.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| module top; | ||||
| sub s0(); | ||||
| foo f0(); | ||||
| endmodule | ||||
| 
 | ||||
| module foo; | ||||
| sub s0(); | ||||
| endmodule | ||||
							
								
								
									
										4
									
								
								tests/techmap/recursive_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/techmap/recursive_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| module sub; | ||||
|     sub _TECHMAP_REPLACE_ (); | ||||
|     bar f0(); | ||||
| endmodule | ||||
							
								
								
									
										3
									
								
								tests/techmap/recursive_runtest.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/techmap/recursive_runtest.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| set -ev | ||||
| 
 | ||||
| ../../yosys -p 'hierarchy -top top; techmap -map recursive_map.v -max_iter 1; select -assert-count 2 t:sub; select -assert-count 2 t:bar' recursive.v | ||||
|  | @ -1,10 +1,20 @@ | |||
| #!/bin/bash | ||||
| #!/usr/bin/env bash | ||||
| set -e | ||||
| for x in *_runtest.sh; do | ||||
| 	echo "Running $x.." | ||||
| 	if ! bash $x &> ${x%.sh}.log; then | ||||
| 		tail ${x%.sh}.log | ||||
| 		echo ERROR | ||||
| 		exit 1 | ||||
| { | ||||
| echo "all::" | ||||
| for x in *.ys; do | ||||
| 	echo "all:: run-$x" | ||||
| 	echo "run-$x:" | ||||
| 	echo "	@echo 'Running $x..'" | ||||
| 	echo "	@../../yosys -ql ${x%.ys}.log $x" | ||||
| done | ||||
| for s in *.sh; do | ||||
| 	if [ "$s" != "run-test.sh" ]; then | ||||
| 		echo "all:: run-$s" | ||||
| 		echo "run-$s:" | ||||
| 		echo "	@echo 'Running $s..'" | ||||
| 		echo "	@bash $s > ${s%.sh}.log 2>&1" | ||||
| 	fi | ||||
| done | ||||
| } > run-test.mk | ||||
| exec ${MAKE:-make} -f run-test.mk | ||||
|  |  | |||
							
								
								
									
										14
									
								
								tests/various/mem2reg.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/various/mem2reg.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| read_verilog <<EOT | ||||
| module top; | ||||
| parameter DATADEPTH=2; | ||||
| parameter DATAWIDTH=1; | ||||
| (* keep, nomem2reg *) reg [DATAWIDTH-1:0] data1 [DATADEPTH-1:0]; | ||||
| (* keep, mem2reg *) reg [DATAWIDTH-1:0] data2 [DATADEPTH-1:0]; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| proc | ||||
| cd top | ||||
| select -assert-count 1 m:data1 a:src=<<EOT:4 %i | ||||
| select -assert-count 2 w:data2[*] a:src=<<EOT:5 %i | ||||
| select -assert-none a:mem2reg | ||||
							
								
								
									
										21
									
								
								tests/various/pmgen_reduce.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/various/pmgen_reduce.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| test_pmgen -generate reduce | ||||
| hierarchy -top pmtest_test_pmgen_pm_reduce | ||||
| flatten; opt_clean | ||||
| 
 | ||||
| design -save gold | ||||
| test_pmgen -reduce_chain | ||||
| design -stash gate | ||||
| 
 | ||||
| design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce | ||||
| design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce | ||||
| miter -equiv -flatten -make_assert gold gate miter | ||||
| sat -verify -prove-asserts miter | ||||
| 
 | ||||
| design -load gold | ||||
| test_pmgen -reduce_tree | ||||
| design -stash gate | ||||
| 
 | ||||
| design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce | ||||
| design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce | ||||
| miter -equiv -flatten -make_assert gold gate miter | ||||
| sat -verify -prove-asserts miter | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue