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 "check -mapped" | ||||||
|     - Added checking of SystemVerilog always block types (always_comb, |     - Added checking of SystemVerilog always block types (always_comb, | ||||||
|       always_latch and always_ff) |       always_latch and always_ff) | ||||||
|  |     - Added support for SystemVerilog wildcard port connections (.*) | ||||||
|     - Added "xilinx_dffopt" pass |     - Added "xilinx_dffopt" pass | ||||||
|     - Added "scratchpad" pass |     - Added "scratchpad" pass | ||||||
|     - Added "abc9 -dff" |     - Added "abc9 -dff" | ||||||
|     - Added "synth_xilinx -dff" |     - Added "synth_xilinx -dff" | ||||||
|  |     - Added "opt_lut_ins" pass | ||||||
| 
 | 
 | ||||||
| Yosys 0.8 .. Yosys 0.9 | 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 |   `abc9` to preserve the integrity of carry-chains. Specifying this attribute | ||||||
|   onto a bus port will affect only its most significant bit. |   onto a bus port will affect only its most significant bit. | ||||||
| 
 | 
 | ||||||
| - The port attribute ``abc9_arrival`` specifies an integer (for output ports | - The output port attribute ``abc9_arrival`` specifies an integer, or a string | ||||||
|   only) to be used as the arrival time of this sequential port. It can be used, |   of space-separated integers to be used as the arrival time of this blackbox | ||||||
|   for example, to specify the clk-to-Q delay of a flip-flop for consideration |   port. It can be used, for example, to specify the clk-to-Q delay of a flip- | ||||||
|   during `abc9` techmapping. |   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 | - 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 |   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 |   according to the type of the always. These are checked for correctness in | ||||||
|   ``proc_dlatch``. |   ``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 | - In addition to the ``(* ... *)`` attribute syntax, Yosys supports | ||||||
|   the non-standard ``{* ... *}`` attribute syntax to set default attributes |   the non-standard ``{* ... *}`` attribute syntax to set default attributes | ||||||
|   for everything that comes after the ``{* ... *}`` statement. (Reset |   for everything that comes after the ``{* ... *}`` statement. (Reset | ||||||
|  |  | ||||||
|  | @ -93,7 +93,6 @@ struct XAigerWriter | ||||||
| 	dict<SigBit, int> ordered_outputs; | 	dict<SigBit, int> ordered_outputs; | ||||||
| 
 | 
 | ||||||
| 	vector<Cell*> box_list; | 	vector<Cell*> box_list; | ||||||
| 	dict<IdString, std::vector<IdString>> box_ports; |  | ||||||
| 
 | 
 | ||||||
| 	int mkgate(int a0, int a1) | 	int mkgate(int a0, int a1) | ||||||
| 	{ | 	{ | ||||||
|  | @ -157,7 +156,6 @@ struct XAigerWriter | ||||||
| 			if (wire->get_bool_attribute(ID::keep)) | 			if (wire->get_bool_attribute(ID::keep)) | ||||||
| 				sigmap.add(wire); | 				sigmap.add(wire); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 		for (auto wire : module->wires()) | 		for (auto wire : module->wires()) | ||||||
| 			for (int i = 0; i < GetSize(wire); i++) | 			for (int i = 0; i < GetSize(wire); i++) | ||||||
| 			{ | 			{ | ||||||
|  | @ -175,23 +173,21 @@ struct XAigerWriter | ||||||
| 				undriven_bits.insert(bit); | 				undriven_bits.insert(bit); | ||||||
| 				unused_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); | 					input_bits.insert(bit); | ||||||
| 
 | 
 | ||||||
| 				if (wire->port_output) { | 				if (wire->port_output || keep) { | ||||||
| 					if (bit != wirebit) | 					if (bit != wirebit) | ||||||
| 						alias_map[wirebit] = bit; | 						alias_map[wirebit] = bit; | ||||||
| 					output_bits.insert(wirebit); | 					output_bits.insert(wirebit); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 		// TODO: Speed up toposort -- ultimately we care about
 | 		dict<IdString,dict<IdString,std::vector<int>>> arrivals_cache; | ||||||
| 		//       box ordering, but not individual AIG cells
 | 		for (auto cell : module->cells()) { | ||||||
| 		dict<SigBit, pool<IdString>> bit_drivers, bit_users; | 			RTLIL::Module* inst_module = module->design->module(cell->type); | ||||||
| 		TopoSort<IdString, RTLIL::sort_by_id_str> toposort; | 			if (!cell->has_keep_attr()) { | ||||||
| 		bool abc9_box_seen = false; |  | ||||||
| 
 |  | ||||||
| 		for (auto cell : module->selected_cells()) { |  | ||||||
| 				if (cell->type == "$_NOT_") | 				if (cell->type == "$_NOT_") | ||||||
| 				{ | 				{ | ||||||
| 					SigBit A = sigmap(cell->getPort("\\A").as_bit()); | 					SigBit A = sigmap(cell->getPort("\\A").as_bit()); | ||||||
|  | @ -199,9 +195,6 @@ struct XAigerWriter | ||||||
| 					unused_bits.erase(A); | 					unused_bits.erase(A); | ||||||
| 					undriven_bits.erase(Y); | 					undriven_bits.erase(Y); | ||||||
| 					not_map[Y] = A; | 					not_map[Y] = A; | ||||||
| 				toposort.node(cell->name); |  | ||||||
| 				bit_users[A].insert(cell->name); |  | ||||||
| 				bit_drivers[Y].insert(cell->name); |  | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | @ -214,10 +207,6 @@ struct XAigerWriter | ||||||
| 					unused_bits.erase(B); | 					unused_bits.erase(B); | ||||||
| 					undriven_bits.erase(Y); | 					undriven_bits.erase(Y); | ||||||
| 					and_map[Y] = make_pair(A, B); | 					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; | 					continue; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | @ -233,49 +222,67 @@ struct XAigerWriter | ||||||
| 					alias_map[Q] = D; | 					alias_map[Q] = D; | ||||||
| 					auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); | 					auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); | ||||||
| 					log_assert(r.second); | 					log_assert(r.second); | ||||||
|  | 					if (input_bits.erase(Q)) | ||||||
|  | 						log_assert(Q.wire->attributes.count(ID::keep)); | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 			RTLIL::Module* inst_module = module->design->module(cell->type); |  | ||||||
| 				if (inst_module) { | 				if (inst_module) { | ||||||
| 				bool abc9_box = inst_module->attributes.count("\\abc9_box_id"); | 					bool abc9_flop = false; | ||||||
| 				bool abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); | 					auto it = cell->attributes.find("\\abc9_box_seq"); | ||||||
| 				if (abc9_box && cell->get_bool_attribute("\\abc9_keep")) | 					if (it != cell->attributes.end()) { | ||||||
| 					abc9_box = false; | 						int abc9_box_seq = it->second.as_int(); | ||||||
| 
 | 						if (GetSize(box_list) <= abc9_box_seq) | ||||||
| 				for (const auto &conn : cell->connections()) { | 							box_list.resize(abc9_box_seq+1); | ||||||
| 					auto port_wire = inst_module->wire(conn.first); | 						box_list[abc9_box_seq] = cell; | ||||||
| 
 | 						// Only flop boxes may have arrival times
 | ||||||
| 					if (abc9_box) { | 						//   (all others are combinatorial)
 | ||||||
| 						// Ignore inout for the sake of topographical ordering
 | 						abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); | ||||||
| 						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); |  | ||||||
| 
 |  | ||||||
| 						if (!abc9_flop) | 						if (!abc9_flop) | ||||||
| 							continue; | 							continue; | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					if (port_wire->port_output) { | 					auto &cell_arrivals = arrivals_cache[cell->type]; | ||||||
| 						int arrival = 0; | 					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"); | 							auto it = port_wire->attributes.find("\\abc9_arrival"); | ||||||
| 						if (it != port_wire->attributes.end()) { | 							if (it == port_wire->attributes.end()) | ||||||
| 							if (it->second.flags != 0) | 								continue; | ||||||
| 								log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); | 							if (it->second.flags == 0) | ||||||
| 							arrival = it->second.as_int(); | 								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)) | 						if (arrivals.empty()) | ||||||
| 								arrival_times[bit] = arrival; | 							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) { | 					if (abc9_flop) | ||||||
| 					abc9_box_seen = true; |  | ||||||
| 					toposort.node(cell->name); |  | ||||||
| 						continue; | 						continue; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | @ -293,6 +300,9 @@ struct XAigerWriter | ||||||
| 					for (auto b : c.second) { | 					for (auto b : c.second) { | ||||||
| 						Wire *w = b.wire; | 						Wire *w = b.wire; | ||||||
| 						if (!w) continue; | 						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) { | 						if (!w->port_output || !cell_known) { | ||||||
| 							SigBit I = sigmap(b); | 							SigBit I = sigmap(b); | ||||||
| 							if (I != 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));
 | 			//log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (abc9_box_seen) { | 		dict<IdString, std::vector<IdString>> box_ports; | ||||||
| 			for (auto &it : bit_users) | 		for (auto cell : box_list) { | ||||||
| 				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); |  | ||||||
| 			log_assert(cell); | 			log_assert(cell); | ||||||
| 
 | 
 | ||||||
| 			RTLIL::Module* box_module = module->design->module(cell->type); | 			RTLIL::Module* box_module = module->design->module(cell->type); | ||||||
| 				if (!box_module || !box_module->attributes.count("\\abc9_box_id")) | 			log_assert(box_module); | ||||||
| 					continue; | 			log_assert(box_module->attributes.count("\\abc9_box_id") || box_module->get_bool_attribute("\\abc9_flop")); | ||||||
| 
 |  | ||||||
| 				bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); |  | ||||||
| 
 | 
 | ||||||
| 			auto r = box_ports.insert(cell->type); | 			auto r = box_ports.insert(cell->type); | ||||||
| 			if (r.second) { | 			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) { | 			for (auto port_name : r.first->second) { | ||||||
| 				auto w = box_module->wire(port_name); | 				auto w = box_module->wire(port_name); | ||||||
| 				log_assert(w); | 				log_assert(w); | ||||||
| 					auto it = cell->connections_.find(port_name); | 				auto rhs = cell->connections_.at(port_name, SigSpec()); | ||||||
| 					if (w->port_input) { | 				rhs.append(Const(State::Sx, GetSize(w)-GetSize(rhs))); | ||||||
| 						RTLIL::SigSpec rhs; | 				if (w->port_input) | ||||||
| 						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); |  | ||||||
| 						} |  | ||||||
| 
 |  | ||||||
| 					for (auto b : rhs) { | 					for (auto b : rhs) { | ||||||
| 						SigBit I = sigmap(b); | 						SigBit I = sigmap(b); | ||||||
| 						if (b == RTLIL::Sx) | 						if (b == RTLIL::Sx) | ||||||
|  | @ -404,29 +376,17 @@ struct XAigerWriter | ||||||
| 						co_bits.emplace_back(b); | 						co_bits.emplace_back(b); | ||||||
| 						unused_bits.erase(I); | 						unused_bits.erase(I); | ||||||
| 					} | 					} | ||||||
| 					} | 				if (w->port_output) | ||||||
| 					if (w->port_output) { | 					for (const auto &b : rhs) { | ||||||
| 						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()) { |  | ||||||
| 						SigBit O = sigmap(b); | 						SigBit O = sigmap(b); | ||||||
| 						if (O != b) | 						if (O != b) | ||||||
| 							alias_map[O] = b; | 							alias_map[O] = b; | ||||||
| 						ci_bits.emplace_back(b); | 						ci_bits.emplace_back(b); | ||||||
| 						undriven_bits.erase(O); | 						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); | 					unused_bits.erase(I); | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 |  | ||||||
| 				box_list.emplace_back(cell); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// TODO: Free memory from toposort, bit_drivers, bit_users
 |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (auto bit : input_bits) | 		for (auto bit : input_bits) | ||||||
|  | @ -501,6 +456,10 @@ struct XAigerWriter | ||||||
| 
 | 
 | ||||||
| 		for (auto &bit : ci_bits) { | 		for (auto &bit : ci_bits) { | ||||||
| 			aig_m++, aig_i++; | 			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)); | 			log_assert(!aig_map.count(bit)); | ||||||
| 			aig_map[bit] = 2*aig_m; | 			aig_map[bit] = 2*aig_m; | ||||||
| 		} | 		} | ||||||
|  | @ -512,7 +471,27 @@ struct XAigerWriter | ||||||
| 
 | 
 | ||||||
| 		for (const auto &bit : output_bits) { | 		for (const auto &bit : output_bits) { | ||||||
| 			ordered_outputs[bit] = aig_o++; | 			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) { | 		for (auto &i : ff_bits) { | ||||||
|  | @ -612,106 +591,45 @@ struct XAigerWriter | ||||||
| 		//	write_o_buffer(0);
 | 		//	write_o_buffer(0);
 | ||||||
| 
 | 
 | ||||||
| 		if (!box_list.empty() || !ff_bits.empty()) { | 		if (!box_list.empty() || !ff_bits.empty()) { | ||||||
| 			RTLIL::Module *holes_module = module->design->addModule("$__holes__"); | 			dict<IdString, std::tuple<int,int,int>> cell_cache; | ||||||
| 			log_assert(holes_module); |  | ||||||
| 
 | 
 | ||||||
| 			dict<IdString, std::tuple<Cell*,int,int,int>> cell_cache; |  | ||||||
| 
 |  | ||||||
| 			int port_id = 1; |  | ||||||
| 			int box_count = 0; | 			int box_count = 0; | ||||||
| 			for (auto cell : box_list) { | 			for (auto cell : box_list) { | ||||||
| 				RTLIL::Module* orig_box_module = module->design->module(cell->type); | 				log_assert(cell); | ||||||
| 				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); |  | ||||||
| 
 | 
 | ||||||
| 				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; | 				auto &v = r.first->second; | ||||||
| 				if (r.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; | 					int box_inputs = 0, box_outputs = 0; | ||||||
| 					if (box_module->get_bool_attribute("\\whitebox")) { | 					for (auto port_name : box_module->ports) { | ||||||
| 						auto holes_cell = holes_module->addCell(cell->name, derived_name); |  | ||||||
| 						for (auto port_name : box_ports.at(cell->type)) { |  | ||||||
| 						RTLIL::Wire *w = box_module->wire(port_name); | 						RTLIL::Wire *w = box_module->wire(port_name); | ||||||
| 						log_assert(w); | 						log_assert(w); | ||||||
| 							log_assert(!w->port_input || !w->port_output); | 						if (w->port_input) | ||||||
| 							auto &conn = holes_cell->connections_[port_name]; | 							box_inputs += GetSize(w); | ||||||
| 							if (w->port_input) { | 						if (w->port_output) | ||||||
| 								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) { |  | ||||||
| 							box_outputs += GetSize(w); | 							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
 | 					// For flops only, create an extra 1-bit input that drives a new wire
 | ||||||
| 					//   called "<cell>.abc9_ff.Q" that is used below
 | 					//   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++; | 						box_inputs++; | ||||||
| 							Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); | 
 | ||||||
| 							if (!holes_wire) { | 					std::get<0>(v) = box_inputs; | ||||||
| 								holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); | 					std::get<1>(v) = box_outputs; | ||||||
| 								holes_wire->port_input = true; | 					std::get<2>(v) = box_module->attributes.at("\\abc9_box_id").as_int(); | ||||||
| 								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))); |  | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				write_h_buffer(std::get<0>(v)); | ||||||
| 				write_h_buffer(std::get<1>(v)); | 				write_h_buffer(std::get<1>(v)); | ||||||
| 				write_h_buffer(std::get<2>(v)); | 				write_h_buffer(std::get<2>(v)); | ||||||
| 				write_h_buffer(std::get<3>(v)); |  | ||||||
| 				write_h_buffer(box_count++); | 				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(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); | ||||||
| 			f.write(buffer_str.data(), buffer_str.size()); | 			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) { | 			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; | 				std::stringstream a_buffer; | ||||||
| 				XAigerWriter writer(holes_module, true /* holes_mode */); | 				XAigerWriter writer(holes_module, true /* holes_mode */); | ||||||
| 				writer.write_aiger(a_buffer, false /*ascii_mode*/); | 				writer.write_aiger(a_buffer, false /*ascii_mode*/); | ||||||
| 				delete holes_design; |  | ||||||
| 
 | 
 | ||||||
| 				f << "a"; | 				f << "a"; | ||||||
| 				std::string buffer_str = a_buffer.str(); | 				std::string buffer_str = a_buffer.str(); | ||||||
| 				int32_t buffer_size_be = to_big_endian(buffer_str.size()); | 				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(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); | ||||||
| 				f.write(buffer_str.data(), buffer_str.size()); | 				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("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("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("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("\n"); | ||||||
| 		log("    -ascii\n"); | 		log("    -ascii\n"); | ||||||
| 		log("        write ASCII version of AIGER format\n"); | 		log("        write ASCII version of AIGER format\n"); | ||||||
|  |  | ||||||
|  | @ -326,7 +326,7 @@ struct EdifBackend : public Backend { | ||||||
| 				continue; | 				continue; | ||||||
| 
 | 
 | ||||||
| 			SigMap sigmap(module); | 			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("    (cell %s\n", EDIF_DEF(module->name)); | ||||||
| 			*f << stringf("      (cellType GENERIC)\n"); | 			*f << stringf("      (cellType GENERIC)\n"); | ||||||
|  | @ -349,7 +349,7 @@ struct EdifBackend : public Backend { | ||||||
| 							add_prop(p.first, p.second); | 							add_prop(p.first, p.second); | ||||||
| 					*f << ")\n"; | 					*f << ")\n"; | ||||||
| 					RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire)); | 					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 { | 				} else { | ||||||
| 					int b[2]; | 					int b[2]; | ||||||
| 					b[wire->upto ? 0 : 1] = wire->start_offset; | 					b[wire->upto ? 0 : 1] = wire->start_offset; | ||||||
|  | @ -362,7 +362,7 @@ struct EdifBackend : public Backend { | ||||||
| 					*f << ")\n"; | 					*f << ")\n"; | ||||||
| 					for (int i = 0; i < wire->width; i++) { | 					for (int i = 0; i < wire->width; i++) { | ||||||
| 						RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, 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", | 							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])); | 									i, log_id(module), log_id(cell), log_id(p.first), log_signal(sig[i])); | ||||||
| 						else if (sig.size() == 1) | 						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 { | 						else { | ||||||
| 							int member_idx = GetSize(sig)-i-1; | 							int member_idx = GetSize(sig)-i-1; | ||||||
| 							auto m = design->module(cell->type); | 							auto m = design->module(cell->type); | ||||||
|  | @ -400,8 +400,8 @@ struct EdifBackend : public Backend { | ||||||
| 								if (w) | 								if (w) | ||||||
| 									member_idx = GetSize(w)-i-1; | 									member_idx = GetSize(w)-i-1; | ||||||
| 							} | 							} | ||||||
| 							net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", | 							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))); | 									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.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) { | ||||||
| 					if (sig == RTLIL::State::Sx) { | 					if (sig == RTLIL::State::Sx) { | ||||||
| 						for (auto &ref : it.second) | 						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; | 						sig = RTLIL::State::S0; | ||||||
|  | 					} else if (sig == RTLIL::State::Sz) { | ||||||
|  | 						continue; | ||||||
| 					} else { | 					} else { | ||||||
| 						for (auto &ref : it.second) | 						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(); | 						log_abort(); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | @ -431,7 +433,7 @@ struct EdifBackend : public Backend { | ||||||
| 				} | 				} | ||||||
| 				*f << stringf("          (net %s (joined\n", EDIF_DEF(netname)); | 				*f << stringf("          (net %s (joined\n", EDIF_DEF(netname)); | ||||||
| 				for (auto &ref : it.second) | 				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 (sig.wire == NULL) { | ||||||
| 					if (nogndvcc) | 					if (nogndvcc) | ||||||
| 						log_error("Design contains constant nodes (map with \"hilomap\" first).\n"); | 						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); | 						add_prop(p.first, p.second); | ||||||
| 				*f << stringf("\n          )\n"); | 				*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"); | 			*f << stringf("      )\n"); | ||||||
| 			*f << stringf("    )\n"); | 			*f << stringf("    )\n"); | ||||||
|  |  | ||||||
|  | @ -33,6 +33,7 @@ struct JsonWriter | ||||||
| 	std::ostream &f; | 	std::ostream &f; | ||||||
| 	bool use_selection; | 	bool use_selection; | ||||||
| 	bool aig_mode; | 	bool aig_mode; | ||||||
|  | 	bool compat_int_mode; | ||||||
| 
 | 
 | ||||||
| 	Design *design; | 	Design *design; | ||||||
| 	Module *module; | 	Module *module; | ||||||
|  | @ -42,8 +43,9 @@ struct JsonWriter | ||||||
| 	dict<SigBit, string> sigids; | 	dict<SigBit, string> sigids; | ||||||
| 	pool<Aig> aig_models; | 	pool<Aig> aig_models; | ||||||
| 
 | 
 | ||||||
| 	JsonWriter(std::ostream &f, bool use_selection, bool 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) { } | 			f(f), use_selection(use_selection), aig_mode(aig_mode), | ||||||
|  | 			compat_int_mode(compat_int_mode) { } | ||||||
| 
 | 
 | ||||||
| 	string get_string(string str) | 	string get_string(string str) | ||||||
| 	{ | 	{ | ||||||
|  | @ -102,8 +104,7 @@ struct JsonWriter | ||||||
| 			if (state < 2) | 			if (state < 2) | ||||||
| 				str += " "; | 				str += " "; | ||||||
| 			f << get_string(str); | 			f << get_string(str); | ||||||
| 		} else | 		} else if (compat_int_mode && GetSize(value) == 32 && value.is_fully_def()) { | ||||||
| 		if (GetSize(value) == 32 && value.is_fully_def()) { |  | ||||||
| 			if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) | 			if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) | ||||||
| 				f << stringf("%d", value.as_int()); | 				f << stringf("%d", value.as_int()); | ||||||
| 			else | 			else | ||||||
|  | @ -294,6 +295,10 @@ struct JsonBackend : public Backend { | ||||||
| 		log("    -aig\n"); | 		log("    -aig\n"); | ||||||
| 		log("        include AIG models for the different gate types\n"); | 		log("        include AIG models for the different gate types\n"); | ||||||
| 		log("\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("\n"); | ||||||
| 		log("The general syntax of the JSON output created by this command is as follows:\n"); | 		log("The general syntax of the JSON output created by this command is as follows:\n"); | ||||||
| 		log("\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("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n"); | ||||||
| 		log("\"z\" instead of a number.\n"); | 		log("\"z\" instead of a number.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("Numeric 32-bit parameter and attribute values are written as decimal values.\n"); | 		log("Bit vectors (including integers) are written as string holding the binary"); | ||||||
| 		log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n"); | 		log("representation of the value. Strings are written as strings, with an appended"); | ||||||
| 		log("as string holding the binary representation of the value. Strings are written\n"); | 		log("blank in cases of strings of the form /[01xz]* */.\n"); | ||||||
| 		log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n"); |  | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("For example the following Verilog code:\n"); | 		log("For example the following Verilog code:\n"); | ||||||
| 		log("\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 | 	void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | ||||||
| 	{ | 	{ | ||||||
| 		bool aig_mode = false; | 		bool aig_mode = false; | ||||||
|  | 		bool compat_int_mode = false; | ||||||
| 
 | 
 | ||||||
| 		size_t argidx; | 		size_t argidx; | ||||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | @ -503,13 +508,17 @@ struct JsonBackend : public Backend { | ||||||
| 				aig_mode = true; | 				aig_mode = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-compat-int") { | ||||||
|  | 				compat_int_mode = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(f, filename, args, argidx); | 		extra_args(f, filename, args, argidx); | ||||||
| 
 | 
 | ||||||
| 		log_header(design, "Executing JSON backend.\n"); | 		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); | 		json_writer.write_design(design); | ||||||
| 	} | 	} | ||||||
| } JsonBackend; | } JsonBackend; | ||||||
|  | @ -530,6 +539,10 @@ struct JsonPass : public Pass { | ||||||
| 		log("    -aig\n"); | 		log("    -aig\n"); | ||||||
| 		log("        also include AIG models for the different gate types\n"); | 		log("        also include AIG models for the different gate types\n"); | ||||||
| 		log("\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("See 'help write_json' for a description of the JSON format used.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 	} | 	} | ||||||
|  | @ -537,6 +550,7 @@ struct JsonPass : public Pass { | ||||||
| 	{ | 	{ | ||||||
| 		std::string filename; | 		std::string filename; | ||||||
| 		bool aig_mode = false; | 		bool aig_mode = false; | ||||||
|  | 		bool compat_int_mode = false; | ||||||
| 
 | 
 | ||||||
| 		size_t argidx; | 		size_t argidx; | ||||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | @ -549,6 +563,10 @@ struct JsonPass : public Pass { | ||||||
| 				aig_mode = true; | 				aig_mode = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-compat-int") { | ||||||
|  | 				compat_int_mode = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
|  | @ -569,7 +587,7 @@ struct JsonPass : public Pass { | ||||||
| 			f = &buf; | 			f = &buf; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		JsonWriter json_writer(*f, true, aig_mode); | 		JsonWriter json_writer(*f, true, aig_mode, compat_int_mode); | ||||||
| 		json_writer.write_design(design); | 		json_writer.write_design(design); | ||||||
| 
 | 
 | ||||||
| 		if (!filename.empty()) { | 		if (!filename.empty()) { | ||||||
|  |  | ||||||
|  | @ -304,7 +304,11 @@ class SmtIo: | ||||||
| 
 | 
 | ||||||
|     def p_open(self): |     def p_open(self): | ||||||
|         assert self.p is None |         assert self.p is None | ||||||
|  |         try: | ||||||
|             self.p = subprocess.Popen(self.popen_vargs, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |             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 |         running_solvers[self.p_index] = self.p | ||||||
|         self.p_running = True |         self.p_running = True | ||||||
|         self.p_next = None |         self.p_next = None | ||||||
|  |  | ||||||
|  | @ -393,21 +393,6 @@ void AigerReader::parse_xaiger() | ||||||
| 	if (f.peek() == '\n') | 	if (f.peek() == '\n') | ||||||
| 		f.get(); | 		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.)
 | 	// Parse footer (symbol table, comments, etc.)
 | ||||||
| 	std::string s; | 	std::string s; | ||||||
| 	for (int c = f.get(); c != EOF; c = f.get()) { | 	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) { | 				for (unsigned j = 0; j < cutLeavesM; ++j) { | ||||||
| 					nodeID = parse_xaiger_literal(f); | 					nodeID = parse_xaiger_literal(f); | ||||||
| 					log_debug2("\t%u\n", nodeID); | 					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)); | 					RTLIL::Wire *wire = module->wire(stringf("$aiger%d$%d", aiger_autoidx, nodeID)); | ||||||
| 					log_assert(wire); | 					log_assert(wire); | ||||||
| 					input_sig.append(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())
 | 				// TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
 | ||||||
| 				ce.clear(); | 				ce.clear(); | ||||||
| 				ce.compute_deps(output_sig, input_sig.to_sigbit_pool()); | 				ce.compute_deps(output_sig, input_sig.to_sigbit_pool()); | ||||||
| 				RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size()); | 				RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << GetSize(input_sig)); | ||||||
| 				for (int j = 0; j < (1 << cutLeavesM); ++j) { | 				for (int j = 0; j < GetSize(lut_mask); ++j) { | ||||||
| 					int gray = j ^ (j >> 1); | 					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); | 					RTLIL::SigBit o(output_sig); | ||||||
| 					bool success YS_ATTRIBUTE(unused) = ce.eval(o); | 					bool success YS_ATTRIBUTE(unused) = ce.eval(o); | ||||||
| 					log_assert(success); | 					log_assert(success); | ||||||
|  | @ -453,11 +444,13 @@ void AigerReader::parse_xaiger() | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else if (c == 'r') { | 		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); | 			flopNum = parse_xaiger_literal(f); | ||||||
| 			log_debug("flopNum = %u\n", flopNum); | 			log_debug("flopNum = %u\n", flopNum); | ||||||
| 			log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); | 			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') { | 		else if (c == 'n') { | ||||||
| 			parse_xaiger_literal(f); | 			parse_xaiger_literal(f); | ||||||
|  | @ -479,11 +472,15 @@ void AigerReader::parse_xaiger() | ||||||
| 			uint32_t boxNum = parse_xaiger_literal(f); | 			uint32_t boxNum = parse_xaiger_literal(f); | ||||||
| 			log_debug("boxNum = %u\n", boxNum); | 			log_debug("boxNum = %u\n", boxNum); | ||||||
| 			for (unsigned i = 0; i < boxNum; i++) { | 			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); | 				uint32_t boxUniqueId = parse_xaiger_literal(f); | ||||||
| 				log_assert(boxUniqueId > 0); | 				log_assert(boxUniqueId > 0); | ||||||
| 				uint32_t oldBoxNum = parse_xaiger_literal(f); | 				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); | 				boxes.emplace_back(cell); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -568,25 +565,18 @@ void AigerReader::parse_aiger_ascii() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Parse outputs
 | 	// Parse outputs
 | ||||||
|  | 	digits = ceil(log10(O)); | ||||||
| 	for (unsigned i = 0; i < O; ++i, ++line_count) { | 	for (unsigned i = 0; i < O; ++i, ++line_count) { | ||||||
| 		if (!(f >> l1)) | 		if (!(f >> l1)) | ||||||
| 			log_error("Line %u cannot be interpreted as an output!\n", line_count); | 			log_error("Line %u cannot be interpreted as an output!\n", line_count); | ||||||
| 
 | 
 | ||||||
| 		log_debug2("%d is an output\n", l1); | 		log_debug2("%d is an output\n", l1); | ||||||
| 		const unsigned variable = l1 >> 1; | 		RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i)); | ||||||
| 		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; |  | ||||||
| 		} |  | ||||||
| 		wire->port_output = true; | 		wire->port_output = true; | ||||||
|  | 		module->connect(wire, createWireIfNotExists(module, l1)); | ||||||
| 		outputs.push_back(wire); | 		outputs.push_back(wire); | ||||||
| 	} | 	} | ||||||
|  | 	//std::getline(f, line); // Ignore up to start of next line
 | ||||||
| 
 | 
 | ||||||
| 	// Parse bad properties
 | 	// Parse bad properties
 | ||||||
| 	for (unsigned i = 0; i < B; ++i, ++line_count) { | 	for (unsigned i = 0; i < B; ++i, ++line_count) { | ||||||
|  | @ -598,6 +588,8 @@ void AigerReader::parse_aiger_ascii() | ||||||
| 		wire->port_output = true; | 		wire->port_output = true; | ||||||
| 		bad_properties.push_back(wire); | 		bad_properties.push_back(wire); | ||||||
| 	} | 	} | ||||||
|  | 	//if (B > 0)
 | ||||||
|  | 	//	std::getline(f, line); // Ignore up to start of next line
 | ||||||
| 
 | 
 | ||||||
| 	// TODO: Parse invariant constraints
 | 	// TODO: Parse invariant constraints
 | ||||||
| 	for (unsigned i = 0; i < C; ++i, ++line_count) | 	for (unsigned i = 0; i < C; ++i, ++line_count) | ||||||
|  | @ -753,74 +745,33 @@ void AigerReader::parse_aiger_binary() | ||||||
| 
 | 
 | ||||||
| void AigerReader::post_process() | void AigerReader::post_process() | ||||||
| { | { | ||||||
| 	dict<IdString, std::vector<IdString>> box_ports; | 	unsigned ci_count = 0, co_count = 0; | ||||||
| 	unsigned ci_count = 0, co_count = 0, flop_count = 0; |  | ||||||
| 	for (auto cell : boxes) { | 	for (auto cell : boxes) { | ||||||
| 		RTLIL::Module* box_module = design->module(cell->type); | 		for (auto &bit : cell->connections_.at("\\i")) { | ||||||
| 		log_assert(box_module); | 			log_assert(bit == State::S0); | ||||||
| 
 |  | ||||||
| 		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) { |  | ||||||
| 			log_assert(co_count < outputs.size()); | 			log_assert(co_count < outputs.size()); | ||||||
| 					wire = outputs[co_count++]; | 			bit = outputs[co_count++]; | ||||||
| 					log_assert(wire); | 			log_assert(bit.wire && GetSize(bit.wire) == 1); | ||||||
| 					log_assert(wire->port_output); | 			log_assert(bit.wire->port_output); | ||||||
| 					wire->port_output = false; | 			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()); | 			log_assert((piNum + ci_count) < inputs.size()); | ||||||
| 					wire = inputs[piNum + ci_count++]; | 			bit = inputs[piNum + ci_count++]; | ||||||
| 					log_assert(wire); | 			log_assert(bit.wire && GetSize(bit.wire) == 1); | ||||||
| 					log_assert(wire->port_input); | 			log_assert(bit.wire->port_input); | ||||||
| 					wire->port_input = false; | 			bit.wire->port_input = false; | ||||||
| 		} | 		} | ||||||
| 				rhs.append(wire); |  | ||||||
| 			} |  | ||||||
| 			cell->setPort(port_name, rhs); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 		if (box_module->attributes.count("\\abc9_flop")) { | 	for (uint32_t i = 0; i < flopNum; i++) { | ||||||
| 			log_assert(co_count < outputs.size()); | 		RTLIL::Wire *d = outputs[outputs.size() - flopNum + i]; | ||||||
| 			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]; |  | ||||||
| 		log_assert(d); | 		log_assert(d); | ||||||
| 		log_assert(d->port_output); | 		log_assert(d->port_output); | ||||||
| 		d->port_output = false; | 		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); | ||||||
| 		log_assert(q->port_input); | 		log_assert(q->port_input); | ||||||
| 		q->port_input = false; | 		q->port_input = false; | ||||||
|  | @ -828,9 +779,7 @@ void AigerReader::post_process() | ||||||
| 		auto ff = module->addCell(NEW_ID, "$__ABC9_FF_"); | 		auto ff = module->addCell(NEW_ID, "$__ABC9_FF_"); | ||||||
| 		ff->setPort("\\D", d); | 		ff->setPort("\\D", d); | ||||||
| 		ff->setPort("\\Q", q); | 		ff->setPort("\\Q", q); | ||||||
| 			flop_count++; | 		ff->attributes["\\abc9_mergeability"] = mergeability[i]; | ||||||
| 			continue; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dict<RTLIL::IdString, int> wideports_cache; | 	dict<RTLIL::IdString, int> wideports_cache; | ||||||
|  | @ -859,6 +808,7 @@ void AigerReader::post_process() | ||||||
| 						wire->port_input = false; | 						wire->port_input = false; | ||||||
| 						module->connect(wire, existing); | 						module->connect(wire, existing); | ||||||
| 					} | 					} | ||||||
|  | 					log_debug(" -> %s\n", log_id(escaped_s)); | ||||||
| 				} | 				} | ||||||
| 				else if (index > 0) { | 				else if (index > 0) { | ||||||
| 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | ||||||
|  | @ -872,18 +822,14 @@ void AigerReader::post_process() | ||||||
| 						module->connect(wire, existing); | 						module->connect(wire, existing); | ||||||
| 						wire->port_input = false; | 						wire->port_input = false; | ||||||
| 					} | 					} | ||||||
|  | 					log_debug(" -> %s\n", log_id(indexed_name)); | ||||||
| 				} | 				} | ||||||
| 				log_debug(" -> %s\n", log_id(wire)); |  | ||||||
| 			} | 			} | ||||||
| 			else if (type == "output") { | 			else if (type == "output") { | ||||||
| 				log_assert(static_cast<unsigned>(variable + co_count) < outputs.size()); | 				log_assert(static_cast<unsigned>(variable + co_count) < outputs.size()); | ||||||
| 				RTLIL::Wire* wire = outputs[variable + co_count]; | 				RTLIL::Wire* wire = outputs[variable + co_count]; | ||||||
| 				log_assert(wire); | 				log_assert(wire); | ||||||
| 				log_assert(wire->port_output); | 				log_assert(wire->port_output); | ||||||
| 				if (escaped_s == "$__dummy__") { |  | ||||||
| 					wire->port_output = false; |  | ||||||
| 					continue; |  | ||||||
| 				} |  | ||||||
| 				log_debug("Renaming output %s", log_id(wire)); | 				log_debug("Renaming output %s", log_id(wire)); | ||||||
| 
 | 
 | ||||||
| 				if (index == 0) { | 				if (index == 0) { | ||||||
|  | @ -896,9 +842,11 @@ void AigerReader::post_process() | ||||||
| 					} | 					} | ||||||
| 					else { | 					else { | ||||||
| 						wire->port_output = false; | 						wire->port_output = false; | ||||||
|  | 						existing->port_output = true; | ||||||
| 						module->connect(wire, existing); | 						module->connect(wire, existing); | ||||||
| 						wire = existing; | 						wire = existing; | ||||||
| 					} | 					} | ||||||
|  | 					log_debug(" -> %s\n", log_id(escaped_s)); | ||||||
| 				} | 				} | ||||||
| 				else if (index > 0) { | 				else if (index > 0) { | ||||||
| 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | 					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); | 							wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); | ||||||
| 					} | 					} | ||||||
| 					else { | 					else { | ||||||
| 						module->connect(wire, existing); |  | ||||||
| 						wire->port_output = false; | 						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; | 				int init; | ||||||
| 				mf >> init; | 				mf >> init; | ||||||
| 				if (init < 2) | 				if (init < 2) | ||||||
|  | @ -921,26 +870,8 @@ void AigerReader::post_process() | ||||||
| 			} | 			} | ||||||
| 			else if (type == "box") { | 			else if (type == "box") { | ||||||
| 				RTLIL::Cell* cell = module->cell(stringf("$box%d", variable)); | 				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); | 					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 | 			else | ||||||
| 				log_error("Symbol type '%s' not recognised.\n", type.c_str()); | 				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("Load module from an AIGER file into the current design.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -module_name <module_name>\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("\n"); | ||||||
| 		log("    -clk_name <wire_name>\n"); | 		log("    -clk_name <wire_name>\n"); | ||||||
| 		log("        If specified, AIGER latches to be transformed into $_DFF_P_ cells\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("        clocked by wire of this name. otherwise, $_FF_ cells will be used\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -map <filename>\n"); | 		log("    -map <filename>\n"); | ||||||
| 		log("        read file with port and latch symbols\n"); | 		log("        read file with port and latch symbols\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -wideports\n"); | 		log("    -wideports\n"); | ||||||
| 		log("        Merge ports that match the pattern 'name[int]' into a single\n"); | 		log("        merge ports that match the pattern 'name[int]' into a single\n"); | ||||||
| 		log("        multi-bit port 'name'.\n"); | 		log("        multi-bit port 'name'\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    -xaiger\n"); | ||||||
|  | 		log("        read XAIGER extensions\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE | 	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 clk_name; | ||||||
| 		RTLIL::IdString module_name; | 		RTLIL::IdString module_name; | ||||||
| 		std::string map_filename; | 		std::string map_filename; | ||||||
| 		bool wideports = false; | 		bool wideports = false, xaiger = false; | ||||||
| 
 | 
 | ||||||
| 		size_t argidx; | 		size_t argidx; | ||||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||||
|  | @ -1060,6 +994,10 @@ struct AigerFrontend : public Frontend { | ||||||
| 				wideports = true; | 				wideports = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (arg == "-xaiger") { | ||||||
|  | 				xaiger = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(f, filename, args, argidx, true); | 		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); | 		AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports); | ||||||
|  | 		if (xaiger) | ||||||
|  | 			reader.parse_xaiger(); | ||||||
|  | 		else | ||||||
| 			reader.parse_aiger(); | 			reader.parse_aiger(); | ||||||
| 	} | 	} | ||||||
| } AigerFrontend; | } AigerFrontend; | ||||||
|  |  | ||||||
|  | @ -45,6 +45,7 @@ struct AigerReader | ||||||
|     std::vector<RTLIL::Wire*> outputs; |     std::vector<RTLIL::Wire*> outputs; | ||||||
|     std::vector<RTLIL::Wire*> bad_properties; |     std::vector<RTLIL::Wire*> bad_properties; | ||||||
|     std::vector<RTLIL::Cell*> boxes; |     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); |     AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); | ||||||
|     void parse_aiger(); |     void parse_aiger(); | ||||||
|  |  | ||||||
|  | @ -244,6 +244,7 @@ namespace AST | ||||||
| 		void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall); | 		void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall); | ||||||
| 		AstNode *eval_const_function(AstNode *fcall); | 		AstNode *eval_const_function(AstNode *fcall); | ||||||
| 		bool is_simple_const_expr(); | 		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)
 | 		// create a human-readable text representation of the AST (for debugging)
 | ||||||
| 		void dumpAst(FILE *f, std::string indent) const; | 		void dumpAst(FILE *f, std::string indent) const; | ||||||
|  |  | ||||||
|  | @ -41,6 +41,103 @@ YOSYS_NAMESPACE_BEGIN | ||||||
| using namespace AST; | using namespace AST; | ||||||
| using namespace AST_INTERNAL; | 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
 | // 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
 | // values, unrolled for-loops, expanded generate blocks, etc. when this function
 | ||||||
| // is done with an AST it can be converted into RTLIL using genRTLIL().
 | // 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) | 		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()); | 			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(); | 		std::string sformat = node_string->bitsAsConst().decode_string(); | ||||||
| 
 | 		std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); | ||||||
| 		// 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]; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Finally, print the message (only include a \n for $display, not for $write)
 | 		// Finally, print the message (only include a \n for $display, not for $write)
 | ||||||
| 		log("%s", sout.c_str()); | 		log("%s", sout.c_str()); | ||||||
| 		if (str == "$display") | 		if (str == "$display") | ||||||
|  | @ -2244,6 +2249,17 @@ skip_dynamic_range_lvalue_expansion:; | ||||||
| 				goto apply_newNode; | 				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) | 			if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION) | ||||||
| 			{ | 			{ | ||||||
| 				AstNode *dpi_decl = current_scope[str]; | 				AstNode *dpi_decl = current_scope[str]; | ||||||
|  |  | ||||||
|  | @ -539,6 +539,14 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr | ||||||
| 		return true; | 		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) { | 	if (inst->Type() == OPER_REDUCE_OR) { | ||||||
| 		cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); | 		cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); | ||||||
| 		import_attributes(cell->attributes, inst); | 		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()) | 	if (!verific_error_msg.empty()) | ||||||
| 		log_error("%s\n", verific_error_msg.c_str()); | 		log_error("%s\n", verific_error_msg.c_str()); | ||||||
| 
 | 
 | ||||||
|  | 	for (auto nl : nl_todo) | ||||||
|  | 	    nl->ChangePortBusStructures(1 /* hierarchical */); | ||||||
|  | 
 | ||||||
| 	VerificExtNets worker; | 	VerificExtNets worker; | ||||||
| 	for (auto nl : nl_todo) | 	for (auto nl : nl_todo) | ||||||
| 		worker.run(nl); | 		worker.run(nl); | ||||||
|  | @ -2408,7 +2419,7 @@ struct VerificPass : public Pass { | ||||||
| 			else | 			else | ||||||
| 			{ | 			{ | ||||||
| 				if (argidx == GetSize(args)) | 				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; | 				Array veri_modules, vhdl_units; | ||||||
| 				for (; argidx < GetSize(args); argidx++) | 				for (; argidx < GetSize(args); argidx++) | ||||||
|  | @ -2470,6 +2481,9 @@ struct VerificPass : public Pass { | ||||||
| 					worker.run(nl); | 					worker.run(nl); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			for (auto nl : nl_todo) | ||||||
|  | 				nl->ChangePortBusStructures(1 /* hierarchical */); | ||||||
|  | 
 | ||||||
| 			if (!dumpfile.empty()) { | 			if (!dumpfile.empty()) { | ||||||
| 				VeriWrite veri_writer; | 				VeriWrite veri_writer; | ||||||
| 				veri_writer.WriteFile(dumpfile.c_str(), Netlist::PresentDesign()); | 				veri_writer.WriteFile(dumpfile.c_str(), Netlist::PresentDesign()); | ||||||
|  | @ -2495,7 +2509,7 @@ struct VerificPass : public Pass { | ||||||
| 			goto check_error; | 			goto check_error; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log_cmd_error("Missing or unsupported mode parameter.\n"); | 		cmd_error(args, argidx, "Missing or unsupported mode parameter.\n"); | ||||||
| 
 | 
 | ||||||
| 	check_error: | 	check_error: | ||||||
| 		if (!verific_error_msg.empty()) | 		if (!verific_error_msg.empty()) | ||||||
|  | @ -2568,14 +2582,14 @@ struct ReadPass : public Pass { | ||||||
| 		static bool use_verific = verific_available; | 		static bool use_verific = verific_available; | ||||||
| 
 | 
 | ||||||
| 		if (args.size() < 2 || args[1][0] != '-') | 		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[1] == "-verific" || args[1] == "-noverific") { | ||||||
| 			if (args.size() != 2) | 			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 (args[1] == "-verific") { | ||||||
| 				if (!verific_available) | 				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; | 				use_verific = true; | ||||||
| 			} else { | 			} else { | ||||||
| 				use_verific = false; | 				use_verific = false; | ||||||
|  | @ -2584,7 +2598,7 @@ struct ReadPass : public Pass { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (args.size() < 3) | 		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 (args[1] == "-vlog95" || args[1] == "-vlog2k") { | ||||||
| 			if (use_verific) { | 			if (use_verific) { | ||||||
|  | @ -2616,7 +2630,7 @@ struct ReadPass : public Pass { | ||||||
| 				args[0] = "verific"; | 				args[0] = "verific"; | ||||||
| 				Pass::call(design, args); | 				Pass::call(design, args); | ||||||
| 			} else { | 			} 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; | 			return; | ||||||
| 		} | 		} | ||||||
|  | @ -2663,7 +2677,7 @@ struct ReadPass : public Pass { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log_cmd_error("Missing or unsupported mode parameter.\n"); | 		cmd_error(args, 1, "Missing or unsupported mode parameter.\n"); | ||||||
| 	} | 	} | ||||||
| } ReadPass; | } 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_POS_INDEXED; } | ||||||
| "-:" { return TOK_NEG_INDEXED; } | "-:" { return TOK_NEG_INDEXED; } | ||||||
| 
 | 
 | ||||||
|  | ".*" { return TOK_WILDCARD_CONNECT; } | ||||||
|  | 
 | ||||||
| [-+]?[=*]> { | [-+]?[=*]> { | ||||||
| 	if (!specify_mode) REJECT; | 	if (!specify_mode) REJECT; | ||||||
| 	frontend_verilog_yylval.string = new std::string(yytext); | 	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 ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END | ||||||
| %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM | %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM | ||||||
| %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP | %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_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_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL | ||||||
| %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH | %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH | ||||||
|  | @ -1580,6 +1580,11 @@ cell_port: | ||||||
| 		node->children.back()->str = *$3; | 		node->children.back()->str = *$3; | ||||||
| 		delete $3; | 		delete $3; | ||||||
| 		free_attr($1); | 		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: | always_comb_or_latch: | ||||||
|  |  | ||||||
|  | @ -295,6 +295,9 @@ int main(int argc, char **argv) | ||||||
| 		printf("    -E <depsfile>\n"); | 		printf("    -E <depsfile>\n"); | ||||||
| 		printf("        write a Makefile dependencies file with in- and output file names\n"); | 		printf("        write a Makefile dependencies file with in- and output file names\n"); | ||||||
| 		printf("\n"); | 		printf("\n"); | ||||||
|  | 		printf("    -x <feature>\n"); | ||||||
|  | 		printf("        do not print warnings for the specified experimental feature\n"); | ||||||
|  | 		printf("\n"); | ||||||
| 		printf("    -g\n"); | 		printf("    -g\n"); | ||||||
| 		printf("        globally enable debug log messages\n"); | 		printf("        globally enable debug log messages\n"); | ||||||
| 		printf("\n"); | 		printf("\n"); | ||||||
|  | @ -317,8 +320,14 @@ int main(int argc, char **argv) | ||||||
| 		exit(0); | 		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; | 	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) | 		switch (opt) | ||||||
| 		{ | 		{ | ||||||
|  | @ -449,6 +458,9 @@ int main(int argc, char **argv) | ||||||
| 		case 'E': | 		case 'E': | ||||||
| 			depsfile = optarg; | 			depsfile = optarg; | ||||||
| 			break; | 			break; | ||||||
|  | 		case 'x': | ||||||
|  | 			log_experimentals_ignored.insert(optarg); | ||||||
|  | 			break; | ||||||
| 		default: | 		default: | ||||||
| 			fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); | 			fprintf(stderr, "Run '%s -h' for help.\n", argv[0]); | ||||||
| 			exit(1); | 			exit(1); | ||||||
|  | @ -561,6 +573,10 @@ int main(int argc, char **argv) | ||||||
| 
 | 
 | ||||||
| 		if (log_warnings_count) | 		if (log_warnings_count) | ||||||
| 			log("Warnings: %d unique messages, %d total\n", GetSize(log_warnings), 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 | #ifdef _WIN32 | ||||||
| 		log("End of script. Logfile hash: %s\n", hash.c_str()); | 		log("End of script. Logfile hash: %s\n", hash.c_str()); | ||||||
| #else | #else | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ std::vector<FILE*> log_files; | ||||||
| std::vector<std::ostream*> log_streams; | std::vector<std::ostream*> log_streams; | ||||||
| std::map<std::string, std::set<std::string>> log_hdump; | std::map<std::string, std::set<std::string>> log_hdump; | ||||||
| std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes; | 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; | int log_warnings_count = 0; | ||||||
| bool log_hdump_all = false; | bool log_hdump_all = false; | ||||||
| FILE *log_errfile = NULL; | FILE *log_errfile = NULL; | ||||||
|  | @ -377,6 +377,19 @@ void log_warning(const char *format, ...) | ||||||
| 	va_end(ap); | 	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, ...) | void log_warning_noprefix(const char *format, ...) | ||||||
| { | { | ||||||
| 	va_list ap; | 	va_list ap; | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ extern std::vector<FILE*> log_files; | ||||||
| extern std::vector<std::ostream*> log_streams; | extern std::vector<std::ostream*> log_streams; | ||||||
| extern std::map<std::string, std::set<std::string>> log_hdump; | 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::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 int log_warnings_count; | ||||||
| extern bool log_hdump_all; | extern bool log_hdump_all; | ||||||
| extern FILE *log_errfile; | 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(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_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_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.
 | // 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)); | 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) | 	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()); | 		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(); | 	size_t orig_sel_stack_pos = design->selection_stack.size(); | ||||||
| 	auto state = pass_register[args[0]]->pre_execute(); | 	auto state = pass_register[args[0]]->pre_execute(); | ||||||
| 	pass_register[args[0]]->execute(args, design); | 	pass_register[args[0]]->execute(args, design); | ||||||
|  | @ -824,6 +827,11 @@ struct HelpPass : public Pass { | ||||||
| 						log("="); | 						log("="); | ||||||
| 					log("\n"); | 					log("\n"); | ||||||
| 					it.second->help(); | 					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") { | 			else if (args[1] == "-cells") { | ||||||
|  | @ -846,6 +854,11 @@ struct HelpPass : public Pass { | ||||||
| 					std::ostringstream buf; | 					std::ostringstream buf; | ||||||
| 					log_streams.push_back(&buf); | 					log_streams.push_back(&buf); | ||||||
| 					it.second->help(); | 					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(); | 					log_streams.pop_back(); | ||||||
| 					write_tex(f, it.first, it.second->short_help, buf.str()); | 					write_tex(f, it.first, it.second->short_help, buf.str()); | ||||||
| 				} | 				} | ||||||
|  | @ -858,6 +871,11 @@ struct HelpPass : public Pass { | ||||||
| 					std::ostringstream buf; | 					std::ostringstream buf; | ||||||
| 					log_streams.push_back(&buf); | 					log_streams.push_back(&buf); | ||||||
| 					it.second->help(); | 					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(); | 					log_streams.pop_back(); | ||||||
| 					write_html(f, it.first, it.second->short_help, buf.str()); | 					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])) { | 			else if (pass_register.count(args[1])) { | ||||||
| 				pass_register.at(args[1])->help(); | 				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])) { | 			else if (cell_help_messages.cell_help.count(args[1])) { | ||||||
| 				log("%s", cell_help_messages.cell_help.at(args[1]).c_str()); | 				log("%s", cell_help_messages.cell_help.at(args[1]).c_str()); | ||||||
|  |  | ||||||
|  | @ -36,6 +36,11 @@ struct Pass | ||||||
| 
 | 
 | ||||||
| 	int call_counter; | 	int call_counter; | ||||||
| 	int64_t runtime_ns; | 	int64_t runtime_ns; | ||||||
|  | 	bool experimental_flag = false; | ||||||
|  | 
 | ||||||
|  | 	void experimental() { | ||||||
|  | 		experimental_flag = true; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	struct pre_post_exec_state_t { | 	struct pre_post_exec_state_t { | ||||||
| 		Pass *parent_pass; | 		Pass *parent_pass; | ||||||
|  |  | ||||||
|  | @ -851,6 +851,8 @@ public: | ||||||
| 
 | 
 | ||||||
| 	RTLIL::SigSpec repeat(int num) const; | 	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; | ||||||
| 	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); } | 	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} | \subsection{Registers} | ||||||
| 
 | 
 | ||||||
| D-Type Flip-Flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK}, | 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 | an input port \B{D} and an output port \B{Q}. The following parameters are available for {\tt \$dff} | ||||||
| cells: | cells: | ||||||
| 
 | 
 | ||||||
| \begin{itemize} | \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}. | edge if this parameter is {\tt 1'b0}. | ||||||
| \end{itemize} | \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} | 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: | input port for the reset pin and the following additional two parameters: | ||||||
| 
 | 
 | ||||||
| \begin{itemize} | \begin{itemize} | ||||||
| \item \B{ARST\_POLARITY} \\ | \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}. | if this parameter is {\tt 1'b0}. | ||||||
| 
 | 
 | ||||||
| \item \B{ARST\_VALUE} \\ | \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. | in the designs RTLIL::Process objects. | ||||||
| \end{sloppypar} | \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} | \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} | \end{fixme} | ||||||
| 
 | 
 | ||||||
| \subsection{Memories} | \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];0; & {\tt \$\_DFF\_PP0\_} \\ | ||||||
| \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_PP1\_} \\ | \lstinline[language=Verilog];posedge; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DFF\_PP1\_} \\ | ||||||
| \end{tabular} | \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} | \caption{Cell types for gate level logic networks} | ||||||
| \label{tab:CellLib_gates} | \label{tab:CellLib_gates} | ||||||
| \end{table} | \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 \$\_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. | {\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 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 \$\_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\_}, | 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 | {\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; | 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; | if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, and \lstinline[language=Verilog];negedge; | ||||||
| otherwise. | otherwise. | ||||||
|  | @ -476,6 +540,25 @@ otherwise. | ||||||
| 			Q <= D; | 			Q <= D; | ||||||
| \end{lstlisting} | \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 | 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} | 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} | 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} | \end{fixme} | ||||||
| 
 | 
 | ||||||
| \begin{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} |  | ||||||
| Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells. |  | ||||||
| \end{fixme} | \end{fixme} | ||||||
| 
 | 
 | ||||||
| \begin{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","                    }") | 		line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", "                    namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END","                    }") | ||||||
| 		ugly_line = unpretty_string(line) | 		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: | 		if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: | ||||||
| 			namespace_name = ugly_line[10:].replace("{","").strip() | 			namespace_name = ugly_line[10:].replace("{","").strip() | ||||||
| 			namespaces.append((namespace_name, ugly_line.count("{"))) | 			namespaces.append((namespace_name, ugly_line.count("{"))) | ||||||
|  |  | ||||||
|  | @ -873,7 +873,7 @@ struct ShowPass : public Pass { | ||||||
| 			#ifdef __APPLE__ | 			#ifdef __APPLE__ | ||||||
| 			std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str()); | 			std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str()); | ||||||
| 			#else | 			#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 | 			#endif | ||||||
| 			log("Exec: %s\n", cmd.c_str()); | 			log("Exec: %s\n", cmd.c_str()); | ||||||
| 			if (run_command(cmd) != 0) | 			if (run_command(cmd) != 0) | ||||||
|  |  | ||||||
|  | @ -34,13 +34,20 @@ static SigSet<sig2driver_entry_t> sig2driver, sig2user; | ||||||
| static std::set<RTLIL::Cell*> muxtree_cells; | static std::set<RTLIL::Cell*> muxtree_cells; | ||||||
| static SigPool sig_at_port; | 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) { | 	if (sig.is_fully_const() || old_sig == sig) { | ||||||
|  | ret_true: | ||||||
|  | 		mux_tree_cache[sig] = true; | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (sig_at_port.check_any(assign_map(sig))) { | 	if (sig_at_port.check_any(assign_map(sig))) { | ||||||
|  | ret_false: | ||||||
|  | 		mux_tree_cache[sig] = false; | ||||||
| 		return 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) | 	for (auto &cellport : cellport_list) | ||||||
| 	{ | 	{ | ||||||
| 		if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") { | 		if ((cellport.first->type != "$mux" && cellport.first->type != "$pmux") || cellport.second != "\\Y") { | ||||||
| 			return false; | 			goto ret_false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (recursion_monitor.count(cellport.first)) { | 		if (recursion_monitor.count(cellport.first)) { | ||||||
| 			log_warning("logic loop in mux tree at signal %s in module %s.\n", | 			log_warning("logic loop in mux tree at signal %s in module %s.\n", | ||||||
| 					log_signal(sig), RTLIL::id2cstr(module->name)); | 					log_signal(sig), RTLIL::id2cstr(module->name)); | ||||||
| 			return false; | 			goto ret_false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		recursion_monitor.insert(cellport.first); | 		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_a = assign_map(cellport.first->getPort("\\A")); | ||||||
| 		RTLIL::SigSpec sig_b = assign_map(cellport.first->getPort("\\B")); | 		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); | 			recursion_monitor.erase(cellport.first); | ||||||
| 			return false; | 			goto ret_false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (int i = 0; i < sig_b.size(); i += sig_a.size()) | 		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); | 				recursion_monitor.erase(cellport.first); | ||||||
| 				return false; | 				goto ret_false; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 		recursion_monitor.erase(cellport.first); | 		recursion_monitor.erase(cellport.first); | ||||||
| 		muxtree_cells.insert(cellport.first); | 		muxtree_cells.insert(cellport.first); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return true; | 	goto ret_true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool check_state_users(RTLIL::SigSpec sig) | static bool check_state_users(RTLIL::SigSpec sig) | ||||||
|  | @ -143,11 +150,12 @@ static void detect_fsm(RTLIL::Wire *wire) | ||||||
| 		pool<Cell*> recursion_monitor; | 		pool<Cell*> recursion_monitor; | ||||||
| 		RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q")); | 		RTLIL::SigSpec sig_q = assign_map(cellport.first->getPort("\\Q")); | ||||||
| 		RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D")); | 		RTLIL::SigSpec sig_d = assign_map(cellport.first->getPort("\\D")); | ||||||
|  | 		dict<RTLIL::SigSpec, bool> mux_tree_cache; | ||||||
| 
 | 
 | ||||||
| 		if (sig_q != assign_map(wire)) | 		if (sig_q != assign_map(wire)) | ||||||
| 			continue; | 			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); | 		looks_like_good_state_reg = check_state_users(sig_q); | ||||||
| 
 | 
 | ||||||
| 		if (!looks_like_state_reg) | 		if (!looks_like_state_reg) | ||||||
|  |  | ||||||
|  | @ -548,6 +548,19 @@ RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod) | ||||||
| 	return NULL; | 	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 { | struct HierarchyPass : public Pass { | ||||||
| 	HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } | 	HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } | ||||||
| 	void help() YS_OVERRIDE | 	void help() YS_OVERRIDE | ||||||
|  | @ -970,15 +983,71 @@ struct HierarchyPass : public Pass { | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		// Determine default values
 | ||||||
|  | 		dict<IdString, dict<IdString, Const>> defaults_db; | ||||||
| 		if (!nodefaults) | 		if (!nodefaults) | ||||||
| 		{ | 		{ | ||||||
| 			dict<IdString, dict<IdString, Const>> defaults_db; |  | ||||||
| 
 |  | ||||||
| 			for (auto module : design->modules()) | 			for (auto module : design->modules()) | ||||||
| 				for (auto wire : module->wires()) | 				for (auto wire : module->wires()) | ||||||
| 					if (wire->port_input && wire->attributes.count("\\defaultvalue")) | 					if (wire->port_input && wire->attributes.count("\\defaultvalue")) | ||||||
| 						defaults_db[module->name][wire->name] = wire->attributes.at("\\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 module : design->modules()) | ||||||
| 				for (auto cell : module->cells()) | 				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) | 		for (auto module : design_modules) | ||||||
| 		{ | 		{ | ||||||
| 			pool<Wire*> wand_wor_index; | 			pool<Wire*> wand_wor_index; | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ OBJS += passes/opt/wreduce.o | ||||||
| OBJS += passes/opt/opt_demorgan.o | OBJS += passes/opt/opt_demorgan.o | ||||||
| OBJS += passes/opt/rmports.o | OBJS += passes/opt/rmports.o | ||||||
| OBJS += passes/opt/opt_lut.o | OBJS += passes/opt/opt_lut.o | ||||||
|  | OBJS += passes/opt/opt_lut_ins.o | ||||||
| OBJS += passes/opt/pmux2shiftx.o | OBJS += passes/opt/pmux2shiftx.o | ||||||
| OBJS += passes/opt/muxpack.o | OBJS += passes/opt/muxpack.o | ||||||
| endif | 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); | 		cells.erase(cell); | ||||||
| 
 | 
 | ||||||
| 		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); | 		RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); | ||||||
|  | 		sig_a.sort_and_unify(); | ||||||
| 		pool<RTLIL::SigBit> new_sig_a_bits; | 		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 (bit == RTLIL::State::S0) { | ||||||
| 				if (cell->type == ID($reduce_and)) { | 				if (cell->type == ID($reduce_and)) { | ||||||
|  | @ -86,6 +87,7 @@ struct OptReduceWorker | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		RTLIL::SigSpec new_sig_a(new_sig_a_bits); | 		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()) { | 		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)); | 			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)); | 			log("      New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second)); | ||||||
| 
 | 
 | ||||||
| 			module->connect(old_sig_conn); | 			module->connect(old_sig_conn); | ||||||
| 			module->check(); |  | ||||||
| 
 | 
 | ||||||
| 			did_something = true; | 			did_something = true; | ||||||
| 			total_count++; | 			total_count++; | ||||||
|  | @ -324,6 +325,8 @@ struct OptReduceWorker | ||||||
| 				opt_mux(cell); | 				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("\\A", st.carry->getPort("\\I0")); | ||||||
| 	cell->setPort("\\B", st.carry->getPort("\\I1")); | 	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("\\CO", st.carry->getPort("\\CO")); | ||||||
| 
 | 
 | ||||||
| 	cell->setPort("\\I0", st.lut->getPort("\\I0")); | 	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->setPort("\\O", st.lut->getPort("\\O")); | ||||||
| 	cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT")); | 	cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT")); | ||||||
| 
 | 
 | ||||||
|  | @ -118,7 +126,8 @@ struct Ice40WrapCarryPass : public Pass { | ||||||
| 					auto lut = module->addCell(lut_name, ID($lut)); | 					auto lut = module->addCell(lut_name, ID($lut)); | ||||||
| 					lut->setParam(ID(WIDTH), 4); | 					lut->setParam(ID(WIDTH), 4); | ||||||
| 					lut->setParam(ID(LUT), cell->getParam(ID(LUT))); | 					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))); | 					lut->setPort(ID(Y), cell->getPort(ID(O))); | ||||||
| 
 | 
 | ||||||
| 					Const src; | 					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("to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series\n"); | ||||||
| 		log("device.\n"); | 		log("device.\n"); | ||||||
| 		log("\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("\n"); | ||||||
| 		log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\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"); | 		log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n"); | ||||||
|  | @ -805,6 +808,10 @@ struct XilinxDspPass : public Pass { | ||||||
| 			family = "xcu"; | 			family = "xcu"; | ||||||
| 
 | 
 | ||||||
| 		for (auto module : design->selected_modules()) { | 		for (auto module : design->selected_modules()) { | ||||||
|  | 
 | ||||||
|  | 			if (design->scratchpad_get_bool("xilinx_dsp.multonly")) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
| 			// Experimental feature: pack $add/$sub cells with
 | 			// Experimental feature: pack $add/$sub cells with
 | ||||||
| 			//   (* use_dsp48="simd" *) into DSP48E1's using its
 | 			//   (* use_dsp48="simd" *) into DSP48E1's using its
 | ||||||
| 			//   SIMD feature
 | 			//   SIMD feature
 | ||||||
|  |  | ||||||
|  | @ -214,14 +214,38 @@ struct Clk2fflogicPass : public Pass { | ||||||
| 					continue; | 					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); | 					Wire *past_clk = module->addWire(NEW_ID); | ||||||
| 					past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0; | 					past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0; | ||||||
|  | 
 | ||||||
|  | 					if (word_dff) | ||||||
| 						module->addFf(NEW_ID, clk, past_clk); | 						module->addFf(NEW_ID, clk, past_clk); | ||||||
|  | 					else | ||||||
|  | 						module->addFfGate(NEW_ID, clk, past_clk); | ||||||
| 
 | 
 | ||||||
| 					SigSpec sig_d = cell->getPort("\\D"); | 					SigSpec sig_d = cell->getPort("\\D"); | ||||||
| 					SigSpec sig_q = cell->getPort("\\Q"); | 					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_d = module->addWire(NEW_ID, GetSize(sig_d)); | ||||||
| 					Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q)); | 					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_d, past_d); | ||||||
| 						module->addFf(NEW_ID, sig_q, past_q); | 						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") | 					if (cell->type == "$adff") | ||||||
| 					{ | 					{ | ||||||
|  | @ -266,6 +296,26 @@ struct Clk2fflogicPass : public Pass { | ||||||
| 							module->addMux(NEW_ID, rstval, qval, arst, sig_q); | 							module->addMux(NEW_ID, rstval, qval, arst, sig_q); | ||||||
| 					} | 					} | ||||||
| 					else | 					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") | 					if (cell->type == "$dffsr") | ||||||
| 					{ | 					{ | ||||||
| 						SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); | 						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); | 						module->addAnd(NEW_ID, qval, clrval, sig_q); | ||||||
| 					} | 					} | ||||||
| 					else | 					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); | 						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; | 					Const initval; | ||||||
| 					bool assign_initval = false; | 					bool assign_initval = false; | ||||||
|  |  | ||||||
|  | @ -269,6 +269,7 @@ struct SatHelper | ||||||
| 				for (int i = 0; i < lhs.size(); i++) { | 				for (int i = 0; i < lhs.size(); i++) { | ||||||
| 					RTLIL::SigSpec bit = lhs.extract(i, 1); | 					RTLIL::SigSpec bit = lhs.extract(i, 1); | ||||||
| 					if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) { | 					if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) { | ||||||
|  | 						if (rhs[i] != State::Sx) | ||||||
| 							removed_bits.append(bit); | 							removed_bits.append(bit); | ||||||
| 						lhs.remove(i, 1); | 						lhs.remove(i, 1); | ||||||
| 						rhs.remove(i, 1); | 						rhs.remove(i, 1); | ||||||
|  |  | ||||||
|  | @ -8,9 +8,12 @@ OBJS += passes/techmap/libparse.o | ||||||
| ifeq ($(ENABLE_ABC),1) | ifeq ($(ENABLE_ABC),1) | ||||||
| OBJS += passes/techmap/abc.o | OBJS += passes/techmap/abc.o | ||||||
| OBJS += passes/techmap/abc9.o | OBJS += passes/techmap/abc9.o | ||||||
|  | OBJS += passes/techmap/abc9_exe.o | ||||||
|  | OBJS += passes/techmap/abc9_ops.o | ||||||
| ifneq ($(ABCEXTERNAL),) | ifneq ($(ABCEXTERNAL),) | ||||||
| passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | ||||||
| passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | ||||||
|  | passes/techmap/abc9_exe.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' | ||||||
| endif | endif | ||||||
| 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->unsetPort(ID(S)); | ||||||
| 					cell->type = tri_type; | 					cell->type = tri_type; | ||||||
| 					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); | 					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); | ||||||
|  | 					module->design->scratchpad_set_bool("tribuf.added_something", true); | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | @ -95,6 +96,7 @@ struct TribufWorker { | ||||||
| 					cell->unsetPort(ID(S)); | 					cell->unsetPort(ID(S)); | ||||||
| 					cell->type = tri_type; | 					cell->type = tri_type; | ||||||
| 					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); | 					tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); | ||||||
|  | 					module->design->scratchpad_set_bool("tribuf.added_something", true); | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | @ -130,8 +132,10 @@ struct TribufWorker { | ||||||
| 
 | 
 | ||||||
| 				if (no_tribuf) | 				if (no_tribuf) | ||||||
| 					module->connect(it.first, muxout); | 					module->connect(it.first, muxout); | ||||||
| 				else | 				else { | ||||||
| 					module->addTribuf(NEW_ID, muxout, module->ReduceOr(NEW_ID, pmux_s), it.first); | 					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/cmp2lut.v)) | ||||||
| $(eval $(call add_share_file,share,techlibs/common/cells.lib)) | $(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/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; |     input [WIDTH-1:0] A; | ||||||
|     output Y; |     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 |     generate | ||||||
|         if (WIDTH == 1) begin |         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])); |                 .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0])); | ||||||
|         end else |         end else | ||||||
|         if (WIDTH == 2) begin |         if (WIDTH == 2) begin | ||||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), |             localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}}; | ||||||
|                 .A(1'b0), .B(1'b0), .C(A[1]), .D(A[0])); |             LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||||
|  |                 .A(1'b0), .B(1'b0), .C(A[0]), .D(A[1])); | ||||||
|         end else |         end else | ||||||
|         if (WIDTH == 3) begin |         if (WIDTH == 3) begin | ||||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), |             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]}}}; | ||||||
|                 .A(1'b0), .B(A[2]), .C(A[1]), .D(A[0])); |             LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||||
|  |                 .A(1'b0), .B(A[0]), .C(A[1]), .D(A[2])); | ||||||
|         end else |         end else | ||||||
|         if (WIDTH == 4) begin |         if (WIDTH == 4) begin | ||||||
|             LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), |             LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), | ||||||
|                 .A(A[3]), .B(A[2]), .C(A[1]), .D(A[0])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|         `ifndef NO_PFUMUX |         `ifndef NO_PFUMUX | ||||||
|         end else |         end else | ||||||
|         if (WIDTH == 5) begin |         if (WIDTH == 5) begin | ||||||
|             wire f0, f1; |             wire f0, f1; | ||||||
|             LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), |             LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), | ||||||
|                 .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), |             LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), | ||||||
|                 .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y)); |             PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y)); | ||||||
|         end else |         end else | ||||||
|         if (WIDTH == 6) begin |         if (WIDTH == 6) begin | ||||||
|             wire f0, f1, f2, f3, g0, g1; |             wire f0, f1, f2, f3, g0, g1; | ||||||
|             LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), |             LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), | ||||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), |             LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), | ||||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
| 
 | 
 | ||||||
|             LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2), |             LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), | ||||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3), |             LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), | ||||||
|                 .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
| 
 | 
 | ||||||
|             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0)); |             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); | ||||||
|             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1)); |             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); | ||||||
|             L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y)); |             L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y)); | ||||||
|         end else |         end else | ||||||
|         if (WIDTH == 7) begin |         if (WIDTH == 7) begin | ||||||
|             wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; |             wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; | ||||||
|             LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), |             LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), |             LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
| 
 | 
 | ||||||
|             LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2), |             LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3), |             LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
| 
 | 
 | ||||||
|             LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4), |             LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5), |             LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
| 
 | 
 | ||||||
|             LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6), |             LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
|             LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7), |             LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7), | ||||||
|                 .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); |                 .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); | ||||||
| 
 | 
 | ||||||
|             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0)); |             PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); | ||||||
|             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1)); |             PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); | ||||||
|             PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2)); |             PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2)); | ||||||
|             PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3)); |             PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3)); | ||||||
|             L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0)); |             L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0)); | ||||||
|             L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1)); |             L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1)); | ||||||
|             L6MUX21 mux7  (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y)); |             L6MUX21 mux7  (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y)); | ||||||
|         `endif |         `endif | ||||||
|         end else begin |         end else begin | ||||||
|             wire _TECHMAP_FAIL_ = 1; |             wire _TECHMAP_FAIL_ = 1; | ||||||
|  |  | ||||||
|  | @ -343,6 +343,7 @@ struct SynthEcp5Pass : public ScriptPass | ||||||
| 			else | 			else | ||||||
| 				run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); | 				run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); | ||||||
| 
 | 
 | ||||||
|  | 			run("opt_lut_ins -tech ecp5"); | ||||||
| 			run("clean"); | 			run("clean"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -246,6 +246,7 @@ struct SynthGowinPass : public ScriptPass | ||||||
| 		if (check_label("map_cells")) | 		if (check_label("map_cells")) | ||||||
| 		{ | 		{ | ||||||
| 			run("techmap -map +/gowin/cells_map.v"); | 			run("techmap -map +/gowin/cells_map.v"); | ||||||
|  | 			run("opt_lut_ins -tech gowin"); | ||||||
| 			run("setundef -undriven -params -zero"); | 			run("setundef -undriven -params -zero"); | ||||||
| 			run("hilomap -singleton -hicell VCC V -locell GND G"); | 			run("hilomap -singleton -hicell VCC V -locell GND G"); | ||||||
| 			if (!noiopads || help_mode) | 			if (!noiopads || help_mode) | ||||||
|  |  | ||||||
|  | @ -9,6 +9,8 @@ module \$__ICE40_CARRY_WRAPPER ( | ||||||
| 	input I0, I3 | 	input I0, I3 | ||||||
| ); | ); | ||||||
| 	parameter LUT = 0; | 	parameter LUT = 0; | ||||||
|  | 	parameter I3_IS_CI = 0; | ||||||
|  | 	wire I3_OR_CI = I3_IS_CI ? CI : I3; | ||||||
| 	SB_CARRY carry ( | 	SB_CARRY carry ( | ||||||
| 		.I0(A), | 		.I0(A), | ||||||
| 		.I1(B), | 		.I1(B), | ||||||
|  | @ -21,7 +23,7 @@ module \$__ICE40_CARRY_WRAPPER ( | ||||||
| 		.I0(I0), | 		.I0(I0), | ||||||
| 		.I1(A), | 		.I1(A), | ||||||
| 		.I2(B), | 		.I2(B), | ||||||
| 		.I3(I3), | 		.I3(I3_OR_CI), | ||||||
| 		.O(O) | 		.O(O) | ||||||
| 	); | 	); | ||||||
| endmodule | endmodule | ||||||
|  |  | ||||||
|  | @ -6,7 +6,6 @@ | ||||||
| 
 | 
 | ||||||
| # Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve | # Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve | ||||||
| #                                 SB_LUT4+SB_CARRY) | #                                 SB_LUT4+SB_CARRY) | ||||||
| # Outputs: O, CO |  | ||||||
| #   (Exception: carry chain input/output must be the | #   (Exception: carry chain input/output must be the | ||||||
| #        last input and output and the entire bus has been | #        last input and output and the entire bus has been | ||||||
| #        moved there overriding the otherwise | #        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[1]: 1100 1100 1100 1100 | ||||||
| 			//    A[2]: 1111 0000 1111 0000 | 			//    A[2]: 1111 0000 1111 0000 | ||||||
| 			//    A[3]: 1111 1111 0000 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 ( | 		) carry ( | ||||||
| 			.A(AA[i]), | 			.A(AA[i]), | ||||||
| 			.B(BB[i]), | 			.B(BB[i]), | ||||||
| 			.CI(C[i]), | 			.CI(C[i]), | ||||||
| 			.I0(1'b0), | 			.I0(1'b0), | ||||||
| 			.I3(C[i]), | 			.I3(1'bx), | ||||||
| 			.CO(CO[i]), | 			.CO(CO[i]), | ||||||
| 			.O(Y[i]) | 			.O(Y[i]) | ||||||
| 		); | 		); | ||||||
|  |  | ||||||
|  | @ -42,19 +42,18 @@ module \$lut (A, Y); | ||||||
|         .I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0])); |         .I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 2) begin |     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), |       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 |     end else | ||||||
|     if (WIDTH == 3) begin |     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), |       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 |     end else | ||||||
|     if (WIDTH == 4) begin |     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(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|       SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3])); | ||||||
|         .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0])); |  | ||||||
|     end else begin |     end else begin | ||||||
|       wire _TECHMAP_FAIL_ = 1; |       wire _TECHMAP_FAIL_ = 1; | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -1126,6 +1126,7 @@ module SB_SPRAM256KA ( | ||||||
| 	input [15:0] DATAIN, | 	input [15:0] DATAIN, | ||||||
| 	input [3:0] MASKWREN, | 	input [3:0] MASKWREN, | ||||||
| 	input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF, | 	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 | 	output reg [15:0] DATAOUT | ||||||
| ); | ); | ||||||
| `ifndef BLACKBOX | `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("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)); | 						log_id(module), log_id(cell), log_signal(replacement_output)); | ||||||
| 				cell->type = "$lut"; | 				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->setPort("\\Y", cell->getPort("\\O")); | ||||||
| 				cell->unsetPort("\\B"); | 				cell->unsetPort("\\B"); | ||||||
| 				cell->unsetPort("\\CI"); | 				cell->unsetPort("\\CI"); | ||||||
|  | @ -148,6 +149,7 @@ static void run_ice40_opts(Module *module) | ||||||
| 				cell->unsetPort("\\CO"); | 				cell->unsetPort("\\CO"); | ||||||
| 				cell->unsetPort("\\O"); | 				cell->unsetPort("\\O"); | ||||||
| 				cell->setParam("\\WIDTH", 4); | 				cell->setParam("\\WIDTH", 4); | ||||||
|  | 				cell->unsetParam("\\I3_IS_CI"); | ||||||
| 			} | 			} | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ USING_YOSYS_NAMESPACE | ||||||
| PRIVATE_NAMESPACE_BEGIN | PRIVATE_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
| struct SynthIntelPass : public ScriptPass { | 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 | 	void help() YS_OVERRIDE | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
|  | @ -74,7 +74,7 @@ | ||||||
| // (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback | // (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 | //     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] INIT = 1'b0; | ||||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|   parameter [0:0] IS_D_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] abc9_ff.init = 1'b0; | ||||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
| endmodule | 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; |   parameter [0:0] INIT = 1'b0; | ||||||
|   wire QQ, $Q; |   wire QQ, $Q; | ||||||
|   generate if (INIT == 1'b1) begin |   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; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
| endmodule | 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] INIT = 1'b1; | ||||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|   parameter [0:0] IS_D_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] abc9_ff.init = 1'b0; | ||||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
| endmodule | 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; |   parameter [0:0] INIT = 1'b1; | ||||||
|   wire QQ, $Q; |   wire QQ, $Q; | ||||||
|   generate if (INIT == 1'b1) begin |   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; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
| endmodule | 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] INIT = 1'b0; | ||||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|   parameter [0:0] IS_D_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] abc9_ff.init = 1'b0; | ||||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
| endmodule | 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; |   parameter [0:0] INIT = 1'b0; | ||||||
|   wire QQ, $Q, $QQ; |   wire QQ, $Q, $QQ; | ||||||
|   generate if (INIT == 1'b1) begin |   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; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
| endmodule | 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] INIT = 1'b1; | ||||||
|   parameter [0:0] IS_C_INVERTED = 1'b0; |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|   parameter [0:0] IS_D_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] abc9_ff.init = 1'b0; | ||||||
|   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
| endmodule | 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; |   parameter [0:0] INIT = 1'b1; | ||||||
|   wire QQ, $Q, $QQ; |   wire QQ, $Q, $QQ; | ||||||
|   generate if (INIT == 1'b1) begin |   generate if (INIT == 1'b1) begin | ||||||
|  |  | ||||||
|  | @ -33,6 +33,11 @@ endmodule | ||||||
| module \$__ABC9_FF_ (input D, output Q); | module \$__ABC9_FF_ (input D, output Q); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | (* abc9_box_id = (9000+DELAY) *) | ||||||
|  | module \$__ABC9_DELAY (input I, output O); | ||||||
|  |   parameter DELAY = 0; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
| // Box to emulate async behaviour of FDC* | // Box to emulate async behaviour of FDC* | ||||||
| (* abc9_box_id = 1000, lib_whitebox *) | (* abc9_box_id = 1000, lib_whitebox *) | ||||||
| module \$__ABC9_ASYNC0 (input A, S, output Y); | module \$__ABC9_ASYNC0 (input A, S, output Y); | ||||||
|  | @ -42,7 +47,7 @@ endmodule | ||||||
| // Box to emulate async behaviour of FDP* | // Box to emulate async behaviour of FDP* | ||||||
| (* abc9_box_id = 1001, lib_whitebox *) | (* abc9_box_id = 1001, lib_whitebox *) | ||||||
| module \$__ABC9_ASYNC1 (input A, S, output Y); | module \$__ABC9_ASYNC1 (input A, S, output Y); | ||||||
|   assign Y = S ? 1'b0 : A; |   assign Y = S ? 1'b1 : A; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| // Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32} | // 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 | #A S | ||||||
| 0  764 # Y | 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 | # Box 2000 : $__ABC9_LUT6 | ||||||
| #            (private cell to emulate async behaviour of LUTRAMs) | #            (private cell to emulate async behaviour of LUTRAMs) | ||||||
| # SLICEM/A6LUT | # 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 | // 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 ( | module FDRE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_C_INVERTED" *) |   (* invertible_pin = "IS_C_INVERTED" *) | ||||||
|   input C, |   input C, | ||||||
|  |   (* abc9_required=109 *) | ||||||
|   input CE, |   input CE, | ||||||
|   (* invertible_pin = "IS_D_INVERTED" *) |   (* invertible_pin = "IS_D_INVERTED" *) | ||||||
|  |   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||||
|   input D, |   input D, | ||||||
|   (* invertible_pin = "IS_R_INVERTED" *) |   (* invertible_pin = "IS_R_INVERTED" *) | ||||||
|  |   (* abc9_required=404 *) | ||||||
|   input R |   input R | ||||||
| ); | ); | ||||||
|   parameter [0:0] INIT = 1'b0; |   parameter [0:0] INIT = 1'b0; | ||||||
|  | @ -349,30 +352,38 @@ module FDRE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1101, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDRE_1 ( | module FDRE_1 ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   input C, |   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; |   parameter [0:0] INIT = 1'b0; | ||||||
|   initial Q <= INIT; |   initial Q <= INIT; | ||||||
|   always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; |   always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1102, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDSE ( | module FDSE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_C_INVERTED" *) |   (* invertible_pin = "IS_C_INVERTED" *) | ||||||
|   input C, |   input C, | ||||||
|  |   (* abc9_required=109 *) | ||||||
|   input CE, |   input CE, | ||||||
|   (* invertible_pin = "IS_D_INVERTED" *) |   (* invertible_pin = "IS_D_INVERTED" *) | ||||||
|  |   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||||
|   input D, |   input D, | ||||||
|   (* invertible_pin = "IS_S_INVERTED" *) |   (* invertible_pin = "IS_S_INVERTED" *) | ||||||
|  |   (* abc9_required=404 *) | ||||||
|   input S |   input S | ||||||
| ); | ); | ||||||
|   parameter [0:0] INIT = 1'b1; |   parameter [0:0] INIT = 1'b1; | ||||||
|  | @ -386,13 +397,18 @@ module FDSE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1103, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDSE_1 ( | module FDSE_1 ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   input C, |   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; |   parameter [0:0] INIT = 1'b1; | ||||||
|   initial Q <= INIT; |   initial Q <= INIT; | ||||||
|  | @ -405,6 +421,7 @@ module FDRSE ( | ||||||
|   (* invertible_pin = "IS_C_INVERTED" *) |   (* invertible_pin = "IS_C_INVERTED" *) | ||||||
|   input C, |   input C, | ||||||
|   (* invertible_pin = "IS_CE_INVERTED" *) |   (* invertible_pin = "IS_CE_INVERTED" *) | ||||||
|  |   (* abc9_required=109 *) | ||||||
|   input CE, |   input CE, | ||||||
|   (* invertible_pin = "IS_D_INVERTED" *) |   (* invertible_pin = "IS_D_INVERTED" *) | ||||||
|   input D, |   input D, | ||||||
|  | @ -434,17 +451,20 @@ module FDRSE ( | ||||||
|       Q <= d; |       Q <= d; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1104, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDCE ( | module FDCE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_C_INVERTED" *) |   (* invertible_pin = "IS_C_INVERTED" *) | ||||||
|   input C, |   input C, | ||||||
|  |   (* abc9_required=109 *) | ||||||
|   input CE, |   input CE, | ||||||
|   (* invertible_pin = "IS_CLR_INVERTED" *) |   (* invertible_pin = "IS_CLR_INVERTED" *) | ||||||
|  |   (* abc9_required=764 *) | ||||||
|   input CLR, |   input CLR, | ||||||
|   (* invertible_pin = "IS_D_INVERTED" *) |   (* invertible_pin = "IS_D_INVERTED" *) | ||||||
|  |   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||||
|   input D |   input D | ||||||
| ); | ); | ||||||
|   parameter [0:0] INIT = 1'b0; |   parameter [0:0] INIT = 1'b0; | ||||||
|  | @ -460,30 +480,38 @@ module FDCE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1105, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDCE_1 ( | module FDCE_1 ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   input C, |   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; |   parameter [0:0] INIT = 1'b0; | ||||||
|   initial Q <= INIT; |   initial Q <= INIT; | ||||||
|   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; |   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1106, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDPE ( | module FDPE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_C_INVERTED" *) |   (* invertible_pin = "IS_C_INVERTED" *) | ||||||
|   input C, |   input C, | ||||||
|  |   (* abc9_required=109 *) | ||||||
|   input CE, |   input CE, | ||||||
|   (* invertible_pin = "IS_D_INVERTED" *) |   (* invertible_pin = "IS_D_INVERTED" *) | ||||||
|  |   //(* abc9_required=-46 *) // Negative required times not currently supported | ||||||
|   input D, |   input D, | ||||||
|   (* invertible_pin = "IS_PRE_INVERTED" *) |   (* invertible_pin = "IS_PRE_INVERTED" *) | ||||||
|  |   (* abc9_required=764 *) | ||||||
|   input PRE |   input PRE | ||||||
| ); | ); | ||||||
|   parameter [0:0] INIT = 1'b1; |   parameter [0:0] INIT = 1'b1; | ||||||
|  | @ -499,13 +527,18 @@ module FDPE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=1107, lib_whitebox, abc9_flop *) | (* abc9_flop, lib_whitebox *) | ||||||
| module FDPE_1 ( | module FDPE_1 ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   input C, |   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; |   parameter [0:0] INIT = 1'b1; | ||||||
|   initial Q <= INIT; |   initial Q <= INIT; | ||||||
|  | @ -1120,15 +1153,33 @@ module RAM16X1D_1 ( | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM32X1D ( | module RAM32X1D ( | ||||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 |   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||||
|   (* abc9_arrival=1188 *) |   (* abc9_arrival=1153 *) | ||||||
|   output DPO, SPO, |   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, |   input  D, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input  WCLK, |   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  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 |   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||||
| ); | ); | ||||||
|   parameter INIT = 32'h0; |   parameter INIT = 32'h0; | ||||||
|  | @ -1143,15 +1194,33 @@ module RAM32X1D ( | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM32X1D_1 ( | module RAM32X1D_1 ( | ||||||
|   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 |   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 | ||||||
|   (* abc9_arrival=1188 *) |   (* abc9_arrival=1153 *) | ||||||
|   output DPO, SPO, |   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, |   input  D, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input  WCLK, |   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  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 |   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 | ||||||
| ); | ); | ||||||
|   parameter INIT = 32'h0; |   parameter INIT = 32'h0; | ||||||
|  | @ -1166,15 +1235,36 @@ module RAM32X1D_1 ( | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM64X1D ( | 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 *) |   (* abc9_arrival=1153 *) | ||||||
|   output DPO, SPO, |   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, |   input  D, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input  WCLK, |   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  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 |   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||||
| ); | ); | ||||||
|   parameter INIT = 64'h0; |   parameter INIT = 64'h0; | ||||||
|  | @ -1189,15 +1279,36 @@ module RAM64X1D ( | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM64X1D_1 ( | 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 *) |   (* abc9_arrival=1153 *) | ||||||
|   output DPO, SPO, |   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, |   input  D, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input  WCLK, |   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  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 |   input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 | ||||||
| ); | ); | ||||||
|   parameter INIT = 64'h0; |   parameter INIT = 64'h0; | ||||||
|  | @ -1212,16 +1323,23 @@ module RAM64X1D_1 ( | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM128X1D ( | module RAM128X1D ( | ||||||
|   // 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 | ||||||
|   //   plus 204ps to cross MUXF7 |   //   plus 208ps to cross MUXF7 | ||||||
|   (* abc9_arrival=1357 *) |   (* abc9_arrival=1359 *) | ||||||
|   output       DPO, SPO, |   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, |   input        D, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input        WCLK, |   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        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 INIT = 128'h0; | ||||||
|   parameter IS_WCLK_INVERTED = 1'b0; |   parameter IS_WCLK_INVERTED = 1'b0; | ||||||
|  | @ -1253,23 +1371,43 @@ endmodule | ||||||
| // Multi port. | // Multi port. | ||||||
| 
 | 
 | ||||||
| module RAM32M ( | 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 |   // 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, |   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 |   // 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, |   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 |   // 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, |   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 |   // 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, |   output [1:0] DOD, | ||||||
|   input [4:0] ADDRA, ADDRB, ADDRC, ADDRD, |   input  [4:0] ADDRA, ADDRB, ADDRC, | ||||||
|   input [1:0] DIA, DIB, DIC, DID, |   // 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 *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input        WCLK, |   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        WE | ||||||
| ); | ); | ||||||
|   parameter [63:0] INIT_A = 64'h0000000000000000; |   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 |   // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093 | ||||||
|   (* abc9_arrival=1163 *) |   (* abc9_arrival=1163 *) | ||||||
|   output       DOD, |   output       DOD, | ||||||
|   input [5:0] ADDRA, ADDRB, ADDRC, ADDRD, |   input  [5:0] ADDRA, ADDRB, ADDRC, | ||||||
|   input DIA, DIB, DIC, DID, |   // 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 *) |   (* clkbuf_sink *) | ||||||
|   (* invertible_pin = "IS_WCLK_INVERTED" *) |   (* invertible_pin = "IS_WCLK_INVERTED" *) | ||||||
|   input        WCLK, |   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        WE | ||||||
| ); | ); | ||||||
|   parameter [63:0] INIT_A = 64'h0000000000000000; |   parameter [63:0] INIT_A = 64'h0000000000000000; | ||||||
|  | @ -2155,7 +2309,235 @@ assign PCOUT = P; | ||||||
| 
 | 
 | ||||||
| endmodule | 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). | // TODO: DSP48E (Virtex 5). | ||||||
| 
 | 
 | ||||||
|  | @ -2169,21 +2551,30 @@ module DSP48E1 ( | ||||||
|     output reg MULTSIGNOUT, |     output reg MULTSIGNOUT, | ||||||
|     output OVERFLOW, |     output OVERFLOW, | ||||||
| `ifdef YOSYS | `ifdef YOSYS | ||||||
|     (* abc9_arrival = \DSP48E1.P_arrival () *) |     (* abc9_arrival = \P.abc9_arrival () *) | ||||||
| `endif | `endif | ||||||
|     output reg signed [47:0] P, |     output reg signed [47:0] P, | ||||||
|     output reg PATTERNBDETECT, |     output reg PATTERNBDETECT, | ||||||
|     output reg PATTERNDETECT, |     output reg PATTERNDETECT, | ||||||
| `ifdef YOSYS | `ifdef YOSYS | ||||||
|     (* abc9_arrival = \DSP48E1.PCOUT_arrival () *) |     (* abc9_arrival = \PCOUT.abc9_arrival () *) | ||||||
| `endif | `endif | ||||||
|     output [47:0] PCOUT, |     output [47:0] PCOUT, | ||||||
|     output UNDERFLOW, |     output UNDERFLOW, | ||||||
|  | `ifdef YOSYS | ||||||
|  |     (* abc9_required = \A.abc9_required () *) | ||||||
|  | `endif | ||||||
|     input signed [29:0] A, |     input signed [29:0] A, | ||||||
|     input [29:0] ACIN, |     input [29:0] ACIN, | ||||||
|     input [3:0] ALUMODE, |     input [3:0] ALUMODE, | ||||||
|  | `ifdef YOSYS | ||||||
|  |     (* abc9_required = \B.abc9_required () *) | ||||||
|  | `endif | ||||||
|     input signed [17:0] B, |     input signed [17:0] B, | ||||||
|     input [17:0] BCIN, |     input [17:0] BCIN, | ||||||
|  | `ifdef YOSYS | ||||||
|  |     (* abc9_required = \C.abc9_required () *) | ||||||
|  | `endif | ||||||
|     input [47:0] C, |     input [47:0] C, | ||||||
|     input CARRYCASCIN, |     input CARRYCASCIN, | ||||||
|     input CARRYIN, |     input CARRYIN, | ||||||
|  | @ -2202,10 +2593,16 @@ module DSP48E1 ( | ||||||
|     input CEM, |     input CEM, | ||||||
|     input CEP, |     input CEP, | ||||||
|     (* clkbuf_sink *) input CLK, |     (* clkbuf_sink *) input CLK, | ||||||
|  | `ifdef YOSYS | ||||||
|  |     (* abc9_required = \D.abc9_required () *) | ||||||
|  | `endif | ||||||
|     input [24:0] D, |     input [24:0] D, | ||||||
|     input [4:0] INMODE, |     input [4:0] INMODE, | ||||||
|     input MULTSIGNIN, |     input MULTSIGNIN, | ||||||
|     input [6:0] OPMODE, |     input [6:0] OPMODE, | ||||||
|  | `ifdef YOSYS | ||||||
|  |     (* abc9_required = \PCIN.abc9_required () *) | ||||||
|  | `endif | ||||||
|     input [47:0] PCIN, |     input [47:0] PCIN, | ||||||
|     input RSTA, |     input RSTA, | ||||||
|     input RSTALLCARRYIN, |     input RSTALLCARRYIN, | ||||||
|  | @ -2250,69 +2647,133 @@ module DSP48E1 ( | ||||||
|     parameter [6:0] IS_OPMODE_INVERTED = 7'b0; |     parameter [6:0] IS_OPMODE_INVERTED = 7'b0; | ||||||
| 
 | 
 | ||||||
| `ifdef YOSYS | `ifdef YOSYS | ||||||
|     function integer \DSP48E1.P_arrival ; |     function integer \A.abc9_required ; | ||||||
|     begin |     begin | ||||||
|         \DSP48E1.P_arrival = 0; |         \A.abc9_required = 0; | ||||||
|         if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin |         if (AREG != 0)           \A.abc9_required =  254; | ||||||
|             if (PREG != 0)      \DSP48E1.P_arrival =  329; |         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin | ||||||
|             // Worst-case from CREG and MREG |             if (MREG != 0)       \A.abc9_required = 1416; | ||||||
|             else if (CREG != 0) \DSP48E1.P_arrival = 1687; |             else if (PREG != 0)  \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3030 : 2739) ; | ||||||
|             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; |  | ||||||
|         end |         end | ||||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin |         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin | ||||||
|             if (PREG != 0)      \DSP48E1.P_arrival =  329; |             // Worst-case from ADREG and MREG | ||||||
|             // Worst-case from CREG and MREG |             if (MREG != 0)       \A.abc9_required = 2400; | ||||||
|             else if (CREG != 0) \DSP48E1.P_arrival = 1687; |             else if (ADREG != 0) \A.abc9_required = 1283; | ||||||
|             else if (MREG != 0) \DSP48E1.P_arrival = 1671; |             else if (PREG != 0)  \A.abc9_required = 3723; | ||||||
|             // Worst-case from AREG, ADREG, BREG, DREG |             else if (PREG != 0)  \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 4014 : 3723) ; | ||||||
|             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; |  | ||||||
|         end |         end | ||||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin |         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 |             // Worst-case from AREG, BREG, CREG | ||||||
|             else if (CREG != 0) \DSP48E1.P_arrival = 1687; |             else if (CREG != 0)  \P.abc9_arrival = 1687; | ||||||
|             else if (AREG != 0) \DSP48E1.P_arrival = 1632; |             else if (AREG != 0)  \P.abc9_arrival = 1632; | ||||||
|             else if (BREG != 0) \DSP48E1.P_arrival = 1616; |             else if (BREG != 0)  \P.abc9_arrival = 1616; | ||||||
|         end |         end | ||||||
|         //else |         //else | ||||||
|         //    $error("Invalid DSP48E1 configuration"); |         //    $error("Invalid DSP48E1 configuration"); | ||||||
|     end |     end | ||||||
|     endfunction |     endfunction | ||||||
|     function integer \DSP48E1.PCOUT_arrival ; |     function integer \PCOUT.abc9_arrival ; | ||||||
|     begin |     begin | ||||||
|         \DSP48E1.PCOUT_arrival = 0; |         \PCOUT.abc9_arrival = 0; | ||||||
|         if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin |         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 |             // Worst-case from CREG and MREG | ||||||
|             else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; |             else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; | ||||||
|             else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819; |             else if (MREG != 0)  \PCOUT.abc9_arrival = 1819; | ||||||
|             // Worst-case from AREG and BREG |             // Worst-case from AREG and BREG | ||||||
|             else if (AREG != 0) \DSP48E1.PCOUT_arrival = 3098; |             else if (AREG != 0)  \PCOUT.abc9_arrival = 3098; | ||||||
|             else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960; |             else if (BREG != 0)  \PCOUT.abc9_arrival = 2960; | ||||||
|         end |         end | ||||||
|         else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin |         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 |             // Worst-case from CREG and MREG | ||||||
|             else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; |             else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; | ||||||
|             else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819; |             else if (MREG != 0)  \PCOUT.abc9_arrival = 1819; | ||||||
|             // Worst-case from AREG, ADREG, BREG, DREG |             // Worst-case from AREG, ADREG, BREG, DREG | ||||||
|             else if (AREG != 0)  \DSP48E1.PCOUT_arrival = 4083; |             else if (AREG != 0)  \PCOUT.abc9_arrival = 4083; | ||||||
|             else if (DREG != 0)  \DSP48E1.PCOUT_arrival = 4056; |             else if (DREG != 0)  \PCOUT.abc9_arrival = 4056; | ||||||
|             else if (BREG != 0)  \DSP48E1.PCOUT_arrival = 2960; |             else if (BREG != 0)  \PCOUT.abc9_arrival = 2960; | ||||||
|             else if (ADREG != 0) \DSP48E1.PCOUT_arrival = 2859; |             else if (ADREG != 0) \PCOUT.abc9_arrival = 2859; | ||||||
|         end |         end | ||||||
|         else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin |         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 |             // Worst-case from AREG, BREG, CREG | ||||||
|             else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; |             else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; | ||||||
|             else if (AREG != 0) \DSP48E1.PCOUT_arrival = 1780; |             else if (AREG != 0)  \PCOUT.abc9_arrival = 1780; | ||||||
|             else if (BREG != 0) \DSP48E1.PCOUT_arrival = 1765; |             else if (BREG != 0)  \PCOUT.abc9_arrival = 1765; | ||||||
|         end |         end | ||||||
|         //else |         //else | ||||||
|         //    $error("Invalid DSP48E1 configuration"); |         //    $error("Invalid DSP48E1 configuration"); | ||||||
|  |  | ||||||
|  | @ -180,18 +180,58 @@ CELLS = [ | ||||||
|     Cell('RAMB18E1', port_attrs={ |     Cell('RAMB18E1', port_attrs={ | ||||||
|         'CLKARDCLK': ['clkbuf_sink'], |         'CLKARDCLK': ['clkbuf_sink'], | ||||||
|         'CLKBWRCLK': ['clkbuf_sink'], |         'CLKBWRCLK': ['clkbuf_sink'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143 | ||||||
|         'DOADO': ['abc9_arrival=2454'], |         'DOADO': ['abc9_arrival=2454'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163 | ||||||
|         'DOBDO': ['abc9_arrival=2454'], |         'DOBDO': ['abc9_arrival=2454'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144 | ||||||
|         'DOPADOP': ['abc9_arrival=2454'], |         'DOPADOP': ['abc9_arrival=2454'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164 | ||||||
|         'DOPBDOP': ['abc9_arrival=2454'], |         '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={ |     Cell('RAMB36E1', port_attrs={ | ||||||
|         'CLKARDCLK': ['clkbuf_sink'], |         'CLKARDCLK': ['clkbuf_sink'], | ||||||
|         'CLKBWRCLK': ['clkbuf_sink'], |         'CLKBWRCLK': ['clkbuf_sink'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143 | ||||||
|         'DOADO': ['abc9_arrival=2454'], |         'DOADO': ['abc9_arrival=2454'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163 | ||||||
|         'DOBDO': ['abc9_arrival=2454'], |         'DOBDO': ['abc9_arrival=2454'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144 | ||||||
|         'DOPADOP': ['abc9_arrival=2454'], |         'DOPADOP': ['abc9_arrival=2454'], | ||||||
|  |         # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164 | ||||||
|         'DOPBDOP': ['abc9_arrival=2454'], |         '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. |     # Ultrascale. | ||||||
|     Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), |     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('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E | ||||||
|     # Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP |     # Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP | ||||||
|     # Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6 |     # 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('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5 | ||||||
|     #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7 |     #Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7 | ||||||
|     Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale |     Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale | ||||||
|  |  | ||||||
|  | @ -4518,13 +4518,21 @@ module RAMB18E1 (...); | ||||||
|     input RSTREGARSTREG; |     input RSTREGARSTREG; | ||||||
|     (* invertible_pin = "IS_RSTREGB_INVERTED" *) |     (* invertible_pin = "IS_RSTREGB_INVERTED" *) | ||||||
|     input RSTREGB; |     input RSTREGB; | ||||||
|  |     (* abc9_required=566 *) | ||||||
|     input [13:0] ADDRARDADDR; |     input [13:0] ADDRARDADDR; | ||||||
|  |     (* abc9_required=566 *) | ||||||
|     input [13:0] ADDRBWRADDR; |     input [13:0] ADDRBWRADDR; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [15:0] DIADI; |     input [15:0] DIADI; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [15:0] DIBDI; |     input [15:0] DIBDI; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [1:0] DIPADIP; |     input [1:0] DIPADIP; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [1:0] DIPBDIP; |     input [1:0] DIPBDIP; | ||||||
|  |     (* abc9_required=532 *) | ||||||
|     input [1:0] WEA; |     input [1:0] WEA; | ||||||
|  |     (* abc9_required=532 *) | ||||||
|     input [3:0] WEBWE; |     input [3:0] WEBWE; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | @ -4742,13 +4750,21 @@ module RAMB36E1 (...); | ||||||
|     input REGCEB; |     input REGCEB; | ||||||
|     input INJECTDBITERR; |     input INJECTDBITERR; | ||||||
|     input INJECTSBITERR; |     input INJECTSBITERR; | ||||||
|  |     (* abc9_required=566 *) | ||||||
|     input [15:0] ADDRARDADDR; |     input [15:0] ADDRARDADDR; | ||||||
|  |     (* abc9_required=566 *) | ||||||
|     input [15:0] ADDRBWRADDR; |     input [15:0] ADDRBWRADDR; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [31:0] DIADI; |     input [31:0] DIADI; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [31:0] DIBDI; |     input [31:0] DIBDI; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [3:0] DIPADIP; |     input [3:0] DIPADIP; | ||||||
|  |     (* abc9_required=737 *) | ||||||
|     input [3:0] DIPBDIP; |     input [3:0] DIPBDIP; | ||||||
|  |     (* abc9_required=532 *) | ||||||
|     input [3:0] WEA; |     input [3:0] WEA; | ||||||
|  |     (* abc9_required=532 *) | ||||||
|     input [7:0] WEBWE; |     input [7:0] WEBWE; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | @ -5476,49 +5492,6 @@ module URAM288_BASE (...); | ||||||
|     input SLEEP; |     input SLEEP; | ||||||
| endmodule | 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 (...); | module DSP48E (...); | ||||||
|     parameter SIM_MODE = "SAFE"; |     parameter SIM_MODE = "SAFE"; | ||||||
|     parameter integer ACASCREG = 1; |     parameter integer ACASCREG = 1; | ||||||
|  |  | ||||||
|  | @ -29,90 +29,65 @@ module \$lut (A, Y); | ||||||
|   input [WIDTH-1:0] A; |   input [WIDTH-1:0] A; | ||||||
|   output Y; |   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 |   generate | ||||||
|     if (WIDTH == 1) begin |     if (WIDTH == 1) begin | ||||||
|       if (P_LUT == 2'b01) begin |       if (LUT == 2'b01) begin | ||||||
|         INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0])); |         INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0])); | ||||||
|       end else begin |       end else begin | ||||||
|         LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), |         LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|           .I0(A[0])); |           .I0(A[0])); | ||||||
|       end |       end | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 2) begin |     if (WIDTH == 2) begin | ||||||
|       LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), |       LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|         .I0(A[1]), .I1(A[0])); |         .I0(A[0]), .I1(A[1])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 3) begin |     if (WIDTH == 3) begin | ||||||
|       LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), |       LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|         .I0(A[2]), .I1(A[1]), .I2(A[0])); |         .I0(A[0]), .I1(A[1]), .I2(A[2])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 4) begin |     if (WIDTH == 4) begin | ||||||
|       LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), |       LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|         .I0(A[3]), .I1(A[2]), .I2(A[1]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[0])); |         .I3(A[3])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 5) begin |     if (WIDTH == 5) begin | ||||||
|       LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), |       LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|         .I0(A[4]), .I1(A[3]), .I2(A[2]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[1]), .I4(A[0])); |         .I3(A[3]), .I4(A[4])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 6) begin |     if (WIDTH == 6) begin | ||||||
|       LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), |       LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), | ||||||
|         .I0(A[5]), .I1(A[4]), .I2(A[3]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[2]), .I4(A[1]), .I5(A[0])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 7) begin |     if (WIDTH == 7) begin | ||||||
|       wire T0, T1; |       wire T0, T1; | ||||||
|       LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0), |       LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), | ||||||
|         .I0(A[6]), .I1(A[5]), .I2(A[4]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[3]), .I4(A[2]), .I5(A[1])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|       LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1), |       LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), | ||||||
|         .I0(A[6]), .I1(A[5]), .I2(A[4]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[3]), .I4(A[2]), .I5(A[1])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|       MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0])); |       MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); | ||||||
|     end else |     end else | ||||||
|     if (WIDTH == 8) begin |     if (WIDTH == 8) begin | ||||||
|       wire T0, T1, T2, T3, T4, T5; |       wire T0, T1, T2, T3, T4, T5; | ||||||
|       LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0), |       LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), | ||||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|       LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1), |       LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), | ||||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|       LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2), |       LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), | ||||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|       LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3), |       LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), | ||||||
|         .I0(A[7]), .I1(A[6]), .I2(A[5]), |         .I0(A[0]), .I1(A[1]), .I2(A[2]), | ||||||
|         .I3(A[4]), .I4(A[3]), .I5(A[2])); |         .I3(A[3]), .I4(A[4]), .I5(A[5])); | ||||||
|       MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1])); |       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[1])); |       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[0])); |       MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); | ||||||
|     end else begin |     end else begin | ||||||
|       wire _TECHMAP_FAIL_ = 1; |       wire _TECHMAP_FAIL_ = 1; | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -153,7 +153,7 @@ endmatch | ||||||
| 
 | 
 | ||||||
| match $__XILINX_RAM32X2Q | match $__XILINX_RAM32X2Q | ||||||
|   min bits 5 |   min bits 5 | ||||||
|   min rports 3 |   min rports 2 | ||||||
|   min wports 1 |   min wports 1 | ||||||
|   make_outreg |   make_outreg | ||||||
|   or_next_if_better |   or_next_if_better | ||||||
|  | @ -161,7 +161,7 @@ endmatch | ||||||
| 
 | 
 | ||||||
| match $__XILINX_RAM64X1Q | match $__XILINX_RAM64X1Q | ||||||
|   min bits 5 |   min bits 5 | ||||||
|   min rports 3 |   min rports 2 | ||||||
|   min wports 1 |   min wports 1 | ||||||
|   make_outreg |   make_outreg | ||||||
| endmatch | endmatch | ||||||
|  |  | ||||||
|  | @ -316,7 +316,11 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 			run("proc"); | 			run("proc"); | ||||||
| 			if (flatten || help_mode) | 			if (flatten || help_mode) | ||||||
| 				run("flatten", "(with '-flatten')"); | 				run("flatten", "(with '-flatten')"); | ||||||
|  | 			if (active_design) | ||||||
|  | 				active_design->scratchpad_unset("tribuf.added_something"); | ||||||
| 			run("tribuf -logic"); | 			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("deminout"); | ||||||
| 			run("opt_expr"); | 			run("opt_expr"); | ||||||
| 			run("opt_clean"); | 			run("opt_clean"); | ||||||
|  | @ -526,7 +530,7 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 		if (check_label("map_cells")) { | 		if (check_label("map_cells")) { | ||||||
| 			// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
 | 			// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
 | ||||||
| 			if (help_mode || !noiopad) | 			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"; | 			std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v"; | ||||||
| 			if (widemux > 0) | 			if (widemux > 0) | ||||||
| 				techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux); | 				techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux); | ||||||
|  | @ -589,12 +593,11 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 			if (!nosrl || help_mode) | 			if (!nosrl || help_mode) | ||||||
| 				run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); | 				run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); | ||||||
| 			std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; | 			std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; | ||||||
| 			if (help_mode) | 			if (help_mode || !abc9) | ||||||
| 				techmap_args += stringf("[-map %s]", ff_map_file.c_str()); |  | ||||||
| 			else if (!abc9) |  | ||||||
| 				techmap_args += stringf(" -map %s", ff_map_file.c_str()); | 				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("xilinx_dffopt"); | ||||||
|  | 			run("opt_lut_ins -tech xilinx"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("finalize")) { | 		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_ref.v | ||||||
| test_dsp48a1_model_uut.v | test_dsp48a1_model_uut.v | ||||||
| test_dsp48a1_model | test_dsp48a1_model | ||||||
|  | test_dsp48_model_ref.v | ||||||
|  | test_dsp48_model_uut.v | ||||||
|  | test_dsp48_model | ||||||
| *.vcd | *.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 | 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) | 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 | 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 | 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 | 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) | 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 | 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 2 t:MUX2_LUT5 | ||||||
| select -assert-count 1 t:MUX2_LUT6 | select -assert-count 1 t:MUX2_LUT6 | ||||||
| select -assert-count 6 t:IBUF | select -assert-count 6 t:IBUF | ||||||
| select -assert-count 1 t:OBUF | 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 | design -load read | ||||||
| hierarchy -top mux8 | 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 11 t:IBUF | ||||||
| select -assert-count 1 t:OBUF | 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 | design -load read | ||||||
| hierarchy -top mux16 | 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 20 t:IBUF | ||||||
| select -assert-count 1 t:OBUF | 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 | read_verilog -icells -formal <<EOT | ||||||
| module top(input CI, I0, output [1:0] CO, output O); | module top(input CI, I0, output [1:0] CO, output O); | ||||||
|     wire A = 1'b0, B = 1'b0; |     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[1]: 1100 1100 1100 1100 | ||||||
| 		//    A[2]: 1111 0000 1111 0000 | 		//    A[2]: 1111 0000 1111 0000 | ||||||
| 		//    A[3]: 1111 1111 0000 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 ( | 	) u0 ( | ||||||
| 		.A(A), | 		.A(A), | ||||||
| 		.B(B), | 		.B(B), | ||||||
| 		.CI(CI), | 		.CI(CI), | ||||||
| 		.I0(I0), | 		.I0(I0), | ||||||
| 		.I3(CI), | 		.I3(1'bx), | ||||||
| 		.CO(CO[0]), | 		.CO(CO[0]), | ||||||
| 		.O(O) | 		.O(O) | ||||||
| 	); | 	); | ||||||
|  | @ -40,7 +21,7 @@ module top(input CI, I0, output [1:0] CO, output O); | ||||||
| endmodule | endmodule | ||||||
| EOT | 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 | design -load postopt | ||||||
| select -assert-count 1 t:* | select -assert-count 1 t:* | ||||||
| select -assert-count 1 t:$lut | 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 | ||||||
| select -assert-count 1 t:SB_CARRY a:keep %i | select -assert-count 1 t:SB_CARRY a:keep %i | ||||||
| select -assert-count 1 t:SB_CARRY c:carry %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;; | proc;; | ||||||
| 
 | 
 | ||||||
| sat -seq 10 -prove-asserts | 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; |   input rst; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| (* abc_box_id=1 *) | (* abc9_box_id=1, whitebox *) | ||||||
| module MUXF8(input I0, I1, S, output O); | module MUXF8(input I0, I1, S, output O); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | @ -291,3 +291,19 @@ module abc9_test035(input clk, d, output reg [1:0] q); | ||||||
| always @(posedge clk) q[0] <= d; | always @(posedge clk) q[0] <= d; | ||||||
| always @(negedge clk) q[1] <= q[0]; | always @(negedge clk) q[1] <= q[0]; | ||||||
| endmodule | 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; \ |     abc9 -lut 4 -box ../abc.box; \ | ||||||
|     clean; \ |     clean; \ | ||||||
|     check -assert; \ |     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 | scratchpad -copy abc9.script.flow3 abc9.script | ||||||
| abc9 -lut 4 | 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 | design -reset | ||||||
| read_verilog -icells <<EOT | read_verilog -icells <<EOT | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ design -import gate -as gate | ||||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
| sat -verify -prove-asserts -show-ports miter | sat -verify -prove-asserts -show-ports miter | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| design -load read | design -load read | ||||||
| hierarchy -top abc9_test028 | hierarchy -top abc9_test028 | ||||||
| proc | 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-count 1 t:unknown | ||||||
| select -assert-none t:$lut t:unknown %% t: %D | select -assert-none t:$lut t:unknown %% t: %D | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| design -load read | design -load read | ||||||
| hierarchy -top abc9_test032 | hierarchy -top abc9_test032 | ||||||
| proc | proc | ||||||
|  | @ -38,3 +40,16 @@ design -import gate -as gate | ||||||
| 
 | 
 | ||||||
| miter -equiv -flatten -make_assert -make_outputs gold gate miter | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
| sat -seq 10 -verify -prove-asserts -show-ports 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