mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into eddie/shiftx2mux
This commit is contained in:
		
						commit
						b6a1f627b5
					
				
					 77 changed files with 4480 additions and 1957 deletions
				
			
		|  | @ -55,10 +55,12 @@ Yosys 0.9 .. Yosys 0.9-dev | |||
|     - Added "check -mapped" | ||||
|     - Added checking of SystemVerilog always block types (always_comb, | ||||
|       always_latch and always_ff) | ||||
|     - Added support for SystemVerilog wildcard port connections (.*) | ||||
|     - Added "xilinx_dffopt" pass | ||||
|     - Added "scratchpad" pass | ||||
|     - Added "abc9 -dff" | ||||
|     - Added "synth_xilinx -dff" | ||||
|     - Added "opt_lut_ins" pass | ||||
| 
 | ||||
| Yosys 0.8 .. Yosys 0.9 | ||||
| ---------------------- | ||||
|  |  | |||
							
								
								
									
										17
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								README.md
									
										
									
									
									
								
							|  | @ -373,10 +373,15 @@ Verilog Attributes and non-standard features | |||
|   `abc9` to preserve the integrity of carry-chains. Specifying this attribute | ||||
|   onto a bus port will affect only its most significant bit. | ||||
| 
 | ||||
| - The port attribute ``abc9_arrival`` specifies an integer (for output ports | ||||
|   only) to be used as the arrival time of this sequential port. It can be used, | ||||
|   for example, to specify the clk-to-Q delay of a flip-flop for consideration | ||||
|   during `abc9` techmapping. | ||||
| - The output port attribute ``abc9_arrival`` specifies an integer, or a string | ||||
|   of space-separated integers to be used as the arrival time of this blackbox | ||||
|   port. It can be used, for example, to specify the clk-to-Q delay of a flip- | ||||
|   flop output for consideration during `abc9` techmapping. | ||||
| 
 | ||||
| - The input port attribute ``abc9_required`` specifies an integer, or a string | ||||
|   of space-separated integers to be used as the required time of this blackbox | ||||
|   port. It can be used, for example, to specify the setup-time of a flip-flop | ||||
|   input for consideration during `abc9` techmapping. | ||||
| 
 | ||||
| - The module attribute ``abc9_flop`` is a boolean marking the module as a | ||||
|   flip-flop. This allows `abc9` to analyse its contents in order to perform | ||||
|  | @ -387,6 +392,10 @@ Verilog Attributes and non-standard features | |||
|   according to the type of the always. These are checked for correctness in | ||||
|   ``proc_dlatch``. | ||||
| 
 | ||||
| - The cell attribute ``wildcard_port_conns`` represents wildcard port | ||||
|   connections (SystemVerilog ``.*``). These are resolved to concrete | ||||
|   connections to matching wires in ``hierarchy``.   | ||||
| 
 | ||||
| - 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 | ||||
|  |  | |||
|  | @ -93,7 +93,6 @@ struct XAigerWriter | |||
| 	dict<SigBit, int> ordered_outputs; | ||||
| 
 | ||||
| 	vector<Cell*> box_list; | ||||
| 	dict<IdString, std::vector<IdString>> box_ports; | ||||
| 
 | ||||
| 	int mkgate(int a0, int a1) | ||||
| 	{ | ||||
|  | @ -157,7 +156,6 @@ struct XAigerWriter | |||
| 			if (wire->get_bool_attribute(ID::keep)) | ||||
| 				sigmap.add(wire); | ||||
| 
 | ||||
| 
 | ||||
| 		for (auto wire : module->wires()) | ||||
| 			for (int i = 0; i < GetSize(wire); i++) | ||||
| 			{ | ||||
|  | @ -175,23 +173,21 @@ struct XAigerWriter | |||
| 				undriven_bits.insert(bit); | ||||
| 				unused_bits.insert(bit); | ||||
| 
 | ||||
| 				if (wire->port_input) | ||||
| 				bool keep = wire->get_bool_attribute(ID::keep); | ||||
| 				if (wire->port_input || keep) | ||||
| 					input_bits.insert(bit); | ||||
| 
 | ||||
| 				if (wire->port_output) { | ||||
| 				if (wire->port_output || keep) { | ||||
| 					if (bit != wirebit) | ||||
| 						alias_map[wirebit] = bit; | ||||
| 					output_bits.insert(wirebit); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 		// TODO: Speed up toposort -- ultimately we care about
 | ||||
| 		//       box ordering, but not individual AIG cells
 | ||||
| 		dict<SigBit, pool<IdString>> bit_drivers, bit_users; | ||||
| 		TopoSort<IdString, RTLIL::sort_by_id_str> toposort; | ||||
| 		bool abc9_box_seen = false; | ||||
| 
 | ||||
| 		for (auto cell : module->selected_cells()) { | ||||
| 		dict<IdString,dict<IdString,std::vector<int>>> arrivals_cache; | ||||
| 		for (auto cell : module->cells()) { | ||||
| 			RTLIL::Module* inst_module = module->design->module(cell->type); | ||||
| 			if (!cell->has_keep_attr()) { | ||||
| 				if (cell->type == "$_NOT_") | ||||
| 				{ | ||||
| 					SigBit A = sigmap(cell->getPort("\\A").as_bit()); | ||||
|  | @ -199,9 +195,6 @@ struct XAigerWriter | |||
| 					unused_bits.erase(A); | ||||
| 					undriven_bits.erase(Y); | ||||
| 					not_map[Y] = A; | ||||
| 				toposort.node(cell->name); | ||||
| 				bit_users[A].insert(cell->name); | ||||
| 				bit_drivers[Y].insert(cell->name); | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
|  | @ -214,10 +207,6 @@ struct XAigerWriter | |||
| 					unused_bits.erase(B); | ||||
| 					undriven_bits.erase(Y); | ||||
| 					and_map[Y] = make_pair(A, B); | ||||
| 				toposort.node(cell->name); | ||||
| 				bit_users[A].insert(cell->name); | ||||
| 				bit_users[B].insert(cell->name); | ||||
| 				bit_drivers[Y].insert(cell->name); | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
|  | @ -233,49 +222,67 @@ struct XAigerWriter | |||
| 					alias_map[Q] = D; | ||||
| 					auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); | ||||
| 					log_assert(r.second); | ||||
| 					if (input_bits.erase(Q)) | ||||
| 						log_assert(Q.wire->attributes.count(ID::keep)); | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 			RTLIL::Module* inst_module = module->design->module(cell->type); | ||||
| 				if (inst_module) { | ||||
| 				bool abc9_box = inst_module->attributes.count("\\abc9_box_id"); | ||||
| 				bool abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); | ||||
| 				if (abc9_box && cell->get_bool_attribute("\\abc9_keep")) | ||||
| 					abc9_box = false; | ||||
| 
 | ||||
| 				for (const auto &conn : cell->connections()) { | ||||
| 					auto port_wire = inst_module->wire(conn.first); | ||||
| 
 | ||||
| 					if (abc9_box) { | ||||
| 						// Ignore inout for the sake of topographical ordering
 | ||||
| 						if (port_wire->port_input && !port_wire->port_output) | ||||
| 							for (auto bit : sigmap(conn.second)) | ||||
| 								bit_users[bit].insert(cell->name); | ||||
| 						if (port_wire->port_output) | ||||
| 							for (auto bit : sigmap(conn.second)) | ||||
| 								bit_drivers[bit].insert(cell->name); | ||||
| 
 | ||||
| 					bool abc9_flop = false; | ||||
| 					auto it = cell->attributes.find("\\abc9_box_seq"); | ||||
| 					if (it != cell->attributes.end()) { | ||||
| 						int abc9_box_seq = it->second.as_int(); | ||||
| 						if (GetSize(box_list) <= abc9_box_seq) | ||||
| 							box_list.resize(abc9_box_seq+1); | ||||
| 						box_list[abc9_box_seq] = cell; | ||||
| 						// Only flop boxes may have arrival times
 | ||||
| 						//   (all others are combinatorial)
 | ||||
| 						abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); | ||||
| 						if (!abc9_flop) | ||||
| 							continue; | ||||
| 					} | ||||
| 
 | ||||
| 					if (port_wire->port_output) { | ||||
| 						int arrival = 0; | ||||
| 					auto &cell_arrivals = arrivals_cache[cell->type]; | ||||
| 					for (const auto &conn : cell->connections()) { | ||||
| 						auto port_wire = inst_module->wire(conn.first); | ||||
| 						if (!port_wire->port_output) | ||||
| 							continue; | ||||
| 
 | ||||
| 						auto r = cell_arrivals.insert(conn.first); | ||||
| 						auto &arrivals = r.first->second; | ||||
| 						if (r.second) { | ||||
| 							auto it = port_wire->attributes.find("\\abc9_arrival"); | ||||
| 						if (it != port_wire->attributes.end()) { | ||||
| 							if (it->second.flags != 0) | ||||
| 								log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); | ||||
| 							arrival = it->second.as_int(); | ||||
| 							if (it == port_wire->attributes.end()) | ||||
| 								continue; | ||||
| 							if (it->second.flags == 0) | ||||
| 								arrivals.emplace_back(it->second.as_int()); | ||||
| 							else | ||||
| 								for (const auto &tok : split_tokens(it->second.decode_string())) | ||||
| 									arrivals.push_back(atoi(tok.c_str())); | ||||
| 						} | ||||
| 						if (arrival) | ||||
| 							for (auto bit : sigmap(conn.second)) | ||||
| 								arrival_times[bit] = arrival; | ||||
| 
 | ||||
| 						if (arrivals.empty()) | ||||
| 							continue; | ||||
| 
 | ||||
| 						if (GetSize(arrivals) > 1 && GetSize(arrivals) != GetSize(port_wire)) | ||||
| 							log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), | ||||
| 									GetSize(port_wire), log_signal(it->second), GetSize(arrivals)); | ||||
| 
 | ||||
| 						auto jt = arrivals.begin(); | ||||
| #ifndef NDEBUG | ||||
| 						if (ys_debug(1)) { | ||||
| 							static std::set<std::pair<IdString,IdString>> seen; | ||||
| 							if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), *jt); | ||||
| 						} | ||||
| #endif | ||||
| 						for (auto bit : sigmap(conn.second)) { | ||||
| 							arrival_times[bit] = *jt; | ||||
| 							if (arrivals.size() > 1) | ||||
| 								jt++; | ||||
| 						} | ||||
| 					} | ||||
| 
 | ||||
| 				if (abc9_box) { | ||||
| 					abc9_box_seen = true; | ||||
| 					toposort.node(cell->name); | ||||
| 					if (abc9_flop) | ||||
| 						continue; | ||||
| 				} | ||||
| 			} | ||||
|  | @ -293,6 +300,9 @@ struct XAigerWriter | |||
| 					for (auto b : c.second) { | ||||
| 						Wire *w = b.wire; | ||||
| 						if (!w) continue; | ||||
| 						// Do not add as PO if bit is already a PI
 | ||||
| 						if (input_bits.count(b)) | ||||
| 							continue; | ||||
| 						if (!w->port_output || !cell_known) { | ||||
| 							SigBit I = sigmap(b); | ||||
| 							if (I != b) | ||||
|  | @ -305,39 +315,13 @@ struct XAigerWriter | |||
| 			//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
 | ||||
| 		} | ||||
| 
 | ||||
| 		if (abc9_box_seen) { | ||||
| 			for (auto &it : bit_users) | ||||
| 				if (bit_drivers.count(it.first)) | ||||
| 					for (auto driver_cell : bit_drivers.at(it.first)) | ||||
| 					for (auto user_cell : it.second) | ||||
| 						toposort.edge(driver_cell, user_cell); | ||||
| 
 | ||||
| #if 0 | ||||
| 			toposort.analyze_loops = true; | ||||
| #endif | ||||
| 			bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); | ||||
| #if 0 | ||||
| 			unsigned i = 0; | ||||
| 			for (auto &it : toposort.loops) { | ||||
| 				log("  loop %d\n", i++); | ||||
| 				for (auto cell_name : it) { | ||||
| 					auto cell = module->cell(cell_name); | ||||
| 					log_assert(cell); | ||||
| 					log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); | ||||
| 				} | ||||
| 			} | ||||
| #endif | ||||
| 			log_assert(no_loops); | ||||
| 
 | ||||
| 			for (auto cell_name : toposort.sorted) { | ||||
| 				RTLIL::Cell *cell = module->cell(cell_name); | ||||
| 		dict<IdString, std::vector<IdString>> box_ports; | ||||
| 		for (auto cell : box_list) { | ||||
| 			log_assert(cell); | ||||
| 
 | ||||
| 			RTLIL::Module* box_module = module->design->module(cell->type); | ||||
| 				if (!box_module || !box_module->attributes.count("\\abc9_box_id")) | ||||
| 					continue; | ||||
| 
 | ||||
| 				bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); | ||||
| 			log_assert(box_module); | ||||
| 			log_assert(box_module->attributes.count("\\abc9_box_id") || box_module->get_bool_attribute("\\abc9_flop")); | ||||
| 
 | ||||
| 			auto r = box_ports.insert(cell->type); | ||||
| 			if (r.second) { | ||||
|  | @ -373,24 +357,12 @@ struct XAigerWriter | |||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 				// 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
 | ||||
| 			for (auto port_name : r.first->second) { | ||||
| 				auto w = box_module->wire(port_name); | ||||
| 				log_assert(w); | ||||
| 					auto it = cell->connections_.find(port_name); | ||||
| 					if (w->port_input) { | ||||
| 						RTLIL::SigSpec rhs; | ||||
| 						if (it != cell->connections_.end()) { | ||||
| 							if (GetSize(it->second) < GetSize(w)) | ||||
| 								it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); | ||||
| 							rhs = it->second; | ||||
| 						} | ||||
| 						else { | ||||
| 							rhs = RTLIL::SigSpec(State::S0, GetSize(w)); | ||||
| 							cell->setPort(port_name, rhs); | ||||
| 						} | ||||
| 
 | ||||
| 				auto rhs = cell->connections_.at(port_name, SigSpec()); | ||||
| 				rhs.append(Const(State::Sx, GetSize(w)-GetSize(rhs))); | ||||
| 				if (w->port_input) | ||||
| 					for (auto b : rhs) { | ||||
| 						SigBit I = sigmap(b); | ||||
| 						if (b == RTLIL::Sx) | ||||
|  | @ -404,29 +376,17 @@ struct XAigerWriter | |||
| 						co_bits.emplace_back(b); | ||||
| 						unused_bits.erase(I); | ||||
| 					} | ||||
| 					} | ||||
| 					if (w->port_output) { | ||||
| 						RTLIL::SigSpec rhs; | ||||
| 						auto it = cell->connections_.find(port_name); | ||||
| 						if (it != cell->connections_.end()) { | ||||
| 							if (GetSize(it->second) < GetSize(w)) | ||||
| 								it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); | ||||
| 							rhs = it->second; | ||||
| 						} | ||||
| 						else { | ||||
| 							Wire *wire = module->addWire(NEW_ID, GetSize(w)); | ||||
| 							if (blackbox) | ||||
| 								wire->set_bool_attribute(ID(abc9_padding)); | ||||
| 							rhs = wire; | ||||
| 							cell->setPort(port_name, rhs); | ||||
| 						} | ||||
| 
 | ||||
| 						for (const auto &b : rhs.bits()) { | ||||
| 				if (w->port_output) | ||||
| 					for (const auto &b : rhs) { | ||||
| 						SigBit O = sigmap(b); | ||||
| 						if (O != b) | ||||
| 							alias_map[O] = b; | ||||
| 						ci_bits.emplace_back(b); | ||||
| 						undriven_bits.erase(O); | ||||
| 						// If PI and CI, then must be a (* keep *) wire
 | ||||
| 						if (input_bits.erase(O)) { | ||||
| 							log_assert(output_bits.count(O)); | ||||
| 							log_assert(O.wire->get_bool_attribute(ID::keep)); | ||||
| 						} | ||||
| 					} | ||||
| 			} | ||||
|  | @ -451,11 +411,6 @@ struct XAigerWriter | |||
| 					unused_bits.erase(I); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 				box_list.emplace_back(cell); | ||||
| 			} | ||||
| 
 | ||||
| 			// TODO: Free memory from toposort, bit_drivers, bit_users
 | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto bit : input_bits) | ||||
|  | @ -501,6 +456,10 @@ struct XAigerWriter | |||
| 
 | ||||
| 		for (auto &bit : ci_bits) { | ||||
| 			aig_m++, aig_i++; | ||||
| 			// 1'bx may exist here due to a box output
 | ||||
| 			//   that has been padded to its full width
 | ||||
| 			if (bit == State::Sx) | ||||
| 				continue; | ||||
| 			log_assert(!aig_map.count(bit)); | ||||
| 			aig_map[bit] = 2*aig_m; | ||||
| 		} | ||||
|  | @ -512,7 +471,27 @@ struct XAigerWriter | |||
| 
 | ||||
| 		for (const auto &bit : output_bits) { | ||||
| 			ordered_outputs[bit] = aig_o++; | ||||
| 			aig_outputs.push_back(bit2aig(bit)); | ||||
| 			int aig; | ||||
| 			// Unlike bit2aig() which checks aig_map first, for
 | ||||
| 			//   inout/keep bits, since aig_map will point to
 | ||||
| 			//   the PI, first attempt to find the NOT/AND driver
 | ||||
| 			//   before resorting to an aig_map lookup (which
 | ||||
| 			//   could be another PO)
 | ||||
| 			if (input_bits.count(bit)) { | ||||
| 				if (not_map.count(bit)) { | ||||
| 					aig = bit2aig(not_map.at(bit)) ^ 1; | ||||
| 				} else if (and_map.count(bit)) { | ||||
| 					auto args = and_map.at(bit); | ||||
| 					int a0 = bit2aig(args.first); | ||||
| 					int a1 = bit2aig(args.second); | ||||
| 					aig = mkgate(a0, a1); | ||||
| 				} | ||||
| 				else | ||||
| 					aig = aig_map.at(bit); | ||||
| 			} | ||||
| 			else | ||||
| 				aig = bit2aig(bit); | ||||
| 			aig_outputs.push_back(aig); | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto &i : ff_bits) { | ||||
|  | @ -612,106 +591,45 @@ struct XAigerWriter | |||
| 		//	write_o_buffer(0);
 | ||||
| 
 | ||||
| 		if (!box_list.empty() || !ff_bits.empty()) { | ||||
| 			RTLIL::Module *holes_module = module->design->addModule("$__holes__"); | ||||
| 			log_assert(holes_module); | ||||
| 			dict<IdString, std::tuple<int,int,int>> cell_cache; | ||||
| 
 | ||||
| 			dict<IdString, std::tuple<Cell*,int,int,int>> cell_cache; | ||||
| 
 | ||||
| 			int port_id = 1; | ||||
| 			int box_count = 0; | ||||
| 			for (auto cell : box_list) { | ||||
| 				RTLIL::Module* orig_box_module = module->design->module(cell->type); | ||||
| 				log_assert(orig_box_module); | ||||
| 				IdString derived_name = orig_box_module->derive(module->design, cell->parameters); | ||||
| 				RTLIL::Module* box_module = module->design->module(derived_name); | ||||
| 				log_assert(cell); | ||||
| 
 | ||||
| 				auto r = cell_cache.insert(derived_name); | ||||
| 				RTLIL::Module* box_module = module->design->module(cell->type); | ||||
| 				log_assert(box_module); | ||||
| 
 | ||||
| 				IdString derived_type = box_module->derive(box_module->design, cell->parameters); | ||||
| 				box_module = box_module->design->module(derived_type); | ||||
| 				log_assert(box_module); | ||||
| 
 | ||||
| 				auto r = cell_cache.insert(derived_type); | ||||
| 				auto &v = r.first->second; | ||||
| 				if (r.second) { | ||||
| 					if (box_module->has_processes()) | ||||
| 						Pass::call_on_module(module->design, box_module, "proc"); | ||||
| 
 | ||||
| 					int box_inputs = 0, box_outputs = 0; | ||||
| 					if (box_module->get_bool_attribute("\\whitebox")) { | ||||
| 						auto holes_cell = holes_module->addCell(cell->name, derived_name); | ||||
| 						for (auto port_name : box_ports.at(cell->type)) { | ||||
| 					for (auto port_name : box_module->ports) { | ||||
| 						RTLIL::Wire *w = box_module->wire(port_name); | ||||
| 						log_assert(w); | ||||
| 							log_assert(!w->port_input || !w->port_output); | ||||
| 							auto &conn = holes_cell->connections_[port_name]; | ||||
| 							if (w->port_input) { | ||||
| 								for (int i = 0; i < GetSize(w); i++) { | ||||
| 									box_inputs++; | ||||
| 									RTLIL::Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); | ||||
| 									if (!holes_wire) { | ||||
| 										holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); | ||||
| 										holes_wire->port_input = true; | ||||
| 										holes_wire->port_id = port_id++; | ||||
| 										holes_module->ports.push_back(holes_wire->name); | ||||
| 									} | ||||
| 									conn.append(holes_wire); | ||||
| 								} | ||||
| 							} | ||||
| 							else if (w->port_output) { | ||||
| 						if (w->port_input) | ||||
| 							box_inputs += GetSize(w); | ||||
| 						if (w->port_output) | ||||
| 							box_outputs += GetSize(w); | ||||
| 								conn = holes_module->addWire(stringf("%s.%s", derived_name.c_str(), log_id(port_name)), GetSize(w)); | ||||
| 							} | ||||
| 					} | ||||
| 
 | ||||
| 					// For flops only, create an extra 1-bit input that drives a new wire
 | ||||
| 					//   called "<cell>.abc9_ff.Q" that is used below
 | ||||
| 						if (box_module->get_bool_attribute("\\abc9_flop")) { | ||||
| 					if (box_module->get_bool_attribute("\\abc9_flop")) | ||||
| 						box_inputs++; | ||||
| 							Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); | ||||
| 							if (!holes_wire) { | ||||
| 								holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); | ||||
| 								holes_wire->port_input = true; | ||||
| 								holes_wire->port_id = port_id++; | ||||
| 								holes_module->ports.push_back(holes_wire->name); | ||||
| 							} | ||||
| 							Wire *Q = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str())); | ||||
| 							holes_module->connect(Q, holes_wire); | ||||
| 						} | ||||
| 
 | ||||
| 						std::get<0>(v) = holes_cell; | ||||
| 					} | ||||
| 					else { | ||||
| 						for (auto port_name : box_ports.at(cell->type)) { | ||||
| 							RTLIL::Wire *w = box_module->wire(port_name); | ||||
| 							log_assert(w); | ||||
| 							log_assert(!w->port_input || !w->port_output); | ||||
| 							if (w->port_input) | ||||
| 								box_inputs += GetSize(w); | ||||
| 							else if (w->port_output) | ||||
| 								box_outputs += GetSize(w); | ||||
| 						} | ||||
| 						log_assert(std::get<0>(v) == nullptr); | ||||
| 					} | ||||
| 
 | ||||
| 					std::get<1>(v) = box_inputs; | ||||
| 					std::get<2>(v) = box_outputs; | ||||
| 					std::get<3>(v) = box_module->attributes.at("\\abc9_box_id").as_int(); | ||||
| 				} | ||||
| 
 | ||||
| 				auto holes_cell = std::get<0>(v); | ||||
| 				for (auto port_name : box_ports.at(cell->type)) { | ||||
| 					RTLIL::Wire *w = box_module->wire(port_name); | ||||
| 					log_assert(w); | ||||
| 					if (!w->port_output) | ||||
| 						continue; | ||||
| 					Wire *holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(port_name)), GetSize(w)); | ||||
| 					holes_wire->port_output = true; | ||||
| 					holes_wire->port_id = port_id++; | ||||
| 					holes_module->ports.push_back(holes_wire->name); | ||||
| 					if (holes_cell) // whitebox
 | ||||
| 						holes_module->connect(holes_wire, holes_cell->getPort(port_name)); | ||||
| 					else // blackbox
 | ||||
| 						holes_module->connect(holes_wire, Const(State::S0, GetSize(w))); | ||||
| 
 | ||||
| 					std::get<0>(v) = box_inputs; | ||||
| 					std::get<1>(v) = box_outputs; | ||||
| 					std::get<2>(v) = box_module->attributes.at("\\abc9_box_id").as_int(); | ||||
| 				} | ||||
| 
 | ||||
| 				write_h_buffer(std::get<0>(v)); | ||||
| 				write_h_buffer(std::get<1>(v)); | ||||
| 				write_h_buffer(std::get<2>(v)); | ||||
| 				write_h_buffer(std::get<3>(v)); | ||||
| 				write_h_buffer(box_count++); | ||||
| 			} | ||||
| 
 | ||||
|  | @ -759,82 +677,17 @@ struct XAigerWriter | |||
| 			f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); | ||||
| 			f.write(buffer_str.data(), buffer_str.size()); | ||||
| 
 | ||||
| 			RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); | ||||
| 			if (holes_module) { | ||||
| 				log_push(); | ||||
| 
 | ||||
| 				// NB: fixup_ports() will sort ports by name
 | ||||
| 				//holes_module->fixup_ports();
 | ||||
| 				holes_module->check(); | ||||
| 
 | ||||
| 				// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
 | ||||
| 				//   since boxes may contain parameters in which case `flatten` would have
 | ||||
| 				//   created a new $paramod ...
 | ||||
| 				Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap"); | ||||
| 
 | ||||
| 				SigMap holes_sigmap(holes_module); | ||||
| 
 | ||||
| 				dict<SigSpec, SigSpec> replace; | ||||
| 				for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { | ||||
| 					auto cell = it->second; | ||||
| 					if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", | ||||
| 								"$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { | ||||
| 						SigBit D = cell->getPort("\\D"); | ||||
| 						SigBit Q = cell->getPort("\\Q"); | ||||
| 						// Remove the $_DFF_* cell from what needs to be a combinatorial box
 | ||||
| 						it = holes_module->cells_.erase(it); | ||||
| 						Wire *port; | ||||
| 						if (GetSize(Q.wire) == 1) | ||||
| 							port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); | ||||
| 						else | ||||
| 							port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); | ||||
| 						log_assert(port); | ||||
| 						// Prepare to replace "assign <port> = $_DFF_*.Q;" with "assign <port> = $_DFF_*.D;"
 | ||||
| 						//   in order to extract just the combinatorial control logic that feeds the box
 | ||||
| 						//   (i.e. clock enable, synchronous reset, etc.)
 | ||||
| 						replace.insert(std::make_pair(Q,D)); | ||||
| 						// Since `flatten` above would have created wires named "<cell>.Q",
 | ||||
| 						//   extract the pre-techmap cell name
 | ||||
| 						auto pos = Q.wire->name.str().rfind("."); | ||||
| 						log_assert(pos != std::string::npos); | ||||
| 						IdString driver = Q.wire->name.substr(0, pos); | ||||
| 						// And drive the signal that was previously driven by "DFF.Q" (typically
 | ||||
| 						//   used to implement clock-enable functionality) with the "<cell>.abc9_ff.Q"
 | ||||
| 						//   wire (which itself is driven by an input port) we inserted above
 | ||||
| 						Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); | ||||
| 						log_assert(currQ); | ||||
| 						holes_module->connect(Q, currQ); | ||||
| 						continue; | ||||
| 					} | ||||
| 					else if (!cell->type.in("$_NOT_", "$_AND_")) | ||||
| 						log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); | ||||
| 					++it; | ||||
| 				} | ||||
| 
 | ||||
| 				for (auto &conn : holes_module->connections_) { | ||||
| 					auto it = replace.find(sigmap(conn.second)); | ||||
| 					if (it != replace.end()) | ||||
| 						conn.second = it->second; | ||||
| 				} | ||||
| 
 | ||||
| 				// Move into a new (temporary) design so that "clean" will only
 | ||||
| 				// operate (and run checks on) this one module
 | ||||
| 				RTLIL::Design *holes_design = new RTLIL::Design; | ||||
| 				module->design->modules_.erase(holes_module->name); | ||||
| 				holes_design->add(holes_module); | ||||
| 				Pass::call(holes_design, "opt -purge"); | ||||
| 
 | ||||
| 				std::stringstream a_buffer; | ||||
| 				XAigerWriter writer(holes_module, true /* holes_mode */); | ||||
| 				writer.write_aiger(a_buffer, false /*ascii_mode*/); | ||||
| 				delete holes_design; | ||||
| 
 | ||||
| 				f << "a"; | ||||
| 				std::string buffer_str = a_buffer.str(); | ||||
| 				int32_t buffer_size_be = to_big_endian(buffer_str.size()); | ||||
| 				f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); | ||||
| 				f.write(buffer_str.data(), buffer_str.size()); | ||||
| 
 | ||||
| 				log_pop(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -917,7 +770,8 @@ struct XAigerBackend : public Backend { | |||
| 		log("Write the top module (according to the (* top *) attribute or if only one module\n"); | ||||
| 		log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or"); | ||||
| 		log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); | ||||
| 		log("pseudo-outputs.\n"); | ||||
| 		log("pseudo-outputs. Whitebox contents will be taken from the '<module-name>$holes'\n"); | ||||
| 		log("module, if it exists.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -ascii\n"); | ||||
| 		log("        write ASCII version of AIGER format\n"); | ||||
|  |  | |||
|  | @ -326,7 +326,7 @@ struct EdifBackend : public Backend { | |||
| 				continue; | ||||
| 
 | ||||
| 			SigMap sigmap(module); | ||||
| 			std::map<RTLIL::SigSpec, std::set<std::string>> net_join_db; | ||||
| 			std::map<RTLIL::SigSpec, std::set<std::pair<std::string, bool>>> net_join_db; | ||||
| 
 | ||||
| 			*f << stringf("    (cell %s\n", EDIF_DEF(module->name)); | ||||
| 			*f << stringf("      (cellType GENERIC)\n"); | ||||
|  | @ -349,7 +349,7 @@ struct EdifBackend : public Backend { | |||
| 							add_prop(p.first, p.second); | ||||
| 					*f << ")\n"; | ||||
| 					RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire)); | ||||
| 					net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name))); | ||||
| 					net_join_db[sig].insert(make_pair(stringf("(portRef %s)", EDIF_REF(wire->name)), wire->port_input)); | ||||
| 				} else { | ||||
| 					int b[2]; | ||||
| 					b[wire->upto ? 0 : 1] = wire->start_offset; | ||||
|  | @ -362,7 +362,7 @@ struct EdifBackend : public Backend { | |||
| 					*f << ")\n"; | ||||
| 					for (int i = 0; i < wire->width; i++) { | ||||
| 						RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i)); | ||||
| 						net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1)); | ||||
| 						net_join_db[sig].insert(make_pair(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), GetSize(wire)-i-1), wire->port_input)); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | @ -391,7 +391,7 @@ struct EdifBackend : public Backend { | |||
| 							log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n", | ||||
| 									i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i])); | ||||
| 						else if (sig.size() == 1) | ||||
| 							net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name))); | ||||
| 							net_join_db[sig[i]].insert(make_pair(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)), cell->output(p.first))); | ||||
| 						else { | ||||
| 							int member_idx = GetSize(sig)-i-1; | ||||
| 							auto m = design->module(cell->type); | ||||
|  | @ -400,8 +400,8 @@ struct EdifBackend : public Backend { | |||
| 								if (w) | ||||
| 									member_idx = GetSize(w)-i-1; | ||||
| 							} | ||||
| 							net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", | ||||
| 									EDIF_REF(p.first), member_idx, EDIF_REF(cell->name))); | ||||
| 							net_join_db[sig[i]].insert(make_pair(stringf("(portRef (member %s %d) (instanceRef %s))", | ||||
| 									EDIF_REF(p.first), member_idx, EDIF_REF(cell->name)), cell->output(p.first))); | ||||
| 						} | ||||
| 				} | ||||
| 			} | ||||
|  | @ -410,11 +410,13 @@ struct EdifBackend : public Backend { | |||
| 				if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) { | ||||
| 					if (sig == RTLIL::State::Sx) { | ||||
| 						for (auto &ref : it.second) | ||||
| 							log_warning("Exporting x-bit on %s as zero bit.\n", ref.c_str()); | ||||
| 							log_warning("Exporting x-bit on %s as zero bit.\n", ref.first.c_str()); | ||||
| 						sig = RTLIL::State::S0; | ||||
| 					} else if (sig == RTLIL::State::Sz) { | ||||
| 						continue; | ||||
| 					} else { | ||||
| 						for (auto &ref : it.second) | ||||
| 							log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.c_str()); | ||||
| 							log_error("Don't know how to handle %s on %s.\n", log_signal(sig), ref.first.c_str()); | ||||
| 						log_abort(); | ||||
| 					} | ||||
| 				} | ||||
|  | @ -431,7 +433,7 @@ struct EdifBackend : public Backend { | |||
| 				} | ||||
| 				*f << stringf("          (net %s (joined\n", EDIF_DEF(netname)); | ||||
| 				for (auto &ref : it.second) | ||||
| 					*f << stringf("            %s\n", ref.c_str()); | ||||
| 					*f << stringf("            %s\n", ref.first.c_str()); | ||||
| 				if (sig.wire == NULL) { | ||||
| 					if (nogndvcc) | ||||
| 						log_error("Design contains constant nodes (map with \"hilomap\" first).\n"); | ||||
|  | @ -446,6 +448,31 @@ struct EdifBackend : public Backend { | |||
| 						add_prop(p.first, p.second); | ||||
| 				*f << stringf("\n          )\n"); | ||||
| 			} | ||||
| 			for (auto &wire_it : module->wires_) { | ||||
| 				RTLIL::Wire *wire = wire_it.second; | ||||
| 				if (!wire->get_bool_attribute(ID::keep)) | ||||
| 					continue; | ||||
| 				for(int i = 0; i < wire->width; i++) { | ||||
| 					SigBit raw_sig = RTLIL::SigSpec(wire, i); | ||||
| 					SigBit mapped_sig = sigmap(raw_sig); | ||||
| 					if (raw_sig == mapped_sig || net_join_db.count(mapped_sig) == 0) | ||||
| 						continue; | ||||
| 					std::string netname = log_signal(raw_sig); | ||||
| 					for (size_t i = 0; i < netname.size(); i++) | ||||
| 						if (netname[i] == ' ' || netname[i] == '\\') | ||||
| 							netname.erase(netname.begin() + i--); | ||||
| 					*f << stringf("          (net %s (joined\n", EDIF_DEF(netname)); | ||||
| 					auto &refs = net_join_db.at(mapped_sig); | ||||
| 					for (auto &ref : refs) | ||||
| 						if (ref.second) | ||||
| 							*f << stringf("            %s\n", ref.first.c_str()); | ||||
| 					*f << stringf("            )"); | ||||
| 					if (attr_properties && raw_sig.wire != NULL) | ||||
| 						for (auto &p : raw_sig.wire->attributes) | ||||
| 							add_prop(p.first, p.second); | ||||
| 					*f << stringf("\n          )\n"); | ||||
| 				} | ||||
| 			} | ||||
| 			*f << stringf("        )\n"); | ||||
| 			*f << stringf("      )\n"); | ||||
| 			*f << stringf("    )\n"); | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ struct JsonWriter | |||
| 	std::ostream &f; | ||||
| 	bool use_selection; | ||||
| 	bool aig_mode; | ||||
| 	bool compat_int_mode; | ||||
| 
 | ||||
| 	Design *design; | ||||
| 	Module *module; | ||||
|  | @ -42,8 +43,9 @@ struct JsonWriter | |||
| 	dict<SigBit, string> sigids; | ||||
| 	pool<Aig> aig_models; | ||||
| 
 | ||||
| 	JsonWriter(std::ostream &f, bool use_selection, bool aig_mode) : | ||||
| 			f(f), use_selection(use_selection), aig_mode(aig_mode) { } | ||||
| 	JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) : | ||||
| 			f(f), use_selection(use_selection), aig_mode(aig_mode), | ||||
| 			compat_int_mode(compat_int_mode) { } | ||||
| 
 | ||||
| 	string get_string(string str) | ||||
| 	{ | ||||
|  | @ -102,8 +104,7 @@ struct JsonWriter | |||
| 			if (state < 2) | ||||
| 				str += " "; | ||||
| 			f << get_string(str); | ||||
| 		} else | ||||
| 		if (GetSize(value) == 32 && value.is_fully_def()) { | ||||
| 		} else if (compat_int_mode && GetSize(value) == 32 && value.is_fully_def()) { | ||||
| 			if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) | ||||
| 				f << stringf("%d", value.as_int()); | ||||
| 			else | ||||
|  | @ -294,6 +295,10 @@ struct JsonBackend : public Backend { | |||
| 		log("    -aig\n"); | ||||
| 		log("        include AIG models for the different gate types\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -compat-int\n"); | ||||
| 		log("        emit 32-bit fully-defined parameter values directly\n"); | ||||
| 		log("        as JSON numbers (for compatibility with old parsers)\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("The general syntax of the JSON output created by this command is as follows:\n"); | ||||
| 		log("\n"); | ||||
|  | @ -368,10 +373,9 @@ struct JsonBackend : public Backend { | |||
| 		log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n"); | ||||
| 		log("\"z\" instead of a number.\n"); | ||||
| 		log("\n"); | ||||
| 		log("Numeric 32-bit parameter and attribute values are written as decimal values.\n"); | ||||
| 		log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n"); | ||||
| 		log("as string holding the binary representation of the value. Strings are written\n"); | ||||
| 		log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n"); | ||||
| 		log("Bit vectors (including integers) are written as string holding the binary"); | ||||
| 		log("representation of the value. Strings are written as strings, with an appended"); | ||||
| 		log("blank in cases of strings of the form /[01xz]* */.\n"); | ||||
| 		log("\n"); | ||||
| 		log("For example the following Verilog code:\n"); | ||||
| 		log("\n"); | ||||
|  | @ -495,6 +499,7 @@ struct JsonBackend : public Backend { | |||
| 	void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		bool aig_mode = false; | ||||
| 		bool compat_int_mode = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
|  | @ -503,13 +508,17 @@ struct JsonBackend : public Backend { | |||
| 				aig_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-compat-int") { | ||||
| 				compat_int_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(f, filename, args, argidx); | ||||
| 
 | ||||
| 		log_header(design, "Executing JSON backend.\n"); | ||||
| 
 | ||||
| 		JsonWriter json_writer(*f, false, aig_mode); | ||||
| 		JsonWriter json_writer(*f, false, aig_mode, compat_int_mode); | ||||
| 		json_writer.write_design(design); | ||||
| 	} | ||||
| } JsonBackend; | ||||
|  | @ -530,6 +539,10 @@ struct JsonPass : public Pass { | |||
| 		log("    -aig\n"); | ||||
| 		log("        also include AIG models for the different gate types\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -compat-int\n"); | ||||
| 		log("        emit 32-bit fully-defined parameter values directly\n"); | ||||
| 		log("        as JSON numbers (for compatibility with old parsers)\n"); | ||||
| 		log("\n"); | ||||
| 		log("See 'help write_json' for a description of the JSON format used.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
|  | @ -537,6 +550,7 @@ struct JsonPass : public Pass { | |||
| 	{ | ||||
| 		std::string filename; | ||||
| 		bool aig_mode = false; | ||||
| 		bool compat_int_mode = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
|  | @ -549,6 +563,10 @@ struct JsonPass : public Pass { | |||
| 				aig_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-compat-int") { | ||||
| 				compat_int_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
|  | @ -569,7 +587,7 @@ struct JsonPass : public Pass { | |||
| 			f = &buf; | ||||
| 		} | ||||
| 
 | ||||
| 		JsonWriter json_writer(*f, true, aig_mode); | ||||
| 		JsonWriter json_writer(*f, true, aig_mode, compat_int_mode); | ||||
| 		json_writer.write_design(design); | ||||
| 
 | ||||
| 		if (!filename.empty()) { | ||||
|  |  | |||
|  | @ -304,7 +304,11 @@ class SmtIo: | |||
| 
 | ||||
|     def p_open(self): | ||||
|         assert self.p is None | ||||
|         try: | ||||
|             self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | ||||
|         except FileNotFoundError: | ||||
|             print("%s SMT Solver '%s' not found in path." % (self.timestamp(), self.popen_vargs[0]), flush=True) | ||||
|             sys.exit(1) | ||||
|         running_solvers[self.p_index] = self.p | ||||
|         self.p_running = True | ||||
|         self.p_next = None | ||||
|  |  | |||
|  | @ -393,21 +393,6 @@ void AigerReader::parse_xaiger() | |||
| 	if (f.peek() == '\n') | ||||
| 		f.get(); | ||||
| 
 | ||||
| 	dict<int,IdString> box_lookup; | ||||
| 	for (auto m : design->modules()) { | ||||
| 		auto it = m->attributes.find(ID(abc9_box_id)); | ||||
| 		if (it == m->attributes.end()) | ||||
| 			continue; | ||||
| 		if (m->name.begins_with("$paramod")) | ||||
| 			continue; | ||||
| 		auto id = it->second.as_int(); | ||||
| 		auto r = box_lookup.insert(std::make_pair(id, m->name)); | ||||
| 		if (!r.second) | ||||
| 			log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", | ||||
| 					log_id(m), id, log_id(r.first->second)); | ||||
| 		log_assert(r.second); | ||||
| 	} | ||||
| 
 | ||||
| 	// Parse footer (symbol table, comments, etc.)
 | ||||
| 	std::string s; | ||||
| 	for (int c = f.get(); c != EOF; c = f.get()) { | ||||
|  | @ -429,17 +414,23 @@ void AigerReader::parse_xaiger() | |||
| 				for (unsigned j = 0; j < cutLeavesM; ++j) { | ||||
| 					nodeID = parse_xaiger_literal(f); | ||||
| 					log_debug2("\t%u\n", nodeID); | ||||
| 					if (nodeID == 0) { | ||||
| 						log_debug("\tLUT '$lut$aiger%d$%d' input %d is constant!\n", aiger_autoidx, rootNodeID, cutLeavesM); | ||||
| 						continue; | ||||
| 					} | ||||
| 					RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID)); | ||||
| 					log_assert(wire); | ||||
| 					input_sig.append(wire); | ||||
| 				} | ||||
| 				// Reverse input order as fastest input is returned first
 | ||||
| 				input_sig.reverse(); | ||||
| 				// TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
 | ||||
| 				ce.clear(); | ||||
| 				ce.compute_deps(output_sig, input_sig.to_sigbit_pool()); | ||||
| 				RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size()); | ||||
| 				for (int j = 0; j < (1 << cutLeavesM); ++j) { | ||||
| 				RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << GetSize(input_sig)); | ||||
| 				for (int j = 0; j < GetSize(lut_mask); ++j) { | ||||
| 					int gray = j ^ (j >> 1); | ||||
| 					ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)}); | ||||
| 					ce.set_incremental(input_sig, RTLIL::Const{gray, GetSize(input_sig)}); | ||||
| 					RTLIL::SigBit o(output_sig); | ||||
| 					bool success YS_ATTRIBUTE(unused) = ce.eval(o); | ||||
| 					log_assert(success); | ||||
|  | @ -453,11 +444,13 @@ void AigerReader::parse_xaiger() | |||
| 			} | ||||
| 		} | ||||
| 		else if (c == 'r') { | ||||
| 			uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); | ||||
| 			uint32_t dataSize = parse_xaiger_literal(f); | ||||
| 			flopNum = parse_xaiger_literal(f); | ||||
| 			log_debug("flopNum = %u\n", flopNum); | ||||
| 			log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); | ||||
| 			f.ignore(flopNum * sizeof(uint32_t)); | ||||
| 			mergeability.reserve(flopNum); | ||||
| 			for (unsigned i = 0; i < flopNum; i++) | ||||
| 				mergeability.emplace_back(parse_xaiger_literal(f)); | ||||
| 		} | ||||
| 		else if (c == 'n') { | ||||
| 			parse_xaiger_literal(f); | ||||
|  | @ -479,11 +472,15 @@ void AigerReader::parse_xaiger() | |||
| 			uint32_t boxNum = parse_xaiger_literal(f); | ||||
| 			log_debug("boxNum = %u\n", boxNum); | ||||
| 			for (unsigned i = 0; i < boxNum; i++) { | ||||
| 				f.ignore(2*sizeof(uint32_t)); | ||||
| 				uint32_t boxInputs = parse_xaiger_literal(f); | ||||
| 				uint32_t boxOutputs = parse_xaiger_literal(f); | ||||
| 				uint32_t boxUniqueId = parse_xaiger_literal(f); | ||||
| 				log_assert(boxUniqueId > 0); | ||||
| 				uint32_t oldBoxNum = parse_xaiger_literal(f); | ||||
| 				RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), box_lookup.at(boxUniqueId)); | ||||
| 				RTLIL::Cell* cell = module->addCell(stringf("$box%u", oldBoxNum), stringf("$__boxid%u", boxUniqueId)); | ||||
| 				cell->setPort("\\i", SigSpec(State::S0, boxInputs)); | ||||
| 				cell->setPort("\\o", SigSpec(State::S0, boxOutputs)); | ||||
| 				cell->attributes["\\abc9_box_seq"] = oldBoxNum; | ||||
| 				boxes.emplace_back(cell); | ||||
| 			} | ||||
| 		} | ||||
|  | @ -568,25 +565,18 @@ void AigerReader::parse_aiger_ascii() | |||
| 	} | ||||
| 
 | ||||
| 	// Parse outputs
 | ||||
| 	digits = ceil(log10(O)); | ||||
| 	for (unsigned i = 0; i < O; ++i, ++line_count) { | ||||
| 		if (!(f >> l1)) | ||||
| 			log_error("Line %u cannot be interpreted as an output!\n", line_count); | ||||
| 
 | ||||
| 		log_debug2("%d is an output\n", l1); | ||||
| 		const unsigned variable = l1 >> 1; | ||||
| 		const bool invert = l1 & 1; | ||||
| 		RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
 | ||||
| 		RTLIL::Wire *wire = module->wire(wire_name); | ||||
| 		if (!wire) | ||||
| 			wire = createWireIfNotExists(module, l1); | ||||
| 		else if (wire->port_input || wire->port_output) { | ||||
| 			RTLIL::Wire *new_wire = module->addWire(NEW_ID); | ||||
| 			module->connect(new_wire, wire); | ||||
| 			wire = new_wire; | ||||
| 		} | ||||
| 		RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i)); | ||||
| 		wire->port_output = true; | ||||
| 		module->connect(wire, createWireIfNotExists(module, l1)); | ||||
| 		outputs.push_back(wire); | ||||
| 	} | ||||
| 	//std::getline(f, line); // Ignore up to start of next line
 | ||||
| 
 | ||||
| 	// Parse bad properties
 | ||||
| 	for (unsigned i = 0; i < B; ++i, ++line_count) { | ||||
|  | @ -598,6 +588,8 @@ void AigerReader::parse_aiger_ascii() | |||
| 		wire->port_output = true; | ||||
| 		bad_properties.push_back(wire); | ||||
| 	} | ||||
| 	//if (B > 0)
 | ||||
| 	//	std::getline(f, line); // Ignore up to start of next line
 | ||||
| 
 | ||||
| 	// TODO: Parse invariant constraints
 | ||||
| 	for (unsigned i = 0; i < C; ++i, ++line_count) | ||||
|  | @ -753,74 +745,33 @@ void AigerReader::parse_aiger_binary() | |||
| 
 | ||||
| void AigerReader::post_process() | ||||
| { | ||||
| 	dict<IdString, std::vector<IdString>> box_ports; | ||||
| 	unsigned ci_count = 0, co_count = 0, flop_count = 0; | ||||
| 	unsigned ci_count = 0, co_count = 0; | ||||
| 	for (auto cell : boxes) { | ||||
| 		RTLIL::Module* box_module = design->module(cell->type); | ||||
| 		log_assert(box_module); | ||||
| 
 | ||||
| 		auto r = box_ports.insert(cell->type); | ||||
| 		if (r.second) { | ||||
| 			// Make carry in the last PI, and carry out the last PO
 | ||||
| 			//   since ABC requires it this way
 | ||||
| 			IdString carry_in, carry_out; | ||||
| 			for (const auto &port_name : box_module->ports) { | ||||
| 				auto w = box_module->wire(port_name); | ||||
| 				log_assert(w); | ||||
| 				if (w->get_bool_attribute("\\abc9_carry")) { | ||||
| 					if (w->port_input) | ||||
| 						carry_in = port_name; | ||||
| 					if (w->port_output) | ||||
| 						carry_out = port_name; | ||||
| 				} | ||||
| 				else | ||||
| 					r.first->second.push_back(port_name); | ||||
| 			} | ||||
| 			if (carry_in != IdString()) { | ||||
| 				log_assert(carry_out != IdString()); | ||||
| 				r.first->second.push_back(carry_in); | ||||
| 				r.first->second.push_back(carry_out); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto port_name : box_ports.at(cell->type)) { | ||||
| 			RTLIL::Wire* port = box_module->wire(port_name); | ||||
| 			log_assert(port); | ||||
| 			RTLIL::SigSpec rhs; | ||||
| 			for (int i = 0; i < GetSize(port); i++) { | ||||
| 				RTLIL::Wire* wire = nullptr; | ||||
| 				if (port->port_input) { | ||||
| 		for (auto &bit : cell->connections_.at("\\i")) { | ||||
| 			log_assert(bit == State::S0); | ||||
| 			log_assert(co_count < outputs.size()); | ||||
| 					wire = outputs[co_count++]; | ||||
| 					log_assert(wire); | ||||
| 					log_assert(wire->port_output); | ||||
| 					wire->port_output = false; | ||||
| 			bit = outputs[co_count++]; | ||||
| 			log_assert(bit.wire && GetSize(bit.wire) == 1); | ||||
| 			log_assert(bit.wire->port_output); | ||||
| 			bit.wire->port_output = false; | ||||
| 		} | ||||
| 				if (port->port_output) { | ||||
| 		for (auto &bit : cell->connections_.at("\\o")) { | ||||
| 			log_assert(bit == State::S0); | ||||
| 			log_assert((piNum + ci_count) < inputs.size()); | ||||
| 					wire = inputs[piNum + ci_count++]; | ||||
| 					log_assert(wire); | ||||
| 					log_assert(wire->port_input); | ||||
| 					wire->port_input = false; | ||||
| 			bit = inputs[piNum + ci_count++]; | ||||
| 			log_assert(bit.wire && GetSize(bit.wire) == 1); | ||||
| 			log_assert(bit.wire->port_input); | ||||
| 			bit.wire->port_input = false; | ||||
| 		} | ||||
| 				rhs.append(wire); | ||||
| 			} | ||||
| 			cell->setPort(port_name, rhs); | ||||
| 	} | ||||
| 
 | ||||
| 		if (box_module->attributes.count("\\abc9_flop")) { | ||||
| 			log_assert(co_count < outputs.size()); | ||||
| 			Wire *wire = outputs[co_count++]; | ||||
| 			log_assert(wire); | ||||
| 			log_assert(wire->port_output); | ||||
| 			wire->port_output = false; | ||||
| 
 | ||||
| 			RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count]; | ||||
| 	for (uint32_t i = 0; i < flopNum; i++) { | ||||
| 		RTLIL::Wire *d = outputs[outputs.size() - flopNum + i]; | ||||
| 		log_assert(d); | ||||
| 		log_assert(d->port_output); | ||||
| 		d->port_output = false; | ||||
| 
 | ||||
| 			RTLIL::Wire *q = inputs[piNum - flopNum + flop_count]; | ||||
| 		RTLIL::Wire *q = inputs[piNum - flopNum + i]; | ||||
| 		log_assert(q); | ||||
| 		log_assert(q->port_input); | ||||
| 		q->port_input = false; | ||||
|  | @ -828,9 +779,7 @@ void AigerReader::post_process() | |||
| 		auto ff = module->addCell(NEW_ID, "$__ABC9_FF_"); | ||||
| 		ff->setPort("\\D", d); | ||||
| 		ff->setPort("\\Q", q); | ||||
| 			flop_count++; | ||||
| 			continue; | ||||
| 		} | ||||
| 		ff->attributes["\\abc9_mergeability"] = mergeability[i]; | ||||
| 	} | ||||
| 
 | ||||
| 	dict<RTLIL::IdString, int> wideports_cache; | ||||
|  | @ -859,6 +808,7 @@ void AigerReader::post_process() | |||
| 						wire->port_input = false; | ||||
| 						module->connect(wire, existing); | ||||
| 					} | ||||
| 					log_debug(" -> %s\n", log_id(escaped_s)); | ||||
| 				} | ||||
| 				else if (index > 0) { | ||||
| 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | ||||
|  | @ -872,18 +822,14 @@ void AigerReader::post_process() | |||
| 						module->connect(wire, existing); | ||||
| 						wire->port_input = false; | ||||
| 					} | ||||
| 					log_debug(" -> %s\n", log_id(indexed_name)); | ||||
| 				} | ||||
| 				log_debug(" -> %s\n", log_id(wire)); | ||||
| 			} | ||||
| 			else if (type == "output") { | ||||
| 				log_assert(static_cast<unsigned>(variable + co_count) < outputs.size()); | ||||
| 				RTLIL::Wire* wire = outputs[variable + co_count]; | ||||
| 				log_assert(wire); | ||||
| 				log_assert(wire->port_output); | ||||
| 				if (escaped_s == "$__dummy__") { | ||||
| 					wire->port_output = false; | ||||
| 					continue; | ||||
| 				} | ||||
| 				log_debug("Renaming output %s", log_id(wire)); | ||||
| 
 | ||||
| 				if (index == 0) { | ||||
|  | @ -896,9 +842,11 @@ void AigerReader::post_process() | |||
| 					} | ||||
| 					else { | ||||
| 						wire->port_output = false; | ||||
| 						existing->port_output = true; | ||||
| 						module->connect(wire, existing); | ||||
| 						wire = existing; | ||||
| 					} | ||||
| 					log_debug(" -> %s\n", log_id(escaped_s)); | ||||
| 				} | ||||
| 				else if (index > 0) { | ||||
| 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | ||||
|  | @ -909,11 +857,12 @@ void AigerReader::post_process() | |||
| 							wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); | ||||
| 					} | ||||
| 					else { | ||||
| 						module->connect(wire, existing); | ||||
| 						wire->port_output = false; | ||||
| 						existing->port_output = true; | ||||
| 						module->connect(wire, existing); | ||||
| 					} | ||||
| 					log_debug(" -> %s\n", log_id(indexed_name)); | ||||
| 				} | ||||
| 				log_debug(" -> %s\n", log_id(wire)); | ||||
| 				int init; | ||||
| 				mf >> init; | ||||
| 				if (init < 2) | ||||
|  | @ -921,26 +870,8 @@ void AigerReader::post_process() | |||
| 			} | ||||
| 			else if (type == "box") { | ||||
| 				RTLIL::Cell* cell = module->cell(stringf("$box%d", variable)); | ||||
| 				if (cell) { // ABC could have optimised this box away
 | ||||
| 				if (cell) // ABC could have optimised this box away
 | ||||
| 					module->rename(cell, escaped_s); | ||||
| 					for (const auto &i : cell->connections()) { | ||||
| 						RTLIL::IdString port_name = i.first; | ||||
| 						RTLIL::SigSpec rhs = i.second; | ||||
| 						int index = 0; | ||||
| 						for (auto bit : rhs.bits()) { | ||||
| 							RTLIL::Wire* wire = bit.wire; | ||||
| 							RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name))); | ||||
| 							if (index == 0) | ||||
| 								module->rename(wire, escaped_s); | ||||
| 							else if (index > 0) { | ||||
| 								module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index)); | ||||
| 								if (wideports) | ||||
| 									wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); | ||||
| 							} | ||||
| 							index++; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 				log_error("Symbol type '%s' not recognised.\n", type.c_str()); | ||||
|  | @ -1018,18 +949,21 @@ struct AigerFrontend : public Frontend { | |||
| 		log("Load module from an AIGER file into the current design.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -module_name <module_name>\n"); | ||||
| 		log("        Name of module to be created (default: <filename>)\n"); | ||||
| 		log("        name of module to be created (default: <filename>)\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -clk_name <wire_name>\n"); | ||||
| 		log("        If specified, AIGER latches to be transformed into $_DFF_P_ cells\n"); | ||||
| 		log("        clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n"); | ||||
| 		log("        if specified, AIGER latches to be transformed into $_DFF_P_ cells\n"); | ||||
| 		log("        clocked by wire of this name. otherwise, $_FF_ cells will be used\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -map <filename>\n"); | ||||
| 		log("        read file with port and latch symbols\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -wideports\n"); | ||||
| 		log("        Merge ports that match the pattern 'name[int]' into a single\n"); | ||||
| 		log("        multi-bit port 'name'.\n"); | ||||
| 		log("        merge ports that match the pattern 'name[int]' into a single\n"); | ||||
| 		log("        multi-bit port 'name'\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -xaiger\n"); | ||||
| 		log("        read XAIGER extensions\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
|  | @ -1039,7 +973,7 @@ struct AigerFrontend : public Frontend { | |||
| 		RTLIL::IdString clk_name; | ||||
| 		RTLIL::IdString module_name; | ||||
| 		std::string map_filename; | ||||
| 		bool wideports = false; | ||||
| 		bool wideports = false, xaiger = false; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||
|  | @ -1060,6 +994,10 @@ struct AigerFrontend : public Frontend { | |||
| 				wideports = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-xaiger") { | ||||
| 				xaiger = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(f, filename, args, argidx, true); | ||||
|  | @ -1079,6 +1017,9 @@ struct AigerFrontend : public Frontend { | |||
| 		} | ||||
| 
 | ||||
| 		AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports); | ||||
| 		if (xaiger) | ||||
| 			reader.parse_xaiger(); | ||||
| 		else | ||||
| 			reader.parse_aiger(); | ||||
| 	} | ||||
| } AigerFrontend; | ||||
|  |  | |||
|  | @ -45,6 +45,7 @@ struct AigerReader | |||
|     std::vector<RTLIL::Wire*> outputs; | ||||
|     std::vector<RTLIL::Wire*> bad_properties; | ||||
|     std::vector<RTLIL::Cell*> boxes; | ||||
|     std::vector<int> mergeability; | ||||
| 
 | ||||
|     AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); | ||||
|     void parse_aiger(); | ||||
|  |  | |||
|  | @ -244,6 +244,7 @@ namespace AST | |||
| 		void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall); | ||||
| 		AstNode *eval_const_function(AstNode *fcall); | ||||
| 		bool is_simple_const_expr(); | ||||
| 		std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint); | ||||
| 
 | ||||
| 		// create a human-readable text representation of the AST (for debugging)
 | ||||
| 		void dumpAst(FILE *f, std::string indent) const; | ||||
|  |  | |||
|  | @ -41,6 +41,103 @@ YOSYS_NAMESPACE_BEGIN | |||
| using namespace AST; | ||||
| using namespace AST_INTERNAL; | ||||
| 
 | ||||
| // Process a format string and arguments for $display, $write, $sprintf, etc
 | ||||
| 
 | ||||
| std::string AstNode::process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint) { | ||||
| 	// Other arguments are placeholders. Process the string as we go through it
 | ||||
| 	std::string sout; | ||||
| 	for (size_t i = 0; i < sformat.length(); i++) | ||||
| 	{ | ||||
| 		// format specifier
 | ||||
| 		if (sformat[i] == '%') | ||||
| 		{ | ||||
| 			// If there's no next character, that's a problem
 | ||||
| 			if (i+1 >= sformat.length()) | ||||
| 				log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str()); | ||||
| 
 | ||||
| 			char cformat = sformat[++i]; | ||||
| 
 | ||||
| 			// %% is special, does not need a matching argument
 | ||||
| 			if (cformat == '%') | ||||
| 			{ | ||||
| 				sout += '%'; | ||||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| 			// Simplify the argument
 | ||||
| 			AstNode *node_arg = nullptr; | ||||
| 
 | ||||
| 			// Everything from here on depends on the format specifier
 | ||||
| 			switch (cformat) | ||||
| 			{ | ||||
| 				case 's': | ||||
| 				case 'S': | ||||
| 				case 'd': | ||||
| 				case 'D': | ||||
| 				case 'x': | ||||
| 				case 'X': | ||||
| 					if (next_arg >= GetSize(children)) | ||||
| 						log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", | ||||
| 								cformat, str.c_str()); | ||||
| 
 | ||||
| 					node_arg = children[next_arg++]; | ||||
| 					while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||
| 					if (node_arg->type != AST_CONSTANT) | ||||
| 						log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); | ||||
| 					break; | ||||
| 
 | ||||
| 				case 'm': | ||||
| 				case 'M': | ||||
| 					break; | ||||
| 
 | ||||
| 				default: | ||||
| 					log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); | ||||
| 					break; | ||||
| 			} | ||||
| 
 | ||||
| 			switch (cformat) | ||||
| 			{ | ||||
| 				case 's': | ||||
| 				case 'S': | ||||
| 					sout += node_arg->bitsAsConst().decode_string(); | ||||
| 					break; | ||||
| 
 | ||||
| 				case 'd': | ||||
| 				case 'D': | ||||
| 					{ | ||||
| 						char tmp[128]; | ||||
| 						snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int()); | ||||
| 						sout += tmp; | ||||
| 					} | ||||
| 					break; | ||||
| 
 | ||||
| 				case 'x': | ||||
| 				case 'X': | ||||
| 					{ | ||||
| 						char tmp[128]; | ||||
| 						snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int()); | ||||
| 						sout += tmp; | ||||
| 					} | ||||
| 					break; | ||||
| 
 | ||||
| 				case 'm': | ||||
| 				case 'M': | ||||
| 					sout += log_id(current_module->name); | ||||
| 					break; | ||||
| 
 | ||||
| 				default: | ||||
| 					log_abort(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// not a format specifier
 | ||||
| 		else | ||||
| 			sout += sformat[i]; | ||||
| 	} | ||||
| 	return sout; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // convert the AST into a simpler AST that has all parameters substituted by their
 | ||||
| // values, unrolled for-loops, expanded generate blocks, etc. when this function
 | ||||
| // is done with an AST it can be converted into RTLIL using genRTLIL().
 | ||||
|  | @ -216,99 +313,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | |||
| 		if (node_string->type != AST_CONSTANT) | ||||
| 			log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); | ||||
| 		std::string sformat = node_string->bitsAsConst().decode_string(); | ||||
| 
 | ||||
| 		// Other arguments are placeholders. Process the string as we go through it
 | ||||
| 		std::string sout; | ||||
| 		int next_arg = 1; | ||||
| 		for (size_t i = 0; i < sformat.length(); i++) | ||||
| 		{ | ||||
| 			// format specifier
 | ||||
| 			if (sformat[i] == '%') | ||||
| 			{ | ||||
| 				// If there's no next character, that's a problem
 | ||||
| 				if (i+1 >= sformat.length()) | ||||
| 					log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str()); | ||||
| 
 | ||||
| 				char cformat = sformat[++i]; | ||||
| 
 | ||||
| 				// %% is special, does not need a matching argument
 | ||||
| 				if (cformat == '%') | ||||
| 				{ | ||||
| 					sout += '%'; | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				// Simplify the argument
 | ||||
| 				AstNode *node_arg = nullptr; | ||||
| 
 | ||||
| 				// Everything from here on depends on the format specifier
 | ||||
| 				switch (cformat) | ||||
| 				{ | ||||
| 					case 's': | ||||
| 					case 'S': | ||||
| 					case 'd': | ||||
| 					case 'D': | ||||
| 					case 'x': | ||||
| 					case 'X': | ||||
| 						if (next_arg >= GetSize(children)) | ||||
| 							log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", | ||||
| 									cformat, str.c_str()); | ||||
| 
 | ||||
| 						node_arg = children[next_arg++]; | ||||
| 						while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||
| 						if (node_arg->type != AST_CONSTANT) | ||||
| 							log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); | ||||
| 						break; | ||||
| 
 | ||||
| 					case 'm': | ||||
| 					case 'M': | ||||
| 						break; | ||||
| 
 | ||||
| 					default: | ||||
| 						log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); | ||||
| 						break; | ||||
| 				} | ||||
| 
 | ||||
| 				switch (cformat) | ||||
| 				{ | ||||
| 					case 's': | ||||
| 					case 'S': | ||||
| 						sout += node_arg->bitsAsConst().decode_string(); | ||||
| 						break; | ||||
| 
 | ||||
| 					case 'd': | ||||
| 					case 'D': | ||||
| 						{ | ||||
| 							char tmp[128]; | ||||
| 							snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int()); | ||||
| 							sout += tmp; | ||||
| 						} | ||||
| 						break; | ||||
| 
 | ||||
| 					case 'x': | ||||
| 					case 'X': | ||||
| 						{ | ||||
| 							char tmp[128]; | ||||
| 							snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int()); | ||||
| 							sout += tmp; | ||||
| 						} | ||||
| 						break; | ||||
| 
 | ||||
| 					case 'm': | ||||
| 					case 'M': | ||||
| 						sout += log_id(current_module->name); | ||||
| 						break; | ||||
| 
 | ||||
| 					default: | ||||
| 						log_abort(); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// not a format specifier
 | ||||
| 			else | ||||
| 				sout += sformat[i]; | ||||
| 		} | ||||
| 
 | ||||
| 		std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); | ||||
| 		// Finally, print the message (only include a \n for $display, not for $write)
 | ||||
| 		log("%s", sout.c_str()); | ||||
| 		if (str == "$display") | ||||
|  | @ -2244,6 +2249,17 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 				goto apply_newNode; | ||||
| 			} | ||||
| 
 | ||||
| 			if (str == "\\$sformatf") { | ||||
| 				AstNode *node_string = children[0]; | ||||
| 				while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } | ||||
| 				if (node_string->type != AST_CONSTANT) | ||||
| 					log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); | ||||
| 				std::string sformat = node_string->bitsAsConst().decode_string(); | ||||
| 				std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); | ||||
| 				newNode = AstNode::mkconst_str(sout); | ||||
| 				goto apply_newNode; | ||||
| 			} | ||||
| 
 | ||||
| 			if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION) | ||||
| 			{ | ||||
| 				AstNode *dpi_decl = current_scope[str]; | ||||
|  |  | |||
|  | @ -539,6 +539,14 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr | |||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (inst->Type() == OPER_REDUCE_NAND) { | ||||
| 		Wire *tmp = module->addWire(NEW_ID); | ||||
| 		cell = module->addReduceAnd(inst_name, IN, tmp, SIGNED); | ||||
| 		module->addNot(NEW_ID, tmp, net_map_at(inst->GetOutput())); | ||||
| 		import_attributes(cell->attributes, inst); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (inst->Type() == OPER_REDUCE_OR) { | ||||
| 		cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); | ||||
| 		import_attributes(cell->attributes, inst); | ||||
|  | @ -1891,6 +1899,9 @@ void verific_import(Design *design, const std::map<std::string,std::string> &par | |||
| 	if (!verific_error_msg.empty()) | ||||
| 		log_error("%s\n", verific_error_msg.c_str()); | ||||
| 
 | ||||
| 	for (auto nl : nl_todo) | ||||
| 	    nl->ChangePortBusStructures(1 /* hierarchical */); | ||||
| 
 | ||||
| 	VerificExtNets worker; | ||||
| 	for (auto nl : nl_todo) | ||||
| 		worker.run(nl); | ||||
|  | @ -2408,7 +2419,7 @@ struct VerificPass : public Pass { | |||
| 			else | ||||
| 			{ | ||||
| 				if (argidx == GetSize(args)) | ||||
| 					log_cmd_error("No top module specified.\n"); | ||||
| 					cmd_error(args, argidx, "No top module specified.\n"); | ||||
| 
 | ||||
| 				Array veri_modules, vhdl_units; | ||||
| 				for (; argidx < GetSize(args); argidx++) | ||||
|  | @ -2470,6 +2481,9 @@ struct VerificPass : public Pass { | |||
| 					worker.run(nl); | ||||
| 			} | ||||
| 
 | ||||
| 			for (auto nl : nl_todo) | ||||
| 				nl->ChangePortBusStructures(1 /* hierarchical */); | ||||
| 
 | ||||
| 			if (!dumpfile.empty()) { | ||||
| 				VeriWrite veri_writer; | ||||
| 				veri_writer.WriteFile(dumpfile.c_str(), Netlist::PresentDesign()); | ||||
|  | @ -2495,7 +2509,7 @@ struct VerificPass : public Pass { | |||
| 			goto check_error; | ||||
| 		} | ||||
| 
 | ||||
| 		log_cmd_error("Missing or unsupported mode parameter.\n"); | ||||
| 		cmd_error(args, argidx, "Missing or unsupported mode parameter.\n"); | ||||
| 
 | ||||
| 	check_error: | ||||
| 		if (!verific_error_msg.empty()) | ||||
|  | @ -2568,14 +2582,14 @@ struct ReadPass : public Pass { | |||
| 		static bool use_verific = verific_available; | ||||
| 
 | ||||
| 		if (args.size() < 2 || args[1][0] != '-') | ||||
| 			log_cmd_error("Missing mode parameter.\n"); | ||||
| 			cmd_error(args, 1, "Missing mode parameter.\n"); | ||||
| 
 | ||||
| 		if (args[1] == "-verific" || args[1] == "-noverific") { | ||||
| 			if (args.size() != 2) | ||||
| 				log_cmd_error("Additional arguments to -verific/-noverific.\n"); | ||||
| 				cmd_error(args, 1, "Additional arguments to -verific/-noverific.\n"); | ||||
| 			if (args[1] == "-verific") { | ||||
| 				if (!verific_available) | ||||
| 					log_cmd_error("This version of Yosys is built without Verific support.\n"); | ||||
| 					cmd_error(args, 1, "This version of Yosys is built without Verific support.\n"); | ||||
| 				use_verific = true; | ||||
| 			} else { | ||||
| 				use_verific = false; | ||||
|  | @ -2584,7 +2598,7 @@ struct ReadPass : public Pass { | |||
| 		} | ||||
| 
 | ||||
| 		if (args.size() < 3) | ||||
| 			log_cmd_error("Missing file name parameter.\n"); | ||||
| 			cmd_error(args, 3, "Missing file name parameter.\n"); | ||||
| 
 | ||||
| 		if (args[1] == "-vlog95" || args[1] == "-vlog2k") { | ||||
| 			if (use_verific) { | ||||
|  | @ -2616,7 +2630,7 @@ struct ReadPass : public Pass { | |||
| 				args[0] = "verific"; | ||||
| 				Pass::call(design, args); | ||||
| 			} else { | ||||
| 				log_cmd_error("This version of Yosys is built without Verific support.\n"); | ||||
| 				cmd_error(args, 1, "This version of Yosys is built without Verific support.\n"); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
|  | @ -2663,7 +2677,7 @@ struct ReadPass : public Pass { | |||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		log_cmd_error("Missing or unsupported mode parameter.\n"); | ||||
| 		cmd_error(args, 1, "Missing or unsupported mode parameter.\n"); | ||||
| 	} | ||||
| } ReadPass; | ||||
| 
 | ||||
|  |  | |||
|  | @ -431,6 +431,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { | |||
| "+:" { return TOK_POS_INDEXED; } | ||||
| "-:" { return TOK_NEG_INDEXED; } | ||||
| 
 | ||||
| ".*" { return TOK_WILDCARD_CONNECT; } | ||||
| 
 | ||||
| [-+]?[=*]> { | ||||
| 	if (!specify_mode) REJECT; | ||||
| 	frontend_verilog_yylval.string = new std::string(yytext); | ||||
|  |  | |||
|  | @ -138,7 +138,7 @@ struct specify_rise_fall { | |||
| %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END | ||||
| %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM | ||||
| %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP | ||||
| %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR | ||||
| %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT | ||||
| %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC | ||||
| %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL | ||||
| %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH | ||||
|  | @ -1580,6 +1580,11 @@ cell_port: | |||
| 		node->children.back()->str = *$3; | ||||
| 		delete $3; | ||||
| 		free_attr($1); | ||||
| 	} | | ||||
| 	attr TOK_WILDCARD_CONNECT { | ||||
| 		if (!sv_mode) | ||||
| 			frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); | ||||
| 		astbuf2->attributes[ID(wildcard_port_conns)] = AstNode::mkconst_int(1, false); | ||||
| 	}; | ||||
| 
 | ||||
| always_comb_or_latch: | ||||
|  |  | |||
|  | @ -295,6 +295,9 @@ int main(int argc, char **argv) | |||
| 		printf("    -E <depsfile>\n"); | ||||
| 		printf("        write a Makefile dependencies file with in- and output file names\n"); | ||||
| 		printf("\n"); | ||||
| 		printf("    -x <feature>\n"); | ||||
| 		printf("        do not print warnings for the specified experimental feature\n"); | ||||
| 		printf("\n"); | ||||
| 		printf("    -g\n"); | ||||
| 		printf("        globally enable debug log messages\n"); | ||||
| 		printf("\n"); | ||||
|  | @ -317,8 +320,14 @@ int main(int argc, char **argv) | |||
| 		exit(0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (argc == 2 && (!strcmp(argv[1], "-V") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version"))) | ||||
| 	{ | ||||
| 		printf("%s\n", yosys_version_str); | ||||
| 		exit(0); | ||||
| 	} | ||||
| 
 | ||||
| 	int opt; | ||||
| 	while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) | ||||
| 	while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:x:")) != -1) | ||||
| 	{ | ||||
| 		switch (opt) | ||||
| 		{ | ||||
|  | @ -449,6 +458,9 @@ int main(int argc, char **argv) | |||
| 		case 'E': | ||||
| 			depsfile = optarg; | ||||
| 			break; | ||||
| 		case 'x': | ||||
| 			log_experimentals_ignored.insert(optarg); | ||||
| 			break; | ||||
| 		default: | ||||
| 			fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); | ||||
| 			exit(1); | ||||
|  | @ -561,6 +573,10 @@ int main(int argc, char **argv) | |||
| 
 | ||||
| 		if (log_warnings_count) | ||||
| 			log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), log_warnings_count); | ||||
| 
 | ||||
| 		if (!log_experimentals.empty()) | ||||
| 			log("Warnings: %d experimental features used (not excluded with -x).\n", GetSize(log_experimentals)); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| 		log("End of script. Logfile hash: %s\n", hash.c_str()); | ||||
| #else | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ std::vector<FILE*> log_files; | |||
| std::vector<std::ostream*> log_streams; | ||||
| std::map<std::string, std::set<std::string>> log_hdump; | ||||
| std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; | ||||
| std::set<std::string> log_warnings; | ||||
| std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; | ||||
| int log_warnings_count = 0; | ||||
| bool log_hdump_all = false; | ||||
| FILE *log_errfile = NULL; | ||||
|  | @ -377,6 +377,19 @@ void log_warning(const char *format, ...) | |||
| 	va_end(ap); | ||||
| } | ||||
| 
 | ||||
| void log_experimental(const char *format, ...) | ||||
| { | ||||
| 	va_list ap; | ||||
| 	va_start(ap, format); | ||||
| 	string s = vstringf(format, ap); | ||||
| 	va_end(ap); | ||||
| 
 | ||||
| 	if (log_experimentals_ignored.count(s) == 0 && log_experimentals.count(s) == 0) { | ||||
| 		log_warning("Feature '%s' is experimental.\n", s.c_str()); | ||||
| 		log_experimentals.insert(s); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void log_warning_noprefix(const char *format, ...) | ||||
| { | ||||
| 	va_list ap; | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ extern std::vector<FILE*> log_files; | |||
| extern std::vector<std::ostream*> log_streams; | ||||
| extern std::map<std::string, std::set<std::string>> log_hdump; | ||||
| extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; | ||||
| extern std::set<std::string> log_warnings; | ||||
| extern std::set<std::string> log_warnings, log_experimentals, log_experimentals_ignored; | ||||
| extern int log_warnings_count; | ||||
| extern bool log_hdump_all; | ||||
| extern FILE *log_errfile; | ||||
|  | @ -77,6 +77,7 @@ YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noretur | |||
| void log(const char *format, ...)  YS_ATTRIBUTE(format(printf, 1, 2)); | ||||
| void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); | ||||
| void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); | ||||
| void log_experimental(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); | ||||
| 
 | ||||
| // Log with filename to report a problem in a source file.
 | ||||
| void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4)); | ||||
|  |  | |||
|  | @ -304,6 +304,9 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args) | |||
| 	if (pass_register.count(args[0]) == 0) | ||||
| 		log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str()); | ||||
| 
 | ||||
| 	if (pass_register[args[0]]->experimental_flag) | ||||
| 		log_experimental("%s", args[0].c_str()); | ||||
| 
 | ||||
| 	size_t orig_sel_stack_pos = design->selection_stack.size(); | ||||
| 	auto state = pass_register[args[0]]->pre_execute(); | ||||
| 	pass_register[args[0]]->execute(args, design); | ||||
|  | @ -824,6 +827,11 @@ struct HelpPass : public Pass { | |||
| 						log("="); | ||||
| 					log("\n"); | ||||
| 					it.second->help(); | ||||
| 					if (it.second->experimental_flag) { | ||||
| 						log("\n"); | ||||
| 						log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); | ||||
| 						log("\n"); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if (args[1] == "-cells") { | ||||
|  | @ -846,6 +854,11 @@ struct HelpPass : public Pass { | |||
| 					std::ostringstream buf; | ||||
| 					log_streams.push_back(&buf); | ||||
| 					it.second->help(); | ||||
| 					if (it.second->experimental_flag) { | ||||
| 						log("\n"); | ||||
| 						log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); | ||||
| 						log("\n"); | ||||
| 					} | ||||
| 					log_streams.pop_back(); | ||||
| 					write_tex(f, it.first, it.second->short_help, buf.str()); | ||||
| 				} | ||||
|  | @ -858,6 +871,11 @@ struct HelpPass : public Pass { | |||
| 					std::ostringstream buf; | ||||
| 					log_streams.push_back(&buf); | ||||
| 					it.second->help(); | ||||
| 					if (it.second->experimental_flag) { | ||||
| 						log("\n"); | ||||
| 						log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str()); | ||||
| 						log("\n"); | ||||
| 					} | ||||
| 					log_streams.pop_back(); | ||||
| 					write_html(f, it.first, it.second->short_help, buf.str()); | ||||
| 				} | ||||
|  | @ -865,6 +883,11 @@ struct HelpPass : public Pass { | |||
| 			} | ||||
| 			else if (pass_register.count(args[1])) { | ||||
| 				pass_register.at(args[1])->help(); | ||||
| 				if (pass_register.at(args[1])->experimental_flag) { | ||||
| 					log("\n"); | ||||
| 					log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", args[1].c_str()); | ||||
| 					log("\n"); | ||||
| 				} | ||||
| 			} | ||||
| 			else if (cell_help_messages.cell_help.count(args[1])) { | ||||
| 				log("%s", cell_help_messages.cell_help.at(args[1]).c_str()); | ||||
|  |  | |||
|  | @ -36,6 +36,11 @@ struct Pass | |||
| 
 | ||||
| 	int call_counter; | ||||
| 	int64_t runtime_ns; | ||||
| 	bool experimental_flag = false; | ||||
| 
 | ||||
| 	void experimental() { | ||||
| 		experimental_flag = true; | ||||
| 	} | ||||
| 
 | ||||
| 	struct pre_post_exec_state_t { | ||||
| 		Pass *parent_pass; | ||||
|  |  | |||
|  | @ -851,6 +851,8 @@ public: | |||
| 
 | ||||
| 	RTLIL::SigSpec repeat(int num) const; | ||||
| 
 | ||||
| 	void reverse() { inline_unpack(); std::reverse(bits_.begin(), bits_.end()); } | ||||
| 
 | ||||
| 	bool operator <(const RTLIL::SigSpec &other) const; | ||||
| 	bool operator ==(const RTLIL::SigSpec &other) const; | ||||
| 	inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); } | ||||
|  |  | |||
|  | @ -198,8 +198,8 @@ calculated signal and a constant zero with an {\tt \$and} gate). | |||
| 
 | ||||
| \subsection{Registers} | ||||
| 
 | ||||
| D-Type Flip-Flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK}, | ||||
| an input port \B{D} and an output port \B{Q}. The following parameters are available for \$dff | ||||
| D-type flip-flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK}, | ||||
| an input port \B{D} and an output port \B{Q}. The following parameters are available for {\tt \$dff} | ||||
| cells: | ||||
| 
 | ||||
| \begin{itemize} | ||||
|  | @ -211,13 +211,23 @@ Clock is active on the positive edge if this parameter has the value {\tt 1'b1} | |||
| edge if this parameter is {\tt 1'b0}. | ||||
| \end{itemize} | ||||
| 
 | ||||
| D-Type Flip-Flops with asynchronous resets are represented by {\tt \$adff} cells. As the {\tt \$dff} | ||||
| D-type flip-flops with enable are represented by {\tt \$dffe} cells. As the {\tt \$dff} | ||||
| cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have a single-bit \B{EN} | ||||
| input port for the enable pin and the following parameter: | ||||
| 
 | ||||
| \begin{itemize} | ||||
| \item \B{EN\_POLARITY} \\ | ||||
| The enable input is active-high if this parameter has the value {\tt 1'b1} and active-low | ||||
| if this parameter is {\tt 1'b0}. | ||||
| \end{itemize} | ||||
| 
 | ||||
| D-type flip-flops with asynchronous reset are represented by {\tt \$adff} cells. As the {\tt \$dff} | ||||
| cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have a single-bit \B{ARST} | ||||
| input port for the reset pin and the following additional two parameters: | ||||
| 
 | ||||
| \begin{itemize} | ||||
| \item \B{ARST\_POLARITY} \\ | ||||
| The asynchronous reset is high-active if this parameter has the value {\tt 1'b1} and low-active | ||||
| The asynchronous reset is active-high if this parameter has the value {\tt 1'b1} and active-low | ||||
| if this parameter is {\tt 1'b0}. | ||||
| 
 | ||||
| \item \B{ARST\_VALUE} \\ | ||||
|  | @ -231,8 +241,27 @@ Usually these cells are generated by the {\tt proc} pass using the information | |||
| in the designs RTLIL::Process objects. | ||||
| \end{sloppypar} | ||||
| 
 | ||||
| D-type flip-flops with asynchronous set and reset are represented by {\tt \$dffsr} cells. | ||||
| As the {\tt \$dff} cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have | ||||
| a single-bit \B{SET} input port for the set pin, a single-bit \B{CLR} input port for the reset pin, | ||||
| and the following two parameters: | ||||
| 
 | ||||
| \begin{itemize} | ||||
| \item \B{SET\_POLARITY} \\ | ||||
| The set input is active-high if this parameter has the value {\tt 1'b1} and active-low | ||||
| if this parameter is {\tt 1'b0}. | ||||
| 
 | ||||
| \item \B{CLR\_POLARITY} \\ | ||||
| The reset input is active-high if this parameter has the value {\tt 1'b1} and active-low | ||||
| if this parameter is {\tt 1'b0}. | ||||
| \end{itemize} | ||||
| 
 | ||||
| When both the set and reset inputs of a {\tt \$dffsr} cell are active, the reset input takes | ||||
| precedence. | ||||
| 
 | ||||
| \begin{fixme} | ||||
| Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches. | ||||
| Add information about {\tt \$sr} cells (set-reset flip-flops), {\tt \$dlatch} cells (d-type latches), | ||||
| and {\tt \$dlatchsr} cells (d-type latches with set/reset). | ||||
| \end{fixme} | ||||
| 
 | ||||
| \subsection{Memories} | ||||
|  | @ -451,6 +480,30 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\ | |||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFF\_PP0\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_PP1\_} \\ | ||||
| \end{tabular} | ||||
| % FIXME: the layout of this is broken and I have no idea how to fix it | ||||
| \hfil | ||||
| \begin{tabular}[t]{lll} | ||||
| $ClkEdge$ & $EnLvl$ & Cell Type \\ | ||||
| \hline | ||||
| \lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & {\tt \$\_DFFE\_NN\_} \\ | ||||
| \lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & {\tt \$\_DFFE\_NP\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & {\tt \$\_DFFE\_PN\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & {\tt \$\_DFFE\_PP\_} \\ | ||||
| \end{tabular} | ||||
| % FIXME: the layout of this is broken too | ||||
| \hfil | ||||
| \begin{tabular}[t]{llll} | ||||
| $ClkEdge$ & $SetLvl$ & $RstLvl$ & Cell Type \\ | ||||
| \hline | ||||
| \lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_NNN\_} \\ | ||||
| \lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_NNP\_} \\ | ||||
| \lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_NPN\_} \\ | ||||
| \lstinline[language=Verilog];negedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_NPP\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_PNN\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_PNP\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DFFSR\_PPN\_} \\ | ||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFFSR\_PPP\_} \\ | ||||
| \end{tabular} | ||||
| \caption{Cell types for gate level logic networks} | ||||
| \label{tab:CellLib_gates} | ||||
| \end{table} | ||||
|  | @ -459,11 +512,22 @@ Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. Th | |||
| {\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_}, | ||||
| {\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic. | ||||
| The cell type {\tt \$\_TBUF\_} is used to model tristate logic. | ||||
| 
 | ||||
| The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops. | ||||
| 
 | ||||
| The cell types {\tt \$\_DFFE\_NN\_}, {\tt \$\_DFFE\_NP\_}, {\tt \$\_DFFE\_PN\_} and {\tt \$\_DFFE\_PP\_} | ||||
| implement d-type flip-flops with enable. The values in the table for these cell types relate to the | ||||
| following Verilog code template. | ||||
| 
 | ||||
| \begin{lstlisting}[mathescape,language=Verilog] | ||||
| 	always @($ClkEdge$ C) | ||||
| 		if (EN == $EnLvl$) | ||||
| 			Q <= D; | ||||
| \end{lstlisting} | ||||
| 
 | ||||
| The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_}, | ||||
| {\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement | ||||
| d-type flip-flops with asynchronous resets. The values in the table for these cell types relate to the | ||||
| d-type flip-flops with asynchronous reset. The values in the table for these cell types relate to the | ||||
| following Verilog code template, where \lstinline[mathescape,language=Verilog];$RstEdge$; is \lstinline[language=Verilog];posedge; | ||||
| if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, and \lstinline[language=Verilog];negedge; | ||||
| otherwise. | ||||
|  | @ -476,6 +540,25 @@ otherwise. | |||
| 			Q <= D; | ||||
| \end{lstlisting} | ||||
| 
 | ||||
| The cell types {\tt \$\_DFFSR\_NNN\_}, {\tt \$\_DFFSR\_NNP\_}, {\tt \$\_DFFSR\_NPN\_}, {\tt \$\_DFFSR\_NPP\_}, | ||||
| {\tt \$\_DFFSR\_PNN\_}, {\tt \$\_DFFSR\_PNP\_}, {\tt \$\_DFFSR\_PPN\_} and {\tt \$\_DFFSR\_PPP\_} implement | ||||
| d-type flip-flops with asynchronous set and reset. The values in the table for these cell types relate to the | ||||
| following Verilog code template, where \lstinline[mathescape,language=Verilog];$RstEdge$; is \lstinline[language=Verilog];posedge; | ||||
| if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, \lstinline[language=Verilog];negedge; | ||||
| otherwise, and \lstinline[mathescape,language=Verilog];$SetEdge$; is \lstinline[language=Verilog];posedge; | ||||
| if \lstinline[mathescape,language=Verilog];$SetLvl$; if \lstinline[language=Verilog];1;, \lstinline[language=Verilog];negedge; | ||||
| otherwise. | ||||
| 
 | ||||
| \begin{lstlisting}[mathescape,language=Verilog] | ||||
| 	always @($ClkEdge$ C, $RstEdge$ R, $SetEdge$ S) | ||||
| 		if (R == $RstLvl$) | ||||
| 			Q <= 0; | ||||
| 		else if (S == $SetLvl$) | ||||
| 			Q <= 1; | ||||
| 		else | ||||
| 			Q <= D; | ||||
| \end{lstlisting} | ||||
| 
 | ||||
| In most cases gate level logic networks are created from RTL networks using the {\tt techmap} pass. The flip-flop cells | ||||
| from the gate level logic network can be mapped to physical flip-flop cells from a Liberty file using the {\tt dfflibmap} | ||||
| pass. The combinatorial logic cells can be mapped to physical cells from a Liberty file via ABC \citeweblink{ABC} | ||||
|  | @ -507,11 +590,7 @@ Add information about {\tt \$ff} and {\tt \$\_FF\_} cells. | |||
| \end{fixme} | ||||
| 
 | ||||
| \begin{fixme} | ||||
| Add information about {\tt \$dffe}, {\tt \$dffsr}, {\tt \$dlatch}, and {\tt \$dlatchsr} cells. | ||||
| \end{fixme} | ||||
| 
 | ||||
| \begin{fixme} | ||||
| Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells. | ||||
| Add information about {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells. | ||||
| \end{fixme} | ||||
| 
 | ||||
| \begin{fixme} | ||||
|  |  | |||
|  | @ -1935,6 +1935,19 @@ def parse_header(source): | |||
| 		line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", "                    namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END","                    }") | ||||
| 		ugly_line = unpretty_string(line) | ||||
| 
 | ||||
| 		# for anonymous unions, ignore union enclosure by skipping start line and replacing end line with new line | ||||
| 		if 'union {' in line: | ||||
| 			j = i+1 | ||||
| 			while j < len(source_text): | ||||
| 				union_line = source_text[j] | ||||
| 				if '};' in union_line: | ||||
| 					source_text[j] = '\n' | ||||
| 					break | ||||
| 				j += 1 | ||||
| 			if j != len(source_text): | ||||
| 				i += 1 | ||||
| 				continue | ||||
| 
 | ||||
| 		if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: | ||||
| 			namespace_name = ugly_line[10:].replace("{","").strip() | ||||
| 			namespaces.append((namespace_name, ugly_line.count("{"))) | ||||
|  |  | |||
|  | @ -873,7 +873,7 @@ struct ShowPass : public Pass { | |||
| 			#ifdef __APPLE__ | ||||
| 			std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str()); | ||||
| 			#else | ||||
| 			std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str()); | ||||
| 			std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid' 2> /dev/null; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str()); | ||||
| 			#endif | ||||
| 			log("Exec: %s\n", cmd.c_str()); | ||||
| 			if (run_command(cmd) != 0) | ||||
|  |  | |||
|  | @ -34,13 +34,20 @@ static SigSet<sig2driver_entry_t> sig2driver, sig2user; | |||
| static std::set<RTLIL::Cell*> muxtree_cells; | ||||
| static SigPool sig_at_port; | ||||
| 
 | ||||
| static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor) | ||||
| static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, pool<Cell*> &recursion_monitor, dict<RTLIL::SigSpec, bool> &mux_tree_cache) | ||||
| { | ||||
| 	if (mux_tree_cache.find(sig) != mux_tree_cache.end()) | ||||
| 		return mux_tree_cache.at(sig); | ||||
| 
 | ||||
| 	if (sig.is_fully_const() || old_sig == sig) { | ||||
| ret_true: | ||||
| 		mux_tree_cache[sig] = true; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sig_at_port.check_any(assign_map(sig))) { | ||||
| ret_false: | ||||
| 		mux_tree_cache[sig] = false; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -49,13 +56,13 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, poo | |||
| 	for (auto &cellport : cellport_list) | ||||
| 	{ | ||||
| 		if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") { | ||||
| 			return false; | ||||
| 			goto ret_false; | ||||
| 		} | ||||
| 
 | ||||
| 		if (recursion_monitor.count(cellport.first)) { | ||||
| 			log_warning("logic loop in mux tree at signal %s in module %s.\n", | ||||
| 					log_signal(sig), RTLIL::id2cstr(module->name)); | ||||
| 			return false; | ||||
| 			goto ret_false; | ||||
| 		} | ||||
| 
 | ||||
| 		recursion_monitor.insert(cellport.first); | ||||
|  | @ -63,22 +70,22 @@ static bool check_state_mux_tree(RTLIL::SigSpec old_sig, RTLIL::SigSpec sig, poo | |||
| 		RTLIL::SigSpec sig_a = assign_map(cellport.first->getPort("\\A")); | ||||
| 		RTLIL::SigSpec sig_b = assign_map(cellport.first->getPort("\\B")); | ||||
| 
 | ||||
| 		if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor)) { | ||||
| 		if (!check_state_mux_tree(old_sig, sig_a, recursion_monitor, mux_tree_cache)) { | ||||
| 			recursion_monitor.erase(cellport.first); | ||||
| 			return false; | ||||
| 			goto ret_false; | ||||
| 		} | ||||
| 
 | ||||
| 		for (int i = 0; i < sig_b.size(); i += sig_a.size()) | ||||
| 			if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor)) { | ||||
| 			if (!check_state_mux_tree(old_sig, sig_b.extract(i, sig_a.size()), recursion_monitor, mux_tree_cache)) { | ||||
| 				recursion_monitor.erase(cellport.first); | ||||
| 				return false; | ||||
| 				goto ret_false; | ||||
| 			} | ||||
| 
 | ||||
| 		recursion_monitor.erase(cellport.first); | ||||
| 		muxtree_cells.insert(cellport.first); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| 	goto ret_true; | ||||
| } | ||||
| 
 | ||||
| static bool check_state_users(RTLIL::SigSpec sig) | ||||
|  | @ -143,11 +150,12 @@ static void detect_fsm(RTLIL::Wire *wire) | |||
| 		pool<Cell*> recursion_monitor; | ||||
| 		RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q")); | ||||
| 		RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D")); | ||||
| 		dict<RTLIL::SigSpec, bool> mux_tree_cache; | ||||
| 
 | ||||
| 		if (sig_q != assign_map(wire)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor); | ||||
| 		looks_like_state_reg = check_state_mux_tree(sig_q, sig_d, recursion_monitor, mux_tree_cache); | ||||
| 		looks_like_good_state_reg = check_state_users(sig_q); | ||||
| 
 | ||||
| 		if (!looks_like_state_reg) | ||||
|  |  | |||
|  | @ -548,6 +548,19 @@ RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod) | |||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| // Find a matching wire for an implicit port connection; traversing generate block scope
 | ||||
| RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::string& port) | ||||
| { | ||||
| 	const std::string &cellname = cell->name.str(); | ||||
| 	size_t idx = cellname.size(); | ||||
| 	while ((idx = cellname.find_last_of('.', idx-1)) != std::string::npos) { | ||||
| 		Wire *found = module->wire(cellname.substr(0, idx+1) + port.substr(1)); | ||||
| 		if (found != nullptr) | ||||
| 			return found; | ||||
| 	} | ||||
| 	return module->wire(port); | ||||
| } | ||||
| 
 | ||||
| struct HierarchyPass : public Pass { | ||||
| 	HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } | ||||
| 	void help() YS_OVERRIDE | ||||
|  | @ -970,15 +983,71 @@ struct HierarchyPass : public Pass { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Determine default values
 | ||||
| 		dict<IdString, dict<IdString, Const>> defaults_db; | ||||
| 		if (!nodefaults) | ||||
| 		{ | ||||
| 			dict<IdString, dict<IdString, Const>> defaults_db; | ||||
| 
 | ||||
| 			for (auto module : design->modules()) | ||||
| 				for (auto wire : module->wires()) | ||||
| 					if (wire->port_input && wire->attributes.count("\\defaultvalue")) | ||||
| 						defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue"); | ||||
| 		} | ||||
| 		// Process SV implicit wildcard port connections
 | ||||
| 		std::set<Module*> blackbox_derivatives; | ||||
| 		std::vector<Module*> design_modules = design->modules(); | ||||
| 
 | ||||
| 		for (auto module : design_modules) | ||||
| 		{ | ||||
| 			for (auto cell : module->cells()) | ||||
| 			{ | ||||
| 				if (!cell->get_bool_attribute(ID(wildcard_port_conns))) | ||||
| 					continue; | ||||
| 				Module *m = design->module(cell->type); | ||||
| 
 | ||||
| 				if (m == nullptr) | ||||
| 					log_error("Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown.\n", | ||||
| 							RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); | ||||
| 
 | ||||
| 				// Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths
 | ||||
| 				if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { | ||||
| 					IdString new_m_name = m->derive(design, cell->parameters, true); | ||||
| 					if (new_m_name.empty()) | ||||
| 						continue; | ||||
| 					if (new_m_name != m->name) { | ||||
| 						m = design->module(new_m_name); | ||||
| 						blackbox_derivatives.insert(m); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				auto old_connections = cell->connections(); | ||||
| 				for (auto wire : m->wires()) { | ||||
| 					// Find ports of the module that aren't explicitly connected
 | ||||
| 					if (!wire->port_input && !wire->port_output) | ||||
| 						continue; | ||||
| 					if (old_connections.count(wire->name)) | ||||
| 						continue; | ||||
| 					// Make sure a wire of correct name exists in the parent
 | ||||
| 					Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str()); | ||||
| 
 | ||||
| 					// Missing wires are OK when a default value is set
 | ||||
| 					if (!nodefaults && parent_wire == nullptr && defaults_db.count(cell->type) && defaults_db.at(cell->type).count(wire->name)) | ||||
| 						continue; | ||||
| 
 | ||||
| 					if (parent_wire == nullptr) | ||||
| 						log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n", | ||||
| 								RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); | ||||
| 					if (parent_wire->width != wire->width) | ||||
| 						log_error("Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s).\n", | ||||
| 								parent_wire->width, wire->width, | ||||
| 								RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); | ||||
| 					cell->setPort(wire->name, parent_wire); | ||||
| 				} | ||||
| 				cell->attributes.erase(ID(wildcard_port_conns)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (!nodefaults) | ||||
| 		{ | ||||
| 			for (auto module : design->modules()) | ||||
| 				for (auto cell : module->cells()) | ||||
| 				{ | ||||
|  | @ -1000,9 +1069,6 @@ struct HierarchyPass : public Pass { | |||
| 				} | ||||
| 		} | ||||
| 
 | ||||
| 		std::set<Module*> blackbox_derivatives; | ||||
| 		std::vector<Module*> design_modules = design->modules(); | ||||
| 
 | ||||
| 		for (auto module : design_modules) | ||||
| 		{ | ||||
| 			pool<Wire*> wand_wor_index; | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ OBJS += passes/opt/wreduce.o | |||
| OBJS += passes/opt/opt_demorgan.o | ||||
| OBJS += passes/opt/rmports.o | ||||
| OBJS += passes/opt/opt_lut.o | ||||
| OBJS += passes/opt/opt_lut_ins.o | ||||
| OBJS += passes/opt/pmux2shiftx.o | ||||
| OBJS += passes/opt/muxpack.o | ||||
| endif | ||||
|  |  | |||
							
								
								
									
										278
									
								
								passes/opt/opt_lut_ins.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										278
									
								
								passes/opt/opt_lut_ins.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,278 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include "kernel/yosys.h" | ||||
| #include "kernel/sigtools.h" | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct OptLutInsPass : public Pass { | ||||
| 	OptLutInsPass() : Pass("opt_lut_ins", "discard unused LUT inputs") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    opt_lut_ins [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This pass removes unused inputs from LUT cells (that is, inputs that can not\n"); | ||||
| 		log("influence the output signal given this LUT's value).  While such LUTs cannot\n"); | ||||
| 		log("be directly emitted by ABC, they can be a result of various post-ABC\n"); | ||||
| 		log("transformations, such as mapping wide LUTs (not all sub-LUTs will use the\n"); | ||||
| 		log("full set of inputs) or optimizations such as xilinx_dffopt.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -tech <technology>\n"); | ||||
| 		log("        Instead of generic $lut cells, operate on LUT cells specific\n"); | ||||
| 		log("        to the given technology.  Valid values are: xilinx, ecp5, gowin.\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing OPT_LUT_INS pass (discard unused LUT inputs).\n"); | ||||
| 		string techname; | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | ||||
| 		{ | ||||
| 			if (args[argidx] == "-tech" && argidx+1 < args.size()) { | ||||
| 				techname = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		if (techname != "" && techname != "xilinx" && techname != "ecp5" && techname != "gowin") | ||||
| 			log_cmd_error("Unsupported technology: '%s'\n", techname.c_str()); | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) | ||||
| 		{ | ||||
| 			log("Optimizing LUTs in %s.\n", log_id(module)); | ||||
| 
 | ||||
| 			std::vector<Cell *> remove_cells; | ||||
| 			// Gather LUTs.
 | ||||
| 			for (auto cell : module->selected_cells()) | ||||
| 			{ | ||||
| 				if (cell->get_bool_attribute(ID::keep)) | ||||
| 					continue; | ||||
| 				Const lut; | ||||
| 				std::vector<SigBit> inputs; | ||||
| 				std::vector<SigBit> output; | ||||
| 				bool ignore_const = false; | ||||
| 				if (techname == "") { | ||||
| 					if (cell->type != ID($lut)) | ||||
| 						continue; | ||||
| 					inputs = cell->getPort(ID::A).bits(); | ||||
| 					output = cell->getPort(ID::Y); | ||||
| 					lut = cell->getParam(ID(LUT)); | ||||
| 				} else if (techname == "xilinx" || techname == "gowin") { | ||||
| 					if (cell->type == ID(LUT1)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID(I0)), | ||||
| 						}; | ||||
| 					} else if (cell->type == ID(LUT2)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID(I0)), | ||||
| 							cell->getPort(ID(I1)), | ||||
| 						}; | ||||
| 					} else if (cell->type == ID(LUT3)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID(I0)), | ||||
| 							cell->getPort(ID(I1)), | ||||
| 							cell->getPort(ID(I2)), | ||||
| 						}; | ||||
| 					} else if (cell->type == ID(LUT4)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID(I0)), | ||||
| 							cell->getPort(ID(I1)), | ||||
| 							cell->getPort(ID(I2)), | ||||
| 							cell->getPort(ID(I3)), | ||||
| 						}; | ||||
| 					} else if (cell->type == ID(LUT5)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID(I0)), | ||||
| 							cell->getPort(ID(I1)), | ||||
| 							cell->getPort(ID(I2)), | ||||
| 							cell->getPort(ID(I3)), | ||||
| 							cell->getPort(ID(I4)), | ||||
| 						}; | ||||
| 					} else if (cell->type == ID(LUT6)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID(I0)), | ||||
| 							cell->getPort(ID(I1)), | ||||
| 							cell->getPort(ID(I2)), | ||||
| 							cell->getPort(ID(I3)), | ||||
| 							cell->getPort(ID(I4)), | ||||
| 							cell->getPort(ID(I5)), | ||||
| 						}; | ||||
| 					} else { | ||||
| 						// Not a LUT.
 | ||||
| 						continue; | ||||
| 					} | ||||
| 					lut = cell->getParam(ID(INIT)); | ||||
| 					if (techname == "xilinx") | ||||
| 						output = cell->getPort(ID(O)); | ||||
| 					else | ||||
| 						output = cell->getPort(ID(F)); | ||||
| 				} else if (techname == "ecp5") { | ||||
| 					if (cell->type == ID(LUT4)) { | ||||
| 						inputs = { | ||||
| 							cell->getPort(ID::A), | ||||
| 							cell->getPort(ID::B), | ||||
| 							cell->getPort(ID(C)), | ||||
| 							cell->getPort(ID(D)), | ||||
| 						}; | ||||
| 						lut = cell->getParam(ID(INIT)); | ||||
| 						output = cell->getPort(ID(Z)); | ||||
| 						ignore_const = true; | ||||
| 					} else { | ||||
| 						// Not a LUT.
 | ||||
| 						continue; | ||||
| 					} | ||||
| 				} | ||||
| 				std::vector<int> swizzle; | ||||
| 				std::vector<SigBit> new_inputs; | ||||
| 				bool doit = false; | ||||
| 				for (int i = 0; i < GetSize(inputs); i++) { | ||||
| 					SigBit input = inputs[i]; | ||||
| 					if (!input.wire) { | ||||
| 						if (input.data == State::S1) | ||||
| 							swizzle.push_back(-2); | ||||
| 						else | ||||
| 							swizzle.push_back(-1); | ||||
| 						// For ECP5, smaller LUTs are
 | ||||
| 						// implemented as LUT4s with
 | ||||
| 						// extra const inputs.  Do not
 | ||||
| 						// consider that to be a reason
 | ||||
| 						// to redo a LUT.
 | ||||
| 						if (!ignore_const) | ||||
| 							doit = true; | ||||
| 					} else { | ||||
| 						bool redundant = true; | ||||
| 						for (int j = 0; j < GetSize(lut); j++) { | ||||
| 							if (lut[j] != lut[j ^ 1 << i]) | ||||
| 								redundant = false; | ||||
| 						} | ||||
| 						if (redundant) { | ||||
| 							swizzle.push_back(-1); | ||||
| 							doit = true; | ||||
| 						} else { | ||||
| 							swizzle.push_back(GetSize(new_inputs)); | ||||
| 							new_inputs.push_back(input); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				if (!doit) | ||||
| 					continue; | ||||
| 				log("  Optimizing lut %s (%d -> %d)\n", log_id(cell), GetSize(inputs), GetSize(new_inputs)); | ||||
| 				if (techname == "ecp5") { | ||||
| 					// Pad the LUT to 4 inputs, adding consts from the front.
 | ||||
| 					int extra = 4 - GetSize(new_inputs); | ||||
| 					log_assert(extra >= 0); | ||||
| 					if (extra) { | ||||
| 						for (int i = 0; i < extra; i++) | ||||
| 							new_inputs.insert(new_inputs.begin(), State::S0); | ||||
| 						for (auto &swz : swizzle) | ||||
| 							if (swz >= 0) | ||||
| 								swz += extra; | ||||
| 					} | ||||
| 				} | ||||
| 				Const new_lut(0, 1 << GetSize(new_inputs)); | ||||
| 				for (int i = 0; i < GetSize(new_lut); i++) { | ||||
| 					int lidx = 0; | ||||
| 					for (int j = 0; j < GetSize(inputs); j++) { | ||||
| 						int val; | ||||
| 						if (swizzle[j] == -2) { | ||||
| 							val = 1; | ||||
| 						} else if (swizzle[j] == -1) { | ||||
| 							val = 0; | ||||
| 						} else { | ||||
| 							val = (i >> swizzle[j]) & 1; | ||||
| 						} | ||||
| 						lidx |= val << j; | ||||
| 					} | ||||
| 					new_lut[i] = lut[lidx]; | ||||
| 				} | ||||
| 				// For ecp5, do not replace with a const driver — the nextpnr
 | ||||
| 				// packer requires a complete set of LUTs for wide LUT muxes.
 | ||||
| 				if (new_inputs.empty() && techname != "ecp5") { | ||||
| 					// const driver.
 | ||||
| 					remove_cells.push_back(cell); | ||||
| 					module->connect(output, new_lut[0]); | ||||
| 				} else { | ||||
| 					if (techname == "") { | ||||
| 						cell->setParam(ID(LUT), new_lut); | ||||
| 						cell->setParam(ID(WIDTH), GetSize(new_inputs)); | ||||
| 						cell->setPort(ID::A, new_inputs); | ||||
| 					} else if (techname == "ecp5") { | ||||
| 						log_assert(GetSize(new_inputs) == 4); | ||||
| 						cell->setParam(ID(INIT), new_lut); | ||||
| 						cell->setPort(ID::A, new_inputs[0]); | ||||
| 						cell->setPort(ID::B, new_inputs[1]); | ||||
| 						cell->setPort(ID(C), new_inputs[2]); | ||||
| 						cell->setPort(ID(D), new_inputs[3]); | ||||
| 					} else { | ||||
| 						// xilinx, gowin
 | ||||
| 						cell->setParam(ID(INIT), new_lut); | ||||
| 						if (techname == "xilinx") | ||||
| 							log_assert(GetSize(new_inputs) <= 6); | ||||
| 						else | ||||
| 							log_assert(GetSize(new_inputs) <= 4); | ||||
| 						if (GetSize(new_inputs) == 1) | ||||
| 							cell->type = ID(LUT1); | ||||
| 						else if (GetSize(new_inputs) == 2) | ||||
| 							cell->type = ID(LUT2); | ||||
| 						else if (GetSize(new_inputs) == 3) | ||||
| 							cell->type = ID(LUT3); | ||||
| 						else if (GetSize(new_inputs) == 4) | ||||
| 							cell->type = ID(LUT4); | ||||
| 						else if (GetSize(new_inputs) == 5) | ||||
| 							cell->type = ID(LUT5); | ||||
| 						else if (GetSize(new_inputs) == 6) | ||||
| 							cell->type = ID(LUT6); | ||||
| 						else | ||||
| 							log_assert(0); | ||||
| 						cell->unsetPort(ID(I0)); | ||||
| 						cell->unsetPort(ID(I1)); | ||||
| 						cell->unsetPort(ID(I2)); | ||||
| 						cell->unsetPort(ID(I3)); | ||||
| 						cell->unsetPort(ID(I4)); | ||||
| 						cell->unsetPort(ID(I5)); | ||||
| 						cell->setPort(ID(I0), new_inputs[0]); | ||||
| 						if (GetSize(new_inputs) >= 2) | ||||
| 							cell->setPort(ID(I1), new_inputs[1]); | ||||
| 						if (GetSize(new_inputs) >= 3) | ||||
| 							cell->setPort(ID(I2), new_inputs[2]); | ||||
| 						if (GetSize(new_inputs) >= 4) | ||||
| 							cell->setPort(ID(I3), new_inputs[3]); | ||||
| 						if (GetSize(new_inputs) >= 5) | ||||
| 							cell->setPort(ID(I4), new_inputs[4]); | ||||
| 						if (GetSize(new_inputs) >= 6) | ||||
| 							cell->setPort(ID(I5), new_inputs[5]); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			for (auto cell : remove_cells) | ||||
| 				module->remove(cell); | ||||
| 		} | ||||
| 	} | ||||
| } XilinxDffOptPass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
| 
 | ||||
|  | @ -44,9 +44,10 @@ struct OptReduceWorker | |||
| 		cells.erase(cell); | ||||
| 
 | ||||
| 		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); | ||||
| 		sig_a.sort_and_unify(); | ||||
| 		pool<RTLIL::SigBit> new_sig_a_bits; | ||||
| 
 | ||||
| 		for (auto &bit : sig_a.to_sigbit_set()) | ||||
| 		for (auto &bit : sig_a) | ||||
| 		{ | ||||
| 			if (bit == RTLIL::State::S0) { | ||||
| 				if (cell->type == ID($reduce_and)) { | ||||
|  | @ -86,6 +87,7 @@ struct OptReduceWorker | |||
| 		} | ||||
| 
 | ||||
| 		RTLIL::SigSpec new_sig_a(new_sig_a_bits); | ||||
| 		new_sig_a.sort_and_unify(); | ||||
| 
 | ||||
| 		if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) { | ||||
| 			log("    New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a)); | ||||
|  | @ -235,7 +237,6 @@ struct OptReduceWorker | |||
| 			log("      New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second)); | ||||
| 
 | ||||
| 			module->connect(old_sig_conn); | ||||
| 			module->check(); | ||||
| 
 | ||||
| 			did_something = true; | ||||
| 			total_count++; | ||||
|  | @ -324,6 +325,8 @@ struct OptReduceWorker | |||
| 				opt_mux(cell); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		module->check(); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,11 +42,19 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm) | |||
| 
 | ||||
| 	cell->setPort("\\A", st.carry->getPort("\\I0")); | ||||
| 	cell->setPort("\\B", st.carry->getPort("\\I1")); | ||||
| 	cell->setPort("\\CI", st.carry->getPort("\\CI")); | ||||
| 	auto CI = st.carry->getPort("\\CI"); | ||||
| 	cell->setPort("\\CI", CI); | ||||
| 	cell->setPort("\\CO", st.carry->getPort("\\CO")); | ||||
| 
 | ||||
| 	cell->setPort("\\I0", st.lut->getPort("\\I0")); | ||||
| 	cell->setPort("\\I3", st.lut->getPort("\\I3")); | ||||
| 	auto I3 = st.lut->getPort("\\I3"); | ||||
| 	if (pm.sigmap(CI) == pm.sigmap(I3)) { | ||||
| 		cell->setParam("\\I3_IS_CI", State::S1); | ||||
| 		I3 = State::Sx; | ||||
| 	} | ||||
| 	else | ||||
| 		cell->setParam("\\I3_IS_CI", State::S0); | ||||
| 	cell->setPort("\\I3", I3); | ||||
| 	cell->setPort("\\O", st.lut->getPort("\\O")); | ||||
| 	cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT")); | ||||
| 
 | ||||
|  | @ -118,7 +126,8 @@ struct Ice40WrapCarryPass : public Pass { | |||
| 					auto lut = module->addCell(lut_name, ID($lut)); | ||||
| 					lut->setParam(ID(WIDTH), 4); | ||||
| 					lut->setParam(ID(LUT), cell->getParam(ID(LUT))); | ||||
| 					lut->setPort(ID(A), {cell->getPort(ID(I0)), cell->getPort(ID(A)), cell->getPort(ID(B)), cell->getPort(ID(I3)) }); | ||||
| 					auto I3 = cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3)); | ||||
| 					lut->setPort(ID(A), { I3, cell->getPort(ID(B)), cell->getPort(ID(A)), cell->getPort(ID(I0)) }); | ||||
| 					lut->setPort(ID(Y), cell->getPort(ID(O))); | ||||
| 
 | ||||
| 					Const src; | ||||
|  |  | |||
|  | @ -767,6 +767,9 @@ struct XilinxDspPass : public Pass { | |||
| 		log("to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series\n"); | ||||
| 		log("device.\n"); | ||||
| 		log("\n"); | ||||
| 		log("This pass is a no-op if the scratchpad variable 'xilinx_dsp.multonly' is set\n"); | ||||
| 		log("to 1.\n"); | ||||
| 		log("\n"); | ||||
| 		log("\n"); | ||||
| 		log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n"); | ||||
| 		log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n"); | ||||
|  | @ -805,6 +808,10 @@ struct XilinxDspPass : public Pass { | |||
| 			family = "xcu"; | ||||
| 
 | ||||
| 		for (auto module : design->selected_modules()) { | ||||
| 
 | ||||
| 			if (design->scratchpad_get_bool("xilinx_dsp.multonly")) | ||||
| 				continue; | ||||
| 
 | ||||
| 			// Experimental feature: pack $add/$sub cells with
 | ||||
| 			//   (* use_dsp48="simd" *) into DSP48E1's using its
 | ||||
| 			//   SIMD feature
 | ||||
|  |  | |||
|  | @ -214,14 +214,38 @@ struct Clk2fflogicPass : public Pass { | |||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
| 				if (cell->type.in("$dff", "$adff", "$dffsr")) | ||||
| 				bool word_dff = cell->type.in("$dff", "$adff", "$dffsr"); | ||||
| 				if (word_dff || cell->type.in(ID($_DFF_N_), ID($_DFF_P_), | ||||
| 						ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), | ||||
| 						ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_), | ||||
| 						ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), | ||||
| 						ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) | ||||
| 				{ | ||||
| 					bool clkpol = cell->parameters["\\CLK_POLARITY"].as_bool(); | ||||
| 					bool clkpol; | ||||
| 					SigSpec clk; | ||||
| 					if (word_dff) { | ||||
| 						clkpol = cell->parameters["\\CLK_POLARITY"].as_bool(); | ||||
| 						clk = cell->getPort("\\CLK"); | ||||
| 					} | ||||
| 					else { | ||||
| 						if (cell->type.in(ID($_DFF_P_), ID($_DFF_N_), | ||||
| 									ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), | ||||
| 									ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_))) | ||||
| 							clkpol = cell->type[6] == 'P'; | ||||
| 						else if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), | ||||
| 									ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) | ||||
| 							clkpol = cell->type[8] == 'P'; | ||||
| 						else log_abort(); | ||||
| 						clk = cell->getPort("\\C"); | ||||
| 					} | ||||
| 
 | ||||
| 					SigSpec clk = cell->getPort("\\CLK"); | ||||
| 					Wire *past_clk = module->addWire(NEW_ID); | ||||
| 					past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0; | ||||
| 
 | ||||
| 					if (word_dff) | ||||
| 						module->addFf(NEW_ID, clk, past_clk); | ||||
| 					else | ||||
| 						module->addFfGate(NEW_ID, clk, past_clk); | ||||
| 
 | ||||
| 					SigSpec sig_d = cell->getPort("\\D"); | ||||
| 					SigSpec sig_q = cell->getPort("\\Q"); | ||||
|  | @ -244,8 +268,14 @@ struct Clk2fflogicPass : public Pass { | |||
| 
 | ||||
| 					Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d)); | ||||
| 					Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q)); | ||||
| 					if (word_dff) { | ||||
| 						module->addFf(NEW_ID, sig_d, past_d); | ||||
| 						module->addFf(NEW_ID, sig_q, past_q); | ||||
| 					} | ||||
| 					else { | ||||
| 						module->addFfGate(NEW_ID, sig_d, past_d); | ||||
| 						module->addFfGate(NEW_ID, sig_q, past_q); | ||||
| 					} | ||||
| 
 | ||||
| 					if (cell->type == "$adff") | ||||
| 					{ | ||||
|  | @ -266,6 +296,26 @@ struct Clk2fflogicPass : public Pass { | |||
| 							module->addMux(NEW_ID, rstval, qval, arst, sig_q); | ||||
| 					} | ||||
| 					else | ||||
| 					if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), | ||||
| 						ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_))) | ||||
| 					{ | ||||
| 						SigSpec arst = cell->getPort("\\R"); | ||||
| 						SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge); | ||||
| 						SigBit rstval = (cell->type[8] == '1'); | ||||
| 
 | ||||
| 						Wire *past_arst = module->addWire(NEW_ID); | ||||
| 						module->addFfGate(NEW_ID, arst, past_arst); | ||||
| 						if (cell->type[7] == 'P') | ||||
| 							arst = module->OrGate(NEW_ID, arst, past_arst); | ||||
| 						else | ||||
| 							arst = module->AndGate(NEW_ID, arst, past_arst); | ||||
| 
 | ||||
| 						if (cell->type[7] == 'P') | ||||
| 							module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q); | ||||
| 						else | ||||
| 							module->addMuxGate(NEW_ID, rstval, qval, arst, sig_q); | ||||
| 					} | ||||
| 					else | ||||
| 					if (cell->type == "$dffsr") | ||||
| 					{ | ||||
| 						SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); | ||||
|  | @ -282,9 +332,30 @@ struct Clk2fflogicPass : public Pass { | |||
| 						module->addAnd(NEW_ID, qval, clrval, sig_q); | ||||
| 					} | ||||
| 					else | ||||
| 					if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), | ||||
| 						ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) | ||||
| 					{ | ||||
| 						SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge); | ||||
| 						SigSpec setval = cell->getPort("\\S"); | ||||
| 						SigSpec clrval = cell->getPort("\\R"); | ||||
| 
 | ||||
| 						if (cell->type[9] != 'P') | ||||
| 							setval = module->Not(NEW_ID, setval); | ||||
| 
 | ||||
| 						if (cell->type[10] == 'P') | ||||
| 							clrval = module->Not(NEW_ID, clrval); | ||||
| 
 | ||||
| 						qval = module->OrGate(NEW_ID, qval, setval); | ||||
| 						module->addAndGate(NEW_ID, qval, clrval, sig_q); | ||||
| 					} | ||||
| 					else if (cell->type == "$dff") | ||||
| 					{ | ||||
| 						module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						module->addMuxGate(NEW_ID, past_q, past_d, clock_edge, sig_q); | ||||
| 					} | ||||
| 
 | ||||
| 					Const initval; | ||||
| 					bool assign_initval = false; | ||||
|  |  | |||
|  | @ -269,6 +269,7 @@ struct SatHelper | |||
| 				for (int i = 0; i < lhs.size(); i++) { | ||||
| 					RTLIL::SigSpec bit = lhs.extract(i, 1); | ||||
| 					if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) { | ||||
| 						if (rhs[i] != State::Sx) | ||||
| 							removed_bits.append(bit); | ||||
| 						lhs.remove(i, 1); | ||||
| 						rhs.remove(i, 1); | ||||
|  |  | |||
|  | @ -8,9 +8,12 @@ OBJS += passes/techmap/libparse.o | |||
| ifeq ($(ENABLE_ABC),1) | ||||
| OBJS += passes/techmap/abc.o | ||||
| OBJS += passes/techmap/abc9.o | ||||
| OBJS += passes/techmap/abc9_exe.o | ||||
| OBJS += passes/techmap/abc9_ops.o | ||||
| ifneq ($(ABCEXTERNAL),) | ||||
| passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | ||||
| passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | ||||
| passes/techmap/abc9_exe.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										530
									
								
								passes/techmap/abc9_exe.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								passes/techmap/abc9_exe.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,530 @@ | |||
| /*
 | ||||
|  *  yosys -- Yosys Open SYnthesis Suite | ||||
|  * | ||||
|  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||
|  *                2019  Eddie Hung <eddie@fpgeh.com> | ||||
|  * | ||||
|  *  Permission to use, copy, modify, and/or distribute this software for any | ||||
|  *  purpose with or without fee is hereby granted, provided that the above | ||||
|  *  copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // [[CITE]] ABC
 | ||||
| // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
 | ||||
| // http://www.eecs.berkeley.edu/~alanmi/abc/
 | ||||
| 
 | ||||
| #include "kernel/register.h" | ||||
| #include "kernel/log.h" | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
| #  include <unistd.h> | ||||
| #  include <dirent.h> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef YOSYS_LINK_ABC | ||||
| extern "C" int Abc_RealMain(int argc, char *argv[]); | ||||
| #endif | ||||
| 
 | ||||
| std::string fold_abc9_cmd(std::string str) | ||||
| { | ||||
| 	std::string token, new_str = "          "; | ||||
| 	int char_counter = 10; | ||||
| 
 | ||||
| 	for (size_t i = 0; i <= str.size(); i++) { | ||||
| 		if (i < str.size()) | ||||
| 			token += str[i]; | ||||
| 		if (i == str.size() || str[i] == ';') { | ||||
| 			if (char_counter + token.size() > 75) | ||||
| 				new_str += "\n              ", char_counter = 14; | ||||
| 			new_str += token, char_counter += token.size(); | ||||
| 			token.clear(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return new_str; | ||||
| } | ||||
| 
 | ||||
| USING_YOSYS_NAMESPACE | ||||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| std::string add_echos_to_abc9_cmd(std::string str) | ||||
| { | ||||
| 	std::string new_str, token; | ||||
| 	for (size_t i = 0; i < str.size(); i++) { | ||||
| 		token += str[i]; | ||||
| 		if (str[i] == ';') { | ||||
| 			while (i+1 < str.size() && str[i+1] == ' ') | ||||
| 				i++; | ||||
| 			new_str += "echo + " + token + " " + token + " "; | ||||
| 			token.clear(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!token.empty()) { | ||||
| 		if (!new_str.empty()) | ||||
| 			new_str += "echo + " + token + "; "; | ||||
| 		new_str += token; | ||||
| 	} | ||||
| 
 | ||||
| 	return new_str; | ||||
| } | ||||
| 
 | ||||
| std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) | ||||
| { | ||||
| 	if (show_tempdir) | ||||
| 		return text; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		size_t pos = text.find(tempdir_name); | ||||
| 		if (pos == std::string::npos) | ||||
| 			break; | ||||
| 		text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name)); | ||||
| 	} | ||||
| 
 | ||||
| 	std::string  selfdir_name = proc_self_dirname(); | ||||
| 	if (selfdir_name != "/") { | ||||
| 		while (1) { | ||||
| 			size_t pos = text.find(selfdir_name); | ||||
| 			if (pos == std::string::npos) | ||||
| 				break; | ||||
| 			text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return text; | ||||
| } | ||||
| 
 | ||||
| struct abc9_output_filter | ||||
| { | ||||
| 	bool got_cr; | ||||
| 	int escape_seq_state; | ||||
| 	std::string linebuf; | ||||
| 	std::string tempdir_name; | ||||
| 	bool show_tempdir; | ||||
| 
 | ||||
| 	abc9_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) | ||||
| 	{ | ||||
| 		got_cr = false; | ||||
| 		escape_seq_state = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	void next_char(char ch) | ||||
| 	{ | ||||
| 		if (escape_seq_state == 0 && ch == '\033') { | ||||
| 			escape_seq_state = 1; | ||||
| 			return; | ||||
| 		} | ||||
| 		if (escape_seq_state == 1) { | ||||
| 			escape_seq_state = ch == '[' ? 2 : 0; | ||||
| 			return; | ||||
| 		} | ||||
| 		if (escape_seq_state == 2) { | ||||
| 			if ((ch < '0' || '9' < ch) && ch != ';') | ||||
| 				escape_seq_state = 0; | ||||
| 			return; | ||||
| 		} | ||||
| 		escape_seq_state = 0; | ||||
| 		if (ch == '\r') { | ||||
| 			got_cr = true; | ||||
| 			return; | ||||
| 		} | ||||
| 		if (ch == '\n') { | ||||
| 			log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); | ||||
| 			got_cr = false, linebuf.clear(); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (got_cr) | ||||
| 			got_cr = false, linebuf.clear(); | ||||
| 		linebuf += ch; | ||||
| 	} | ||||
| 
 | ||||
| 	void next_line(const std::string &line) | ||||
| 	{ | ||||
| 		//int pi, po;
 | ||||
| 		//if (sscanf(line.c_str(), "Start-point = pi%d.  End-point = po%d.", &pi, &po) == 2) {
 | ||||
| 		//	log("ABC: Start-point = pi%d (%s).  End-point = po%d (%s).\n",
 | ||||
| 		//			pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???",
 | ||||
| 		//			po, po_map.count(po) ? po_map.at(po).c_str() : "???");
 | ||||
| 		//	return;
 | ||||
| 		//}
 | ||||
| 
 | ||||
| 		for (char ch : line) | ||||
| 			next_char(ch); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe_file, | ||||
| 		vector<int> lut_costs, bool dff_mode, 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, std::string tempdir_name | ||||
| ) | ||||
| { | ||||
| 	std::string abc9_script; | ||||
| 
 | ||||
| 	if (!lut_costs.empty()) | ||||
| 		abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); | ||||
| 	else if (!lut_file.empty()) | ||||
| 		abc9_script += stringf("read_lut %s; ", lut_file.c_str()); | ||||
| 	else | ||||
| 		log_abort(); | ||||
| 
 | ||||
| 	log_assert(!box_file.empty()); | ||||
| 	abc9_script += stringf("read_box %s; ", box_file.c_str()); | ||||
| 	abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); | ||||
| 
 | ||||
| 	if (!script_file.empty()) { | ||||
| 		if (script_file[0] == '+') { | ||||
| 			for (size_t i = 1; i < script_file.size(); i++) | ||||
| 				if (script_file[i] == '\'') | ||||
| 					abc9_script += "'\\''"; | ||||
| 				else if (script_file[i] == ',') | ||||
| 					abc9_script += " "; | ||||
| 				else | ||||
| 					abc9_script += script_file[i]; | ||||
| 		} else | ||||
| 			abc9_script += stringf("source %s", script_file.c_str()); | ||||
| 	} else if (!lut_costs.empty() || !lut_file.empty()) { | ||||
| 		abc9_script += fast_mode ? RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos) | ||||
| 			: RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos); | ||||
| 	} else | ||||
| 		log_abort(); | ||||
| 
 | ||||
| 	for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) | ||||
| 		abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); | ||||
| 
 | ||||
| 	//for (size_t pos = abc9_script.find("{S}"); pos != std::string::npos; pos = abc9_script.find("{S}", pos))
 | ||||
| 	//	abc9_script = abc9_script.substr(0, pos) + lutin_shared + abc9_script.substr(pos+3);
 | ||||
| 
 | ||||
| 	for (size_t pos = abc9_script.find("{W}"); pos != std::string::npos; pos = abc9_script.find("{W}", pos)) | ||||
| 		abc9_script = abc9_script.substr(0, pos) + wire_delay + abc9_script.substr(pos+3); | ||||
| 
 | ||||
| 	std::string C; | ||||
| 	if (design->scratchpad.count("abc9.if.C")) | ||||
| 		C = "-C " + design->scratchpad_get_string("abc9.if.C"); | ||||
| 	for (size_t pos = abc9_script.find("{C}"); pos != std::string::npos; pos = abc9_script.find("{C}", pos)) | ||||
| 		abc9_script = abc9_script.substr(0, pos) + C + abc9_script.substr(pos+3); | ||||
| 
 | ||||
| 	std::string R; | ||||
| 	if (design->scratchpad.count("abc9.if.R")) | ||||
| 		R = "-R " + design->scratchpad_get_string("abc9.if.R"); | ||||
| 	for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos)) | ||||
| 		abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3); | ||||
| 
 | ||||
| 	abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str()); | ||||
| 	if (design->scratchpad_get_bool("abc9.verify")) { | ||||
| 		if (dff_mode) | ||||
| 			abc9_script += "; verify -s"; | ||||
| 		else | ||||
| 			abc9_script += "; verify"; | ||||
| 	} | ||||
| 	abc9_script += "; time"; | ||||
| 	abc9_script = add_echos_to_abc9_cmd(abc9_script); | ||||
| 
 | ||||
| 	for (size_t i = 0; i+1 < abc9_script.size(); i++) | ||||
| 		if (abc9_script[i] == ';' && abc9_script[i+1] == ' ') | ||||
| 			abc9_script[i+1] = '\n'; | ||||
| 
 | ||||
| 	FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); | ||||
| 	fprintf(f, "%s\n", abc9_script.c_str()); | ||||
| 	fclose(f); | ||||
| 
 | ||||
| 	std::string buffer; | ||||
| 
 | ||||
| 	log_header(design, "Executing ABC9.\n"); | ||||
| 
 | ||||
| 	if (!lut_costs.empty()) { | ||||
| 		buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); | ||||
| 		f = fopen(buffer.c_str(), "wt"); | ||||
| 		if (f == NULL) | ||||
| 			log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); | ||||
| 		for (int i = 0; i < GetSize(lut_costs); i++) | ||||
| 			fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); | ||||
| 		fclose(f); | ||||
| 	} | ||||
| 
 | ||||
| 	buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); | ||||
| 	log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); | ||||
| 
 | ||||
| #ifndef YOSYS_LINK_ABC | ||||
| 	abc9_output_filter filt(tempdir_name, show_tempdir); | ||||
| 	int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1)); | ||||
| #else | ||||
| 	// These needs to be mutable, supposedly due to getopt
 | ||||
| 	char *abc9_argv[5]; | ||||
| 	string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); | ||||
| 	abc9_argv[0] = strdup(exe_file.c_str()); | ||||
| 	abc9_argv[1] = strdup("-s"); | ||||
| 	abc9_argv[2] = strdup("-f"); | ||||
| 	abc9_argv[3] = strdup(tmp_script_name.c_str()); | ||||
| 	abc9_argv[4] = 0; | ||||
| 	int ret = Abc_RealMain(4, abc9_argv); | ||||
| 	free(abc9_argv[0]); | ||||
| 	free(abc9_argv[1]); | ||||
| 	free(abc9_argv[2]); | ||||
| 	free(abc9_argv[3]); | ||||
| #endif | ||||
| 	if (ret != 0) | ||||
| 		log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); | ||||
| } | ||||
| 
 | ||||
| struct Abc9ExePass : public Pass { | ||||
| 	Abc9ExePass() : Pass("abc9_exe", "use ABC9 for technology mapping") { } | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    abc9_exe [options]\n"); | ||||
| 		log("\n"); | ||||
| 		log(" \n"); | ||||
| 		log("This pass uses the ABC tool [1] for technology mapping of the top module\n"); | ||||
| 		log("(according to the (* top *) attribute or if only one module is currently selected)\n"); | ||||
| 		log("to a target FPGA architecture.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -exe <command>\n"); | ||||
| #ifdef ABCEXTERNAL | ||||
| 		log("        use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); | ||||
| #else | ||||
| 		log("        use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n"); | ||||
| #endif | ||||
| 		log("        This can e.g. be used to call a specific version of ABC or a wrapper.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -script <file>\n"); | ||||
| 		log("        use the specified ABC script file instead of the default script.\n"); | ||||
| 		log("\n"); | ||||
| 		log("        if <file> starts with a plus sign (+), then the rest of the filename\n"); | ||||
| 		log("        string is interpreted as the command string to be passed to ABC. The\n"); | ||||
| 		log("        leading plus sign is removed and all commas (,) in the string are\n"); | ||||
| 		log("        replaced with blanks before the string is passed to ABC.\n"); | ||||
| 		log("\n"); | ||||
| 		log("        if no -script parameter is given, the following scripts are used:\n"); | ||||
| 		log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default").substr(1,std::string::npos)).c_str()); | ||||
| 		log("\n"); | ||||
| 		log("    -fast\n"); | ||||
| 		log("        use different default scripts that are slightly faster (at the cost\n"); | ||||
| 		log("        of output quality):\n"); | ||||
| 		log("%s\n", fold_abc9_cmd(RTLIL::constpad.at("abc9.script.default.fast").substr(1,std::string::npos)).c_str()); | ||||
| 		log("\n"); | ||||
| 		log("    -D <picoseconds>\n"); | ||||
| 		log("        set delay target. the string {D} in the default scripts above is\n"); | ||||
| 		log("        replaced by this option when used, and an empty string otherwise\n"); | ||||
| 		log("        (indicating best possible delay).\n"); | ||||
| 		log("\n"); | ||||
| //		log("    -S <num>\n");
 | ||||
| //		log("        maximum number of LUT inputs shared.\n");
 | ||||
| //		log("        (replaces {S} in the default scripts above, default: -S 1)\n");
 | ||||
| //		log("\n");
 | ||||
| 		log("    -lut <width>\n"); | ||||
| 		log("        generate netlist using luts of (max) the specified width.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -lut <w1>:<w2>\n"); | ||||
| 		log("        generate netlist using luts of (max) the specified width <w2>. All\n"); | ||||
| 		log("        luts with width <= <w1> have constant cost. for luts larger than <w1>\n"); | ||||
| 		log("        the area cost doubles with each additional input bit. the delay cost\n"); | ||||
| 		log("        is still constant for all lut widths.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -lut <file>\n"); | ||||
| 		log("        pass this file with lut library to ABC.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n"); | ||||
| 		log("        generate netlist using luts. Use the specified costs for luts with 1,\n"); | ||||
| 		log("        2, 3, .. inputs.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -showtmp\n"); | ||||
| 		log("        print the temp dir name in log. usually this is suppressed so that the\n"); | ||||
| 		log("        command output is identical across runs.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -box <file>\n"); | ||||
| 		log("        pass this file with box library to ABC.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -cwd <dir>\n"); | ||||
| 		log("        use this as the current working directory, inside which the 'input.xaig'\n"); | ||||
| 		log("        file is expected. temporary files will be created in this directory, and\n"); | ||||
| 		log("        the mapped result will be written to 'output.aig'.\n"); | ||||
| 		log("\n"); | ||||
| 		log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); | ||||
| 		log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); | ||||
| 		log("ABC on logic snippets extracted from your design. You will not get any useful\n"); | ||||
| 		log("output when passing an ABC script that writes a file. Instead write your full\n"); | ||||
| 		log("design as BLIF file with write_blif and then load that into ABC externally if\n"); | ||||
| 		log("you want to use ABC to convert your design into another format.\n"); | ||||
| 		log("\n"); | ||||
| 		log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||
| 	{ | ||||
| 		log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n"); | ||||
| 
 | ||||
| #ifdef ABCEXTERNAL | ||||
| 		std::string exe_file = ABCEXTERNAL; | ||||
| #else | ||||
| 		std::string exe_file = proc_self_dirname() + "yosys-abc"; | ||||
| #endif | ||||
| 		std::string script_file, clk_str, box_file, lut_file; | ||||
| 		std::string delay_target, lutin_shared = "-S 1", wire_delay; | ||||
| 		std::string tempdir_name; | ||||
| 		bool fast_mode = false, dff_mode = false; | ||||
| 		bool show_tempdir = false; | ||||
| 		vector<int> lut_costs; | ||||
| 
 | ||||
| #if 0 | ||||
| 		cleanup = false; | ||||
| 		show_tempdir = true; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #ifndef ABCEXTERNAL | ||||
| 		if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) | ||||
| 			exe_file = proc_self_dirname() + "..\\yosys-abc"; | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| 		std::string lut_arg, luts_arg; | ||||
| 		exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */); | ||||
| 		script_file = design->scratchpad_get_string("abc9.script", script_file); | ||||
| 		if (design->scratchpad.count("abc9.D")) { | ||||
| 			delay_target = "-D " + design->scratchpad_get_string("abc9.D"); | ||||
| 		} | ||||
| 		lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); | ||||
| 		luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); | ||||
| 		fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); | ||||
| 		dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode); | ||||
| 		show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); | ||||
| 		box_file = design->scratchpad_get_string("abc9.box", box_file); | ||||
| 		if (design->scratchpad.count("abc9.W")) { | ||||
| 			wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); | ||||
| 		} | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		char pwd [PATH_MAX]; | ||||
| 		if (!getcwd(pwd, sizeof(pwd))) { | ||||
| 			log_cmd_error("getcwd failed: %s\n", strerror(errno)); | ||||
| 			log_abort(); | ||||
| 		} | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||
| 			std::string arg = args[argidx]; | ||||
| 			if (arg == "-exe" && argidx+1 < args.size()) { | ||||
| 				exe_file = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-script" && argidx+1 < args.size()) { | ||||
| 				script_file = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-D" && argidx+1 < args.size()) { | ||||
| 				delay_target = "-D " + args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			//if (arg == "-S" && argidx+1 < args.size()) {
 | ||||
| 			//	lutin_shared = "-S " + args[++argidx];
 | ||||
| 			//	continue;
 | ||||
| 			//}
 | ||||
| 			if (arg == "-lut" && argidx+1 < args.size()) { | ||||
| 				lut_arg = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-luts" && argidx+1 < args.size()) { | ||||
| 				lut_arg = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-fast") { | ||||
| 				fast_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-dff") { | ||||
| 				dff_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-showtmp") { | ||||
| 				show_tempdir = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-box" && argidx+1 < args.size()) { | ||||
| 				box_file = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-W" && argidx+1 < args.size()) { | ||||
| 				wire_delay = "-W " + args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-cwd" && argidx+1 < args.size()) { | ||||
| 				tempdir_name = args[++argidx]; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		rewrite_filename(script_file); | ||||
| 		if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') | ||||
| 			script_file = std::string(pwd) + "/" + script_file; | ||||
| 
 | ||||
| 		// handle -lut / -luts args
 | ||||
| 		if (!lut_arg.empty()) { | ||||
| 			string arg = lut_arg; | ||||
| 			if (arg.find_first_not_of("0123456789:") == std::string::npos) { | ||||
| 				size_t pos = arg.find_first_of(':'); | ||||
| 				int lut_mode = 0, lut_mode2 = 0; | ||||
| 				if (pos != string::npos) { | ||||
| 					lut_mode = atoi(arg.substr(0, pos).c_str()); | ||||
| 					lut_mode2 = atoi(arg.substr(pos+1).c_str()); | ||||
| 				} else { | ||||
| 					lut_mode = atoi(arg.c_str()); | ||||
| 					lut_mode2 = lut_mode; | ||||
| 				} | ||||
| 				lut_costs.clear(); | ||||
| 				for (int i = 0; i < lut_mode; i++) | ||||
| 					lut_costs.push_back(1); | ||||
| 				for (int i = lut_mode; i < lut_mode2; i++) | ||||
| 					lut_costs.push_back(2 << (i - lut_mode)); | ||||
| 			} | ||||
| 			else { | ||||
| 				lut_file = arg; | ||||
| 				rewrite_filename(lut_file); | ||||
| 				if (!lut_file.empty() && !is_absolute_path(lut_file) && lut_file[0] != '+') | ||||
| 					lut_file = std::string(pwd) + "/" + lut_file; | ||||
| 			} | ||||
| 		} | ||||
| 		if (!luts_arg.empty()) { | ||||
| 			lut_costs.clear(); | ||||
| 			for (auto &tok : split_tokens(luts_arg, ",")) { | ||||
| 				auto parts = split_tokens(tok, ":"); | ||||
| 				if (GetSize(parts) == 0 && !lut_costs.empty()) | ||||
| 					lut_costs.push_back(lut_costs.back()); | ||||
| 				else if (GetSize(parts) == 1) | ||||
| 					lut_costs.push_back(atoi(parts.at(0).c_str())); | ||||
| 				else if (GetSize(parts) == 2) | ||||
| 					while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) | ||||
| 						lut_costs.push_back(atoi(parts.at(1).c_str())); | ||||
| 				else | ||||
| 					log_cmd_error("Invalid -luts syntax.\n"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (box_file.empty()) | ||||
| 			log_cmd_error("abc9_exe '-box' option is mandatory.\n"); | ||||
| 
 | ||||
| 		rewrite_filename(box_file); | ||||
| 		if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') | ||||
| 			box_file = std::string(pwd) + "/" + box_file; | ||||
| 
 | ||||
| 		if (tempdir_name.empty()) | ||||
| 			log_cmd_error("abc9_exe '-cwd' option is mandatory.\n"); | ||||
| 
 | ||||
| 
 | ||||
| 		abc9_module(design, script_file, exe_file, lut_costs, dff_mode, | ||||
| 				delay_target, lutin_shared, fast_mode, show_tempdir, | ||||
| 				box_file, lut_file, wire_delay, tempdir_name); | ||||
| 	} | ||||
| } Abc9ExePass; | ||||
| 
 | ||||
| PRIVATE_NAMESPACE_END | ||||
							
								
								
									
										1120
									
								
								passes/techmap/abc9_ops.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1120
									
								
								passes/techmap/abc9_ops.cc
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -86,6 +86,7 @@ struct TribufWorker { | |||
| 					cell->unsetPort(ID(S)); | ||||
| 					cell->type = tri_type; | ||||
| 					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); | ||||
| 					module->design->scratchpad_set_bool("tribuf.added_something", true); | ||||
| 					continue; | ||||
| 				} | ||||
| 
 | ||||
|  | @ -95,6 +96,7 @@ struct TribufWorker { | |||
| 					cell->unsetPort(ID(S)); | ||||
| 					cell->type = tri_type; | ||||
| 					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); | ||||
| 					module->design->scratchpad_set_bool("tribuf.added_something", true); | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
|  | @ -130,8 +132,10 @@ struct TribufWorker { | |||
| 
 | ||||
| 				if (no_tribuf) | ||||
| 					module->connect(it.first, muxout); | ||||
| 				else | ||||
| 				else { | ||||
| 					module->addTribuf(NEW_ID, muxout, module->ReduceOr(NEW_ID, pmux_s), it.first); | ||||
| 					module->design->scratchpad_set_bool("tribuf.added_something", true); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -29,4 +29,3 @@ $(eval $(call add_share_file,share,techlibs/common/gate2lut.v)) | |||
| $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/cells.lib)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/dummy.box)) | ||||
|  |  | |||
|  | @ -1 +0,0 @@ | |||
| (dummy) 1 0 0 0 | ||||
|  | @ -73,102 +73,80 @@ module \$lut (A, Y); | |||
|     input [WIDTH-1:0] A; | ||||
|     output Y; | ||||
| 
 | ||||
|     // Need to swap input ordering, and fix init accordingly, | ||||
|     // to match ABC's expectation of LUT inputs in non-decreasing | ||||
|     // delay order | ||||
|     localparam P_WIDTH = WIDTH < 4 ? 4 : WIDTH; | ||||
|     function [P_WIDTH-1:0] permute_index; | ||||
|         input [P_WIDTH-1:0] i; | ||||
|         integer j; | ||||
|         begin | ||||
|             permute_index = 0; | ||||
|             for (j = 0; j < P_WIDTH; j = j + 1) | ||||
|                 permute_index[P_WIDTH-1 - j] = i[j]; | ||||
|         end | ||||
|     endfunction | ||||
| 
 | ||||
|     function [2**P_WIDTH-1:0] permute_init; | ||||
|         integer i; | ||||
|         begin | ||||
|             permute_init = 0; | ||||
|             for (i = 0; i < 2**P_WIDTH; i = i + 1) | ||||
|                 permute_init[i] = LUT[permute_index(i)]; | ||||
|         end | ||||
|     endfunction | ||||
| 
 | ||||
|     parameter [2**P_WIDTH-1:0] P_LUT = permute_init(); | ||||
| 
 | ||||
|     generate | ||||
|         if (WIDTH == 1) begin | ||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|             localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}}; | ||||
|             LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0])); | ||||
|         end else | ||||
|         if (WIDTH == 2) begin | ||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(1'b0), .B(1'b0), .C(A[1]), .D(A[0])); | ||||
|             localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}}; | ||||
|             LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(1'b0), .B(1'b0), .C(A[0]), .D(A[1])); | ||||
|         end else | ||||
|         if (WIDTH == 3) begin | ||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(1'b0), .B(A[2]), .C(A[1]), .D(A[0])); | ||||
|             localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}}; | ||||
|             LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(1'b0), .B(A[0]), .C(A[1]), .D(A[2])); | ||||
|         end else | ||||
|         if (WIDTH == 4) begin | ||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(A[3]), .B(A[2]), .C(A[1]), .D(A[0])); | ||||
|             LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|         `ifndef NO_PFUMUX | ||||
|         end else | ||||
|         if (WIDTH == 5) begin | ||||
|             wire f0, f1; | ||||
|             LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), | ||||
|                 .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1])); | ||||
|             LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), | ||||
|                 .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1])); | ||||
|             PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y)); | ||||
|             LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y)); | ||||
|         end else | ||||
|         if (WIDTH == 6) begin | ||||
|             wire f0, f1, f2, f3, g0, g1; | ||||
|             LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), | ||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); | ||||
|             LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), | ||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); | ||||
|             LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
| 
 | ||||
|             LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2), | ||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); | ||||
|             LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3), | ||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); | ||||
|             LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
| 
 | ||||
|             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0)); | ||||
|             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1)); | ||||
|             L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y)); | ||||
|             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); | ||||
|             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); | ||||
|             L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y)); | ||||
|         end else | ||||
|         if (WIDTH == 7) begin | ||||
|             wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; | ||||
|             LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
| 
 | ||||
|             LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
| 
 | ||||
|             LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
| 
 | ||||
|             LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7), | ||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
|             LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7), | ||||
|                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||
| 
 | ||||
|             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0)); | ||||
|             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1)); | ||||
|             PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2)); | ||||
|             PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3)); | ||||
|             L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0)); | ||||
|             L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1)); | ||||
|             L6MUX21 mux7  (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y)); | ||||
|             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); | ||||
|             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); | ||||
|             PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2)); | ||||
|             PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3)); | ||||
|             L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0)); | ||||
|             L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1)); | ||||
|             L6MUX21 mux7  (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y)); | ||||
|         `endif | ||||
|         end else begin | ||||
|             wire _TECHMAP_FAIL_ = 1; | ||||
|  |  | |||
|  | @ -343,6 +343,7 @@ struct SynthEcp5Pass : public ScriptPass | |||
| 			else | ||||
| 				run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); | ||||
| 
 | ||||
| 			run("opt_lut_ins -tech ecp5"); | ||||
| 			run("clean"); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -246,6 +246,7 @@ struct SynthGowinPass : public ScriptPass | |||
| 		if (check_label("map_cells")) | ||||
| 		{ | ||||
| 			run("techmap -map +/gowin/cells_map.v"); | ||||
| 			run("opt_lut_ins -tech gowin"); | ||||
| 			run("setundef -undriven -params -zero"); | ||||
| 			run("hilomap -singleton -hicell VCC V -locell GND G"); | ||||
| 			if (!noiopads || help_mode) | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ module \$__ICE40_CARRY_WRAPPER ( | |||
| 	input I0, I3 | ||||
| ); | ||||
| 	parameter LUT = 0; | ||||
| 	parameter I3_IS_CI = 0; | ||||
| 	wire I3_OR_CI = I3_IS_CI ? CI : I3; | ||||
| 	SB_CARRY carry ( | ||||
| 		.I0(A), | ||||
| 		.I1(B), | ||||
|  | @ -21,7 +23,7 @@ module \$__ICE40_CARRY_WRAPPER ( | |||
| 		.I0(I0), | ||||
| 		.I1(A), | ||||
| 		.I2(B), | ||||
| 		.I3(I3), | ||||
| 		.I3(I3_OR_CI), | ||||
| 		.O(O) | ||||
| 	); | ||||
| endmodule | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ | |||
| 
 | ||||
| # Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve | ||||
| #                                 SB_LUT4+SB_CARRY) | ||||
| # Outputs: O, CO | ||||
| #   (Exception: carry chain input/output must be the | ||||
| #        last input and output and the entire bus has been | ||||
| #        moved there overriding the otherwise | ||||
|  |  | |||
|  | @ -49,13 +49,14 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO); | |||
| 			//    A[1]: 1100 1100 1100 1100 | ||||
| 			//    A[2]: 1111 0000 1111 0000 | ||||
| 			//    A[3]: 1111 1111 0000 0000 | ||||
| 			.LUT(16'b 0110_1001_1001_0110) | ||||
| 			.LUT(16'b 0110_1001_1001_0110), | ||||
| 			.I3_IS_CI(1'b1) | ||||
| 		) carry ( | ||||
| 			.A(AA[i]), | ||||
| 			.B(BB[i]), | ||||
| 			.CI(C[i]), | ||||
| 			.I0(1'b0), | ||||
| 			.I3(C[i]), | ||||
| 			.I3(1'bx), | ||||
| 			.CO(CO[i]), | ||||
| 			.O(Y[i]) | ||||
| 		); | ||||
|  |  | |||
|  | @ -42,19 +42,18 @@ module \$lut (A, Y); | |||
|         .I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0])); | ||||
|     end else | ||||
|     if (WIDTH == 2) begin | ||||
|       localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}}; | ||||
|       localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}}; | ||||
|       SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0])); | ||||
|         .I0(1'b0), .I1(1'b0), .I2(A[0]), .I3(A[1])); | ||||
|     end else | ||||
|     if (WIDTH == 3) begin | ||||
|       localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}}; | ||||
|       localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}}; | ||||
|       SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0])); | ||||
|         .I0(1'b0), .I1(A[0]), .I2(A[1]), .I3(A[2])); | ||||
|     end else | ||||
|     if (WIDTH == 4) begin | ||||
|       localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]}; | ||||
|       SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0])); | ||||
|       SB_LUT4 #(.LUT_INIT(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 | ||||
|  |  | |||
|  | @ -1126,6 +1126,7 @@ module SB_SPRAM256KA ( | |||
| 	input [15:0] DATAIN, | ||||
| 	input [3:0] MASKWREN, | ||||
| 	input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF, | ||||
| 	`ABC9_ARRIVAL_U(1821)  // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13207 | ||||
| 	output reg [15:0] DATAOUT | ||||
| ); | ||||
| `ifndef BLACKBOX | ||||
|  |  | |||
|  | @ -139,7 +139,8 @@ static void run_ice40_opts(Module *module) | |||
| 				log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n", | ||||
| 						log_id(module), log_id(cell), log_signal(replacement_output)); | ||||
| 				cell->type = "$lut"; | ||||
| 				cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], cell->getPort("\\I3") }); | ||||
| 				auto I3 = get_bit_or_zero(cell->getPort(cell->getParam(ID(I3_IS_CI)).as_bool() ? ID(CI) : ID(I3))); | ||||
| 				cell->setPort("\\A", { I3, inbit[1], inbit[0], get_bit_or_zero(cell->getPort("\\I0")) }); | ||||
| 				cell->setPort("\\Y", cell->getPort("\\O")); | ||||
| 				cell->unsetPort("\\B"); | ||||
| 				cell->unsetPort("\\CI"); | ||||
|  | @ -148,6 +149,7 @@ static void run_ice40_opts(Module *module) | |||
| 				cell->unsetPort("\\CO"); | ||||
| 				cell->unsetPort("\\O"); | ||||
| 				cell->setParam("\\WIDTH", 4); | ||||
| 				cell->unsetParam("\\I3_IS_CI"); | ||||
| 			} | ||||
| 			continue; | ||||
| 		} | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE | |||
| PRIVATE_NAMESPACE_BEGIN | ||||
| 
 | ||||
| struct SynthIntelPass : public ScriptPass { | ||||
| 	SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {} | ||||
| 	SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { experimental(); } | ||||
| 
 | ||||
| 	void help() YS_OVERRIDE | ||||
| 	{ | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ | |||
| // (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback | ||||
| //     into the (combinatorial) FD* cell to facilitate clock-enable behaviour | ||||
| 
 | ||||
| module FDRE (output Q, input C, CE, D, R); | ||||
| module FDRE (output Q, (* techmap_autopurge *) input C, 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; | ||||
|  | @ -110,7 +110,7 @@ module FDRE (output Q, input C, CE, D, R); | |||
|   wire [0:0] abc9_ff.init = 1'b0; | ||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||
| endmodule | ||||
| module FDRE_1 (output Q, input C, CE, D, R); | ||||
| module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   wire QQ, $Q; | ||||
|   generate if (INIT == 1'b1) begin | ||||
|  | @ -138,7 +138,7 @@ module FDRE_1 (output Q, input C, CE, D, R); | |||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||
| endmodule | ||||
| 
 | ||||
| module FDSE (output Q, input C, CE, D, S); | ||||
| module FDSE (output Q, (* techmap_autopurge *) input C, 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; | ||||
|  | @ -173,7 +173,7 @@ module FDSE (output Q, input C, CE, D, S); | |||
|   wire [0:0] abc9_ff.init = 1'b0; | ||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||
| endmodule | ||||
| module FDSE_1 (output Q, input C, CE, D, S); | ||||
| module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   wire QQ, $Q; | ||||
|   generate if (INIT == 1'b1) begin | ||||
|  | @ -200,7 +200,7 @@ module FDSE_1 (output Q, input C, CE, D, S); | |||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||
| endmodule | ||||
| 
 | ||||
| module FDCE (output Q, input C, CE, D, CLR); | ||||
| module FDCE (output Q, (* techmap_autopurge *) input C, 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; | ||||
|  | @ -249,7 +249,7 @@ module FDCE (output Q, input C, CE, D, CLR); | |||
|   wire [0:0] abc9_ff.init = 1'b0; | ||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||
| endmodule | ||||
| module FDCE_1 (output Q, input C, CE, D, CLR); | ||||
| module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   wire QQ, $Q, $QQ; | ||||
|   generate if (INIT == 1'b1) begin | ||||
|  | @ -288,7 +288,7 @@ module FDCE_1 (output Q, input C, CE, D, CLR); | |||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||
| endmodule | ||||
| 
 | ||||
| module FDPE (output Q, input C, CE, D, PRE); | ||||
| module FDPE (output Q, (* techmap_autopurge *) input C, 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; | ||||
|  | @ -335,7 +335,7 @@ module FDPE (output Q, input C, CE, D, PRE); | |||
|   wire [0:0] abc9_ff.init = 1'b0; | ||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||
| endmodule | ||||
| module FDPE_1 (output Q, input C, CE, D, PRE); | ||||
| module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   wire QQ, $Q, $QQ; | ||||
|   generate if (INIT == 1'b1) begin | ||||
|  |  | |||
|  | @ -33,6 +33,11 @@ endmodule | |||
| module \$__ABC9_FF_ (input D, output Q); | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id = (9000+DELAY) *) | ||||
| module \$__ABC9_DELAY (input I, output O); | ||||
|   parameter DELAY = 0; | ||||
| endmodule | ||||
| 
 | ||||
| // Box to emulate async behaviour of FDC* | ||||
| (* abc9_box_id = 1000, lib_whitebox *) | ||||
| module \$__ABC9_ASYNC0 (input A, S, output Y); | ||||
|  | @ -42,7 +47,7 @@ endmodule | |||
| // Box to emulate async behaviour of FDP* | ||||
| (* abc9_box_id = 1001, lib_whitebox *) | ||||
| module \$__ABC9_ASYNC1 (input A, S, output Y); | ||||
|   assign Y = S ? 1'b0 : A; | ||||
|   assign Y = S ? 1'b1 : A; | ||||
| endmodule | ||||
| 
 | ||||
| // Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32} | ||||
|  |  | |||
|  | @ -62,67 +62,6 @@ $__ABC9_ASYNC1 1001 1   2   1 | |||
| #A S | ||||
| 0  764 # Y | ||||
| 
 | ||||
| # Flop boxes: | ||||
| # * Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251 | ||||
| #                   https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277 | ||||
| # * Exception: $abc9_currQ is a special input (located last) necessary for clock-enable functionality | ||||
| 
 | ||||
| # Box 1100 : FDRE | ||||
| # name ID   w/b ins outs | ||||
| FDRE   1100 1   5   1 | ||||
| #C CE  D   R   $abc9_currQ | ||||
| #0 109 -46 404 0 | ||||
| 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1101 : FDRE_1 | ||||
| # name ID   w/b ins outs | ||||
| FDRE_1 1101 1   5   1 | ||||
| #C CE  D   R   $abc9_currQ | ||||
| #0 109 -46 404 0 | ||||
| 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1102 : FDSE | ||||
| # name ID   w/b ins outs | ||||
| FDSE   1102 1   5   1 | ||||
| #C CE  D   R   $abc9_currQ | ||||
| #0 109 -46 404 0 | ||||
| 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1103 : FDSE_1 | ||||
| # name ID   w/b ins outs | ||||
| FDSE_1 1103 1   5   1 | ||||
| #C CE  D   R   $abc9_currQ | ||||
| #0 109 -46 404 0 | ||||
| 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1104 : FDCE | ||||
| # name ID   w/b ins outs | ||||
| FDCE   1104 1   5   1 | ||||
| #C CE  CLR D   $abc9_currQ | ||||
| #0 109 764 -46 0 | ||||
| 0 109 764 0   0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1105 : FDCE_1 | ||||
| # name ID   w/b ins outs | ||||
| FDCE_1 1105 1   5   1 | ||||
| #C CE  CLR D   $abc9_currQ | ||||
| #0 109 764 -46 0 | ||||
| 0 109 764 0   0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1106 : FDPE | ||||
| # name ID   w/b ins outs | ||||
| FDPE   1106 1   5   1 | ||||
| #C CE  D   PRE $abc9_currQ | ||||
| #0 109 -46 764 0 | ||||
| 0 109 0   764 0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 1107 : FDPE_1 | ||||
| # name ID   w/b ins outs | ||||
| FDPE_1 1107 1   5   1 | ||||
| #C CE  D   PRE $abc9_currQ | ||||
| #0 109 -46 764 0 | ||||
| 0 109 0   764 0 # Q (-46ps Tsu clamped to 0) | ||||
| 
 | ||||
| # Box 2000 : $__ABC9_LUT6 | ||||
| #            (private cell to emulate async behaviour of LUTRAMs) | ||||
| # SLICEM/A6LUT | ||||
|  |  | |||
|  | @ -325,17 +325,20 @@ endmodule | |||
| 
 | ||||
| // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250 | ||||
| 
 | ||||
| (* abc9_box_id=1100, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDRE ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_R_INVERTED" *) | ||||
|   (* abc9_required=404 *) | ||||
|   input R | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|  | @ -349,30 +352,38 @@ module FDRE ( | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id=1101, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDRE_1 ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, R | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D, | ||||
|   (* abc9_required=404 *) | ||||
|   input R | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|   initial Q <= INIT; | ||||
|   always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id=1102, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDSE ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_S_INVERTED" *) | ||||
|   (* abc9_required=404 *) | ||||
|   input S | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|  | @ -386,13 +397,18 @@ module FDSE ( | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id=1103, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDSE_1 ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, S | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D, | ||||
|   (* abc9_required=404 *) | ||||
|   input S | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   initial Q <= INIT; | ||||
|  | @ -405,6 +421,7 @@ module FDRSE ( | |||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   (* invertible_pin = "IS_CE_INVERTED" *) | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   input D, | ||||
|  | @ -434,17 +451,20 @@ module FDRSE ( | |||
|       Q <= d; | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id=1104, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDCE ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_CLR_INVERTED" *) | ||||
|   (* abc9_required=764 *) | ||||
|   input CLR, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b0; | ||||
|  | @ -460,30 +480,38 @@ module FDCE ( | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id=1105, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDCE_1 ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, CLR | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   (* abc9_required=764 *) | ||||
|   input CLR, | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D | ||||
| ); | ||||
|   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 | ||||
| 
 | ||||
| (* abc9_box_id=1106, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDPE ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_C_INVERTED" *) | ||||
|   input C, | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   (* invertible_pin = "IS_D_INVERTED" *) | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D, | ||||
|   (* invertible_pin = "IS_PRE_INVERTED" *) | ||||
|   (* abc9_required=764 *) | ||||
|   input PRE | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|  | @ -499,13 +527,18 @@ module FDPE ( | |||
|   endcase endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| (* abc9_box_id=1107, lib_whitebox, abc9_flop *) | ||||
| (* abc9_flop, lib_whitebox *) | ||||
| module FDPE_1 ( | ||||
|   (* abc9_arrival=303 *) | ||||
|   output reg Q, | ||||
|   (* clkbuf_sink *) | ||||
|   input C, | ||||
|   input CE, D, PRE | ||||
|   (* abc9_required=109 *) | ||||
|   input CE, | ||||
|   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||
|   input D, | ||||
|   (* abc9_required=764 *) | ||||
|   input PRE | ||||
| ); | ||||
|   parameter [0:0] INIT = 1'b1; | ||||
|   initial Q <= INIT; | ||||
|  | @ -1120,15 +1153,33 @@ module RAM16X1D_1 ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM32X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 | ||||
|   (* abc9_arrival=1188 *) | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||
|   (* abc9_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 | ||||
|   (* abc9_required=453 *) | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input  WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800 | ||||
|   (* abc9_required=245 *) | ||||
|   input  A0, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798 | ||||
|   (* abc9_required=208 *) | ||||
|   input  A1, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796 | ||||
|   (* abc9_required=147 *) | ||||
|   input  A2, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794 | ||||
|   (* abc9_required=68 *) | ||||
|   input  A3, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792 | ||||
|   (* abc9_required=66 *) | ||||
|   input  A4, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||
| ); | ||||
|   parameter INIT = 32'h0; | ||||
|  | @ -1143,15 +1194,33 @@ module RAM32X1D ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM32X1D_1 ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 | ||||
|   (* abc9_arrival=1188 *) | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||
|   (* abc9_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 | ||||
|   (* abc9_required=453 *) | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input  WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800 | ||||
|   (* abc9_required=245 *) | ||||
|   input  A0, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798 | ||||
|   (* abc9_required=208 *) | ||||
|   input  A1, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796 | ||||
|   (* abc9_required=147 *) | ||||
|   input  A2, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794 | ||||
|   (* abc9_required=68 *) | ||||
|   input  A3, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792 | ||||
|   (* abc9_required=66 *) | ||||
|   input  A4, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||
| ); | ||||
|   parameter INIT = 32'h0; | ||||
|  | @ -1166,15 +1235,36 @@ module RAM32X1D_1 ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM64X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||
|   (* abc9_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 | ||||
|   (* abc9_required=453 *) | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input  WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, A5, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828 | ||||
|   (* abc9_required=362 *) | ||||
|   input  A0, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826 | ||||
|   (* abc9_required=245 *) | ||||
|   input  A1, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824 | ||||
|   (* abc9_required=208 *) | ||||
|   input  A2, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822 | ||||
|   (* abc9_required=147 *) | ||||
|   input  A3, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820 | ||||
|   (* abc9_required=68 *) | ||||
|   input  A4, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818 | ||||
|   (* abc9_required=66 *) | ||||
|   input  A5, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||
| ); | ||||
|   parameter INIT = 64'h0; | ||||
|  | @ -1189,15 +1279,36 @@ module RAM64X1D ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM64X1D_1 ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||
|   (* abc9_arrival=1153 *) | ||||
|   output DPO, SPO, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 | ||||
|   (* abc9_required=453 *) | ||||
|   input  D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input  WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input  WE, | ||||
|   input  A0, A1, A2, A3, A4, A5, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828 | ||||
|   (* abc9_required=362 *) | ||||
|   input  A0, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826 | ||||
|   (* abc9_required=245 *) | ||||
|   input  A1, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824 | ||||
|   (* abc9_required=208 *) | ||||
|   input  A2, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822 | ||||
|   (* abc9_required=147 *) | ||||
|   input  A3, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820 | ||||
|   (* abc9_required=68 *) | ||||
|   input  A4, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818 | ||||
|   (* abc9_required=66 *) | ||||
|   input  A5, | ||||
|   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||
| ); | ||||
|   parameter INIT = 64'h0; | ||||
|  | @ -1212,16 +1323,23 @@ module RAM64X1D_1 ( | |||
| endmodule | ||||
| 
 | ||||
| module RAM128X1D ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 | ||||
|   //   plus 204ps to cross MUXF7 | ||||
|   (* abc9_arrival=1357 *) | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||
|   //   plus 208ps to cross MUXF7 | ||||
|   (* abc9_arrival=1359 *) | ||||
|   output       DPO, SPO, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 | ||||
|   (* abc9_required=453 *) | ||||
|   input        D, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input        WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input        WE, | ||||
|   input  [6:0] A, DPRA | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830 | ||||
|   (* abc9_required="616 362 245 208 147 68 66" *) | ||||
|   input  [6:0] A, | ||||
|   input  [6:0] DPRA | ||||
| ); | ||||
|   parameter INIT = 128'h0; | ||||
|   parameter IS_WCLK_INVERTED = 1'b0; | ||||
|  | @ -1253,23 +1371,43 @@ endmodule | |||
| // Multi port. | ||||
| 
 | ||||
| module RAM32M ( | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 | ||||
|   (* abc9_arrival=1188 *) | ||||
|   (* abc9_arrival="1153 1188" *) | ||||
|   output [1:0] DOA, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925 | ||||
|   (* abc9_arrival=1187 *) | ||||
|   (* abc9_arrival="1161 1187" *) | ||||
|   output [1:0] DOB, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025 | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993 | ||||
|   (* abc9_arrival=1180 *) | ||||
|   (* abc9_arrival="1158 1180" *) | ||||
|   output [1:0] DOC, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093 | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061 | ||||
|   (* abc9_arrival=1190 *) | ||||
|   (* abc9_arrival="1163 1190" *) | ||||
|   output [1:0] DOD, | ||||
|   input [4:0] ADDRA, ADDRB, ADDRC, ADDRD, | ||||
|   input [1:0] DIA, DIB, DIC, DID, | ||||
|   input  [4:0] ADDRA, ADDRB, ADDRC, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792-L802 | ||||
|   (* abc9_required="245 208 147 68 66" *) | ||||
|   input  [4:0] ADDRD, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988 | ||||
|   (* abc9_required="453 384" *) | ||||
|   input  [1:0] DIA, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056 | ||||
|   (* abc9_required="461 354" *) | ||||
|   input  [1:0] DIB, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124 | ||||
|   (* abc9_required="457 375" *) | ||||
|   input  [1:0] DIC, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192 | ||||
|   (* abc9_required="310 334" *) | ||||
|   input  [1:0] DID, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input        WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input        WE | ||||
| ); | ||||
|   parameter [63:0] INIT_A = 64'h0000000000000000; | ||||
|  | @ -1377,11 +1515,27 @@ module RAM64M ( | |||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093 | ||||
|   (* abc9_arrival=1163 *) | ||||
|   output       DOD, | ||||
|   input [5:0] ADDRA, ADDRB, ADDRC, ADDRD, | ||||
|   input DIA, DIB, DIC, DID, | ||||
|   input  [5:0] ADDRA, ADDRB, ADDRC, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830 | ||||
|   (* abc9_required="362 245 208 147 68 66" *) | ||||
|   input  [5:0] ADDRD, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988 | ||||
|   (* abc9_required=384 *) | ||||
|   input        DIA, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056 | ||||
|   (* abc9_required=354 *) | ||||
|   input        DIB, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124 | ||||
|   (* abc9_required=375 *) | ||||
|   input        DIC, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192 | ||||
|   (* abc9_required=310 *) | ||||
|   input        DID, | ||||
|   (* clkbuf_sink *) | ||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||
|   input        WCLK, | ||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 | ||||
|   (* abc9_required=654 *) | ||||
|   input        WE | ||||
| ); | ||||
|   parameter [63:0] INIT_A = 64'h0000000000000000; | ||||
|  | @ -2155,7 +2309,235 @@ assign PCOUT = P; | |||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // TODO: DSP48 (Virtex 4). | ||||
| module DSP48 ( | ||||
|     input signed [17:0] A, | ||||
|     input signed [17:0] B, | ||||
|     input signed [47:0] C, | ||||
|     input signed [17:0] BCIN, | ||||
|     input signed [47:0] PCIN, | ||||
|     input CARRYIN, | ||||
|     input [6:0] OPMODE, | ||||
|     input SUBTRACT, | ||||
|     input [1:0] CARRYINSEL, | ||||
|     output signed [47:0] P, | ||||
|     output signed [17:0] BCOUT, | ||||
|     output signed [47:0] PCOUT, | ||||
|     (* clkbuf_sink *) | ||||
|     input CLK, | ||||
|     input CEA, | ||||
|     input CEB, | ||||
|     input CEC, | ||||
|     input CEM, | ||||
|     input CECARRYIN, | ||||
|     input CECINSUB, | ||||
|     input CECTRL, | ||||
|     input CEP, | ||||
|     input RSTA, | ||||
|     input RSTB, | ||||
|     input RSTC, | ||||
|     input RSTM, | ||||
|     input RSTCARRYIN, | ||||
|     input RSTCTRL, | ||||
|     input RSTP | ||||
| ); | ||||
| 
 | ||||
| parameter integer AREG = 1; | ||||
| parameter integer BREG = 1; | ||||
| parameter integer CREG = 1; | ||||
| parameter integer MREG = 1; | ||||
| parameter integer PREG = 1; | ||||
| parameter integer CARRYINREG = 1; | ||||
| parameter integer CARRYINSELREG = 1; | ||||
| parameter integer OPMODEREG = 1; | ||||
| parameter integer SUBTRACTREG = 1; | ||||
| parameter B_INPUT = "DIRECT"; | ||||
| parameter LEGACY_MODE = "MULT18X18S"; | ||||
| 
 | ||||
| wire signed [17:0] A_OUT; | ||||
| wire signed [17:0] B_OUT; | ||||
| wire signed [47:0] C_OUT; | ||||
| wire signed [35:0] M_MULT; | ||||
| wire signed [35:0] M_OUT; | ||||
| wire signed [47:0] P_IN; | ||||
| wire [6:0] OPMODE_OUT; | ||||
| wire [1:0] CARRYINSEL_OUT; | ||||
| wire CARRYIN_OUT; | ||||
| wire SUBTRACT_OUT; | ||||
| reg INT_CARRYIN_XY; | ||||
| reg INT_CARRYIN_Z; | ||||
| reg signed [47:0] XMUX; | ||||
| reg signed [47:0] YMUX; | ||||
| wire signed [47:0] XYMUX; | ||||
| reg signed [47:0] ZMUX; | ||||
| reg CIN; | ||||
| 
 | ||||
| // The B input multiplexer. | ||||
| wire signed [17:0] B_MUX; | ||||
| assign B_MUX = (B_INPUT == "DIRECT") ? B : BCIN; | ||||
| 
 | ||||
| // The cascade output. | ||||
| assign BCOUT = B_OUT; | ||||
| assign PCOUT = P; | ||||
| 
 | ||||
| // The registers. | ||||
| reg signed [17:0] A0_REG; | ||||
| reg signed [17:0] A1_REG; | ||||
| reg signed [17:0] B0_REG; | ||||
| reg signed [17:0] B1_REG; | ||||
| reg signed [47:0] C_REG; | ||||
| reg signed [35:0] M_REG; | ||||
| reg signed [47:0] P_REG; | ||||
| reg [6:0] OPMODE_REG; | ||||
| reg [1:0] CARRYINSEL_REG; | ||||
| reg SUBTRACT_REG; | ||||
| reg CARRYIN_REG; | ||||
| reg INT_CARRYIN_XY_REG; | ||||
| 
 | ||||
| initial begin | ||||
| 	A0_REG = 0; | ||||
| 	A1_REG = 0; | ||||
| 	B0_REG = 0; | ||||
| 	B1_REG = 0; | ||||
| 	C_REG = 0; | ||||
| 	M_REG = 0; | ||||
| 	P_REG = 0; | ||||
| 	OPMODE_REG = 0; | ||||
| 	CARRYINSEL_REG = 0; | ||||
| 	SUBTRACT_REG = 0; | ||||
| 	CARRYIN_REG = 0; | ||||
| 	INT_CARRYIN_XY_REG = 0; | ||||
| end | ||||
| 
 | ||||
| always @(posedge CLK) begin | ||||
| 	if (RSTA) begin | ||||
| 		A0_REG <= 0; | ||||
| 		A1_REG <= 0; | ||||
| 	end else if (CEA) begin | ||||
| 		A0_REG <= A; | ||||
| 		A1_REG <= A0_REG; | ||||
| 	end | ||||
| 	if (RSTB) begin | ||||
| 		B0_REG <= 0; | ||||
| 		B1_REG <= 0; | ||||
| 	end else if (CEB) begin | ||||
| 		B0_REG <= B_MUX; | ||||
| 		B1_REG <= B0_REG; | ||||
| 	end | ||||
| 	if (RSTC) begin | ||||
| 		C_REG <= 0; | ||||
| 	end else if (CEC) begin | ||||
| 		C_REG <= C; | ||||
| 	end | ||||
| 	if (RSTM) begin | ||||
| 		M_REG <= 0; | ||||
| 	end else if (CEM) begin | ||||
| 		M_REG <= M_MULT; | ||||
| 	end | ||||
| 	if (RSTP) begin | ||||
| 		P_REG <= 0; | ||||
| 	end else if (CEP) begin | ||||
| 		P_REG <= P_IN; | ||||
| 	end | ||||
| 	if (RSTCTRL) begin | ||||
| 		OPMODE_REG <= 0; | ||||
| 		CARRYINSEL_REG <= 0; | ||||
| 		SUBTRACT_REG <= 0; | ||||
| 	end else begin | ||||
| 		if (CECTRL) begin | ||||
| 			OPMODE_REG <= OPMODE; | ||||
| 			CARRYINSEL_REG <= CARRYINSEL; | ||||
| 		end | ||||
| 		if (CECINSUB) | ||||
| 			SUBTRACT_REG <= SUBTRACT; | ||||
| 	end | ||||
| 	if (RSTCARRYIN) begin | ||||
| 		CARRYIN_REG <= 0; | ||||
| 		INT_CARRYIN_XY_REG <= 0; | ||||
| 	end else begin | ||||
| 		if (CECINSUB) | ||||
| 			CARRYIN_REG <= CARRYIN; | ||||
| 		if (CECARRYIN) | ||||
| 			INT_CARRYIN_XY_REG <= INT_CARRYIN_XY; | ||||
| 	end | ||||
| end | ||||
| 
 | ||||
| // The register enables. | ||||
| assign A_OUT = (AREG == 2) ? A1_REG : (AREG == 1) ? A0_REG : A; | ||||
| assign B_OUT = (BREG == 2) ? B1_REG : (BREG == 1) ? B0_REG : B_MUX; | ||||
| assign C_OUT = (CREG == 1) ? C_REG : C; | ||||
| assign M_OUT = (MREG == 1) ? M_REG : M_MULT; | ||||
| assign P = (PREG == 1) ? P_REG : P_IN; | ||||
| assign OPMODE_OUT = (OPMODEREG == 1) ? OPMODE_REG : OPMODE; | ||||
| assign SUBTRACT_OUT = (SUBTRACTREG == 1) ? SUBTRACT_REG : SUBTRACT; | ||||
| assign CARRYINSEL_OUT = (CARRYINSELREG == 1) ? CARRYINSEL_REG : CARRYINSEL; | ||||
| assign CARRYIN_OUT = (CARRYINREG == 1) ? CARRYIN_REG : CARRYIN; | ||||
| 
 | ||||
| // The multiplier. | ||||
| assign M_MULT = A_OUT * B_OUT; | ||||
| 
 | ||||
| // The post-adder inputs. | ||||
| always @* begin | ||||
| 	case (OPMODE_OUT[1:0]) | ||||
| 		2'b00: XMUX <= 0; | ||||
| 		2'b10: XMUX <= P; | ||||
| 		2'b11: XMUX <= {{12{A_OUT[17]}}, A_OUT, B_OUT}; | ||||
| 		default: XMUX <= 48'hxxxxxxxxxxxx; | ||||
| 	endcase | ||||
| 	case (OPMODE_OUT[1:0]) | ||||
| 		2'b01: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17]; | ||||
| 		2'b11: INT_CARRYIN_XY <= ~A_OUT[17]; | ||||
| 		// TODO: not tested in hardware. | ||||
| 		default: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17]; | ||||
| 	endcase | ||||
| end | ||||
| 
 | ||||
| always @* begin | ||||
| 	case (OPMODE_OUT[3:2]) | ||||
| 		2'b00: YMUX <= 0; | ||||
| 		2'b11: YMUX <= C_OUT; | ||||
| 		default: YMUX <= 48'hxxxxxxxxxxxx; | ||||
| 	endcase | ||||
| end | ||||
| 
 | ||||
| assign XYMUX = (OPMODE_OUT[3:0] == 4'b0101) ? M_OUT : (XMUX + YMUX); | ||||
| 
 | ||||
| always @* begin | ||||
| 	case (OPMODE_OUT[6:4]) | ||||
| 		3'b000: ZMUX <= 0; | ||||
| 		3'b001: ZMUX <= PCIN; | ||||
| 		3'b010: ZMUX <= P; | ||||
| 		3'b011: ZMUX <= C_OUT; | ||||
| 		3'b101: ZMUX <= {{17{PCIN[47]}}, PCIN[47:17]}; | ||||
| 		3'b110: ZMUX <= {{17{P[47]}}, P[47:17]}; | ||||
| 		default: ZMUX <= 48'hxxxxxxxxxxxx; | ||||
| 	endcase | ||||
| 	// TODO: check how all this works on actual hw. | ||||
| 	if (OPMODE_OUT[1:0] == 2'b10) | ||||
| 		INT_CARRYIN_Z <= ~P[47]; | ||||
| 	else | ||||
| 		case (OPMODE_OUT[6:4]) | ||||
| 			3'b001: INT_CARRYIN_Z <= ~PCIN[47]; | ||||
| 			3'b010: INT_CARRYIN_Z <= ~P[47]; | ||||
| 			3'b101: INT_CARRYIN_Z <= ~PCIN[47]; | ||||
| 			3'b110: INT_CARRYIN_Z <= ~P[47]; | ||||
| 			default: INT_CARRYIN_Z <= 1'bx; | ||||
| 		endcase | ||||
| end | ||||
| 
 | ||||
| always @* begin | ||||
| 	case (CARRYINSEL_OUT) | ||||
| 		2'b00: CIN <= CARRYIN_OUT; | ||||
| 		2'b01: CIN <= INT_CARRYIN_Z; | ||||
| 		2'b10: CIN <= INT_CARRYIN_XY; | ||||
| 		2'b11: CIN <= INT_CARRYIN_XY_REG; | ||||
| 		default: CIN <= 1'bx; | ||||
| 	endcase | ||||
| end | ||||
| 
 | ||||
| // The post-adder. | ||||
| assign P_IN = SUBTRACT_OUT ? (ZMUX - (XYMUX + CIN)) : (ZMUX + XYMUX + CIN); | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // TODO: DSP48E (Virtex 5). | ||||
| 
 | ||||
|  | @ -2169,21 +2551,30 @@ module DSP48E1 ( | |||
|     output reg MULTSIGNOUT, | ||||
|     output OVERFLOW, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_arrival = \DSP48E1.P_arrival () *) | ||||
|     (* abc9_arrival = \P.abc9_arrival () *) | ||||
| `endif | ||||
|     output reg signed [47:0] P, | ||||
|     output reg PATTERNBDETECT, | ||||
|     output reg PATTERNDETECT, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_arrival = \DSP48E1.PCOUT_arrival () *) | ||||
|     (* abc9_arrival = \PCOUT.abc9_arrival () *) | ||||
| `endif | ||||
|     output [47:0] PCOUT, | ||||
|     output UNDERFLOW, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_required = \A.abc9_required () *) | ||||
| `endif | ||||
|     input signed [29:0] A, | ||||
|     input [29:0] ACIN, | ||||
|     input [3:0] ALUMODE, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_required = \B.abc9_required () *) | ||||
| `endif | ||||
|     input signed [17:0] B, | ||||
|     input [17:0] BCIN, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_required = \C.abc9_required () *) | ||||
| `endif | ||||
|     input [47:0] C, | ||||
|     input CARRYCASCIN, | ||||
|     input CARRYIN, | ||||
|  | @ -2202,10 +2593,16 @@ module DSP48E1 ( | |||
|     input CEM, | ||||
|     input CEP, | ||||
|     (* clkbuf_sink *) input CLK, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_required = \D.abc9_required () *) | ||||
| `endif | ||||
|     input [24:0] D, | ||||
|     input [4:0] INMODE, | ||||
|     input MULTSIGNIN, | ||||
|     input [6:0] OPMODE, | ||||
| `ifdef YOSYS | ||||
|     (* abc9_required = \PCIN.abc9_required () *) | ||||
| `endif | ||||
|     input [47:0] PCIN, | ||||
|     input RSTA, | ||||
|     input RSTALLCARRYIN, | ||||
|  | @ -2250,69 +2647,133 @@ module DSP48E1 ( | |||
|     parameter [6:0] IS_OPMODE_INVERTED = 7'b0; | ||||
| 
 | ||||
| `ifdef YOSYS | ||||
|     function integer \DSP48E1.P_arrival ; | ||||
|     function integer \A.abc9_required ; | ||||
|     begin | ||||
|         \DSP48E1.P_arrival = 0; | ||||
|         if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)      \DSP48E1.P_arrival =  329; | ||||
|             // Worst-case from CREG and MREG | ||||
|             else if (CREG != 0) \DSP48E1.P_arrival = 1687; | ||||
|             else if (MREG != 0) \DSP48E1.P_arrival = 1671; | ||||
|             // Worst-case from AREG and BREG | ||||
|             else if (AREG != 0) \DSP48E1.P_arrival = 2952; | ||||
|             else if (BREG != 0) \DSP48E1.P_arrival = 2813; | ||||
|         \A.abc9_required = 0; | ||||
|         if (AREG != 0)           \A.abc9_required =  254; | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||
|             if (MREG != 0)       \A.abc9_required = 1416; | ||||
|             else if (PREG != 0)  \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3030 : 2739) ; | ||||
|         end | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin | ||||
|             if (PREG != 0)      \DSP48E1.P_arrival =  329; | ||||
|             // Worst-case from CREG and MREG | ||||
|             else if (CREG != 0) \DSP48E1.P_arrival = 1687; | ||||
|             else if (MREG != 0) \DSP48E1.P_arrival = 1671; | ||||
|             // Worst-case from AREG, ADREG, BREG, DREG | ||||
|             else if (AREG != 0)  \DSP48E1.P_arrival = 3935; | ||||
|             else if (DREG != 0)  \DSP48E1.P_arrival = 3908; | ||||
|             else if (ADREG != 0) \DSP48E1.P_arrival = 2958; | ||||
|             else if (BREG != 0)  \DSP48E1.P_arrival = 2813; | ||||
|             // Worst-case from ADREG and MREG | ||||
|             if (MREG != 0)       \A.abc9_required = 2400; | ||||
|             else if (ADREG != 0) \A.abc9_required = 1283; | ||||
|             else if (PREG != 0)  \A.abc9_required = 3723; | ||||
|             else if (PREG != 0)  \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 4014 : 3723) ; | ||||
|         end | ||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)      \DSP48E1.P_arrival =  329; | ||||
|             if (PREG != 0)       \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1730 : 1441) ; | ||||
|         end | ||||
|     end | ||||
|     endfunction | ||||
|     function integer \B.abc9_required ; | ||||
|     begin | ||||
|         \B.abc9_required = 0; | ||||
|         if (BREG != 0)      \B.abc9_required =  324; | ||||
|         else if (MREG != 0) \B.abc9_required = 1285; | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)  \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ; | ||||
|         end | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin | ||||
|             if (PREG != 0)  \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ; | ||||
|         end | ||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)  \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1718 : 1428) ; | ||||
|         end | ||||
|     end | ||||
|     endfunction | ||||
|     function integer \C.abc9_required ; | ||||
|     begin | ||||
|         \C.abc9_required = 0; | ||||
|         if (CREG != 0)      \C.abc9_required =  168; | ||||
|         else if (PREG != 0) \C.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1534 : 1244) ; | ||||
|     end | ||||
|     endfunction | ||||
|     function integer \D.abc9_required ; | ||||
|     begin | ||||
|         \D.abc9_required = 0; | ||||
|         if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||
|         end | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin | ||||
|             if (DREG != 0)       \D.abc9_required =  248; | ||||
|             else if (ADREG != 0) \D.abc9_required = 1195; | ||||
|             else if (MREG != 0)  \D.abc9_required = 2310; | ||||
|             else if (PREG != 0)  \D.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3925 : 3635) ; | ||||
|         end | ||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin | ||||
|         end | ||||
|     end | ||||
|     endfunction | ||||
|     function integer \PCIN.abc9_required ; | ||||
|     begin | ||||
|         \PCIN.abc9_required = 0; | ||||
|         if (PREG != 0) \PCIN.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1315 : 1025) ; | ||||
|     end | ||||
|     endfunction | ||||
|     function integer \P.abc9_arrival ; | ||||
|     begin | ||||
|         \P.abc9_arrival = 0; | ||||
|         if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)       \P.abc9_arrival =  329; | ||||
|             // Worst-case from CREG and MREG | ||||
|             else if (CREG != 0)  \P.abc9_arrival = 1687; | ||||
|             else if (MREG != 0)  \P.abc9_arrival = 1671; | ||||
|             // Worst-case from AREG and BREG | ||||
|             else if (AREG != 0)  \P.abc9_arrival = 2952; | ||||
|             else if (BREG != 0)  \P.abc9_arrival = 2813; | ||||
|         end | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin | ||||
|             if (PREG != 0)       \P.abc9_arrival =  329; | ||||
|             // Worst-case from CREG and MREG | ||||
|             else if (CREG != 0)  \P.abc9_arrival = 1687; | ||||
|             else if (MREG != 0)  \P.abc9_arrival = 1671; | ||||
|             // Worst-case from AREG, ADREG, BREG, DREG | ||||
|             else if (AREG != 0)  \P.abc9_arrival = 3935; | ||||
|             else if (DREG != 0)  \P.abc9_arrival = 3908; | ||||
|             else if (ADREG != 0) \P.abc9_arrival = 2958; | ||||
|             else if (BREG != 0)  \P.abc9_arrival = 2813; | ||||
|         end | ||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)       \P.abc9_arrival =  329; | ||||
|             // Worst-case from AREG, BREG, CREG | ||||
|             else if (CREG != 0) \DSP48E1.P_arrival = 1687; | ||||
|             else if (AREG != 0) \DSP48E1.P_arrival = 1632; | ||||
|             else if (BREG != 0) \DSP48E1.P_arrival = 1616; | ||||
|             else if (CREG != 0)  \P.abc9_arrival = 1687; | ||||
|             else if (AREG != 0)  \P.abc9_arrival = 1632; | ||||
|             else if (BREG != 0)  \P.abc9_arrival = 1616; | ||||
|         end | ||||
|         //else | ||||
|         //    $error("Invalid DSP48E1 configuration"); | ||||
|     end | ||||
|     endfunction | ||||
|     function integer \DSP48E1.PCOUT_arrival ; | ||||
|     function integer \PCOUT.abc9_arrival ; | ||||
|     begin | ||||
|         \DSP48E1.PCOUT_arrival = 0; | ||||
|         \PCOUT.abc9_arrival = 0; | ||||
|         if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)      \DSP48E1.PCOUT_arrival =  435; | ||||
|             if (PREG != 0)       \PCOUT.abc9_arrival =  435; | ||||
|             // Worst-case from CREG and MREG | ||||
|             else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; | ||||
|             else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819; | ||||
|             else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; | ||||
|             else if (MREG != 0)  \PCOUT.abc9_arrival = 1819; | ||||
|             // Worst-case from AREG and BREG | ||||
|             else if (AREG != 0) \DSP48E1.PCOUT_arrival = 3098; | ||||
|             else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960; | ||||
|             else if (AREG != 0)  \PCOUT.abc9_arrival = 3098; | ||||
|             else if (BREG != 0)  \PCOUT.abc9_arrival = 2960; | ||||
|         end | ||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin | ||||
|             if (PREG != 0)      \DSP48E1.PCOUT_arrival =  435; | ||||
|             if (PREG != 0)       \PCOUT.abc9_arrival =  435; | ||||
|             // Worst-case from CREG and MREG | ||||
|             else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; | ||||
|             else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819; | ||||
|             else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; | ||||
|             else if (MREG != 0)  \PCOUT.abc9_arrival = 1819; | ||||
|             // Worst-case from AREG, ADREG, BREG, DREG | ||||
|             else if (AREG != 0)  \DSP48E1.PCOUT_arrival = 4083; | ||||
|             else if (DREG != 0)  \DSP48E1.PCOUT_arrival = 4056; | ||||
|             else if (BREG != 0)  \DSP48E1.PCOUT_arrival = 2960; | ||||
|             else if (ADREG != 0) \DSP48E1.PCOUT_arrival = 2859; | ||||
|             else if (AREG != 0)  \PCOUT.abc9_arrival = 4083; | ||||
|             else if (DREG != 0)  \PCOUT.abc9_arrival = 4056; | ||||
|             else if (BREG != 0)  \PCOUT.abc9_arrival = 2960; | ||||
|             else if (ADREG != 0) \PCOUT.abc9_arrival = 2859; | ||||
|         end | ||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin | ||||
|             if (PREG != 0)      \DSP48E1.PCOUT_arrival =  435; | ||||
|             if (PREG != 0)       \PCOUT.abc9_arrival =  435; | ||||
|             // Worst-case from AREG, BREG, CREG | ||||
|             else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; | ||||
|             else if (AREG != 0) \DSP48E1.PCOUT_arrival = 1780; | ||||
|             else if (BREG != 0) \DSP48E1.PCOUT_arrival = 1765; | ||||
|             else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; | ||||
|             else if (AREG != 0)  \PCOUT.abc9_arrival = 1780; | ||||
|             else if (BREG != 0)  \PCOUT.abc9_arrival = 1765; | ||||
|         end | ||||
|         //else | ||||
|         //    $error("Invalid DSP48E1 configuration"); | ||||
|  |  | |||
|  | @ -180,18 +180,58 @@ CELLS = [ | |||
|     Cell('RAMB18E1', port_attrs={ | ||||
|         'CLKARDCLK': ['clkbuf_sink'], | ||||
|         'CLKBWRCLK': ['clkbuf_sink'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143 | ||||
|         'DOADO': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163 | ||||
|         'DOBDO': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144 | ||||
|         'DOPADOP': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164 | ||||
|         'DOPBDOP': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13 | ||||
|         'ADDRARDADDR': ['abc9_required=566'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17 | ||||
|         'ADDRBWRADDR': ['abc9_required=566'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19 | ||||
|         'WEA': ['abc9_required=532'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21 | ||||
|         'WEBWE': ['abc9_required=532'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123 | ||||
|         'DIADI': ['abc9_required=737'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133 | ||||
|         'DIBDI': ['abc9_required=737'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125 | ||||
|         'DIPADIP': ['abc9_required=737'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135 | ||||
|         'DIPBDIP': ['abc9_required=737'], | ||||
|     }), | ||||
|     Cell('RAMB36E1', port_attrs={ | ||||
|         'CLKARDCLK': ['clkbuf_sink'], | ||||
|         'CLKBWRCLK': ['clkbuf_sink'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143 | ||||
|         'DOADO': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163 | ||||
|         'DOBDO': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144 | ||||
|         'DOPADOP': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164 | ||||
|         'DOPBDOP': ['abc9_arrival=2454'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13 | ||||
|         'ADDRARDADDR': ['abc9_required=566'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17 | ||||
|         'ADDRBWRADDR': ['abc9_required=566'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19 | ||||
|         'WEA': ['abc9_required=532'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21 | ||||
|         'WEBWE': ['abc9_required=532'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123 | ||||
|         'DIADI': ['abc9_required=737'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133 | ||||
|         'DIBDI': ['abc9_required=737'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125 | ||||
|         'DIPADIP': ['abc9_required=737'], | ||||
|         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135 | ||||
|         'DIPBDIP': ['abc9_required=737'], | ||||
|     }), | ||||
|     # Ultrascale. | ||||
|     Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), | ||||
|  | @ -209,7 +249,7 @@ CELLS = [ | |||
|     # Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E | ||||
|     # Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP | ||||
|     # Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6 | ||||
|     Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4 | ||||
|     # Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4 | ||||
|     Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5 | ||||
|     #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7 | ||||
|     Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale | ||||
|  |  | |||
|  | @ -4518,13 +4518,21 @@ module RAMB18E1 (...); | |||
|     input RSTREGARSTREG; | ||||
|     (* invertible_pin = "IS_RSTREGB_INVERTED" *) | ||||
|     input RSTREGB; | ||||
|     (* abc9_required=566 *) | ||||
|     input [13:0] ADDRARDADDR; | ||||
|     (* abc9_required=566 *) | ||||
|     input [13:0] ADDRBWRADDR; | ||||
|     (* abc9_required=737 *) | ||||
|     input [15:0] DIADI; | ||||
|     (* abc9_required=737 *) | ||||
|     input [15:0] DIBDI; | ||||
|     (* abc9_required=737 *) | ||||
|     input [1:0] DIPADIP; | ||||
|     (* abc9_required=737 *) | ||||
|     input [1:0] DIPBDIP; | ||||
|     (* abc9_required=532 *) | ||||
|     input [1:0] WEA; | ||||
|     (* abc9_required=532 *) | ||||
|     input [3:0] WEBWE; | ||||
| endmodule | ||||
| 
 | ||||
|  | @ -4742,13 +4750,21 @@ module RAMB36E1 (...); | |||
|     input REGCEB; | ||||
|     input INJECTDBITERR; | ||||
|     input INJECTSBITERR; | ||||
|     (* abc9_required=566 *) | ||||
|     input [15:0] ADDRARDADDR; | ||||
|     (* abc9_required=566 *) | ||||
|     input [15:0] ADDRBWRADDR; | ||||
|     (* abc9_required=737 *) | ||||
|     input [31:0] DIADI; | ||||
|     (* abc9_required=737 *) | ||||
|     input [31:0] DIBDI; | ||||
|     (* abc9_required=737 *) | ||||
|     input [3:0] DIPADIP; | ||||
|     (* abc9_required=737 *) | ||||
|     input [3:0] DIPBDIP; | ||||
|     (* abc9_required=532 *) | ||||
|     input [3:0] WEA; | ||||
|     (* abc9_required=532 *) | ||||
|     input [7:0] WEBWE; | ||||
| endmodule | ||||
| 
 | ||||
|  | @ -5476,49 +5492,6 @@ module URAM288_BASE (...); | |||
|     input SLEEP; | ||||
| endmodule | ||||
| 
 | ||||
| module DSP48 (...); | ||||
|     parameter integer AREG = 1; | ||||
|     parameter integer BREG = 1; | ||||
|     parameter B_INPUT = "DIRECT"; | ||||
|     parameter integer CARRYINREG = 1; | ||||
|     parameter integer CARRYINSELREG = 1; | ||||
|     parameter integer CREG = 1; | ||||
|     parameter LEGACY_MODE = "MULT18X18S"; | ||||
|     parameter integer MREG = 1; | ||||
|     parameter integer OPMODEREG = 1; | ||||
|     parameter integer PREG = 1; | ||||
|     parameter integer SUBTRACTREG = 1; | ||||
|     output [17:0] BCOUT; | ||||
|     output [47:0] P; | ||||
|     output [47:0] PCOUT; | ||||
|     input [17:0] A; | ||||
|     input [17:0] B; | ||||
|     input [17:0] BCIN; | ||||
|     input [47:0] C; | ||||
|     input CARRYIN; | ||||
|     input [1:0] CARRYINSEL; | ||||
|     input CEA; | ||||
|     input CEB; | ||||
|     input CEC; | ||||
|     input CECARRYIN; | ||||
|     input CECINSUB; | ||||
|     input CECTRL; | ||||
|     input CEM; | ||||
|     input CEP; | ||||
|     (* clkbuf_sink *) | ||||
|     input CLK; | ||||
|     input [6:0] OPMODE; | ||||
|     input [47:0] PCIN; | ||||
|     input RSTA; | ||||
|     input RSTB; | ||||
|     input RSTC; | ||||
|     input RSTCARRYIN; | ||||
|     input RSTCTRL; | ||||
|     input RSTM; | ||||
|     input RSTP; | ||||
|     input SUBTRACT; | ||||
| endmodule | ||||
| 
 | ||||
| module DSP48E (...); | ||||
|     parameter SIM_MODE = "SAFE"; | ||||
|     parameter integer ACASCREG = 1; | ||||
|  |  | |||
|  | @ -29,90 +29,65 @@ module \$lut (A, Y); | |||
|   input [WIDTH-1:0] A; | ||||
|   output Y; | ||||
| 
 | ||||
|   // Need to swap input ordering, and fix init accordingly, | ||||
|   // to match ABC's expectation of LUT inputs in non-decreasing | ||||
|   // delay order | ||||
|   function [WIDTH-1:0] permute_index; | ||||
|       input [WIDTH-1:0] i; | ||||
|       integer j; | ||||
|       begin | ||||
|           permute_index = 0; | ||||
|           for (j = 0; j < WIDTH; j = j + 1) | ||||
|               permute_index[WIDTH-1 - j] = i[j]; | ||||
|       end | ||||
|   endfunction | ||||
| 
 | ||||
|   function [2**WIDTH-1:0] permute_init; | ||||
|       input [2**WIDTH-1:0] orig; | ||||
|       integer i; | ||||
|       begin | ||||
|           permute_init = 0; | ||||
|           for (i = 0; i < 2**WIDTH; i = i + 1) | ||||
|               permute_init[i] = orig[permute_index(i)]; | ||||
|       end | ||||
|   endfunction | ||||
| 
 | ||||
|   parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT); | ||||
| 
 | ||||
|   generate | ||||
|     if (WIDTH == 1) begin | ||||
|       if (P_LUT == 2'b01) begin | ||||
|       if (LUT == 2'b01) begin | ||||
|         INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0])); | ||||
|       end else begin | ||||
|         LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|           .I0(A[0])); | ||||
|       end | ||||
|     end else | ||||
|     if (WIDTH == 2) begin | ||||
|       LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[1]), .I1(A[0])); | ||||
|       LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[0]), .I1(A[1])); | ||||
|     end else | ||||
|     if (WIDTH == 3) begin | ||||
|       LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[2]), .I1(A[1]), .I2(A[0])); | ||||
|       LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2])); | ||||
|     end else | ||||
|     if (WIDTH == 4) begin | ||||
|       LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[3]), .I1(A[2]), .I2(A[1]), | ||||
|         .I3(A[0])); | ||||
|       LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3])); | ||||
|     end else | ||||
|     if (WIDTH == 5) begin | ||||
|       LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[4]), .I1(A[3]), .I2(A[2]), | ||||
|         .I3(A[1]), .I4(A[0])); | ||||
|       LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4])); | ||||
|     end else | ||||
|     if (WIDTH == 6) begin | ||||
|       LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[5]), .I1(A[4]), .I2(A[3]), | ||||
|         .I3(A[2]), .I4(A[1]), .I5(A[0])); | ||||
|       LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|     end else | ||||
|     if (WIDTH == 7) begin | ||||
|       wire T0, T1; | ||||
|       LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0), | ||||
|         .I0(A[6]), .I1(A[5]), .I2(A[4]), | ||||
|         .I3(A[3]), .I4(A[2]), .I5(A[1])); | ||||
|       LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1), | ||||
|         .I0(A[6]), .I1(A[5]), .I2(A[4]), | ||||
|         .I3(A[3]), .I4(A[2]), .I5(A[1])); | ||||
|       MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0])); | ||||
|       LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|       LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|       MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); | ||||
|     end else | ||||
|     if (WIDTH == 8) begin | ||||
|       wire T0, T1, T2, T3, T4, T5; | ||||
|       LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0), | ||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), | ||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); | ||||
|       LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1), | ||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), | ||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); | ||||
|       LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2), | ||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), | ||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); | ||||
|       LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3), | ||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), | ||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); | ||||
|       MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1])); | ||||
|       MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1])); | ||||
|       MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0])); | ||||
|       LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|       LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|       LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|       LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), | ||||
|         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||
|         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||
|       MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); | ||||
|       MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); | ||||
|       MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); | ||||
|     end else begin | ||||
|       wire _TECHMAP_FAIL_ = 1; | ||||
|     end | ||||
|  |  | |||
|  | @ -153,7 +153,7 @@ endmatch | |||
| 
 | ||||
| match $__XILINX_RAM32X2Q | ||||
|   min bits 5 | ||||
|   min rports 3 | ||||
|   min rports 2 | ||||
|   min wports 1 | ||||
|   make_outreg | ||||
|   or_next_if_better | ||||
|  | @ -161,7 +161,7 @@ endmatch | |||
| 
 | ||||
| match $__XILINX_RAM64X1Q | ||||
|   min bits 5 | ||||
|   min rports 3 | ||||
|   min rports 2 | ||||
|   min wports 1 | ||||
|   make_outreg | ||||
| endmatch | ||||
|  |  | |||
|  | @ -316,7 +316,11 @@ struct SynthXilinxPass : public ScriptPass | |||
| 			run("proc"); | ||||
| 			if (flatten || help_mode) | ||||
| 				run("flatten", "(with '-flatten')"); | ||||
| 			if (active_design) | ||||
| 				active_design->scratchpad_unset("tribuf.added_something"); | ||||
| 			run("tribuf -logic"); | ||||
| 			if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something")) | ||||
| 				log_error("Tristate buffers are unsupported without the '-iopad' option.\n"); | ||||
| 			run("deminout"); | ||||
| 			run("opt_expr"); | ||||
| 			run("opt_clean"); | ||||
|  | @ -526,7 +530,7 @@ struct SynthXilinxPass : public ScriptPass | |||
| 		if (check_label("map_cells")) { | ||||
| 			// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
 | ||||
| 			if (help_mode || !noiopad) | ||||
| 				run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(only if not '-noiopad')"); | ||||
| 				run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(skip if '-noiopad')"); | ||||
| 			std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v"; | ||||
| 			if (widemux > 0) | ||||
| 				techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux); | ||||
|  | @ -589,12 +593,11 @@ struct SynthXilinxPass : public ScriptPass | |||
| 			if (!nosrl || help_mode) | ||||
| 				run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); | ||||
| 			std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; | ||||
| 			if (help_mode) | ||||
| 				techmap_args += stringf("[-map %s]", ff_map_file.c_str()); | ||||
| 			else if (!abc9) | ||||
| 			if (help_mode || !abc9) | ||||
| 				techmap_args += stringf(" -map %s", ff_map_file.c_str()); | ||||
| 			run("techmap " + techmap_args, "(only if '-abc9')"); | ||||
| 			run("techmap " + techmap_args); | ||||
| 			run("xilinx_dffopt"); | ||||
| 			run("opt_lut_ins -tech xilinx"); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("finalize")) { | ||||
|  |  | |||
							
								
								
									
										3
									
								
								techlibs/xilinx/tests/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								techlibs/xilinx/tests/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -12,4 +12,7 @@ test_dsp48a_model_ref.v | |||
| test_dsp48a1_model_ref.v | ||||
| test_dsp48a1_model_uut.v | ||||
| test_dsp48a1_model | ||||
| test_dsp48_model_ref.v | ||||
| test_dsp48_model_uut.v | ||||
| test_dsp48_model | ||||
| *.vcd | ||||
|  |  | |||
							
								
								
									
										14
									
								
								techlibs/xilinx/tests/test_dsp48_model.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								techlibs/xilinx/tests/test_dsp48_model.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #!/bin/bash | ||||
| set -ex | ||||
| if [ -z $ISE_DIR ]; then | ||||
| 	ISE_DIR=/opt/Xilinx/ISE/14.7 | ||||
| fi | ||||
| sed 's/DSP48 /DSP48_UUT /; /DSP48_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48_model_uut.v | ||||
| if [ ! -f "test_dsp48_model_ref.v" ]; then | ||||
| 	cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48.v test_dsp48_model_ref.v | ||||
| fi | ||||
| for tb in mult_allreg mult_noreg mult_inreg | ||||
| do | ||||
| 	iverilog -s $tb -s glbl -o test_dsp48_model test_dsp48_model.v test_dsp48_model_uut.v test_dsp48_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v | ||||
| 	vvp -N ./test_dsp48_model | ||||
| done | ||||
							
								
								
									
										287
									
								
								techlibs/xilinx/tests/test_dsp48_model.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								techlibs/xilinx/tests/test_dsp48_model.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,287 @@ | |||
| `timescale 1ns / 1ps | ||||
| 
 | ||||
| module testbench; | ||||
| 	parameter integer AREG = 1; | ||||
| 	parameter integer BREG = 1; | ||||
| 	parameter integer CREG = 1; | ||||
| 	parameter integer MREG = 1; | ||||
| 	parameter integer PREG = 1; | ||||
| 	parameter integer CARRYINREG = 1; | ||||
| 	parameter integer CARRYINSELREG = 1; | ||||
| 	parameter integer OPMODEREG = 1; | ||||
| 	parameter integer SUBTRACTREG = 1; | ||||
| 	parameter B_INPUT = "DIRECT"; | ||||
| 	parameter LEGACY_MODE = "NONE"; | ||||
| 
 | ||||
| 	reg CLK; | ||||
| 	reg CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL; | ||||
| 	reg RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL; | ||||
| 	reg [17:0] A; | ||||
| 	reg [17:0] B; | ||||
| 	reg [47:0] C; | ||||
| 	reg [17:0] BCIN; | ||||
| 	reg [47:0] PCIN; | ||||
| 	reg CARRYIN; | ||||
| 	reg [6:0] OPMODE; | ||||
| 	reg SUBTRACT; | ||||
| 	reg [1:0] CARRYINSEL; | ||||
| 
 | ||||
| 	output [47:0] P, REF_P; | ||||
| 	output [17:0] BCOUT, REF_BCOUT; | ||||
| 	output [47:0] PCOUT, REF_PCOUT; | ||||
| 
 | ||||
| 	integer errcount = 0; | ||||
| 
 | ||||
| 	reg ERROR_FLAG = 0; | ||||
| 
 | ||||
| 	task clkcycle; | ||||
| 		begin | ||||
| 			#5; | ||||
| 			CLK = ~CLK; | ||||
| 			#10; | ||||
| 			CLK = ~CLK; | ||||
| 			#2; | ||||
| 			ERROR_FLAG = 0; | ||||
| 			if (REF_BCOUT !== BCOUT) begin | ||||
| 				$display("ERROR at %1t: REF_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, BCOUT, REF_BCOUT ^ BCOUT); | ||||
| 				errcount = errcount + 1; | ||||
| 				ERROR_FLAG = 1; | ||||
| 			end | ||||
| 			if (REF_P !== P) begin | ||||
| 				$display("ERROR at %1t: REF_P=%b UUT_P=%b DIFF=%b", $time, REF_P, P, REF_P ^ P); | ||||
| 				errcount = errcount + 1; | ||||
| 				ERROR_FLAG = 1; | ||||
| 			end | ||||
| 			if (REF_PCOUT !== PCOUT) begin | ||||
| 				$display("ERROR at %1t: REF_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, PCOUT, REF_PCOUT ^ PCOUT); | ||||
| 				errcount = errcount + 1; | ||||
| 				ERROR_FLAG = 1; | ||||
| 			end | ||||
| 			#3; | ||||
| 		end | ||||
| 	endtask | ||||
| 
 | ||||
| 	reg config_valid = 0; | ||||
| 	task drc; | ||||
| 		begin | ||||
| 			config_valid = 1; | ||||
| 
 | ||||
| 			if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0; | ||||
| 			if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b10) config_valid = 0; | ||||
| 			if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b10) config_valid = 0; | ||||
| 			if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b11) config_valid = 0; | ||||
| 			if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b11) config_valid = 0; | ||||
| 			if (OPMODE[3:2] == 2'b10) config_valid = 0; | ||||
| 			if ((OPMODE[3:2] == 2'b01) ^ (OPMODE[1:0] == 2'b01) == 1'b1) config_valid = 0; | ||||
| 			if ((OPMODE[6:4] == 3'b010 || OPMODE[6:4] == 3'b110) && PREG != 1) config_valid = 0; | ||||
| 			if (OPMODE[6:4] == 3'b100) config_valid = 0; | ||||
| 			if (OPMODE[6:4] == 3'b111) config_valid = 0; | ||||
| 			if (OPMODE[6:4] == 3'b000 && CARRYINSEL == 2'b01) config_valid = 0; | ||||
| 			if (OPMODE[6:4] == 3'b011 && CARRYINSEL == 2'b01) config_valid = 0; | ||||
| 
 | ||||
| 			// Xilinx models consider these combinations invalid for an unknown reason. | ||||
| 			if (CARRYINSEL == 2'b01 && OPMODE[3:2] == 2'b00) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000101) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b10 && OPMODE == 7'b0100011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b10 && OPMODE == 7'b0111111) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b10 && OPMODE == 7'b1100011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000101) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0011111) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0010011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100101) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0101111) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0110011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b0111111) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b1010011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b1011111) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100011) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100101) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE == 7'b1101111) config_valid = 0; | ||||
| 
 | ||||
| 			if (CARRYINSEL == 2'b10 && OPMODE[3:0] == 4'b0101 && MREG == 1) config_valid = 0; | ||||
| 			if (CARRYINSEL == 2'b11 && OPMODE[3:0] == 4'b0101 && MREG == 0) config_valid = 0; | ||||
| 		end | ||||
| 	endtask | ||||
| 
 | ||||
| 	initial begin | ||||
| 		$dumpfile("test_dsp48_model.vcd"); | ||||
| 		$dumpvars(0, testbench); | ||||
| 
 | ||||
| 		#2; | ||||
| 		CLK = 1'b0; | ||||
| 		{CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = 8'b11111111; | ||||
| 		{A, B, C, PCIN, OPMODE, SUBTRACT, CARRYIN, CARRYINSEL} = 0; | ||||
| 		{RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 7'b1111111; | ||||
| 		repeat (10) begin | ||||
| 			#10; | ||||
| 			CLK = 1'b1; | ||||
| 			#10; | ||||
| 			CLK = 1'b0; | ||||
| 			#10; | ||||
| 			CLK = 1'b1; | ||||
| 			#10; | ||||
| 			CLK = 1'b0; | ||||
| 		end | ||||
| 		{RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 0; | ||||
| 
 | ||||
| 		repeat (100000) begin | ||||
| 			clkcycle; | ||||
| 			config_valid = 0; | ||||
| 			while (!config_valid) begin | ||||
| 				A = $urandom; | ||||
| 				B = $urandom; | ||||
| 				C = {$urandom, $urandom}; | ||||
| 				BCIN = $urandom; | ||||
| 				PCIN = {$urandom, $urandom}; | ||||
| 
 | ||||
| 				{CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = $urandom | $urandom | $urandom; | ||||
| 				{RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom; | ||||
| 				{CARRYIN, CARRYINSEL, OPMODE, SUBTRACT} = $urandom; | ||||
| 
 | ||||
| 				drc; | ||||
| 			end | ||||
| 		end | ||||
| 
 | ||||
| 		if (errcount == 0) begin | ||||
| 			$display("All tests passed."); | ||||
| 			$finish; | ||||
| 		end else begin | ||||
| 			$display("Caught %1d errors.", errcount); | ||||
| 			$stop; | ||||
| 		end | ||||
| 	end | ||||
| 
 | ||||
| 	DSP48 #( | ||||
| 		.AREG               (AREG), | ||||
| 		.BREG               (BREG), | ||||
| 		.CREG               (CREG), | ||||
| 		.MREG               (MREG), | ||||
| 		.PREG               (PREG), | ||||
| 		.CARRYINREG         (CARRYINREG), | ||||
| 		.CARRYINSELREG      (CARRYINSELREG), | ||||
| 		.OPMODEREG          (OPMODEREG), | ||||
| 		.SUBTRACTREG        (SUBTRACTREG), | ||||
| 		.B_INPUT            (B_INPUT), | ||||
| 		.LEGACY_MODE        (LEGACY_MODE) | ||||
| 	) ref ( | ||||
| 		.A             (A), | ||||
| 		.B             (B), | ||||
| 		.C             (C), | ||||
| 		.BCIN          (BCIN), | ||||
| 		.PCIN          (PCIN), | ||||
| 		.CARRYIN       (CARRYIN), | ||||
| 		.OPMODE        (OPMODE), | ||||
| 		.SUBTRACT      (SUBTRACT), | ||||
| 		.CARRYINSEL    (CARRYINSEL), | ||||
| 		.BCOUT         (REF_BCOUT), | ||||
| 		.P             (REF_P), | ||||
| 		.PCOUT         (REF_PCOUT), | ||||
| 		.CEA           (CEA), | ||||
| 		.CEB           (CEB), | ||||
| 		.CEC           (CEC), | ||||
| 		.CEM           (CEM), | ||||
| 		.CEP           (CEP), | ||||
| 		.CECARRYIN     (CECARRYIN), | ||||
| 		.CECINSUB       (CECINSUB), | ||||
| 		.CECTRL        (CECTRL), | ||||
| 		.CLK           (CLK), | ||||
| 		.RSTA          (RSTA), | ||||
| 		.RSTB          (RSTB), | ||||
| 		.RSTC          (RSTC), | ||||
| 		.RSTM          (RSTM), | ||||
| 		.RSTP          (RSTP), | ||||
| 		.RSTCARRYIN    (RSTCARRYIN), | ||||
| 		.RSTCTRL       (RSTCTRL) | ||||
| 	); | ||||
| 
 | ||||
| 	DSP48_UUT #( | ||||
| 		.AREG               (AREG), | ||||
| 		.BREG               (BREG), | ||||
| 		.CREG               (CREG), | ||||
| 		.MREG               (MREG), | ||||
| 		.PREG               (PREG), | ||||
| 		.CARRYINREG         (CARRYINREG), | ||||
| 		.CARRYINSELREG      (CARRYINSELREG), | ||||
| 		.OPMODEREG          (OPMODEREG), | ||||
| 		.SUBTRACTREG        (SUBTRACTREG), | ||||
| 		.B_INPUT            (B_INPUT), | ||||
| 		.LEGACY_MODE        (LEGACY_MODE) | ||||
| 	) uut ( | ||||
| 		.A             (A), | ||||
| 		.B             (B), | ||||
| 		.C             (C), | ||||
| 		.BCIN          (BCIN), | ||||
| 		.PCIN          (PCIN), | ||||
| 		.CARRYIN       (CARRYIN), | ||||
| 		.OPMODE        (OPMODE), | ||||
| 		.SUBTRACT      (SUBTRACT), | ||||
| 		.CARRYINSEL    (CARRYINSEL), | ||||
| 		.BCOUT         (BCOUT), | ||||
| 		.P             (P), | ||||
| 		.PCOUT         (PCOUT), | ||||
| 		.CEA           (CEA), | ||||
| 		.CEB           (CEB), | ||||
| 		.CEC           (CEC), | ||||
| 		.CEM           (CEM), | ||||
| 		.CEP           (CEP), | ||||
| 		.CECARRYIN     (CECARRYIN), | ||||
| 		.CECINSUB       (CECINSUB), | ||||
| 		.CECTRL        (CECTRL), | ||||
| 		.CLK           (CLK), | ||||
| 		.RSTA          (RSTA), | ||||
| 		.RSTB          (RSTB), | ||||
| 		.RSTC          (RSTC), | ||||
| 		.RSTM          (RSTM), | ||||
| 		.RSTP          (RSTP), | ||||
| 		.RSTCARRYIN    (RSTCARRYIN), | ||||
| 		.RSTCTRL       (RSTCTRL) | ||||
| 	); | ||||
| endmodule | ||||
| 
 | ||||
| module mult_noreg; | ||||
| 	testbench #( | ||||
| 		.AREG               (0), | ||||
| 		.BREG               (0), | ||||
| 		.CREG               (0), | ||||
| 		.MREG               (0), | ||||
| 		.PREG               (0), | ||||
| 		.CARRYINREG         (0), | ||||
| 		.CARRYINSELREG      (0), | ||||
| 		.OPMODEREG          (0), | ||||
| 		.SUBTRACTREG        (0), | ||||
| 		.B_INPUT            ("DIRECT") | ||||
| 	) testbench (); | ||||
| endmodule | ||||
| 
 | ||||
| module mult_allreg; | ||||
| 	testbench #( | ||||
| 		.AREG               (1), | ||||
| 		.BREG               (1), | ||||
| 		.CREG               (1), | ||||
| 		.MREG               (1), | ||||
| 		.PREG               (1), | ||||
| 		.CARRYINREG         (1), | ||||
| 		.CARRYINSELREG      (1), | ||||
| 		.OPMODEREG          (1), | ||||
| 		.SUBTRACTREG        (1), | ||||
| 		.B_INPUT            ("CASCADE") | ||||
| 	) testbench (); | ||||
| endmodule | ||||
| 
 | ||||
| module mult_inreg; | ||||
| 	testbench #( | ||||
| 		.AREG               (1), | ||||
| 		.BREG               (1), | ||||
| 		.CREG               (1), | ||||
| 		.MREG               (0), | ||||
| 		.PREG               (0), | ||||
| 		.CARRYINREG         (1), | ||||
| 		.CARRYINSELREG      (0), | ||||
| 		.OPMODEREG          (0), | ||||
| 		.SUBTRACTREG        (0), | ||||
| 		.B_INPUT            ("DIRECT") | ||||
| 	) testbench (); | ||||
| endmodule | ||||
							
								
								
									
										32
									
								
								tests/arch/ecp5/opt_lut_ins.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/arch/ecp5/opt_lut_ins.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| read_ilang << EOF | ||||
| 
 | ||||
| module \top | ||||
| 
 | ||||
|   wire input 1 \A | ||||
|   wire input 2 \B | ||||
|   wire input 3 \C | ||||
|   wire input 4 \D | ||||
| 
 | ||||
|   wire output 5 \Z | ||||
| 
 | ||||
|   cell \LUT4 $0 | ||||
|     parameter \INIT 16'1111110011000000 | ||||
|     connect \A \A | ||||
|     connect \B \B | ||||
|     connect \C \C | ||||
|     connect \D \D | ||||
|     connect \Z \Z | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| read_verilog -lib +/ecp5/cells_sim.v | ||||
| 
 | ||||
| equiv_opt -assert -map +/ecp5/cells_sim.v opt_lut_ins -tech ecp5 | ||||
| 
 | ||||
| design -load postopt | ||||
| 
 | ||||
| select -assert-count 1 top/t:LUT4 | ||||
| select -assert-count 0 top/w:A %co top/t:LUT4 %i | ||||
| select -assert-count 1 top/w:B %co top/t:LUT4 %i | ||||
|  | @ -36,6 +36,6 @@ proc | |||
| equiv_opt -assert -map +/efinix/cells_sim.v synth_efinix # equivalency check | ||||
| design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) | ||||
| cd mux16 # Constrain all select calls below inside the top module | ||||
| select -assert-count 11 t:EFX_LUT4 | ||||
| select -assert-max 12 t:EFX_LUT4 | ||||
| 
 | ||||
| select -assert-none t:EFX_LUT4 %% t:* %D | ||||
|  |  | |||
|  | @ -18,13 +18,13 @@ proc | |||
| equiv_opt -assert -map +/gowin/cells_sim.v synth_gowin # equivalency check | ||||
| design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) | ||||
| cd mux4 # Constrain all select calls below inside the top module | ||||
| select -assert-count 4 t:LUT4 | ||||
| select -assert-count 4 t:LUT* | ||||
| select -assert-count 2 t:MUX2_LUT5 | ||||
| select -assert-count 1 t:MUX2_LUT6 | ||||
| select -assert-count 6 t:IBUF | ||||
| select -assert-count 1 t:OBUF | ||||
| 
 | ||||
| select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D | ||||
| select -assert-none t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D | ||||
| 
 | ||||
| design -load read | ||||
| hierarchy -top mux8 | ||||
|  | @ -35,7 +35,7 @@ cd mux8 # Constrain all select calls below inside the top module | |||
| select -assert-count 11 t:IBUF | ||||
| select -assert-count 1 t:OBUF | ||||
| 
 | ||||
| select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D | ||||
| select -assert-none t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:IBUF t:OBUF %% t:* %D | ||||
| 
 | ||||
| design -load read | ||||
| hierarchy -top mux16 | ||||
|  | @ -46,4 +46,4 @@ cd mux16 # Constrain all select calls below inside the top module | |||
| select -assert-count 20 t:IBUF | ||||
| select -assert-count 1 t:OBUF | ||||
| 
 | ||||
| select -assert-none t:LUT4 t:MUX2_LUT6 t:MUX2_LUT5 t:MUX2_LUT6 t:MUX2_LUT7 t:MUX2_LUT8 t:IBUF t:OBUF %% t:* %D | ||||
| select -assert-none t:GND t:VCC t:LUT* t:MUX2_LUT6 t:MUX2_LUT5 t:MUX2_LUT6 t:MUX2_LUT7 t:MUX2_LUT8 t:IBUF t:OBUF %% t:* %D | ||||
|  |  | |||
							
								
								
									
										72
									
								
								tests/arch/ice40/bug1597.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								tests/arch/ice40/bug1597.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| read_verilog <<EOT | ||||
| module top ( | ||||
|     input CLK, PIN_1, PIN_2, PIN_3, PIN_4, PIN_5, | ||||
|         PIN_6, PIN_7, PIN_8, PIN_9, PIN_10, PIN_11, PIN_12, PIN_13, PIN_25, | ||||
|     output USBPU, PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, | ||||
|         PIN_19, PIN_20, PIN_21, PIN_22, PIN_23, PIN_24, | ||||
| ); | ||||
|     assign USBPU = 0; | ||||
| 
 | ||||
|     wire[5:0] parOut; | ||||
|     wire[5:0] chrg; | ||||
| 
 | ||||
|     assign PIN_14 = parOut[0]; | ||||
|     assign PIN_15 = parOut[1]; | ||||
|     assign PIN_16 = parOut[2]; | ||||
|     assign PIN_17 = parOut[3]; | ||||
|     assign PIN_18 = parOut[4]; | ||||
|     assign PIN_19 = parOut[5]; | ||||
|     assign chrg[0] = PIN_3; | ||||
|     assign chrg[1] = PIN_4; | ||||
|     assign chrg[2] = PIN_5; | ||||
|     assign chrg[3] = PIN_6; | ||||
|     assign chrg[4] = PIN_7; | ||||
|     assign chrg[5] = PIN_8; | ||||
| 
 | ||||
|     SSCounter6o sc6(PIN_1, CLK, PIN_2, PIN_9, chrg, parOut); | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| module SSCounter6 (input wire rst, clk, adv, jmp, input wire [5:0] in, output reg[5:0] out); | ||||
|     always @(posedge clk, posedge rst) | ||||
|         if (rst) out <= 0; | ||||
|         else if (adv || jmp) out <= jmp ? in : out + 1; | ||||
| endmodule | ||||
| 
 | ||||
| // Optimized 6 bit counter, it should takes 7 cells. | ||||
| /* b[5:1]                       /* b[0] | ||||
| 1010101010101010 in             1010101010101010 in | ||||
| 1100110011001100 jmp            1100110011001100 jmp | ||||
| 1111000011110000 loop           1111000011110000 loop | ||||
| 1111111100000000 carry          1111111100000000 - | ||||
| ----------------------          ---------------------- | ||||
| 1000101110111000 out            1000101110001011 out | ||||
|    8   B   B   8                   8   B   8   B | ||||
| */ | ||||
| module SSCounter6o (input wire rst, clk, adv, jmp, input wire [5:0] in, output wire[5:0] out); | ||||
|     wire[4:0] co; | ||||
|     wire[5:0] lo; | ||||
|     wire ien; | ||||
|     SB_LUT4 #(.LUT_INIT(16'hFFF0)) lien (ien, 0, 0, adv, jmp); | ||||
|     SB_CARRY c0 (co[0], jmp, out[0], 1), | ||||
|              c1 (co[1], jmp, out[1], co[0]), | ||||
|              c2 (co[2], jmp, out[2], co[1]), | ||||
|              c3 (co[3], jmp, out[3], co[2]), | ||||
|              c4 (co[4], jmp, out[4], co[3]); | ||||
|     SB_DFFER d0 (out[0], clk, ien, rst, lo[0]), | ||||
|              d1 (out[1], clk, ien, rst, lo[1]), | ||||
|              d2 (out[2], clk, ien, rst, lo[2]), | ||||
|              d3 (out[3], clk, ien, rst, lo[3]), | ||||
|              d4 (out[4], clk, ien, rst, lo[4]), | ||||
|              d5 (out[5], clk, ien, rst, lo[5]); | ||||
|     SB_LUT4 #(.LUT_INIT(16'h8B8B)) l0 (lo[0], in[0], jmp, out[0], 0); | ||||
|     SB_LUT4 #(.LUT_INIT(16'h8BB8)) l1 (lo[1], in[1], jmp, out[1], co[0]); | ||||
|     SB_LUT4 #(.LUT_INIT(16'h8BB8)) l2 (lo[2], in[2], jmp, out[2], co[1]); | ||||
|     SB_LUT4 #(.LUT_INIT(16'h8BB8)) l3 (lo[3], in[3], jmp, out[3], co[2]); | ||||
|     SB_LUT4 #(.LUT_INIT(16'h8BB8)) l4 (lo[4], in[4], jmp, out[4], co[3]); | ||||
|     SB_LUT4 #(.LUT_INIT(16'h8BB8)) l5 (lo[5], in[5], jmp, out[5], co[4]); | ||||
| endmodule | ||||
| EOT | ||||
| hierarchy -top top | ||||
| flatten | ||||
| equiv_opt -multiclock -map +/ice40/cells_sim.v synth_ice40 | ||||
|  | @ -1,23 +1,3 @@ | |||
| read_verilog -icells -formal <<EOT | ||||
| module \$__ICE40_CARRY_WRAPPER (output CO, O, input A, B, CI, I0, I3); | ||||
|   parameter LUT = 0; | ||||
|   SB_CARRY carry ( | ||||
|     .I0(A), | ||||
|     .I1(B), | ||||
|     .CI(CI), | ||||
|     .CO(CO) | ||||
|   ); | ||||
|   \$lut #( | ||||
|     .WIDTH(4), | ||||
|     .LUT(LUT) | ||||
|   ) lut ( | ||||
|     .A({I0,A,B,I3}), | ||||
|     .Y(O) | ||||
|   ); | ||||
| endmodule | ||||
| EOT | ||||
| design -stash unmap | ||||
| 
 | ||||
| read_verilog -icells -formal <<EOT | ||||
| module top(input CI, I0, output [1:0] CO, output O); | ||||
|     wire A = 1'b0, B = 1'b0; | ||||
|  | @ -26,13 +6,14 @@ module top(input CI, I0, output [1:0] CO, output O); | |||
| 		//    A[1]: 1100 1100 1100 1100 | ||||
| 		//    A[2]: 1111 0000 1111 0000 | ||||
| 		//    A[3]: 1111 1111 0000 0000 | ||||
| 		.LUT(~16'b 0110_1001_1001_0110) | ||||
| 		.LUT(~16'b 0110_1001_1001_0110), | ||||
| 		.I3_IS_CI(1'b1) | ||||
| 	) u0 ( | ||||
| 		.A(A), | ||||
| 		.B(B), | ||||
| 		.CI(CI), | ||||
| 		.I0(I0), | ||||
| 		.I3(CI), | ||||
| 		.I3(1'bx), | ||||
| 		.CO(CO[0]), | ||||
| 		.O(O) | ||||
| 	); | ||||
|  | @ -40,7 +21,7 @@ module top(input CI, I0, output [1:0] CO, output O); | |||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| equiv_opt -assert -map %unmap -map +/ice40/cells_sim.v ice40_opt | ||||
| equiv_opt -assert -map +/ice40/abc9_model.v -map +/ice40/cells_sim.v ice40_opt | ||||
| design -load postopt | ||||
| select -assert-count 1 t:* | ||||
| select -assert-count 1 t:$lut | ||||
|  | @ -105,3 +86,33 @@ select -assert-count 1 t:SB_LUT4 | |||
| select -assert-count 1 t:SB_CARRY | ||||
| select -assert-count 1 t:SB_CARRY a:keep %i | ||||
| select -assert-count 1 t:SB_CARRY c:carry %i | ||||
| 
 | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module top(input I3, I2, I1, I0, output O, O2); | ||||
| 	SB_LUT4 #( | ||||
| 		.LUT_INIT(8'b 1001_0110) | ||||
| 	) u0 ( | ||||
| 		.I0(I0), | ||||
| 		.I1(I1), | ||||
| 		.I2(I2), | ||||
| 		.I3(), | ||||
| 		.O(O) | ||||
| 	); | ||||
| 	wire CO; | ||||
| 	\$__ICE40_CARRY_WRAPPER #( | ||||
| 		.LUT(~8'b 1001_0110), | ||||
| 		.I3_IS_CI(1'b0) | ||||
| 	) u1 ( | ||||
| 		.A(1'b0), | ||||
| 		.B(1'b0), | ||||
| 		.CI(1'b0), | ||||
| 		.I0(), | ||||
| 		.I3(), | ||||
| 		.CO(CO), | ||||
| 		.O(O2) | ||||
| 	); | ||||
| endmodule | ||||
| EOT | ||||
| ice40_opt | ||||
|  |  | |||
							
								
								
									
										25
									
								
								tests/arch/xilinx/opt_lut_ins.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/arch/xilinx/opt_lut_ins.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| read_ilang << EOF | ||||
| 
 | ||||
| module \top | ||||
| 
 | ||||
|   wire width 4 input 1 \A | ||||
| 
 | ||||
|   wire output 2 \O | ||||
| 
 | ||||
|   cell \LUT4 $0 | ||||
|     parameter \INIT 16'1111110011000000 | ||||
|     connect \I0 \A [0] | ||||
|     connect \I1 \A [1] | ||||
|     connect \I2 \A [2] | ||||
|     connect \I3 \A [3] | ||||
|     connect \O \O | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| equiv_opt -assert -map +/xilinx/cells_sim.v opt_lut_ins -tech xilinx | ||||
| 
 | ||||
| design -load postopt | ||||
| 
 | ||||
| select -assert-count 1 t:LUT3 | ||||
							
								
								
									
										5
									
								
								tests/arch/xilinx/tribuf.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/arch/xilinx/tribuf.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| ! ../../../yosys ../common/tribuf.v -qp "synth_xilinx" | ||||
| ../../../yosys ../common/tribuf.v -qp "synth_xilinx -iopad; \ | ||||
| select -assert-count 2 t:IBUF; \ | ||||
| select -assert-count 1 t:INV; \ | ||||
| select -assert-count 1 t:OBUFT" | ||||
							
								
								
									
										23
									
								
								tests/opt/opt_lut_ins.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/opt/opt_lut_ins.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | |||
| read_ilang << EOF | ||||
| 
 | ||||
| module \top | ||||
| 
 | ||||
|   wire width 4 input 1 \A | ||||
| 
 | ||||
|   wire output 2 \Y | ||||
| 
 | ||||
|   cell $lut \lut | ||||
|     parameter \LUT 16'1111110011000000 | ||||
|     parameter \WIDTH 4 | ||||
|     connect \A \A | ||||
|     connect \Y \Y | ||||
|   end | ||||
| end | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| equiv_opt -assert opt_lut_ins | ||||
| 
 | ||||
| design -load postopt | ||||
| 
 | ||||
| select -assert-count 1 t:$lut r:WIDTH=3 %i | ||||
							
								
								
									
										66
									
								
								tests/sat/clk2fflogic.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								tests/sat/clk2fflogic.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| read_verilog -icells <<EOT | ||||
| module top(input clk, d, s, r, output reg [17:0] q); | ||||
| always @(posedge clk or posedge s) if ( s) q[ 0] <= 1'b1; else q[ 0] <= d; | ||||
| always @(posedge clk or negedge s) if (!s) q[ 1] <= 1'b1; else q[ 1] <= d; | ||||
| always @(posedge clk or posedge r) if ( r) q[ 2] <= 1'b0; else q[ 2] <= d; | ||||
| always @(posedge clk or negedge r) if (!r) q[ 3] <= 1'b0; else q[ 3] <= d; | ||||
| always @(negedge clk or posedge s) if ( s) q[ 4] <= 1'b1; else q[ 4] <= d; | ||||
| always @(negedge clk or negedge s) if (!s) q[ 5] <= 1'b1; else q[ 5] <= d; | ||||
| always @(negedge clk or posedge r) if ( r) q[ 6] <= 1'b0; else q[ 6] <= d; | ||||
| always @(negedge clk or negedge r) if (!r) q[ 7] <= 1'b0; else q[ 7] <= d; | ||||
| 
 | ||||
| // Seems like proc_dlatch always sets {SET,CLR}_POLARITY to true | ||||
| always @(posedge clk or posedge s or posedge r) if ( r) q[ 8] <= 1'b0; else if ( s) q[ 8] <= 1'b1; else q[ 8] <= d; | ||||
| //always @(posedge clk or posedge s or negedge r) if (!r) q[ 9] <= 1'b0; else if ( s) q[ 9] <= 1'b1; else q[ 9] <= d; | ||||
| //always @(posedge clk or negedge s or posedge r) if ( r) q[10] <= 1'b0; else if (!s) q[10] <= 1'b1; else q[10] <= d; | ||||
| //always @(posedge clk or negedge s or negedge r) if (!r) q[11] <= 1'b0; else if (!s) q[11] <= 1'b1; else q[11] <= d; | ||||
| $dffsr  #(.CLK_POLARITY(1'h1), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h1), .WIDTH(32'd1)) ppn (.CLK(clk), .CLR(r), .D(d), .Q(q[ 9]), .SET(s)); | ||||
| $dffsr  #(.CLK_POLARITY(1'h1), .CLR_POLARITY(1'h1), .SET_POLARITY(1'h0), .WIDTH(32'd1)) pnp (.CLK(clk), .CLR(r), .D(d), .Q(q[10]), .SET(s)); | ||||
| $dffsr  #(.CLK_POLARITY(1'h1), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h0), .WIDTH(32'd1)) pnn (.CLK(clk), .CLR(r), .D(d), .Q(q[11]), .SET(s)); | ||||
| 
 | ||||
| always @(negedge clk or posedge s or posedge r) if ( r) q[12] <= 1'b0; else if ( s) q[12] <= 1'b1; else q[12] <= d; | ||||
| //always @(negedge clk or posedge s or negedge r) if (!r) q[13] <= 1'b0; else if ( s) q[13] <= 1'b1; else q[13] <= d; | ||||
| //always @(negedge clk or negedge s or posedge r) if ( r) q[14] <= 1'b0; else if (!s) q[14] <= 1'b1; else q[14] <= d; | ||||
| //always @(negedge clk or negedge s or negedge r) if (!r) q[15] <= 1'b0; else if (!s) q[15] <= 1'b1; else q[15] <= d; | ||||
| $dffsr  #(.CLK_POLARITY(1'h0), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h1), .WIDTH(32'd1)) npn (.CLK(clk), .CLR(r), .D(d), .Q(q[13]), .SET(s)); | ||||
| $dffsr  #(.CLK_POLARITY(1'h0), .CLR_POLARITY(1'h1), .SET_POLARITY(1'h0), .WIDTH(32'd1)) nnp (.CLK(clk), .CLR(r), .D(d), .Q(q[14]), .SET(s)); | ||||
| $dffsr  #(.CLK_POLARITY(1'h0), .CLR_POLARITY(1'h0), .SET_POLARITY(1'h0), .WIDTH(32'd1)) nnn (.CLK(clk), .CLR(r), .D(d), .Q(q[15]), .SET(s)); | ||||
| 
 | ||||
| always @(posedge clk) q[16] <= d; | ||||
| always @(negedge clk) q[17] <= d; | ||||
| endmodule | ||||
| EOT | ||||
| proc | ||||
| select -assert-count 8 t:$adff | ||||
| select -assert-count 8 t:$dffsr | ||||
| select -assert-count 2 t:$dff | ||||
| design -save gold | ||||
| 
 | ||||
| simplemap | ||||
| select -assert-count 1 t:$_DFF_NN0_ | ||||
| select -assert-count 1 t:$_DFF_NN1_ | ||||
| select -assert-count 1 t:$_DFF_NP0_ | ||||
| select -assert-count 1 t:$_DFF_NP1_ | ||||
| select -assert-count 1 t:$_DFF_PN0_ | ||||
| select -assert-count 1 t:$_DFF_PN1_ | ||||
| select -assert-count 1 t:$_DFF_PP0_ | ||||
| select -assert-count 1 t:$_DFF_PP1_ | ||||
| stat | ||||
| select -assert-count 1 t:$_DFFSR_NNN_ | ||||
| select -assert-count 1 t:$_DFFSR_NNP_ | ||||
| select -assert-count 1 t:$_DFFSR_NPN_ | ||||
| select -assert-count 1 t:$_DFFSR_NPP_ | ||||
| select -assert-count 1 t:$_DFFSR_PNN_ | ||||
| select -assert-count 1 t:$_DFFSR_PNP_ | ||||
| select -assert-count 1 t:$_DFFSR_PPN_ | ||||
| select -assert-count 1 t:$_DFFSR_PPP_ | ||||
| select -assert-count 1 t:$_DFF_N_ | ||||
| select -assert-count 1 t:$_DFF_P_ | ||||
| design -stash gate | ||||
| 
 | ||||
| design -import gold -as gold | ||||
| design -import gate -as gate | ||||
| clk2fflogic | ||||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports -set-init-undef -seq 10 miter | ||||
|  | @ -2,3 +2,14 @@ read_verilog -sv initval.v | |||
| proc;; | ||||
| 
 | ||||
| sat -seq 10 -prove-asserts | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module top(input clk, i, output [1:0] o); | ||||
| (* init = 2'bx0 *) | ||||
| wire [1:0] o; | ||||
| assign o[1] = o[0]; | ||||
| $_DFF_P_ dff (.C(clk), .D(i), .Q(o[0])); | ||||
| endmodule | ||||
| EOT | ||||
| sat -seq 1 | ||||
|  |  | |||
|  | @ -213,7 +213,7 @@ module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encode | |||
|   input rst; | ||||
| endmodule | ||||
| 
 | ||||
| (* abc_box_id=1 *) | ||||
| (* abc9_box_id=1, whitebox *) | ||||
| module MUXF8(input I0, I1, S, output O); | ||||
| endmodule | ||||
| 
 | ||||
|  | @ -291,3 +291,19 @@ module abc9_test035(input clk, d, output reg [1:0] q); | |||
| always @(posedge clk) q[0] <= d; | ||||
| always @(negedge clk) q[1] <= q[0]; | ||||
| endmodule | ||||
| 
 | ||||
| module abc9_test036(input A, B, S, output [1:0] O); | ||||
|   (* keep *) | ||||
|   MUXF8 m  ( | ||||
|     .I0(I0), | ||||
|     .I1(I1), | ||||
|     .O(O[0]), | ||||
|     .S(S) | ||||
|   ); | ||||
|   MUXF8 m2  ( | ||||
|     .I0(I0), | ||||
|     .I1(I1), | ||||
|     .O(O[1]), | ||||
|     .S(S) | ||||
|   ); | ||||
| endmodule | ||||
|  |  | |||
|  | @ -28,4 +28,5 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p | |||
|     abc9 -lut 4 -box ../abc.box; \ | ||||
|     clean; \ | ||||
|     check -assert; \ | ||||
|     select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'" | ||||
|     select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \ | ||||
|     setattr -mod -unset whitebox'" | ||||
|  |  | |||
|  | @ -39,6 +39,35 @@ design -load gold | |||
| scratchpad -copy abc9.script.flow3 abc9.script | ||||
| abc9 -lut 4 | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog <<EOT | ||||
| module top(input a, b, output o); | ||||
| (* keep *) wire w = a & b; | ||||
| assign o = ~w; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| simplemap | ||||
| equiv_opt -assert abc9 -lut 4 | ||||
| design -load postopt | ||||
| select -assert-count 2 t:$lut | ||||
| 
 | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module top(input a, b, output o); | ||||
| wire w; | ||||
| (* keep *) $_AND_ gate (.Y(w), .A(a), .B(b)); | ||||
| assign o = ~w; | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| simplemap | ||||
| equiv_opt -assert abc9 -lut 4 | ||||
| design -load postopt | ||||
| select -assert-count 1 t:$lut | ||||
| select -assert-count 1 t:$_AND_ | ||||
| 
 | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ design -import gate -as gate | |||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| 
 | ||||
| design -load read | ||||
| hierarchy -top abc9_test028 | ||||
| proc | ||||
|  | @ -23,6 +24,7 @@ select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i | |||
| select -assert-count 1 t:unknown | ||||
| select -assert-none t:$lut t:unknown %% t: %D | ||||
| 
 | ||||
| 
 | ||||
| design -load read | ||||
| hierarchy -top abc9_test032 | ||||
| proc | ||||
|  | @ -38,3 +40,16 @@ design -import gate -as gate | |||
| 
 | ||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||
| sat -seq 10 -verify -prove-asserts -show-ports miter | ||||
| 
 | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog -icells <<EOT | ||||
| module abc9_test036(input clk, d, output q); | ||||
| (* keep *) reg w; | ||||
| $__ABC9_FF_ ff(.D(d), .Q(w)); | ||||
| wire \ff.clock = clk; | ||||
| wire \ff.init = 1'b0; | ||||
| assign q = w; | ||||
| endmodule | ||||
| EOT | ||||
| abc9 -lut 4 -dff | ||||
|  |  | |||
							
								
								
									
										2
									
								
								tests/various/help.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/various/help.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| help -all | ||||
| help -celltypes | ||||
							
								
								
									
										12
									
								
								tests/various/sformatf.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/various/sformatf.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| read_verilog <<EOT | ||||
| 
 | ||||
| module top; | ||||
| 	localparam a = $sformatf("0x%x", 8'h5A); | ||||
| 	localparam b = $sformatf("%d", 4'b011); | ||||
| 	generate | ||||
| 		if (a != "0x5a") $error("a incorrect!"); | ||||
| 		if (b != "3") $error("b incorrect!"); | ||||
| 	endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| EOT | ||||
							
								
								
									
										124
									
								
								tests/various/sv_implicit_ports.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										124
									
								
								tests/various/sv_implicit_ports.sh
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,124 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| trap 'echo "ERROR in sv_implicit_ports.sh" >&2; exit 1' ERR | ||||
| 
 | ||||
| # Simple case | ||||
| ../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT | ||||
| module add(input [7:0] a, input [7:0] b, output [7:0] q); | ||||
| 	assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	wire [7:0] b = 8'd42; | ||||
| 	add add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| # Generate block | ||||
| ../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT | ||||
| module add(input [7:0] a, input [7:0] b, output [7:0] q); | ||||
| assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	generate | ||||
| 	if (1) begin:ablock | ||||
| 		wire [7:0] b = 8'd42; | ||||
| 		add add_i(.*); | ||||
| 	end | ||||
| 	endgenerate | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| # Missing wire | ||||
| ((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT | ||||
| module add(input [7:0] a, input [7:0] b, output [7:0] q); | ||||
| 	assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	add add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| ) 2>&1 | grep -F "ERROR: No matching wire for implicit port connection \`b' of cell top.add_i (add)." > /dev/null | ||||
| 
 | ||||
| # Incorrectly sized wire | ||||
| ((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT | ||||
| module add(input [7:0] a, input [7:0] b, output [7:0] q); | ||||
| 	assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	wire [6:0] b = 6'd42; | ||||
| 	add add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| ) 2>&1 | grep -F "ERROR: Width mismatch between wire (7 bits) and port (8 bits) for implicit port connection \`b' of cell top.add_i (add)." > /dev/null | ||||
| 
 | ||||
| # Defaults | ||||
| ../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT | ||||
| module add(input [7:0] a = 8'd00, input [7:0] b = 8'd01, output [7:0] q); | ||||
| assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	add add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| # Parameterised module | ||||
| ../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT | ||||
| module add #(parameter N=3) (input [N-1:0] a = 8'd00, input [N-1:0] b = 8'd01, output [N-1:0] q); | ||||
| assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	add #(.N(8)) add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| # Parameterised blackbox module | ||||
| ../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - <<EOT | ||||
| (* blackbox *) | ||||
| module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q); | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, b, output [7:0] q); | ||||
| 	add #(.N(8)) add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| # Parameterised blackbox module - incorrect width | ||||
| ((../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - || true) <<EOT | ||||
| (* blackbox *) | ||||
| module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q); | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, b, output [7:0] q); | ||||
| 	add #(.N(6)) add_i(.*); | ||||
| endmodule | ||||
| EOT | ||||
| ) 2>&1 | grep -F "ERROR: Width mismatch between wire (8 bits) and port (6 bits) for implicit port connection \`q' of cell top.add_i (add)." > /dev/null | ||||
| 
 | ||||
| # Mixed implicit and explicit 1 | ||||
| ../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT | ||||
| module add(input [7:0] a, input [7:0] b, output [7:0] q); | ||||
| 	assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, output [7:0] q); | ||||
| 	add add_i(.b(8'd42), .*); | ||||
| endmodule | ||||
| EOT | ||||
| 
 | ||||
| # Mixed implicit and explicit 2 | ||||
| (../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT | ||||
| module add(input [7:0] a, input [7:0] b, output [7:0] q); | ||||
| 	assign q = a + b; | ||||
| endmodule | ||||
| 
 | ||||
| module top(input [7:0] a, input [9:0] b, output [7:0] q); | ||||
| 	add add_i(.b, .*); | ||||
| endmodule | ||||
| EOT | ||||
| ) 2>&1 | grep -F "Warning: Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue