mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into eddie/abc9_mfs
This commit is contained in:
		
						commit
						94ab3791ce
					
				
					 30 changed files with 1577 additions and 1080 deletions
				
			
		|  | @ -57,6 +57,8 @@ Yosys 0.9 .. Yosys 0.9-dev | ||||||
|       always_latch and always_ff) |       always_latch and always_ff) | ||||||
|     - Added "xilinx_dffopt" pass |     - Added "xilinx_dffopt" pass | ||||||
|     - Added "scratchpad" pass |     - Added "scratchpad" pass | ||||||
|  |     - Added "abc9 -dff" | ||||||
|  |     - Added "synth_xilinx -dff" | ||||||
| 
 | 
 | ||||||
| Yosys 0.8 .. Yosys 0.9 | Yosys 0.8 .. Yosys 0.9 | ||||||
| ---------------------- | ---------------------- | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -128,7 +128,7 @@ bumpversion: | ||||||
| # is just a symlink to your actual ABC working directory, as 'make mrproper'
 | # is just a symlink to your actual ABC working directory, as 'make mrproper'
 | ||||||
| # will remove the 'abc' directory and you do not want to accidentally
 | # will remove the 'abc' directory and you do not want to accidentally
 | ||||||
| # delete your work on ABC..
 | # delete your work on ABC..
 | ||||||
| ABCREV = 1485e63 | ABCREV = 144c5be | ||||||
| ABCPULL = 1 | ABCPULL = 1 | ||||||
| ABCURL ?= https://github.com/berkeley-abc/abc | ABCURL ?= https://github.com/berkeley-abc/abc | ||||||
| ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 | ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 | ||||||
|  |  | ||||||
|  | @ -376,7 +376,11 @@ Verilog Attributes and non-standard features | ||||||
| - The port attribute ``abc9_arrival`` specifies an integer (for output ports | - The port attribute ``abc9_arrival`` specifies an integer (for output ports | ||||||
|   only) to be used as the arrival time of this sequential port. It can be used, |   only) to be used as the arrival time of this sequential port. It can be used, | ||||||
|   for example, to specify the clk-to-Q delay of a flip-flop for consideration |   for example, to specify the clk-to-Q delay of a flip-flop for consideration | ||||||
|   during techmapping. |   during `abc9` techmapping. | ||||||
|  | 
 | ||||||
|  | - The module attribute ``abc9_flop`` is a boolean marking the module as a | ||||||
|  |   flip-flop. This allows `abc9` to analyse its contents in order to perform | ||||||
|  |   sequential synthesis. | ||||||
| 
 | 
 | ||||||
| - The frontend sets attributes ``always_comb``, ``always_latch`` and | - The frontend sets attributes ``always_comb``, ``always_latch`` and | ||||||
|   ``always_ff`` on processes derived from SystemVerilog style always blocks |   ``always_ff`` on processes derived from SystemVerilog style always blocks | ||||||
|  |  | ||||||
|  | @ -787,6 +787,14 @@ struct AigerBackend : public Backend { | ||||||
| 		if (top_module == nullptr) | 		if (top_module == nullptr) | ||||||
| 			log_error("Can't find top module in current design!\n"); | 			log_error("Can't find top module in current design!\n"); | ||||||
| 
 | 
 | ||||||
|  | 		if (!design->selected_whole_module(top_module)) | ||||||
|  | 			log_cmd_error("Can't handle partially selected module %s!\n", log_id(top_module)); | ||||||
|  | 
 | ||||||
|  | 		if (!top_module->processes.empty()) | ||||||
|  | 			log_error("Found unmapped processes in module %s: unmapped processes are not supported in AIGER backend!\n", log_id(top_module)); | ||||||
|  | 		if (!top_module->memories.empty()) | ||||||
|  | 			log_error("Found unmapped memories in module %s: unmapped memories are not supported in AIGER backend!\n", log_id(top_module)); | ||||||
|  | 
 | ||||||
| 		AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode); | 		AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode); | ||||||
| 		writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); | 		writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -82,6 +82,7 @@ struct XAigerWriter | ||||||
| 	dict<SigBit, SigBit> not_map, alias_map; | 	dict<SigBit, SigBit> not_map, alias_map; | ||||||
| 	dict<SigBit, pair<SigBit, SigBit>> and_map; | 	dict<SigBit, pair<SigBit, SigBit>> and_map; | ||||||
| 	vector<SigBit> ci_bits, co_bits; | 	vector<SigBit> ci_bits, co_bits; | ||||||
|  | 	dict<SigBit, Cell*> ff_bits; | ||||||
| 	dict<SigBit, float> arrival_times; | 	dict<SigBit, float> arrival_times; | ||||||
| 
 | 
 | ||||||
| 	vector<pair<int, int>> aig_gates; | 	vector<pair<int, int>> aig_gates; | ||||||
|  | @ -92,7 +93,7 @@ struct XAigerWriter | ||||||
| 	dict<SigBit, int> ordered_outputs; | 	dict<SigBit, int> ordered_outputs; | ||||||
| 
 | 
 | ||||||
| 	vector<Cell*> box_list; | 	vector<Cell*> box_list; | ||||||
| 	bool omode = false; | 	dict<IdString, std::vector<IdString>> box_ports; | ||||||
| 
 | 
 | ||||||
| 	int mkgate(int a0, int a1) | 	int mkgate(int a0, int a1) | ||||||
| 	{ | 	{ | ||||||
|  | @ -140,7 +141,6 @@ struct XAigerWriter | ||||||
| 	{ | 	{ | ||||||
| 		pool<SigBit> undriven_bits; | 		pool<SigBit> undriven_bits; | ||||||
| 		pool<SigBit> unused_bits; | 		pool<SigBit> unused_bits; | ||||||
| 		pool<SigBit> keep_bits; |  | ||||||
| 
 | 
 | ||||||
| 		// promote public wires
 | 		// promote public wires
 | ||||||
| 		for (auto wire : module->wires()) | 		for (auto wire : module->wires()) | ||||||
|  | @ -152,46 +152,38 @@ struct XAigerWriter | ||||||
| 			if (wire->port_input) | 			if (wire->port_input) | ||||||
| 				sigmap.add(wire); | 				sigmap.add(wire); | ||||||
| 
 | 
 | ||||||
|  | 		// promote keep wires
 | ||||||
| 		for (auto wire : module->wires()) | 		for (auto wire : module->wires()) | ||||||
| 		{ | 			if (wire->get_bool_attribute(ID::keep)) | ||||||
| 			bool keep = wire->attributes.count("\\keep"); | 				sigmap.add(wire); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 		for (auto wire : module->wires()) | ||||||
| 			for (int i = 0; i < GetSize(wire); i++) | 			for (int i = 0; i < GetSize(wire); i++) | ||||||
| 			{ | 			{ | ||||||
| 				SigBit wirebit(wire, i); | 				SigBit wirebit(wire, i); | ||||||
| 				SigBit bit = sigmap(wirebit); | 				SigBit bit = sigmap(wirebit); | ||||||
| 
 | 
 | ||||||
| 				if (bit.wire) { | 				if (bit.wire == nullptr) { | ||||||
|  | 					if (wire->port_output) { | ||||||
|  | 						aig_map[wirebit] = (bit == State::S1) ? 1 : 0; | ||||||
|  | 						output_bits.insert(wirebit); | ||||||
|  | 					} | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				undriven_bits.insert(bit); | 				undriven_bits.insert(bit); | ||||||
| 				unused_bits.insert(bit); | 				unused_bits.insert(bit); | ||||||
| 				} |  | ||||||
| 
 | 
 | ||||||
| 				if (keep) | 				if (wire->port_input) | ||||||
| 					keep_bits.insert(wirebit); | 					input_bits.insert(bit); | ||||||
| 
 | 
 | ||||||
| 				if (wire->port_input || keep) { | 				if (wire->port_output) { | ||||||
| 					if (bit != wirebit) |  | ||||||
| 						alias_map[bit] = wirebit; |  | ||||||
| 					input_bits.insert(wirebit); |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (wire->port_output || keep) { |  | ||||||
| 					if (bit != RTLIL::Sx) { |  | ||||||
| 					if (bit != wirebit) | 					if (bit != wirebit) | ||||||
| 						alias_map[wirebit] = bit; | 						alias_map[wirebit] = bit; | ||||||
| 					output_bits.insert(wirebit); | 					output_bits.insert(wirebit); | ||||||
| 				} | 				} | ||||||
| 					else |  | ||||||
| 						log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit)); |  | ||||||
| 			} | 			} | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (auto bit : input_bits) |  | ||||||
| 			undriven_bits.erase(sigmap(bit)); |  | ||||||
| 		for (auto bit : output_bits) |  | ||||||
| 			if (!bit.wire->port_input) |  | ||||||
| 				unused_bits.erase(bit); |  | ||||||
| 
 | 
 | ||||||
| 		// TODO: Speed up toposort -- ultimately we care about
 | 		// TODO: Speed up toposort -- ultimately we care about
 | ||||||
| 		//       box ordering, but not individual AIG cells
 | 		//       box ordering, but not individual AIG cells
 | ||||||
|  | @ -207,11 +199,9 @@ 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; | ||||||
| 				if (!holes_mode) { |  | ||||||
| 				toposort.node(cell->name); | 				toposort.node(cell->name); | ||||||
| 				bit_users[A].insert(cell->name); | 				bit_users[A].insert(cell->name); | ||||||
| 				bit_drivers[Y].insert(cell->name); | 				bit_drivers[Y].insert(cell->name); | ||||||
| 				} |  | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -224,39 +214,72 @@ 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); | ||||||
| 				if (!holes_mode) { |  | ||||||
| 				toposort.node(cell->name); | 				toposort.node(cell->name); | ||||||
| 				bit_users[A].insert(cell->name); | 				bit_users[A].insert(cell->name); | ||||||
| 				bit_users[B].insert(cell->name); | 				bit_users[B].insert(cell->name); | ||||||
| 				bit_drivers[Y].insert(cell->name); | 				bit_drivers[Y].insert(cell->name); | ||||||
| 				} |  | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			log_assert(!holes_mode); | 			if (cell->type == "$__ABC9_FF_" && | ||||||
| 
 |                                         // The presence of an abc9_mergeability attribute indicates
 | ||||||
| 			RTLIL::Module* inst_module = module->design->module(cell->type); |                                         //   that we do want to pass this flop to ABC
 | ||||||
| 			if (inst_module && inst_module->attributes.count("\\abc9_box_id")) { |                                         cell->attributes.count("\\abc9_mergeability")) | ||||||
| 				abc9_box_seen = true; | 			{ | ||||||
| 
 | 				SigBit D = sigmap(cell->getPort("\\D").as_bit()); | ||||||
| 				if (!holes_mode) { | 				SigBit Q = sigmap(cell->getPort("\\Q").as_bit()); | ||||||
| 					toposort.node(cell->name); | 				unused_bits.erase(D); | ||||||
| 					for (const auto &conn : cell->connections()) { | 				undriven_bits.erase(Q); | ||||||
| 						auto port_wire = inst_module->wire(conn.first); | 				alias_map[Q] = D; | ||||||
| 						if (port_wire->port_input) { | 				auto r YS_ATTRIBUTE(unused) = ff_bits.insert(std::make_pair(D, cell)); | ||||||
| 							// Ignore inout for the sake of topographical ordering
 | 				log_assert(r.second); | ||||||
| 							if (port_wire->port_output) continue; | 				continue; | ||||||
| 							for (auto bit : sigmap(conn.second)) |  | ||||||
| 								bit_users[bit].insert(cell->name); |  | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			RTLIL::Module* inst_module = module->design->module(cell->type); | ||||||
|  | 			if (inst_module) { | ||||||
|  | 				bool abc9_box = inst_module->attributes.count("\\abc9_box_id"); | ||||||
|  | 				bool abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); | ||||||
|  | 				if (abc9_box && cell->get_bool_attribute("\\abc9_keep")) | ||||||
|  | 					abc9_box = false; | ||||||
|  | 
 | ||||||
|  | 				for (const auto &conn : cell->connections()) { | ||||||
|  | 					auto port_wire = inst_module->wire(conn.first); | ||||||
|  | 
 | ||||||
|  | 					if (abc9_box) { | ||||||
|  | 						// Ignore inout for the sake of topographical ordering
 | ||||||
|  | 						if (port_wire->port_input && !port_wire->port_output) | ||||||
|  | 							for (auto bit : sigmap(conn.second)) | ||||||
|  | 								bit_users[bit].insert(cell->name); | ||||||
| 						if (port_wire->port_output) | 						if (port_wire->port_output) | ||||||
| 							for (auto bit : sigmap(conn.second)) | 							for (auto bit : sigmap(conn.second)) | ||||||
| 								bit_drivers[bit].insert(cell->name); | 								bit_drivers[bit].insert(cell->name); | ||||||
|  | 
 | ||||||
|  | 						if (!abc9_flop) | ||||||
|  | 							continue; | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (port_wire->port_output) { | ||||||
|  | 						int arrival = 0; | ||||||
|  | 						auto it = port_wire->attributes.find("\\abc9_arrival"); | ||||||
|  | 						if (it != port_wire->attributes.end()) { | ||||||
|  | 							if (it->second.flags != 0) | ||||||
|  | 								log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); | ||||||
|  | 							arrival = it->second.as_int(); | ||||||
|  | 						} | ||||||
|  | 						if (arrival) | ||||||
|  | 							for (auto bit : sigmap(conn.second)) | ||||||
|  | 								arrival_times[bit] = arrival; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				if (abc9_box) { | ||||||
|  | 					abc9_box_seen = true; | ||||||
|  | 					toposort.node(cell->name); | ||||||
|  | 					continue; | ||||||
| 				} | 				} | ||||||
| 			else { | 			} | ||||||
|  | 
 | ||||||
| 			bool cell_known = inst_module || cell->known(); | 			bool cell_known = inst_module || cell->known(); | ||||||
| 			for (const auto &c : cell->connections()) { | 			for (const auto &c : cell->connections()) { | ||||||
| 				if (c.second.is_fully_const()) continue; | 				if (c.second.is_fully_const()) continue; | ||||||
|  | @ -266,7 +289,7 @@ struct XAigerWriter | ||||||
| 				if (!is_input && !is_output) | 				if (!is_input && !is_output) | ||||||
| 					log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); | 					log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); | ||||||
| 
 | 
 | ||||||
| 					if (is_input) { | 				if (is_input) | ||||||
| 					for (auto b : c.second) { | 					for (auto b : c.second) { | ||||||
| 						Wire *w = b.wire; | 						Wire *w = b.wire; | ||||||
| 						if (!w) continue; | 						if (!w) continue; | ||||||
|  | @ -275,36 +298,6 @@ struct XAigerWriter | ||||||
| 							if (I != b) | 							if (I != b) | ||||||
| 								alias_map[b] = I; | 								alias_map[b] = I; | ||||||
| 							output_bits.insert(b); | 							output_bits.insert(b); | ||||||
| 								unused_bits.erase(b); |  | ||||||
| 
 |  | ||||||
| 								if (!cell_known) |  | ||||||
| 									keep_bits.insert(b); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					if (is_output) { |  | ||||||
| 						int arrival = 0; |  | ||||||
| 						if (port_wire) { |  | ||||||
| 							auto it = port_wire->attributes.find("\\abc9_arrival"); |  | ||||||
| 							if (it != port_wire->attributes.end()) { |  | ||||||
| 								if (it->second.flags != 0) |  | ||||||
| 									log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); |  | ||||||
| 								arrival = it->second.as_int(); |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 
 |  | ||||||
| 						for (auto b : c.second) { |  | ||||||
| 							Wire *w = b.wire; |  | ||||||
| 							if (!w) continue; |  | ||||||
| 							input_bits.insert(b); |  | ||||||
| 							SigBit O = sigmap(b); |  | ||||||
| 							if (O != b) |  | ||||||
| 								alias_map[O] = b; |  | ||||||
| 							undriven_bits.erase(O); |  | ||||||
| 
 |  | ||||||
| 							if (arrival) |  | ||||||
| 								arrival_times[b] = arrival; |  | ||||||
| 						} |  | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 			} | 			} | ||||||
|  | @ -346,12 +339,44 @@ struct XAigerWriter | ||||||
| 
 | 
 | ||||||
| 				bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); | 				bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); | ||||||
| 
 | 
 | ||||||
|  | 				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) { | ||||||
|  | 								if (carry_in != IdString()) | ||||||
|  | 									log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); | ||||||
|  | 								carry_in = port_name; | ||||||
|  | 							} | ||||||
|  | 							if (w->port_output) { | ||||||
|  | 								if (carry_out != IdString()) | ||||||
|  | 									log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); | ||||||
|  | 								carry_out = port_name; | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 							r.first->second.push_back(port_name); | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if (carry_in != IdString() && carry_out == IdString()) | ||||||
|  | 						log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); | ||||||
|  | 					if (carry_in == IdString() && carry_out != IdString()) | ||||||
|  | 						log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); | ||||||
|  | 					if (carry_in != IdString()) { | ||||||
|  | 						r.first->second.push_back(carry_in); | ||||||
|  | 						r.first->second.push_back(carry_out); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				// Fully pad all unused input connections of this box cell with S0
 | 				// 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
 | 				// Fully pad all undriven output connections of this box cell with anonymous wires
 | ||||||
| 				// NB: Assume box_module->ports are sorted alphabetically
 | 				for (auto port_name : r.first->second) { | ||||||
| 				//     (as RTLIL::Module::fixup_ports() would do)
 | 					auto w = box_module->wire(port_name); | ||||||
| 				for (const auto &port_name : box_module->ports) { |  | ||||||
| 					RTLIL::Wire* w = box_module->wire(port_name); |  | ||||||
| 					log_assert(w); | 					log_assert(w); | ||||||
| 					auto it = cell->connections_.find(port_name); | 					auto it = cell->connections_.find(port_name); | ||||||
| 					if (w->port_input) { | 					if (w->port_input) { | ||||||
|  | @ -366,7 +391,7 @@ struct XAigerWriter | ||||||
| 							cell->setPort(port_name, rhs); | 							cell->setPort(port_name, rhs); | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
| 						for (auto b : rhs.bits()) { | 						for (auto b : rhs) { | ||||||
| 							SigBit I = sigmap(b); | 							SigBit I = sigmap(b); | ||||||
| 							if (b == RTLIL::Sx) | 							if (b == RTLIL::Sx) | ||||||
| 								b = State::S0; | 								b = State::S0; | ||||||
|  | @ -377,7 +402,7 @@ struct XAigerWriter | ||||||
| 									alias_map[b] = I; | 									alias_map[b] = I; | ||||||
| 							} | 							} | ||||||
| 							co_bits.emplace_back(b); | 							co_bits.emplace_back(b); | ||||||
| 							unused_bits.erase(b); | 							unused_bits.erase(I); | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 					if (w->port_output) { | 					if (w->port_output) { | ||||||
|  | @ -397,65 +422,53 @@ struct XAigerWriter | ||||||
| 						} | 						} | ||||||
| 
 | 
 | ||||||
| 						for (const auto &b : rhs.bits()) { | 						for (const auto &b : rhs.bits()) { | ||||||
| 							ci_bits.emplace_back(b); |  | ||||||
| 							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); | ||||||
| 							undriven_bits.erase(O); | 							undriven_bits.erase(O); | ||||||
| 							input_bits.erase(b); |  | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				// Connect <cell>.abc9_ff.Q (inserted by abc9_map.v) as the last input to the flop box
 | ||||||
|  | 				if (box_module->get_bool_attribute("\\abc9_flop")) { | ||||||
|  | 					SigSpec rhs = module->wire(stringf("%s.abc9_ff.Q", cell->name.c_str())); | ||||||
|  | 					if (rhs.empty()) | ||||||
|  | 						log_error("'%s.abc9_ff.Q' is not a wire present in module '%s'.\n", log_id(cell), log_id(module)); | ||||||
|  | 
 | ||||||
|  | 					for (auto b : rhs) { | ||||||
|  | 						SigBit I = sigmap(b); | ||||||
|  | 						if (b == RTLIL::Sx) | ||||||
|  | 							b = State::S0; | ||||||
|  | 						else if (I != b) { | ||||||
|  | 							if (I == RTLIL::Sx) | ||||||
|  | 								alias_map[b] = State::S0; | ||||||
|  | 							else | ||||||
|  | 								alias_map[b] = I; | ||||||
|  | 						} | ||||||
|  | 						co_bits.emplace_back(b); | ||||||
|  | 						unused_bits.erase(I); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				box_list.emplace_back(cell); | 				box_list.emplace_back(cell); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// TODO: Free memory from toposort, bit_drivers, bit_users
 | 			// TODO: Free memory from toposort, bit_drivers, bit_users
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (auto bit : input_bits) { | 		for (auto bit : input_bits) | ||||||
| 			if (!output_bits.count(bit)) | 			undriven_bits.erase(bit); | ||||||
| 				continue; | 		for (auto bit : output_bits) | ||||||
| 			RTLIL::Wire *wire = bit.wire; | 			unused_bits.erase(sigmap(bit)); | ||||||
| 			// If encountering an inout port, or a keep-ed wire, then create a new wire
 |  | ||||||
| 			// with $inout.out suffix, make it a PO driven by the existing inout, and
 |  | ||||||
| 			// inherit existing inout's drivers
 |  | ||||||
| 			if ((wire->port_input && wire->port_output && !undriven_bits.count(bit)) |  | ||||||
| 					|| keep_bits.count(bit)) { |  | ||||||
| 				RTLIL::IdString wire_name = stringf("$%s$inout.out", wire->name.c_str()); |  | ||||||
| 				RTLIL::Wire *new_wire = module->wire(wire_name); |  | ||||||
| 				if (!new_wire) |  | ||||||
| 					new_wire = module->addWire(wire_name, GetSize(wire)); |  | ||||||
| 				SigBit new_bit(new_wire, bit.offset); |  | ||||||
| 				module->connect(new_bit, bit); |  | ||||||
| 				if (not_map.count(bit)) { |  | ||||||
| 					auto a = not_map.at(bit); |  | ||||||
| 					not_map[new_bit] = a; |  | ||||||
| 				} |  | ||||||
| 				else if (and_map.count(bit)) { |  | ||||||
| 					auto a = and_map.at(bit); |  | ||||||
| 					and_map[new_bit] = a; |  | ||||||
| 				} |  | ||||||
| 				else if (alias_map.count(bit)) { |  | ||||||
| 					auto a = alias_map.at(bit); |  | ||||||
| 					alias_map[new_bit] = a; |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 					alias_map[new_bit] = bit; |  | ||||||
| 				output_bits.erase(bit); |  | ||||||
| 				output_bits.insert(new_bit); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (auto bit : unused_bits) | 		for (auto bit : unused_bits) | ||||||
| 			undriven_bits.erase(bit); | 			undriven_bits.erase(bit); | ||||||
| 
 | 
 | ||||||
| 		if (!undriven_bits.empty() && !holes_mode) { | 		// Make all undriven bits a primary input
 | ||||||
| 			undriven_bits.sort(); |  | ||||||
| 		for (auto bit : undriven_bits) { | 		for (auto bit : undriven_bits) { | ||||||
| 				log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit)); |  | ||||||
| 			input_bits.insert(bit); | 			input_bits.insert(bit); | ||||||
| 			} | 			undriven_bits.erase(bit); | ||||||
| 			log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module)); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (holes_mode) { | 		if (holes_mode) { | ||||||
|  | @ -467,25 +480,27 @@ struct XAigerWriter | ||||||
| 			input_bits.sort(sort_by_port_id()); | 			input_bits.sort(sort_by_port_id()); | ||||||
| 			output_bits.sort(sort_by_port_id()); | 			output_bits.sort(sort_by_port_id()); | ||||||
| 		} | 		} | ||||||
| 		else { |  | ||||||
| 			input_bits.sort(); |  | ||||||
| 			output_bits.sort(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		not_map.sort(); |  | ||||||
| 		and_map.sort(); |  | ||||||
| 
 | 
 | ||||||
| 		aig_map[State::S0] = 0; | 		aig_map[State::S0] = 0; | ||||||
| 		aig_map[State::S1] = 1; | 		aig_map[State::S1] = 1; | ||||||
| 
 | 
 | ||||||
| 		for (auto bit : input_bits) { | 		for (const auto &bit : input_bits) { | ||||||
| 			aig_m++, aig_i++; | 			aig_m++, aig_i++; | ||||||
| 			log_assert(!aig_map.count(bit)); | 			log_assert(!aig_map.count(bit)); | ||||||
| 			aig_map[bit] = 2*aig_m; | 			aig_map[bit] = 2*aig_m; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (auto bit : ci_bits) { | 		for (const auto &i : ff_bits) { | ||||||
|  | 			const Cell *cell = i.second; | ||||||
|  | 			const SigBit &q = sigmap(cell->getPort("\\Q")); | ||||||
| 			aig_m++, aig_i++; | 			aig_m++, aig_i++; | ||||||
|  | 			log_assert(!aig_map.count(q)); | ||||||
|  | 			aig_map[q] = 2*aig_m; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for (auto &bit : ci_bits) { | ||||||
|  | 			aig_m++, aig_i++; | ||||||
|  | 			log_assert(!aig_map.count(bit)); | ||||||
| 			aig_map[bit] = 2*aig_m; | 			aig_map[bit] = 2*aig_m; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -494,15 +509,16 @@ struct XAigerWriter | ||||||
| 			aig_outputs.push_back(bit2aig(bit)); | 			aig_outputs.push_back(bit2aig(bit)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (output_bits.empty()) { | 		for (const auto &bit : output_bits) { | ||||||
| 			output_bits.insert(State::S0); |  | ||||||
| 			omode = true; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (auto bit : output_bits) { |  | ||||||
| 			ordered_outputs[bit] = aig_o++; | 			ordered_outputs[bit] = aig_o++; | ||||||
| 			aig_outputs.push_back(bit2aig(bit)); | 			aig_outputs.push_back(bit2aig(bit)); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		for (auto &i : ff_bits) { | ||||||
|  | 			const SigBit &d = i.first; | ||||||
|  | 			aig_o++; | ||||||
|  | 			aig_outputs.push_back(aig_map.at(d)); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void write_aiger(std::ostream &f, bool ascii_mode) | 	void write_aiger(std::ostream &f, bool ascii_mode) | ||||||
|  | @ -564,7 +580,6 @@ struct XAigerWriter | ||||||
| 
 | 
 | ||||||
| 		f << "c"; | 		f << "c"; | ||||||
| 
 | 
 | ||||||
| 		log_assert(!output_bits.empty()); |  | ||||||
| 		auto write_buffer = [](std::stringstream &buffer, int i32) { | 		auto write_buffer = [](std::stringstream &buffer, int i32) { | ||||||
| 			int32_t i32_be = to_big_endian(i32); | 			int32_t i32_be = to_big_endian(i32); | ||||||
| 			buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); | 			buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); | ||||||
|  | @ -572,14 +587,14 @@ struct XAigerWriter | ||||||
| 		std::stringstream h_buffer; | 		std::stringstream h_buffer; | ||||||
| 		auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); | 		auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); | ||||||
| 		write_h_buffer(1); | 		write_h_buffer(1); | ||||||
| 		log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits)); | 		log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_bits) + GetSize(ci_bits)); | ||||||
| 		write_h_buffer(input_bits.size() + ci_bits.size()); | 		write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size()); | ||||||
| 		log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits)); | 		log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_bits) + GetSize(co_bits)); | ||||||
| 		write_h_buffer(output_bits.size() + GetSize(co_bits)); | 		write_h_buffer(output_bits.size() + GetSize(ff_bits) + GetSize(co_bits)); | ||||||
| 		log_debug("piNum = %d\n", GetSize(input_bits)); | 		log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_bits)); | ||||||
| 		write_h_buffer(input_bits.size()); | 		write_h_buffer(input_bits.size() + ff_bits.size()); | ||||||
| 		log_debug("poNum = %d\n", GetSize(output_bits)); | 		log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_bits)); | ||||||
| 		write_h_buffer(output_bits.size()); | 		write_h_buffer(output_bits.size() + ff_bits.size()); | ||||||
| 		log_debug("boxNum = %d\n", GetSize(box_list)); | 		log_debug("boxNum = %d\n", GetSize(box_list)); | ||||||
| 		write_h_buffer(box_list.size()); | 		write_h_buffer(box_list.size()); | ||||||
| 
 | 
 | ||||||
|  | @ -595,7 +610,7 @@ struct XAigerWriter | ||||||
| 		//for (auto bit : output_bits)
 | 		//for (auto bit : output_bits)
 | ||||||
| 		//	write_o_buffer(0);
 | 		//	write_o_buffer(0);
 | ||||||
| 
 | 
 | ||||||
| 		if (!box_list.empty()) { | 		if (!box_list.empty() || !ff_bits.empty()) { | ||||||
| 			RTLIL::Module *holes_module = module->design->addModule("$__holes__"); | 			RTLIL::Module *holes_module = module->design->addModule("$__holes__"); | ||||||
| 			log_assert(holes_module); | 			log_assert(holes_module); | ||||||
| 
 | 
 | ||||||
|  | @ -609,35 +624,23 @@ struct XAigerWriter | ||||||
| 				IdString derived_name = orig_box_module->derive(module->design, cell->parameters); | 				IdString derived_name = orig_box_module->derive(module->design, cell->parameters); | ||||||
| 				RTLIL::Module* box_module = module->design->module(derived_name); | 				RTLIL::Module* box_module = module->design->module(derived_name); | ||||||
| 				if (box_module->has_processes()) | 				if (box_module->has_processes()) | ||||||
| 					log_error("ABC9 box '%s' contains processes!\n", box_module->name.c_str()); | 					Pass::call_on_module(module->design, box_module, "proc"); | ||||||
| 
 | 
 | ||||||
| 				int box_inputs = 0, box_outputs = 0; |  | ||||||
| 				auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); | 				auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); | ||||||
| 				Cell *holes_cell = r.first->second; | 				Cell *holes_cell = r.first->second; | ||||||
| 				if (r.second && box_module->get_bool_attribute("\\whitebox")) { | 				if (r.second && box_module->get_bool_attribute("\\whitebox")) { | ||||||
| 					holes_cell = holes_module->addCell(cell->name, cell->type); | 					holes_cell = holes_module->addCell(cell->name, cell->type); | ||||||
| 					holes_cell->parameters = cell->parameters; | 					holes_cell->parameters = cell->parameters; | ||||||
| 					r.first->second = holes_cell; | 					r.first->second = holes_cell; | ||||||
| 
 |  | ||||||
| 					// Since Module::derive() will create a new module, there
 |  | ||||||
| 					//   is a chance that the ports will be alphabetically ordered
 |  | ||||||
| 					//   again, which is a problem when carry-chains are involved.
 |  | ||||||
| 					//   Inherit the port ordering from the original module here...
 |  | ||||||
| 					//   (and set the port_id below, when iterating through those)
 |  | ||||||
| 					log_assert(GetSize(box_module->ports) == GetSize(orig_box_module->ports)); |  | ||||||
| 					box_module->ports = orig_box_module->ports; |  | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				// NB: Assume box_module->ports are sorted alphabetically
 | 				int box_inputs = 0, box_outputs = 0; | ||||||
| 				//     (as RTLIL::Module::fixup_ports() would do)
 | 				for (auto port_name : box_ports.at(cell->type)) { | ||||||
| 				int box_port_id = 1; |  | ||||||
| 				for (const auto &port_name : box_module->ports) { |  | ||||||
| 					RTLIL::Wire *w = box_module->wire(port_name); | 					RTLIL::Wire *w = box_module->wire(port_name); | ||||||
| 					log_assert(w); | 					log_assert(w); | ||||||
| 					if (r.second) |  | ||||||
| 						w->port_id = box_port_id++; |  | ||||||
| 					RTLIL::Wire *holes_wire; | 					RTLIL::Wire *holes_wire; | ||||||
| 					RTLIL::SigSpec port_sig; | 					RTLIL::SigSpec port_sig; | ||||||
|  | 
 | ||||||
| 					if (w->port_input) | 					if (w->port_input) | ||||||
| 						for (int i = 0; i < GetSize(w); i++) { | 						for (int i = 0; i < GetSize(w); i++) { | ||||||
| 							box_inputs++; | 							box_inputs++; | ||||||
|  | @ -655,9 +658,9 @@ struct XAigerWriter | ||||||
| 						box_outputs += GetSize(w); | 						box_outputs += GetSize(w); | ||||||
| 						for (int i = 0; i < GetSize(w); i++) { | 						for (int i = 0; i < GetSize(w); i++) { | ||||||
| 							if (GetSize(w) == 1) | 							if (GetSize(w) == 1) | ||||||
| 								holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), log_id(w->name))); | 								holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name))); | ||||||
| 							else | 							else | ||||||
| 								holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), log_id(w->name), i)); | 								holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i)); | ||||||
| 							holes_wire->port_output = true; | 							holes_wire->port_output = true; | ||||||
| 							holes_wire->port_id = port_id++; | 							holes_wire->port_id = port_id++; | ||||||
| 							holes_module->ports.push_back(holes_wire->name); | 							holes_module->ports.push_back(holes_wire->name); | ||||||
|  | @ -675,6 +678,23 @@ struct XAigerWriter | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				// For flops only, create an extra 1-bit input that drives a new wire
 | ||||||
|  | 				//   called "<cell>.abc9_ff.Q" that is used below
 | ||||||
|  | 				if (box_module->get_bool_attribute("\\abc9_flop")) { | ||||||
|  | 					log_assert(holes_cell); | ||||||
|  | 
 | ||||||
|  | 					box_inputs++; | ||||||
|  | 					Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); | ||||||
|  | 					if (!holes_wire) { | ||||||
|  | 						holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); | ||||||
|  | 						holes_wire->port_input = true; | ||||||
|  | 						holes_wire->port_id = port_id++; | ||||||
|  | 						holes_module->ports.push_back(holes_wire->name); | ||||||
|  | 					} | ||||||
|  | 					Wire *w = holes_module->addWire(stringf("%s.abc9_ff.Q", cell->name.c_str())); | ||||||
|  | 					holes_module->connect(w, holes_wire); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				write_h_buffer(box_inputs); | 				write_h_buffer(box_inputs); | ||||||
| 				write_h_buffer(box_outputs); | 				write_h_buffer(box_outputs); | ||||||
| 				write_h_buffer(box_module->attributes.at("\\abc9_box_id").as_int()); | 				write_h_buffer(box_module->attributes.at("\\abc9_box_id").as_int()); | ||||||
|  | @ -683,13 +703,48 @@ struct XAigerWriter | ||||||
| 
 | 
 | ||||||
| 			std::stringstream r_buffer; | 			std::stringstream r_buffer; | ||||||
| 			auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1); | 			auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1); | ||||||
| 			write_r_buffer(0); | 			log_debug("flopNum = %d\n", GetSize(ff_bits)); | ||||||
|  | 			write_r_buffer(ff_bits.size()); | ||||||
|  | 
 | ||||||
|  | 			std::stringstream s_buffer; | ||||||
|  | 			auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1); | ||||||
|  | 			write_s_buffer(ff_bits.size()); | ||||||
|  | 
 | ||||||
|  | 			for (const auto &i : ff_bits) { | ||||||
|  | 				const SigBit &d = i.first; | ||||||
|  | 				const Cell *cell = i.second; | ||||||
|  | 
 | ||||||
|  | 				int mergeability = cell->attributes.at(ID(abc9_mergeability)).as_int(); | ||||||
|  | 				log_assert(mergeability > 0); | ||||||
|  | 				write_r_buffer(mergeability); | ||||||
|  | 
 | ||||||
|  | 				Const init = cell->attributes.at(ID(abc9_init)); | ||||||
|  | 				log_assert(GetSize(init) == 1); | ||||||
|  | 				if (init == State::S1) | ||||||
|  | 					write_s_buffer(1); | ||||||
|  | 				else if (init == State::S0) | ||||||
|  | 					write_s_buffer(0); | ||||||
|  | 				else { | ||||||
|  | 					log_assert(init == State::Sx); | ||||||
|  | 					write_s_buffer(0); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				write_i_buffer(arrival_times.at(d, 0)); | ||||||
|  | 				//write_o_buffer(0);
 | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			f << "r"; | 			f << "r"; | ||||||
| 			std::string buffer_str = r_buffer.str(); | 			std::string buffer_str = r_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()); | ||||||
| 
 | 
 | ||||||
|  | 			f << "s"; | ||||||
|  | 			buffer_str = s_buffer.str(); | ||||||
|  | 			buffer_size_be = to_big_endian(buffer_str.size()); | ||||||
|  | 			f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); | ||||||
|  | 			f.write(buffer_str.data(), buffer_str.size()); | ||||||
|  | 
 | ||||||
| 			if (holes_module) { | 			if (holes_module) { | ||||||
| 				log_push(); | 				log_push(); | ||||||
| 
 | 
 | ||||||
|  | @ -697,34 +752,64 @@ struct XAigerWriter | ||||||
| 				//holes_module->fixup_ports();
 | 				//holes_module->fixup_ports();
 | ||||||
| 				holes_module->check(); | 				holes_module->check(); | ||||||
| 
 | 
 | ||||||
| 				holes_module->design->selection_stack.emplace_back(false); |  | ||||||
| 				RTLIL::Selection& sel = holes_module->design->selection_stack.back(); |  | ||||||
| 				sel.select(holes_module); |  | ||||||
| 
 |  | ||||||
| 				Pass::call(holes_module->design, "flatten -wb"); |  | ||||||
| 
 |  | ||||||
| 				// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
 | 				// Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger
 | ||||||
| 				//   since boxes may contain parameters in which case `flatten` would have
 | 				//   since boxes may contain parameters in which case `flatten` would have
 | ||||||
| 				//   created a new $paramod ...
 | 				//   created a new $paramod ...
 | ||||||
| 				Pass::call(holes_module->design, "techmap"); | 				Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap"); | ||||||
| 				Pass::call(holes_module->design, "aigmap"); |  | ||||||
| 				for (auto cell : holes_module->cells()) |  | ||||||
| 					if (!cell->type.in("$_NOT_", "$_AND_")) |  | ||||||
| 						log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); |  | ||||||
| 
 | 
 | ||||||
| 				holes_module->design->selection_stack.pop_back(); | 				dict<SigSig, SigSig> 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 the combinatorial control logic that feeds the box
 | ||||||
|  | 						//   (i.e. clock enable, synchronous reset, etc.)
 | ||||||
|  | 						replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,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 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(conn); | ||||||
|  | 					if (it != replace.end()) | ||||||
|  | 						conn = it->second; | ||||||
|  | 				} | ||||||
| 
 | 
 | ||||||
| 				// Move into a new (temporary) design so that "clean" will only
 | 				// Move into a new (temporary) design so that "clean" will only
 | ||||||
| 				// operate (and run checks on) this one module
 | 				// operate (and run checks on) this one module
 | ||||||
| 				RTLIL::Design *holes_design = new RTLIL::Design; | 				RTLIL::Design *holes_design = new RTLIL::Design; | ||||||
| 				holes_module->design->modules_.erase(holes_module->name); | 				module->design->modules_.erase(holes_module->name); | ||||||
| 				holes_design->add(holes_module); | 				holes_design->add(holes_module); | ||||||
| 				Pass::call(holes_design, "clean -purge"); | 				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; | 				delete holes_design; | ||||||
| 
 | 
 | ||||||
| 				f << "a"; | 				f << "a"; | ||||||
|  | @ -755,19 +840,20 @@ struct XAigerWriter | ||||||
| 		//f.write(buffer_str.data(), buffer_str.size());
 | 		//f.write(buffer_str.data(), buffer_str.size());
 | ||||||
| 
 | 
 | ||||||
| 		f << stringf("Generated by %s\n", yosys_version_str); | 		f << stringf("Generated by %s\n", yosys_version_str); | ||||||
|  | 
 | ||||||
|  | 		module->design->scratchpad_set_int("write_xaiger.num_ands", and_map.size()); | ||||||
|  | 		module->design->scratchpad_set_int("write_xaiger.num_wires", aig_map.size()); | ||||||
|  | 		module->design->scratchpad_set_int("write_xaiger.num_inputs", input_bits.size()); | ||||||
|  | 		module->design->scratchpad_set_int("write_xaiger.num_outputs", output_bits.size()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void write_map(std::ostream &f, bool verbose_map) | 	void write_map(std::ostream &f) | ||||||
| 	{ | 	{ | ||||||
| 		dict<int, string> input_lines; | 		dict<int, string> input_lines; | ||||||
| 		dict<int, string> output_lines; | 		dict<int, string> output_lines; | ||||||
| 		dict<int, string> wire_lines; |  | ||||||
| 
 | 
 | ||||||
| 		for (auto wire : module->wires()) | 		for (auto wire : module->wires()) | ||||||
| 		{ | 		{ | ||||||
| 			//if (!verbose_map && wire->name[0] == '$')
 |  | ||||||
| 			//	continue;
 |  | ||||||
| 
 |  | ||||||
| 			SigSpec sig = sigmap(wire); | 			SigSpec sig = sigmap(wire); | ||||||
| 
 | 
 | ||||||
| 			for (int i = 0; i < GetSize(wire); i++) | 			for (int i = 0; i < GetSize(wire); i++) | ||||||
|  | @ -781,17 +867,10 @@ struct XAigerWriter | ||||||
| 
 | 
 | ||||||
| 				if (output_bits.count(b)) { | 				if (output_bits.count(b)) { | ||||||
| 					int o = ordered_outputs.at(b); | 					int o = ordered_outputs.at(b); | ||||||
| 					output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire)); | 					int init = 2; | ||||||
|  | 					output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init); | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 
 |  | ||||||
| 				if (verbose_map) { |  | ||||||
| 					if (aig_map.count(sig[i]) == 0) |  | ||||||
| 						continue; |  | ||||||
| 
 |  | ||||||
| 					int a = aig_map.at(sig[i]); |  | ||||||
| 					wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire)); |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -805,15 +884,9 @@ struct XAigerWriter | ||||||
| 			f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); | 			f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); | ||||||
| 
 | 
 | ||||||
| 		output_lines.sort(); | 		output_lines.sort(); | ||||||
| 		if (omode) |  | ||||||
| 			output_lines[State::S0] = "output 0 0 $__dummy__\n"; |  | ||||||
| 		for (auto &it : output_lines) | 		for (auto &it : output_lines) | ||||||
| 			f << it.second; | 			f << it.second; | ||||||
| 		log_assert(output_lines.size() == output_bits.size()); | 		log_assert(output_lines.size() == output_bits.size()); | ||||||
| 
 |  | ||||||
| 		wire_lines.sort(); |  | ||||||
| 		for (auto &it : wire_lines) |  | ||||||
| 			f << it.second; |  | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -825,8 +898,10 @@ struct XAigerBackend : public Backend { | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    write_xaiger [options] [filename]\n"); | 		log("    write_xaiger [options] [filename]\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("Write the current design to an XAIGER file. The design must be flattened and\n"); | 		log("Write the top module (according to the (* top *) attribute or if only one module\n"); | ||||||
| 		log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n"); | 		log("is currently selected) to an XAIGER file. Any non $_NOT_, $_AND_, $_ABC9_FF_, or"); | ||||||
|  | 		log("non (* abc9_box_id *) cells will be converted into psuedo-inputs and\n"); | ||||||
|  | 		log("pseudo-outputs.\n"); | ||||||
| 		log("\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"); | ||||||
|  | @ -834,14 +909,10 @@ struct XAigerBackend : public Backend { | ||||||
| 		log("    -map <filename>\n"); | 		log("    -map <filename>\n"); | ||||||
| 		log("        write an extra file with port and box symbols\n"); | 		log("        write an extra file with port and box symbols\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -vmap <filename>\n"); |  | ||||||
| 		log("        like -map, but more verbose\n"); |  | ||||||
| 		log("\n"); |  | ||||||
| 	} | 	} | ||||||
| 	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 ascii_mode = false; | 		bool ascii_mode = false; | ||||||
| 		bool verbose_map = false; |  | ||||||
| 		std::string map_filename; | 		std::string map_filename; | ||||||
| 
 | 
 | ||||||
| 		log_header(design, "Executing XAIGER backend.\n"); | 		log_header(design, "Executing XAIGER backend.\n"); | ||||||
|  | @ -857,11 +928,6 @@ struct XAigerBackend : public Backend { | ||||||
| 				map_filename = args[++argidx]; | 				map_filename = args[++argidx]; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) { |  | ||||||
| 				map_filename = args[++argidx]; |  | ||||||
| 				verbose_map = true; |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(f, filename, args, argidx, !ascii_mode); | 		extra_args(f, filename, args, argidx, !ascii_mode); | ||||||
|  | @ -871,6 +937,14 @@ struct XAigerBackend : public Backend { | ||||||
| 		if (top_module == nullptr) | 		if (top_module == nullptr) | ||||||
| 			log_error("Can't find top module in current design!\n"); | 			log_error("Can't find top module in current design!\n"); | ||||||
| 
 | 
 | ||||||
|  | 		if (!design->selected_whole_module(top_module)) | ||||||
|  | 			log_cmd_error("Can't handle partially selected module %s!\n", log_id(top_module)); | ||||||
|  | 
 | ||||||
|  | 		if (!top_module->processes.empty()) | ||||||
|  | 			log_error("Found unmapped processes in module %s: unmapped processes are not supported in XAIGER backend!\n", log_id(top_module)); | ||||||
|  | 		if (!top_module->memories.empty()) | ||||||
|  | 			log_error("Found unmapped memories in module %s: unmapped memories are not supported in XAIGER backend!\n", log_id(top_module)); | ||||||
|  | 
 | ||||||
| 		XAigerWriter writer(top_module); | 		XAigerWriter writer(top_module); | ||||||
| 		writer.write_aiger(*f, ascii_mode); | 		writer.write_aiger(*f, ascii_mode); | ||||||
| 
 | 
 | ||||||
|  | @ -879,7 +953,7 @@ struct XAigerBackend : public Backend { | ||||||
| 			mapf.open(map_filename.c_str(), std::ofstream::trunc); | 			mapf.open(map_filename.c_str(), std::ofstream::trunc); | ||||||
| 			if (mapf.fail()) | 			if (mapf.fail()) | ||||||
| 				log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); | 				log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); | ||||||
| 			writer.write_map(mapf, verbose_map); | 			writer.write_map(mapf); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } XAigerBackend; | } XAigerBackend; | ||||||
|  |  | ||||||
|  | @ -255,7 +255,7 @@ end_of_header: | ||||||
| 	else | 	else | ||||||
| 		log_abort(); | 		log_abort(); | ||||||
| 
 | 
 | ||||||
| 	RTLIL::Wire* n0 = module->wire("\\__0__"); | 	RTLIL::Wire* n0 = module->wire("$0"); | ||||||
| 	if (n0) | 	if (n0) | ||||||
| 		module->connect(n0, State::S0); | 		module->connect(n0, State::S0); | ||||||
| 
 | 
 | ||||||
|  | @ -271,14 +271,24 @@ end_of_header: | ||||||
| 			if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size())) | 			if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size())) | ||||||
| 				log_error("Line %u has invalid symbol position!\n", line_count); | 				log_error("Line %u has invalid symbol position!\n", line_count); | ||||||
| 
 | 
 | ||||||
|  | 			RTLIL::IdString escaped_s = stringf("\\%s", s.c_str()); | ||||||
| 			RTLIL::Wire* wire; | 			RTLIL::Wire* wire; | ||||||
| 			if (c == 'i') wire = inputs[l1]; | 			if (c == 'i') wire = inputs[l1]; | ||||||
| 			else if (c == 'l') wire = latches[l1]; | 			else if (c == 'l') wire = latches[l1]; | ||||||
| 			else if (c == 'o') wire = outputs[l1]; | 			else if (c == 'o') { | ||||||
|  | 				wire = module->wire(escaped_s); | ||||||
|  | 				if (wire) { | ||||||
|  | 					// Could have been renamed by a latch
 | ||||||
|  | 					module->swap_names(wire, outputs[l1]); | ||||||
|  | 					module->connect(outputs[l1], wire); | ||||||
|  | 					goto next; | ||||||
|  | 				} | ||||||
|  | 				wire = outputs[l1]; | ||||||
|  | 			} | ||||||
| 			else if (c == 'b') wire = bad_properties[l1]; | 			else if (c == 'b') wire = bad_properties[l1]; | ||||||
| 			else log_abort(); | 			else log_abort(); | ||||||
| 
 | 
 | ||||||
| 			module->rename(wire, stringf("\\%s", s.c_str())); | 			module->rename(wire, escaped_s); | ||||||
| 		} | 		} | ||||||
| 		else if (c == 'j' || c == 'f') { | 		else if (c == 'j' || c == 'f') { | ||||||
| 			// TODO
 | 			// TODO
 | ||||||
|  | @ -293,6 +303,7 @@ end_of_header: | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 			log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); | 			log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); | ||||||
|  | next: | ||||||
| 		std::getline(f, line); // Ignore up to start of next line
 | 		std::getline(f, line); // Ignore up to start of next line
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -316,14 +327,14 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera | ||||||
| { | { | ||||||
| 	const unsigned variable = literal >> 1; | 	const unsigned variable = literal >> 1; | ||||||
| 	const bool invert = literal & 1; | 	const bool invert = literal & 1; | ||||||
| 	RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); | 	RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : "")); | ||||||
| 	RTLIL::Wire *wire = module->wire(wire_name); | 	RTLIL::Wire *wire = module->wire(wire_name); | ||||||
| 	if (wire) return wire; | 	if (wire) return wire; | ||||||
| 	log_debug2("Creating %s\n", wire_name.c_str()); | 	log_debug2("Creating %s\n", wire_name.c_str()); | ||||||
| 	wire = module->addWire(wire_name); | 	wire = module->addWire(wire_name); | ||||||
| 	wire->port_input = wire->port_output = false; | 	wire->port_input = wire->port_output = false; | ||||||
| 	if (!invert) return wire; | 	if (!invert) return wire; | ||||||
| 	RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable)); | 	RTLIL::IdString wire_inv_name(stringf("$%d", variable)); | ||||||
| 	RTLIL::Wire *wire_inv = module->wire(wire_inv_name); | 	RTLIL::Wire *wire_inv = module->wire(wire_inv_name); | ||||||
| 	if (wire_inv) { | 	if (wire_inv) { | ||||||
| 		if (module->cell(wire_inv_name)) return wire; | 		if (module->cell(wire_inv_name)) return wire; | ||||||
|  | @ -335,12 +346,12 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); | 	log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); | ||||||
| 	module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); | 	module->addNotGate(stringf("$%d$not", variable), wire_inv, wire); | ||||||
| 
 | 
 | ||||||
| 	return wire; | 	return wire; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) | void AigerReader::parse_xaiger() | ||||||
| { | { | ||||||
| 	std::string header; | 	std::string header; | ||||||
| 	f >> header; | 	f >> header; | ||||||
|  | @ -372,23 +383,34 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) | ||||||
| 	else | 	else | ||||||
| 		log_abort(); | 		log_abort(); | ||||||
| 
 | 
 | ||||||
| 	RTLIL::Wire* n0 = module->wire("\\__0__"); | 	RTLIL::Wire* n0 = module->wire("$0"); | ||||||
| 	if (n0) | 	if (n0) | ||||||
| 		module->connect(n0, State::S0); | 		module->connect(n0, State::S0); | ||||||
| 
 | 
 | ||||||
|  | 	int c = f.get(); | ||||||
|  | 	if (c != 'c') | ||||||
|  | 		log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); | ||||||
|  | 	if (f.peek() == '\n') | ||||||
|  | 		f.get(); | ||||||
|  | 
 | ||||||
|  | 	dict<int,IdString> box_lookup; | ||||||
|  | 	for (auto m : design->modules()) { | ||||||
|  | 		auto it = m->attributes.find(ID(abc9_box_id)); | ||||||
|  | 		if (it == m->attributes.end()) | ||||||
|  | 			continue; | ||||||
|  | 		if (m->name.begins_with("$paramod")) | ||||||
|  | 			continue; | ||||||
|  | 		auto id = it->second.as_int(); | ||||||
|  | 		auto r = box_lookup.insert(std::make_pair(id, m->name)); | ||||||
|  | 		if (!r.second) | ||||||
|  | 			log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", | ||||||
|  | 					log_id(m), id, log_id(r.first->second)); | ||||||
|  | 		log_assert(r.second); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// Parse footer (symbol table, comments, etc.)
 | 	// Parse footer (symbol table, comments, etc.)
 | ||||||
| 	std::string s; | 	std::string s; | ||||||
| 	bool comment_seen = false; | 	for (int c = f.get(); c != EOF; c = f.get()) { | ||||||
| 	for (int c = f.peek(); c != EOF; c = f.peek()) { |  | ||||||
| 		if (comment_seen || c == 'c') { |  | ||||||
| 			if (!comment_seen) { |  | ||||||
| 				f.ignore(1); |  | ||||||
| 				c = f.peek(); |  | ||||||
| 				comment_seen = true; |  | ||||||
| 			} |  | ||||||
| 			if (c == '\n') |  | ||||||
| 				break; |  | ||||||
| 			f.ignore(1); |  | ||||||
| 		// XAIGER extensions
 | 		// XAIGER extensions
 | ||||||
| 		if (c == 'm') { | 		if (c == 'm') { | ||||||
| 			uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); | 			uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); | ||||||
|  | @ -400,13 +422,13 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) | ||||||
| 				uint32_t rootNodeID = parse_xaiger_literal(f); | 				uint32_t rootNodeID = parse_xaiger_literal(f); | ||||||
| 				uint32_t cutLeavesM = parse_xaiger_literal(f); | 				uint32_t cutLeavesM = parse_xaiger_literal(f); | ||||||
| 				log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); | 				log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); | ||||||
| 					RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID)); | 				RTLIL::Wire *output_sig = module->wire(stringf("$%d", rootNodeID)); | ||||||
| 				uint32_t nodeID; | 				uint32_t nodeID; | ||||||
| 				RTLIL::SigSpec input_sig; | 				RTLIL::SigSpec input_sig; | ||||||
| 				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); | ||||||
| 						RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID)); | 					RTLIL::Wire *wire = module->wire(stringf("$%d", nodeID)); | ||||||
| 					log_assert(wire); | 					log_assert(wire); | ||||||
| 					input_sig.append(wire); | 					input_sig.append(wire); | ||||||
| 				} | 				} | ||||||
|  | @ -423,16 +445,16 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) | ||||||
| 					log_assert(o.wire == nullptr); | 					log_assert(o.wire == nullptr); | ||||||
| 					lut_mask[gray] = o.data; | 					lut_mask[gray] = o.data; | ||||||
| 				} | 				} | ||||||
| 					RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID)); | 				RTLIL::Cell *output_cell = module->cell(stringf("$%d$and", rootNodeID)); | ||||||
| 				log_assert(output_cell); | 				log_assert(output_cell); | ||||||
| 				module->remove(output_cell); | 				module->remove(output_cell); | ||||||
| 					module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask)); | 				module->addLut(stringf("$%d$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask)); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else if (c == 'r') { | 		else if (c == 'r') { | ||||||
| 			uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); | 			uint32_t dataSize YS_ATTRIBUTE(unused) = 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)); | 			f.ignore(flopNum * sizeof(uint32_t)); | ||||||
| 		} | 		} | ||||||
|  | @ -460,21 +482,19 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) | ||||||
| 				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), box_lookup.at(boxUniqueId)); | ||||||
| 				boxes.emplace_back(cell); | 				boxes.emplace_back(cell); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 			else if (c == 'a' || c == 'i' || c == 'o') { | 		else if (c == 'a' || c == 'i' || c == 'o' || c == 's') { | ||||||
| 			uint32_t dataSize = parse_xaiger_literal(f); | 			uint32_t dataSize = parse_xaiger_literal(f); | ||||||
| 			f.ignore(dataSize); | 			f.ignore(dataSize); | ||||||
|  | 			log_debug("ignoring '%c'\n", c); | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 		else |  | ||||||
| 			log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	post_process(); | 	post_process(); | ||||||
| } | } | ||||||
|  | @ -487,13 +507,15 @@ void AigerReader::parse_aiger_ascii() | ||||||
| 	unsigned l1, l2, l3; | 	unsigned l1, l2, l3; | ||||||
| 
 | 
 | ||||||
| 	// Parse inputs
 | 	// Parse inputs
 | ||||||
|  | 	int digits = ceil(log10(I)); | ||||||
| 	for (unsigned i = 1; i <= I; ++i, ++line_count) { | 	for (unsigned i = 1; i <= I; ++i, ++line_count) { | ||||||
| 		if (!(f >> l1)) | 		if (!(f >> l1)) | ||||||
| 			log_error("Line %u cannot be interpreted as an input!\n", line_count); | 			log_error("Line %u cannot be interpreted as an input!\n", line_count); | ||||||
| 		log_debug2("%d is an input\n", l1); | 		log_debug2("%d is an input\n", l1); | ||||||
| 		log_assert(!(l1 & 1)); // Inputs can't be inverted
 | 		log_assert(!(l1 & 1)); // Inputs can't be inverted
 | ||||||
| 		RTLIL::Wire *wire = createWireIfNotExists(module, l1); | 		RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, l1 >> 1)); | ||||||
| 		wire->port_input = true; | 		wire->port_input = true; | ||||||
|  | 		module->connect(createWireIfNotExists(module, l1), wire); | ||||||
| 		inputs.push_back(wire); | 		inputs.push_back(wire); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -507,12 +529,14 @@ void AigerReader::parse_aiger_ascii() | ||||||
| 		clk_wire->port_input = true; | 		clk_wire->port_input = true; | ||||||
| 		clk_wire->port_output = false; | 		clk_wire->port_output = false; | ||||||
| 	} | 	} | ||||||
|  | 	digits = ceil(log10(L)); | ||||||
| 	for (unsigned i = 0; i < L; ++i, ++line_count) { | 	for (unsigned i = 0; i < L; ++i, ++line_count) { | ||||||
| 		if (!(f >> l1 >> l2)) | 		if (!(f >> l1 >> l2)) | ||||||
| 			log_error("Line %u cannot be interpreted as a latch!\n", line_count); | 			log_error("Line %u cannot be interpreted as a latch!\n", line_count); | ||||||
| 		log_debug2("%d %d is a latch\n", l1, l2); | 		log_debug2("%d %d is a latch\n", l1, l2); | ||||||
| 		log_assert(!(l1 & 1)); | 		log_assert(!(l1 & 1)); | ||||||
| 		RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); | 		RTLIL::Wire *q_wire = module->addWire(stringf("$l%0*d", digits, l1 >> 1)); | ||||||
|  | 		module->connect(createWireIfNotExists(module, l1), q_wire); | ||||||
| 		RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); | 		RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); | ||||||
| 
 | 
 | ||||||
| 		if (clk_wire) | 		if (clk_wire) | ||||||
|  | @ -550,7 +574,7 @@ void AigerReader::parse_aiger_ascii() | ||||||
| 		log_debug2("%d is an output\n", l1); | 		log_debug2("%d is an output\n", l1); | ||||||
| 		const unsigned variable = l1 >> 1; | 		const unsigned variable = l1 >> 1; | ||||||
| 		const bool invert = l1 & 1; | 		const bool invert = l1 & 1; | ||||||
| 		RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
 | 		RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
 | ||||||
| 		RTLIL::Wire *wire = module->wire(wire_name); | 		RTLIL::Wire *wire = module->wire(wire_name); | ||||||
| 		if (!wire) | 		if (!wire) | ||||||
| 			wire = createWireIfNotExists(module, l1); | 			wire = createWireIfNotExists(module, l1); | ||||||
|  | @ -616,11 +640,12 @@ void AigerReader::parse_aiger_binary() | ||||||
| 	std::string line; | 	std::string line; | ||||||
| 
 | 
 | ||||||
| 	// Parse inputs
 | 	// Parse inputs
 | ||||||
|  | 	int digits = ceil(log10(I)); | ||||||
| 	for (unsigned i = 1; i <= I; ++i) { | 	for (unsigned i = 1; i <= I; ++i) { | ||||||
| 		log_debug2("%d is an input\n", i); | 		log_debug2("%d is an input\n", i); | ||||||
| 		RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); | 		RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, i)); | ||||||
| 		wire->port_input = true; | 		wire->port_input = true; | ||||||
| 		log_assert(!wire->port_output); | 		module->connect(createWireIfNotExists(module, i << 1), wire); | ||||||
| 		inputs.push_back(wire); | 		inputs.push_back(wire); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -634,12 +659,14 @@ void AigerReader::parse_aiger_binary() | ||||||
| 		clk_wire->port_input = true; | 		clk_wire->port_input = true; | ||||||
| 		clk_wire->port_output = false; | 		clk_wire->port_output = false; | ||||||
| 	} | 	} | ||||||
|  | 	digits = ceil(log10(L)); | ||||||
| 	l1 = (I+1) * 2; | 	l1 = (I+1) * 2; | ||||||
| 	for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { | 	for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) { | ||||||
| 		if (!(f >> l2)) | 		if (!(f >> l2)) | ||||||
| 			log_error("Line %u cannot be interpreted as a latch!\n", line_count); | 			log_error("Line %u cannot be interpreted as a latch!\n", line_count); | ||||||
| 		log_debug("%d %d is a latch\n", l1, l2); | 		log_debug("%d %d is a latch\n", l1, l2); | ||||||
| 		RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); | 		RTLIL::Wire *q_wire = module->addWire(stringf("$l%0*d", digits, l1 >> 1)); | ||||||
|  | 		module->connect(createWireIfNotExists(module, l1), q_wire); | ||||||
| 		RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); | 		RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); | ||||||
| 
 | 
 | ||||||
| 		if (clk_wire) | 		if (clk_wire) | ||||||
|  | @ -670,23 +697,15 @@ void AigerReader::parse_aiger_binary() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// 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
 | 	std::getline(f, line); // Ignore up to start of next line
 | ||||||
|  | @ -733,56 +752,37 @@ void AigerReader::parse_aiger_binary() | ||||||
| 
 | 
 | ||||||
| void AigerReader::post_process() | void AigerReader::post_process() | ||||||
| { | { | ||||||
| 	pool<IdString> seen_boxes; | 	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); | 		RTLIL::Module* box_module = design->module(cell->type); | ||||||
| 		log_assert(box_module); | 		log_assert(box_module); | ||||||
| 
 | 
 | ||||||
| 		if (seen_boxes.insert(cell->type).second) { | 		auto r = box_ports.insert(cell->type); | ||||||
| 			auto it = box_module->attributes.find("\\abc9_carry"); | 		if (r.second) { | ||||||
| 			if (it != box_module->attributes.end()) { | 			// Make carry in the last PI, and carry out the last PO
 | ||||||
| 				RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; | 			//   since ABC requires it this way
 | ||||||
| 				auto carry_in_out = it->second.decode_string(); | 			IdString carry_in, carry_out; | ||||||
| 				auto pos = carry_in_out.find(','); | 			for (const auto &port_name : box_module->ports) { | ||||||
| 				if (pos == std::string::npos) | 				auto w = box_module->wire(port_name); | ||||||
| 					log_error("'abc9_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type)); |  | ||||||
| 				auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos)); |  | ||||||
| 				carry_in = box_module->wire(carry_in_name); |  | ||||||
| 				if (!carry_in || !carry_in->port_input) |  | ||||||
| 					log_error("'abc9_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str()); |  | ||||||
| 
 |  | ||||||
| 				auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1)); |  | ||||||
| 				carry_out = box_module->wire(carry_out_name); |  | ||||||
| 				if (!carry_out || !carry_out->port_output) |  | ||||||
| 					log_error("'abc9_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str()); |  | ||||||
| 
 |  | ||||||
| 				auto &ports = box_module->ports; |  | ||||||
| 				for (auto jt = ports.begin(); jt != ports.end(); ) { |  | ||||||
| 					RTLIL::Wire* w = box_module->wire(*jt); |  | ||||||
| 				log_assert(w); | 				log_assert(w); | ||||||
| 					if (w == carry_in || w == carry_out) { | 				if (w->get_bool_attribute("\\abc9_carry")) { | ||||||
| 						jt = ports.erase(jt); | 					if (w->port_input) | ||||||
| 						continue; | 						carry_in = port_name; | ||||||
|  | 					if (w->port_output) | ||||||
|  | 						carry_out = port_name; | ||||||
| 				} | 				} | ||||||
| 					if (w->port_id > carry_in->port_id) | 				else | ||||||
| 						--w->port_id; | 					r.first->second.push_back(port_name); | ||||||
| 					if (w->port_id > carry_out->port_id) |  | ||||||
| 						--w->port_id; |  | ||||||
| 					log_assert(w->port_input || w->port_output); |  | ||||||
| 					log_assert(ports[w->port_id-1] == w->name); |  | ||||||
| 					++jt; |  | ||||||
| 			} | 			} | ||||||
| 				ports.push_back(carry_in->name); | 			if (carry_in != IdString()) { | ||||||
| 				carry_in->port_id = ports.size(); | 				log_assert(carry_out != IdString()); | ||||||
| 				ports.push_back(carry_out->name); | 				r.first->second.push_back(carry_in); | ||||||
| 				carry_out->port_id = ports.size(); | 				r.first->second.push_back(carry_out); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// NB: Assume box_module->ports are sorted alphabetically
 | 		for (auto port_name : box_ports.at(cell->type)) { | ||||||
| 		//     (as RTLIL::Module::fixup_ports() would do)
 |  | ||||||
| 		for (auto port_name : box_module->ports) { |  | ||||||
| 			RTLIL::Wire* port = box_module->wire(port_name); | 			RTLIL::Wire* port = box_module->wire(port_name); | ||||||
| 			log_assert(port); | 			log_assert(port); | ||||||
| 			RTLIL::SigSpec rhs; | 			RTLIL::SigSpec rhs; | ||||||
|  | @ -804,9 +804,32 @@ void AigerReader::post_process() | ||||||
| 				} | 				} | ||||||
| 				rhs.append(wire); | 				rhs.append(wire); | ||||||
| 			} | 			} | ||||||
| 
 |  | ||||||
| 			cell->setPort(port_name, rhs); | 			cell->setPort(port_name, rhs); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (box_module->attributes.count("\\abc9_flop")) { | ||||||
|  | 			log_assert(co_count < outputs.size()); | ||||||
|  | 			Wire *wire = outputs[co_count++]; | ||||||
|  | 			log_assert(wire); | ||||||
|  | 			log_assert(wire->port_output); | ||||||
|  | 			wire->port_output = false; | ||||||
|  | 
 | ||||||
|  | 			RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count]; | ||||||
|  | 			log_assert(d); | ||||||
|  | 			log_assert(d->port_output); | ||||||
|  | 			d->port_output = false; | ||||||
|  | 
 | ||||||
|  | 			RTLIL::Wire *q = inputs[piNum - flopNum + flop_count]; | ||||||
|  | 			log_assert(q); | ||||||
|  | 			log_assert(q->port_input); | ||||||
|  | 			q->port_input = false; | ||||||
|  | 
 | ||||||
|  | 			auto ff = module->addCell(NEW_ID, "$__ABC9_FF_"); | ||||||
|  | 			ff->setPort("\\D", d); | ||||||
|  | 			ff->setPort("\\Q", q); | ||||||
|  | 			flop_count++; | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	dict<RTLIL::IdString, int> wideports_cache; | 	dict<RTLIL::IdString, int> wideports_cache; | ||||||
|  | @ -868,15 +891,6 @@ void AigerReader::post_process() | ||||||
| 					// simply connect the latter to the former
 | 					// simply connect the latter to the former
 | ||||||
| 					RTLIL::Wire* existing = module->wire(escaped_s); | 					RTLIL::Wire* existing = module->wire(escaped_s); | ||||||
| 					if (!existing) { | 					if (!existing) { | ||||||
| 						if (escaped_s.ends_with("$inout.out")) { |  | ||||||
| 							wire->port_output = false; |  | ||||||
| 							RTLIL::Wire *in_wire = module->wire(escaped_s.substr(1, escaped_s.size()-11)); |  | ||||||
| 							log_assert(in_wire); |  | ||||||
| 							log_assert(in_wire->port_input && !in_wire->port_output); |  | ||||||
| 							in_wire->port_output = true; |  | ||||||
| 							module->connect(in_wire, wire); |  | ||||||
| 						} |  | ||||||
| 						else |  | ||||||
| 						module->rename(wire, escaped_s); | 						module->rename(wire, escaped_s); | ||||||
| 					} | 					} | ||||||
| 					else { | 					else { | ||||||
|  | @ -889,29 +903,23 @@ void AigerReader::post_process() | ||||||
| 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | 					std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); | ||||||
| 					RTLIL::Wire* existing = module->wire(indexed_name); | 					RTLIL::Wire* existing = module->wire(indexed_name); | ||||||
| 					if (!existing) { | 					if (!existing) { | ||||||
| 						if (escaped_s.ends_with("$inout.out")) { |  | ||||||
| 							wire->port_output = false; |  | ||||||
| 							RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(1, escaped_s.size()-11).c_str(), index)); |  | ||||||
| 							log_assert(in_wire); |  | ||||||
| 							log_assert(in_wire->port_input && !in_wire->port_output); |  | ||||||
| 							in_wire->port_output = true; |  | ||||||
| 							module->connect(in_wire, wire); |  | ||||||
| 						} |  | ||||||
| 						else { |  | ||||||
| 						module->rename(wire, indexed_name); | 						module->rename(wire, indexed_name); | ||||||
| 						if (wideports) | 						if (wideports) | ||||||
| 							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); | 						module->connect(wire, existing); | ||||||
| 						wire->port_output = false; | 						wire->port_output = false; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				log_debug(" -> %s\n", log_id(wire)); | 				log_debug(" -> %s\n", log_id(wire)); | ||||||
|  | 				int init; | ||||||
|  | 				mf >> init; | ||||||
|  | 				if (init < 2) | ||||||
|  | 					wire->attributes["\\init"] = init; | ||||||
| 			} | 			} | ||||||
| 			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()) { | 					for (const auto &i : cell->connections()) { | ||||||
|  | @ -968,15 +976,10 @@ void AigerReader::post_process() | ||||||
| 			if (other_wire) { | 			if (other_wire) { | ||||||
| 				other_wire->port_input = false; | 				other_wire->port_input = false; | ||||||
| 				other_wire->port_output = false; | 				other_wire->port_output = false; | ||||||
| 			} | 				if (wire->port_input) | ||||||
| 			if (wire->port_input) { |  | ||||||
| 				if (other_wire) |  | ||||||
| 					module->connect(other_wire, SigSpec(wire, i)); | 					module->connect(other_wire, SigSpec(wire, i)); | ||||||
| 			} | 				else | ||||||
| 			else { | 					module->connect(SigSpec(wire, i), other_wire); | ||||||
| 								  // Since we skip POs that are connected to Sx,
 |  | ||||||
| 								  // re-connect them here
 |  | ||||||
| 				module->connect(SigSpec(wire, i), other_wire ? other_wire : SigSpec(RTLIL::Sx)); |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -1032,7 +1035,7 @@ struct AigerFrontend : public Frontend { | ||||||
| 	{ | 	{ | ||||||
| 		log_header(design, "Executing AIGER frontend.\n"); | 		log_header(design, "Executing AIGER frontend.\n"); | ||||||
| 
 | 
 | ||||||
| 		RTLIL::IdString clk_name = "\\clk"; | 		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; | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ struct AigerReader | ||||||
| 
 | 
 | ||||||
|     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(); | ||||||
|     void parse_xaiger(const dict<int,IdString> &box_lookup); |     void parse_xaiger(); | ||||||
|     void parse_aiger_ascii(); |     void parse_aiger_ascii(); | ||||||
|     void parse_aiger_binary(); |     void parse_aiger_binary(); | ||||||
|     void post_process(); |     void post_process(); | ||||||
|  |  | ||||||
|  | @ -63,22 +63,16 @@ extern "C" int Abc_RealMain(int argc, char *argv[]); | ||||||
| USING_YOSYS_NAMESPACE | USING_YOSYS_NAMESPACE | ||||||
| PRIVATE_NAMESPACE_BEGIN | PRIVATE_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
| bool markgroups; |  | ||||||
| int map_autoidx; | int map_autoidx; | ||||||
| SigMap assign_map; |  | ||||||
| RTLIL::Module *module; |  | ||||||
| 
 |  | ||||||
| bool clk_polarity, en_polarity; |  | ||||||
| RTLIL::SigSpec clk_sig, en_sig; |  | ||||||
| 
 | 
 | ||||||
| inline std::string remap_name(RTLIL::IdString abc9_name) | inline std::string remap_name(RTLIL::IdString abc9_name) | ||||||
| { | { | ||||||
| 	return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); | 	return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void handle_loops(RTLIL::Design *design) | void handle_loops(RTLIL::Design *design, RTLIL::Module *module) | ||||||
| { | { | ||||||
| 	Pass::call(design, "scc -set_attr abc9_scc_id {}"); | 	Pass::call(design, "scc -set_attr abc9_scc_id {} % w:*"); | ||||||
| 
 | 
 | ||||||
| 	// For every unique SCC found, (arbitrarily) find the first
 | 	// For every unique SCC found, (arbitrarily) find the first
 | ||||||
| 	// cell in the component, and select (and mark) all its output
 | 	// cell in the component, and select (and mark) all its output
 | ||||||
|  | @ -253,49 +247,14 @@ struct abc9_output_filter | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, | void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file, | ||||||
| 		bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, | 		bool cleanup, vector<int> lut_costs, bool dff_mode, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, | ||||||
| 		bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, |  | ||||||
| 		bool show_tempdir, std::string box_file, std::string lut_file, | 		bool show_tempdir, std::string box_file, std::string lut_file, | ||||||
| 		std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs | 		std::string wire_delay, bool nomfs | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	module = current_module; |  | ||||||
| 	map_autoidx = autoidx++; | 	map_autoidx = autoidx++; | ||||||
| 
 | 
 | ||||||
| 	if (clk_str != "$") |  | ||||||
| 	{ |  | ||||||
| 		clk_polarity = true; |  | ||||||
| 		clk_sig = RTLIL::SigSpec(); |  | ||||||
| 
 |  | ||||||
| 		en_polarity = true; |  | ||||||
| 		en_sig = RTLIL::SigSpec(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!clk_str.empty() && clk_str != "$") |  | ||||||
| 	{ |  | ||||||
| 		if (clk_str.find(',') != std::string::npos) { |  | ||||||
| 			int pos = clk_str.find(','); |  | ||||||
| 			std::string en_str = clk_str.substr(pos+1); |  | ||||||
| 			clk_str = clk_str.substr(0, pos); |  | ||||||
| 			if (en_str[0] == '!') { |  | ||||||
| 				en_polarity = false; |  | ||||||
| 				en_str = en_str.substr(1); |  | ||||||
| 			} |  | ||||||
| 			if (module->wires_.count(RTLIL::escape_id(en_str)) != 0) |  | ||||||
| 				en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0)); |  | ||||||
| 		} |  | ||||||
| 		if (clk_str[0] == '!') { |  | ||||||
| 			clk_polarity = false; |  | ||||||
| 			clk_str = clk_str.substr(1); |  | ||||||
| 		} |  | ||||||
| 		if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0) |  | ||||||
| 			clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (dff_mode && clk_sig.empty()) |  | ||||||
| 		log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); |  | ||||||
| 
 |  | ||||||
| 	std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; | 	std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; | ||||||
| 	if (!cleanup) | 	if (!cleanup) | ||||||
| 		tempdir_name[0] = tempdir_name[4] = '_'; | 		tempdir_name[0] = tempdir_name[4] = '_'; | ||||||
|  | @ -308,13 +267,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 	if (!lut_costs.empty()) { | 	if (!lut_costs.empty()) { | ||||||
| 		abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); | 		abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); | ||||||
| 		if (!box_file.empty()) | 		if (!box_file.empty()) | ||||||
| 			abc9_script += stringf("read_box -v %s; ", box_file.c_str()); | 			abc9_script += stringf("read_box %s; ", box_file.c_str()); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	if (!lut_file.empty()) { | 	if (!lut_file.empty()) { | ||||||
| 		abc9_script += stringf("read_lut %s; ", lut_file.c_str()); | 		abc9_script += stringf("read_lut %s; ", lut_file.c_str()); | ||||||
| 		if (!box_file.empty()) | 		if (!box_file.empty()) | ||||||
| 			abc9_script += stringf("read_box -v %s; ", box_file.c_str()); | 			abc9_script += stringf("read_box %s; ", box_file.c_str()); | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 		log_abort(); | 		log_abort(); | ||||||
|  | @ -333,20 +292,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 		} else | 		} else | ||||||
| 			abc9_script += stringf("source %s", script_file.c_str()); | 			abc9_script += stringf("source %s", script_file.c_str()); | ||||||
| 	} else if (!lut_costs.empty() || !lut_file.empty()) { | 	} else if (!lut_costs.empty() || !lut_file.empty()) { | ||||||
| 		//bool all_luts_cost_same = true;
 |  | ||||||
| 		//for (int this_cost : lut_costs)
 |  | ||||||
| 		//	if (this_cost != lut_costs.front())
 |  | ||||||
| 		//		all_luts_cost_same = false;
 |  | ||||||
| 		abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; | 		abc9_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; | ||||||
| 		//if (all_luts_cost_same && !fast_mode)
 |  | ||||||
| 		//	abc9_script += "; lutpack {S}";
 |  | ||||||
| 	} else | 	} else | ||||||
| 		log_abort(); | 		log_abort(); | ||||||
| 
 | 
 | ||||||
| 	//if (script_file.empty() && !delay_target.empty())
 |  | ||||||
| 	//	for (size_t pos = abc9_script.find("dretime;"); pos != std::string::npos; pos = abc9_script.find("dretime;", pos+1))
 |  | ||||||
| 	//		abc9_script = abc9_script.substr(0, pos) + "dretime; retime -o {D};" + abc9_script.substr(pos+8);
 |  | ||||||
| 
 |  | ||||||
| 	for (size_t pos = abc9_script.find("{D}"); pos != std::string::npos; pos = abc9_script.find("{D}", pos)) | 	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); | 		abc9_script = abc9_script.substr(0, pos) + delay_target + abc9_script.substr(pos+3); | ||||||
| 
 | 
 | ||||||
|  | @ -360,7 +309,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 		for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) | 		for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) | ||||||
| 			abc9_script = abc9_script.erase(pos, strlen("&mfs")); | 			abc9_script = abc9_script.erase(pos, strlen("&mfs")); | ||||||
| 
 | 
 | ||||||
| 	abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); | 	abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str()); | ||||||
| 	abc9_script = add_echos_to_abc9_cmd(abc9_script); | 	abc9_script = add_echos_to_abc9_cmd(abc9_script); | ||||||
| 
 | 
 | ||||||
| 	for (size_t i = 0; i+1 < abc9_script.size(); i++) | 	for (size_t i = 0; i+1 < abc9_script.size(); i++) | ||||||
|  | @ -371,45 +320,22 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 	fprintf(f, "%s\n", abc9_script.c_str()); | 	fprintf(f, "%s\n", abc9_script.c_str()); | ||||||
| 	fclose(f); | 	fclose(f); | ||||||
| 
 | 
 | ||||||
| 	if (dff_mode || !clk_str.empty()) |  | ||||||
| 	{ |  | ||||||
| 		if (clk_sig.size() == 0) |  | ||||||
| 			log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); |  | ||||||
| 		else { |  | ||||||
| 			log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); |  | ||||||
| 			if (en_sig.size() != 0) |  | ||||||
| 				log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); |  | ||||||
| 			log("\n"); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	bool count_output = false; |  | ||||||
| 	for (auto port_name : module->ports) { |  | ||||||
| 		RTLIL::Wire *port_wire = module->wire(port_name); |  | ||||||
| 		log_assert(port_wire); |  | ||||||
| 		if (port_wire->port_output) { |  | ||||||
| 			count_output = true; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	log_push(); | 	log_push(); | ||||||
| 
 | 
 | ||||||
| 	if (count_output) | 	handle_loops(design, module); | ||||||
| 	{ |  | ||||||
| 		design->selection_stack.emplace_back(false); |  | ||||||
| 		RTLIL::Selection& sel = design->selection_stack.back(); |  | ||||||
| 		sel.select(module); |  | ||||||
| 
 | 
 | ||||||
| 		handle_loops(design); | 	Pass::call(design, "aigmap -select"); | ||||||
| 
 |  | ||||||
| 		Pass::call(design, "aigmap"); |  | ||||||
| 
 |  | ||||||
| 		//log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
 |  | ||||||
| 		//		count_gates, GetSize(signal_list), count_input, count_output);
 |  | ||||||
| 
 | 
 | ||||||
| 	Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); | 	Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); | ||||||
| 
 | 
 | ||||||
|  | 	int count_outputs = design->scratchpad_get_int("write_xaiger.num_outputs"); | ||||||
|  | 	log("Extracted %d AND gates and %d wires to a netlist network with %d inputs and %d outputs.\n", | ||||||
|  | 			design->scratchpad_get_int("write_xaiger.num_ands"), | ||||||
|  | 			design->scratchpad_get_int("write_xaiger.num_wires"), | ||||||
|  | 			design->scratchpad_get_int("write_xaiger.num_inputs"), | ||||||
|  | 			count_outputs); | ||||||
|  | 
 | ||||||
|  | 	if (count_outputs > 0) { | ||||||
| 		std::string buffer; | 		std::string buffer; | ||||||
| 		std::ifstream ifs; | 		std::ifstream ifs; | ||||||
| #if 0 | #if 0 | ||||||
|  | @ -420,16 +346,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 		buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); | 		buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); | ||||||
| 		log_assert(!design->module(ID($__abc9__))); | 		log_assert(!design->module(ID($__abc9__))); | ||||||
| 		{ | 		{ | ||||||
| 			AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); | 			AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, /*buffer.c_str()*/ "" /* map_filename */, true /* wideports */); | ||||||
| 			reader.parse_xaiger(); | 			reader.parse_xaiger(); | ||||||
| 		} | 		} | ||||||
| 		ifs.close(); | 		ifs.close(); | ||||||
| 		Pass::call(design, stringf("write_verilog -noexpr -norename")); | 		Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected")); | ||||||
| 		design->remove(design->module(ID($__abc9__))); | 		design->remove(design->module(ID($__abc9__))); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 		design->selection_stack.pop_back(); |  | ||||||
| 
 |  | ||||||
| 		log_header(design, "Executing ABC9.\n"); | 		log_header(design, "Executing ABC9.\n"); | ||||||
| 
 | 
 | ||||||
| 		if (!lut_costs.empty()) { | 		if (!lut_costs.empty()) { | ||||||
|  | @ -475,11 +399,11 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 		log_assert(!design->module(ID($__abc9__))); | 		log_assert(!design->module(ID($__abc9__))); | ||||||
| 
 | 
 | ||||||
| 		AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); | 		AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); | ||||||
| 		reader.parse_xaiger(box_lookup); | 		reader.parse_xaiger(); | ||||||
| 		ifs.close(); | 		ifs.close(); | ||||||
| 
 | 
 | ||||||
| #if 0 | #if 0 | ||||||
| 		Pass::call(design, stringf("write_verilog -noexpr -norename")); | 		Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected")); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 		log_header(design, "Re-integrating ABC9 results.\n"); | 		log_header(design, "Re-integrating ABC9 results.\n"); | ||||||
|  | @ -487,43 +411,32 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 		if (mapped_mod == NULL) | 		if (mapped_mod == NULL) | ||||||
| 			log_error("ABC output file does not contain a module `$__abc9__'.\n"); | 			log_error("ABC output file does not contain a module `$__abc9__'.\n"); | ||||||
| 
 | 
 | ||||||
| 		pool<RTLIL::SigBit> output_bits; | 		for (auto w : mapped_mod->wires()) | ||||||
| 		for (auto &it : mapped_mod->wires_) { | 			module->addWire(remap_name(w->name), GetSize(w)); | ||||||
| 			RTLIL::Wire *w = it.second; |  | ||||||
| 			RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); |  | ||||||
| 			if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; |  | ||||||
| 			if (w->port_output) { |  | ||||||
| 				RTLIL::Wire *wire = module->wire(w->name); |  | ||||||
| 				log_assert(wire); |  | ||||||
| 				for (int i = 0; i < GetSize(w); i++) |  | ||||||
| 					output_bits.insert({wire, i}); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (auto &it : module->connections_) { |  | ||||||
| 			auto &signal = it.first; |  | ||||||
| 			auto bits = signal.bits(); |  | ||||||
| 			for (auto &b : bits) |  | ||||||
| 				if (output_bits.count(b)) |  | ||||||
| 					b = module->addWire(NEW_ID); |  | ||||||
| 			signal = std::move(bits); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		dict<IdString, bool> abc9_box; | 		dict<IdString, bool> abc9_box; | ||||||
| 		vector<RTLIL::Cell*> boxes; | 		vector<RTLIL::Cell*> boxes; | ||||||
| 		for (const auto &it : module->cells_) { | 		for (auto it = module->cells_.begin(); it != module->cells_.end(); ) { | ||||||
| 			auto cell = it.second; | 			auto cell = it->second; | ||||||
| 			if (cell->type.in(ID($_AND_), ID($_NOT_))) { | 			if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) { | ||||||
| 				module->remove(cell); | 				it = module->cells_.erase(it); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			auto jt = abc9_box.find(cell->type); | 			++it; | ||||||
| 			if (jt == abc9_box.end()) { |  | ||||||
| 			RTLIL::Module* box_module = design->module(cell->type); | 			RTLIL::Module* box_module = design->module(cell->type); | ||||||
|  | 			auto jt = abc9_box.find(cell->type); | ||||||
|  | 			if (jt == abc9_box.end()) | ||||||
| 				jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; | 				jt = abc9_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc9_box_id)))).first; | ||||||
| 			} | 			if (jt->second) { | ||||||
| 			if (jt->second) | 				if (box_module->get_bool_attribute("\\abc9_flop")) { | ||||||
|  | 					if (dff_mode) | ||||||
| 						boxes.emplace_back(cell); | 						boxes.emplace_back(cell); | ||||||
|  | 					else | ||||||
|  | 						box_module->set_bool_attribute("\\abc9_keep", false); | ||||||
|  | 				} | ||||||
|  | 				else | ||||||
|  | 					boxes.emplace_back(cell); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		dict<SigBit, pool<IdString>> bit_drivers, bit_users; | 		dict<SigBit, pool<IdString>> bit_drivers, bit_users; | ||||||
|  | @ -532,19 +445,19 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 		dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks; | 		dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks; | ||||||
| 
 | 
 | ||||||
| 		std::map<IdString, int> cell_stats; | 		std::map<IdString, int> cell_stats; | ||||||
| 		for (auto c : mapped_mod->cells()) | 		for (auto mapped_cell : mapped_mod->cells()) | ||||||
| 		{ | 		{ | ||||||
| 			toposort.node(c->name); | 			toposort.node(mapped_cell->name); | ||||||
| 
 | 
 | ||||||
| 			RTLIL::Cell *cell = nullptr; | 			RTLIL::Cell *cell = nullptr; | ||||||
| 			if (c->type == ID($_NOT_)) { | 			if (mapped_cell->type == ID($_NOT_)) { | ||||||
| 				RTLIL::SigBit a_bit = c->getPort(ID::A); | 				RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); | ||||||
| 				RTLIL::SigBit y_bit = c->getPort(ID::Y); | 				RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); | ||||||
| 				bit_users[a_bit].insert(c->name); | 				bit_users[a_bit].insert(mapped_cell->name); | ||||||
| 				bit_drivers[y_bit].insert(c->name); | 				bit_drivers[y_bit].insert(mapped_cell->name); | ||||||
| 
 | 
 | ||||||
| 				if (!a_bit.wire) { | 				if (!a_bit.wire) { | ||||||
| 					c->setPort(ID::Y, module->addWire(NEW_ID)); | 					mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); | ||||||
| 					RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); | 					RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); | ||||||
| 					log_assert(wire); | 					log_assert(wire); | ||||||
| 					module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); | 					module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); | ||||||
|  | @ -568,7 +481,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 					if (!driver_lut) { | 					if (!driver_lut) { | ||||||
| 						// If a driver couldn't be found (could be from PI or box CI)
 | 						// If a driver couldn't be found (could be from PI or box CI)
 | ||||||
| 						// then implement using a LUT
 | 						// then implement using a LUT
 | ||||||
| 						cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), | 						cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), | ||||||
| 								RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), | 								RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), | ||||||
| 								RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), | 								RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), | ||||||
| 								RTLIL::Const::from_string("01")); | 								RTLIL::Const::from_string("01")); | ||||||
|  | @ -576,44 +489,46 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 						cell_stats[ID($lut)]++; | 						cell_stats[ID($lut)]++; | ||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| 						not2drivers[c] = driver_lut; | 						not2drivers[mapped_cell] = driver_lut; | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 				else | 				else | ||||||
| 					log_abort(); | 					log_abort(); | ||||||
| 				if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; |  | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			cell_stats[c->type]++; | 			cell_stats[mapped_cell->type]++; | ||||||
| 
 | 
 | ||||||
| 			RTLIL::Cell *existing_cell = nullptr; | 			RTLIL::Cell *existing_cell = nullptr; | ||||||
| 			if (c->type == ID($lut)) { | 			if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { | ||||||
| 				if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { | 				if (mapped_cell->type == ID($lut) && | ||||||
| 					SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); | 						GetSize(mapped_cell->getPort(ID::A)) == 1 && | ||||||
| 					SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); | 						mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { | ||||||
|  | 					SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name)); | ||||||
|  | 					SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name)); | ||||||
| 					module->connect(my_y, my_a); | 					module->connect(my_y, my_a); | ||||||
| 					if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; |  | ||||||
| 					log_abort(); | 					log_abort(); | ||||||
| 					continue; | 					continue; | ||||||
| 				} | 				} | ||||||
| 				cell = module->addCell(remap_name(c->name), c->type); | 				cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| 				existing_cell = module->cell(c->name); | 				existing_cell = module->cell(mapped_cell->name); | ||||||
| 				log_assert(existing_cell); | 				log_assert(existing_cell); | ||||||
| 				cell = module->addCell(remap_name(c->name), c->type); | 				cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; |  | ||||||
| 			if (existing_cell) { | 			if (existing_cell) { | ||||||
| 				cell->parameters = existing_cell->parameters; | 				cell->parameters = existing_cell->parameters; | ||||||
| 				cell->attributes = existing_cell->attributes; | 				cell->attributes = existing_cell->attributes; | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| 				cell->parameters = c->parameters; | 				cell->parameters = mapped_cell->parameters; | ||||||
| 				cell->attributes = c->attributes; | 				cell->attributes = mapped_cell->attributes; | ||||||
| 			} | 			} | ||||||
| 			for (auto &conn : c->connections()) { | 
 | ||||||
|  | 			RTLIL::Module* box_module = design->module(mapped_cell->type); | ||||||
|  | 			auto abc9_flop = box_module && box_module->get_bool_attribute("\\abc9_flop"); | ||||||
|  | 			for (auto &conn : mapped_cell->connections()) { | ||||||
| 				RTLIL::SigSpec newsig; | 				RTLIL::SigSpec newsig; | ||||||
| 				for (auto c : conn.second.chunks()) { | 				for (auto c : conn.second.chunks()) { | ||||||
| 					if (c.width == 0) | 					if (c.width == 0) | ||||||
|  | @ -625,15 +540,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri | ||||||
| 				} | 				} | ||||||
| 				cell->setPort(conn.first, newsig); | 				cell->setPort(conn.first, newsig); | ||||||
| 
 | 
 | ||||||
|  | 				if (!abc9_flop) { | ||||||
| 					if (cell->input(conn.first)) { | 					if (cell->input(conn.first)) { | ||||||
| 						for (auto i : newsig) | 						for (auto i : newsig) | ||||||
| 							bit2sinks[i].push_back(cell); | 							bit2sinks[i].push_back(cell); | ||||||
| 						for (auto i : conn.second) | 						for (auto i : conn.second) | ||||||
| 						bit_users[i].insert(c->name); | 							bit_users[i].insert(mapped_cell->name); | ||||||
| 					} | 					} | ||||||
| 					if (cell->output(conn.first)) | 					if (cell->output(conn.first)) | ||||||
| 						for (auto i : conn.second) | 						for (auto i : conn.second) | ||||||
| 						bit_drivers[i].insert(c->name); | 							bit_drivers[i].insert(mapped_cell->name); | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -821,7 +738,7 @@ struct Abc9Pass : public Pass { | ||||||
| 		log("    abc9 [options] [selection]\n"); | 		log("    abc9 [options] [selection]\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); | 		log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); | ||||||
| 		log("library to a target architecture.\n"); | 		log("library to a target architecture. Only fully-selected modules are supported.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -exe <command>\n"); | 		log("    -exe <command>\n"); | ||||||
| #ifdef ABCEXTERNAL | #ifdef ABCEXTERNAL | ||||||
|  | @ -842,7 +759,7 @@ struct Abc9Pass : public Pass { | ||||||
| 		log("        if no -script parameter is given, the following scripts are used:\n"); | 		log("        if no -script parameter is given, the following scripts are used:\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("        for -lut/-luts (only one LUT size):\n"); | 		log("        for -lut/-luts (only one LUT size):\n"); | ||||||
| 		log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); | 		log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("        for -lut/-luts (different LUT sizes):\n"); | 		log("        for -lut/-luts (different LUT sizes):\n"); | ||||||
| 		log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); | 		log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); | ||||||
|  | @ -858,8 +775,6 @@ struct Abc9Pass : public Pass { | ||||||
| 		log("        set delay target. the string {D} in the default scripts above is\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("        replaced by this option when used, and an empty string otherwise\n"); | ||||||
| 		log("        (indicating best possible delay).\n"); | 		log("        (indicating best possible delay).\n"); | ||||||
| //		log("        This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
 |  | ||||||
| //		log("        default scripts above.\n");
 |  | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| //		log("    -S <num>\n");
 | //		log("    -S <num>\n");
 | ||||||
| //		log("        maximum number of LUT inputs shared.\n");
 | //		log("        maximum number of LUT inputs shared.\n");
 | ||||||
|  | @ -881,19 +796,10 @@ struct Abc9Pass : public Pass { | ||||||
| 		log("        generate netlist using luts. Use the specified costs for luts with 1,\n"); | 		log("        generate netlist using luts. Use the specified costs for luts with 1,\n"); | ||||||
| 		log("        2, 3, .. inputs.\n"); | 		log("        2, 3, .. inputs.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| //		log("    -dff\n");
 | 		log("    -dff\n"); | ||||||
| //		log("        also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
 | 		log("        also pass $_ABC9_FF_ cells through to ABC. modules with many clock\n"); | ||||||
| //		log("        clock domains are automatically partitioned in clock domains and each\n");
 | 		log("        domains are marked as such and automatically partitioned by ABC.\n"); | ||||||
| //		log("        domain is passed through ABC independently.\n");
 | 		log("\n"); | ||||||
| //		log("\n");
 |  | ||||||
| //		log("    -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
 |  | ||||||
| //		log("        use only the specified clock domain. this is like -dff, but only FF\n");
 |  | ||||||
| //		log("        cells that belong to the specified clock domain are used.\n");
 |  | ||||||
| //		log("\n");
 |  | ||||||
| //		log("    -keepff\n");
 |  | ||||||
| //		log("        set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
 |  | ||||||
| //		log("        them, for example for equivalence checking.)\n");
 |  | ||||||
| //		log("\n");
 |  | ||||||
| 		log("    -nocleanup\n"); | 		log("    -nocleanup\n"); | ||||||
| 		log("        when this option is used, the temporary files created by this pass\n"); | 		log("        when this option is used, the temporary files created by this pass\n"); | ||||||
| 		log("        are not removed. this is useful for debugging.\n"); | 		log("        are not removed. this is useful for debugging.\n"); | ||||||
|  | @ -902,11 +808,6 @@ struct Abc9Pass : public Pass { | ||||||
| 		log("        print the temp dir name in log. usually this is suppressed so that the\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("        command output is identical across runs.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -markgroups\n"); |  | ||||||
| 		log("        set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); |  | ||||||
| 		log("        this attribute is a unique integer for each ABC process started. This\n"); |  | ||||||
| 		log("        is useful for debugging the partitioning of clock domains.\n"); |  | ||||||
| 		log("\n"); |  | ||||||
| 		log("    -box <file>\n"); | 		log("    -box <file>\n"); | ||||||
| 		log("        pass this file with box library to ABC. Use with -lut.\n"); | 		log("        pass this file with box library to ABC. Use with -lut.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | @ -914,8 +815,8 @@ struct Abc9Pass : public Pass { | ||||||
| 		log("internally. This is not going to \"run ABC on your design\". It will instead run\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("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("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("design as an XAIGER file with `write_xaiger' and then load that into ABC\n"); | ||||||
| 		log("you want to use ABC to convert your design into another format.\n"); | 		log("externally if you want to use ABC to convert your design into another format.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); | 		log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | @ -925,8 +826,6 @@ struct Abc9Pass : public Pass { | ||||||
| 		log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); | 		log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); | ||||||
| 		log_push(); | 		log_push(); | ||||||
| 
 | 
 | ||||||
| 		assign_map.clear(); |  | ||||||
| 
 |  | ||||||
| #ifdef ABCEXTERNAL | #ifdef ABCEXTERNAL | ||||||
| 		std::string exe_file = ABCEXTERNAL; | 		std::string exe_file = ABCEXTERNAL; | ||||||
| #else | #else | ||||||
|  | @ -934,11 +833,10 @@ struct Abc9Pass : public Pass { | ||||||
| #endif | #endif | ||||||
| 		std::string script_file, clk_str, box_file, lut_file; | 		std::string script_file, clk_str, box_file, lut_file; | ||||||
| 		std::string delay_target, lutin_shared = "-S 1", wire_delay; | 		std::string delay_target, lutin_shared = "-S 1", wire_delay; | ||||||
| 		bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; | 		bool fast_mode = false, dff_mode = false, cleanup = true; | ||||||
| 		bool show_tempdir = false; | 		bool show_tempdir = false; | ||||||
| 		bool nomfs = false; | 		bool nomfs = false; | ||||||
| 		vector<int> lut_costs; | 		vector<int> lut_costs; | ||||||
| 		markgroups = false; |  | ||||||
| 
 | 
 | ||||||
| #if 0 | #if 0 | ||||||
| 		cleanup = false; | 		cleanup = false; | ||||||
|  | @ -962,9 +860,9 @@ struct Abc9Pass : public Pass { | ||||||
| 		lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); | 		lut_arg = design->scratchpad_get_string("abc9.lut", lut_arg); | ||||||
| 		luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); | 		luts_arg = design->scratchpad_get_string("abc9.luts", luts_arg); | ||||||
| 		fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); | 		fast_mode = design->scratchpad_get_bool("abc9.fast", fast_mode); | ||||||
|  | 		dff_mode = design->scratchpad_get_bool("abc9.dff", dff_mode); | ||||||
| 		cleanup = !design->scratchpad_get_bool("abc9.nocleanup", !cleanup); | 		cleanup = !design->scratchpad_get_bool("abc9.nocleanup", !cleanup); | ||||||
| 		show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); | 		show_tempdir = design->scratchpad_get_bool("abc9.showtmp", show_tempdir); | ||||||
| 		markgroups = design->scratchpad_get_bool("abc9.markgroups", markgroups); |  | ||||||
| 		box_file = design->scratchpad_get_string("abc9.box", box_file); | 		box_file = design->scratchpad_get_string("abc9.box", box_file); | ||||||
| 		if (design->scratchpad.count("abc9.W")) { | 		if (design->scratchpad.count("abc9.W")) { | ||||||
| 			wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); | 			wire_delay = "-W " + design->scratchpad_get_string("abc9.W"); | ||||||
|  | @ -1010,19 +908,10 @@ struct Abc9Pass : public Pass { | ||||||
| 				fast_mode = true; | 				fast_mode = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			//if (arg == "-dff") {
 | 			if (arg == "-dff") { | ||||||
| 			//	dff_mode = true;
 | 				dff_mode = true; | ||||||
| 			//	continue;
 | 				continue; | ||||||
| 			//}
 | 			} | ||||||
| 			//if (arg == "-clk" && argidx+1 < args.size()) {
 |  | ||||||
| 			//	clk_str = args[++argidx];
 |  | ||||||
| 			//	dff_mode = true;
 |  | ||||||
| 			//	continue;
 |  | ||||||
| 			//}
 |  | ||||||
| 			//if (arg == "-keepff") {
 |  | ||||||
| 			//	keepff = true;
 |  | ||||||
| 			//	continue;
 |  | ||||||
| 			//}
 |  | ||||||
| 			if (arg == "-nocleanup") { | 			if (arg == "-nocleanup") { | ||||||
| 				cleanup = false; | 				cleanup = false; | ||||||
| 				continue; | 				continue; | ||||||
|  | @ -1031,10 +920,6 @@ struct Abc9Pass : public Pass { | ||||||
| 				show_tempdir = true; | 				show_tempdir = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (arg == "-markgroups") { |  | ||||||
| 				markgroups = true; |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 			if (arg == "-box" && argidx+1 < args.size()) { | 			if (arg == "-box" && argidx+1 < args.size()) { | ||||||
| 				box_file = args[++argidx]; | 				box_file = args[++argidx]; | ||||||
| 				continue; | 				continue; | ||||||
|  | @ -1105,234 +990,64 @@ struct Abc9Pass : public Pass { | ||||||
| 		if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') | 		if (!box_file.empty() && !is_absolute_path(box_file) && box_file[0] != '+') | ||||||
| 		    box_file = std::string(pwd) + "/" + box_file; | 		    box_file = std::string(pwd) + "/" + box_file; | ||||||
| 
 | 
 | ||||||
| 		dict<int,IdString> box_lookup; | 		SigMap assign_map; | ||||||
| 		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); |  | ||||||
| 
 |  | ||||||
| 			RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; |  | ||||||
| 			for (auto p : m->ports) { |  | ||||||
| 				auto w = m->wire(p); |  | ||||||
| 				log_assert(w); |  | ||||||
| 				if (w->attributes.count(ID(abc9_carry))) { |  | ||||||
| 					if (w->port_input) { |  | ||||||
| 						if (carry_in) |  | ||||||
| 							log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); |  | ||||||
| 						carry_in = w; |  | ||||||
| 					} |  | ||||||
| 					else if (w->port_output) { |  | ||||||
| 						if (carry_out) |  | ||||||
| 							log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); |  | ||||||
| 						carry_out = w; |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			if (carry_in || carry_out) { |  | ||||||
| 				if (carry_in && !carry_out) |  | ||||||
| 					log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); |  | ||||||
| 				if (!carry_in && carry_out) |  | ||||||
| 					log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); |  | ||||||
| 				// Make carry_in the last PI, and carry_out the last PO
 |  | ||||||
| 				//   since ABC requires it this way
 |  | ||||||
| 				auto &ports = m->ports; |  | ||||||
| 				for (auto it = ports.begin(); it != ports.end(); ) { |  | ||||||
| 					RTLIL::Wire* w = m->wire(*it); |  | ||||||
| 					log_assert(w); |  | ||||||
| 					if (w == carry_in || w == carry_out) { |  | ||||||
| 						it = ports.erase(it); |  | ||||||
| 						continue; |  | ||||||
| 					} |  | ||||||
| 					if (w->port_id > carry_in->port_id) |  | ||||||
| 						--w->port_id; |  | ||||||
| 					if (w->port_id > carry_out->port_id) |  | ||||||
| 						--w->port_id; |  | ||||||
| 					log_assert(w->port_input || w->port_output); |  | ||||||
| 					log_assert(ports[w->port_id-1] == w->name); |  | ||||||
| 					++it; |  | ||||||
| 				} |  | ||||||
| 				ports.push_back(carry_in->name); |  | ||||||
| 				carry_in->port_id = ports.size(); |  | ||||||
| 				ports.push_back(carry_out->name); |  | ||||||
| 				carry_out->port_id = ports.size(); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		for (auto mod : design->selected_modules()) |  | ||||||
| 		{ |  | ||||||
| 			if (mod->attributes.count(ID(abc9_box_id))) |  | ||||||
| 				continue; |  | ||||||
| 
 |  | ||||||
| 			if (mod->processes.size() > 0) { |  | ||||||
| 				log("Skipping module %s as it contains processes.\n", log_id(mod)); |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			assign_map.set(mod); |  | ||||||
| 
 |  | ||||||
| 			if (!dff_mode || !clk_str.empty()) { |  | ||||||
| 				abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, |  | ||||||
| 						delay_target, lutin_shared, fast_mode, show_tempdir, |  | ||||||
| 						box_file, lut_file, wire_delay, box_lookup, nomfs); |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 		CellTypes ct(design); | 		CellTypes ct(design); | ||||||
| 
 | 		for (auto module : design->selected_modules()) | ||||||
| 			std::vector<RTLIL::Cell*> all_cells = mod->selected_cells(); |  | ||||||
| 			std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end()); |  | ||||||
| 
 |  | ||||||
| 			std::set<RTLIL::Cell*> expand_queue, next_expand_queue; |  | ||||||
| 			std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up; |  | ||||||
| 			std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down; |  | ||||||
| 
 |  | ||||||
| 			typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t; |  | ||||||
| 			std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells; |  | ||||||
| 			std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse; |  | ||||||
| 
 |  | ||||||
| 			std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down; |  | ||||||
| 			std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down; |  | ||||||
| 
 |  | ||||||
| 			for (auto cell : all_cells) |  | ||||||
| 		{ | 		{ | ||||||
| 				clkdomain_t key; | 			if (module->processes.size() > 0) { | ||||||
|  | 				log("Skipping module %s as it contains processes.\n", log_id(module)); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			log_assert(!module->attributes.count(ID(abc9_box_id))); | ||||||
| 
 | 
 | ||||||
| 				for (auto &conn : cell->connections()) | 			if (!design->selected_whole_module(module)) | ||||||
| 				for (auto bit : conn.second) { | 				log_error("Can't handle partially selected module %s!\n", log_id(module)); | ||||||
| 					bit = assign_map(bit); |  | ||||||
| 					if (bit.wire != nullptr) { |  | ||||||
| 						cell_to_bit[cell].insert(bit); |  | ||||||
| 						bit_to_cell[bit].insert(cell); |  | ||||||
| 						if (ct.cell_input(cell->type, conn.first)) { |  | ||||||
| 							cell_to_bit_up[cell].insert(bit); |  | ||||||
| 							bit_to_cell_down[bit].insert(cell); |  | ||||||
| 						} |  | ||||||
| 						if (ct.cell_output(cell->type, conn.first)) { |  | ||||||
| 							cell_to_bit_down[cell].insert(bit); |  | ||||||
| 							bit_to_cell_up[bit].insert(cell); |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 
 | 
 | ||||||
| 				if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) | 			assign_map.set(module); | ||||||
| 				{ | 
 | ||||||
| 					key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); | 			typedef SigSpec clkdomain_t; | ||||||
| 				} | 			dict<clkdomain_t, int> clk_to_mergeability; | ||||||
| 				else | 
 | ||||||
| 				if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) | 			if (dff_mode) | ||||||
| 				{ | 				for (auto cell : module->cells()) { | ||||||
| 					bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); | 					if (cell->type != "$__ABC9_FF_") | ||||||
| 					bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); |  | ||||||
| 					key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); |  | ||||||
| 				} |  | ||||||
| 				else |  | ||||||
| 						continue; | 						continue; | ||||||
| 
 | 
 | ||||||
| 				unassigned_cells.erase(cell); | 					Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str())); | ||||||
| 				expand_queue.insert(cell); | 					if (abc9_clock_wire == NULL) | ||||||
| 				expand_queue_up.insert(cell); | 						log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); | ||||||
| 				expand_queue_down.insert(cell); | 					SigSpec abc9_clock = assign_map(abc9_clock_wire); | ||||||
| 
 | 
 | ||||||
| 				assigned_cells[key].push_back(cell); | 					clkdomain_t key(abc9_clock); | ||||||
| 				assigned_cells_reverse[cell] = key; | 
 | ||||||
|  | 					auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); | ||||||
|  | 					auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); | ||||||
|  | 					log_assert(r2.second); | ||||||
|  | 
 | ||||||
|  | 					Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str())); | ||||||
|  | 					if (abc9_init_wire == NULL) | ||||||
|  | 						log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); | ||||||
|  | 					log_assert(GetSize(abc9_init_wire) == 1); | ||||||
|  | 					SigSpec abc9_init = assign_map(abc9_init_wire); | ||||||
|  | 					if (!abc9_init.is_fully_const()) | ||||||
|  | 						log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); | ||||||
|  | 					r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); | ||||||
|  | 					log_assert(r2.second); | ||||||
|  | 				} | ||||||
|  | 			else | ||||||
|  | 				for (auto cell : module->cells()) { | ||||||
|  | 					auto inst_module = design->module(cell->type); | ||||||
|  | 					if (!inst_module || !inst_module->get_bool_attribute("\\abc9_flop")) | ||||||
|  | 						continue; | ||||||
|  | 					cell->set_bool_attribute("\\abc9_keep"); | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 			while (!expand_queue_up.empty() || !expand_queue_down.empty()) | 			design->selected_active_module = module->name.str(); | ||||||
| 			{ | 			abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, dff_mode, | ||||||
| 				if (!expand_queue_up.empty()) | 					delay_target, lutin_shared, fast_mode, show_tempdir, | ||||||
| 				{ | 					box_file, lut_file, wire_delay, nomfs); | ||||||
| 					RTLIL::Cell *cell = *expand_queue_up.begin(); | 			design->selected_active_module.clear(); | ||||||
| 					clkdomain_t key = assigned_cells_reverse.at(cell); |  | ||||||
| 					expand_queue_up.erase(cell); |  | ||||||
| 
 |  | ||||||
| 					for (auto bit : cell_to_bit_up[cell]) |  | ||||||
| 					for (auto c : bit_to_cell_up[bit]) |  | ||||||
| 						if (unassigned_cells.count(c)) { |  | ||||||
| 							unassigned_cells.erase(c); |  | ||||||
| 							next_expand_queue_up.insert(c); |  | ||||||
| 							assigned_cells[key].push_back(c); |  | ||||||
| 							assigned_cells_reverse[c] = key; |  | ||||||
| 							expand_queue.insert(c); |  | ||||||
| 		} | 		} | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (!expand_queue_down.empty()) |  | ||||||
| 				{ |  | ||||||
| 					RTLIL::Cell *cell = *expand_queue_down.begin(); |  | ||||||
| 					clkdomain_t key = assigned_cells_reverse.at(cell); |  | ||||||
| 					expand_queue_down.erase(cell); |  | ||||||
| 
 |  | ||||||
| 					for (auto bit : cell_to_bit_down[cell]) |  | ||||||
| 					for (auto c : bit_to_cell_down[bit]) |  | ||||||
| 						if (unassigned_cells.count(c)) { |  | ||||||
| 							unassigned_cells.erase(c); |  | ||||||
| 							next_expand_queue_up.insert(c); |  | ||||||
| 							assigned_cells[key].push_back(c); |  | ||||||
| 							assigned_cells_reverse[c] = key; |  | ||||||
| 							expand_queue.insert(c); |  | ||||||
| 						} |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (expand_queue_up.empty() && expand_queue_down.empty()) { |  | ||||||
| 					expand_queue_up.swap(next_expand_queue_up); |  | ||||||
| 					expand_queue_down.swap(next_expand_queue_down); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			while (!expand_queue.empty()) |  | ||||||
| 			{ |  | ||||||
| 				RTLIL::Cell *cell = *expand_queue.begin(); |  | ||||||
| 				clkdomain_t key = assigned_cells_reverse.at(cell); |  | ||||||
| 				expand_queue.erase(cell); |  | ||||||
| 
 |  | ||||||
| 				for (auto bit : cell_to_bit.at(cell)) { |  | ||||||
| 					for (auto c : bit_to_cell[bit]) |  | ||||||
| 						if (unassigned_cells.count(c)) { |  | ||||||
| 							unassigned_cells.erase(c); |  | ||||||
| 							next_expand_queue.insert(c); |  | ||||||
| 							assigned_cells[key].push_back(c); |  | ||||||
| 							assigned_cells_reverse[c] = key; |  | ||||||
| 						} |  | ||||||
| 					bit_to_cell[bit].clear(); |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				if (expand_queue.empty()) |  | ||||||
| 					expand_queue.swap(next_expand_queue); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); |  | ||||||
| 			for (auto cell : unassigned_cells) { |  | ||||||
| 				assigned_cells[key].push_back(cell); |  | ||||||
| 				assigned_cells_reverse[cell] = key; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			log_header(design, "Summary of detected clock domains:\n"); |  | ||||||
| 			for (auto &it : assigned_cells) |  | ||||||
| 				log("  %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), |  | ||||||
| 						std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), |  | ||||||
| 						std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); |  | ||||||
| 
 |  | ||||||
| 			for (auto &it : assigned_cells) { |  | ||||||
| 				clk_polarity = std::get<0>(it.first); |  | ||||||
| 				clk_sig = assign_map(std::get<1>(it.first)); |  | ||||||
| 				en_polarity = std::get<2>(it.first); |  | ||||||
| 				en_sig = assign_map(std::get<3>(it.first)); |  | ||||||
| 				abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", |  | ||||||
| 						keepff, delay_target, lutin_shared, fast_mode, show_tempdir, |  | ||||||
| 						box_file, lut_file, wire_delay, box_lookup, nomfs); |  | ||||||
| 				assign_map.set(mod); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		assign_map.clear(); |  | ||||||
| 
 | 
 | ||||||
| 		log_pop(); | 		log_pop(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1,43 +1,36 @@ | ||||||
| # NB: Inputs/Outputs must be ordered alphabetically | # NB: Box inputs/outputs must each be in the same order | ||||||
| #     (with exceptions for carry in/out) | #     as their corresponding module definition | ||||||
|  | #     (with exceptions detailed below) | ||||||
| 
 | 
 | ||||||
| # Box 1 : CCU2C (2xCARRY + 2xLUT4) | # Box 1 : CCU2C (2xCARRY + 2xLUT4) | ||||||
| # Outputs: S0, S1, COUT | #   (Exception: carry chain input/output must be the | ||||||
| #   (NB: carry chain input/output must be last | #        last input and output and the entire bus has been | ||||||
| #        input/output and bus has been moved | #        moved there overriding the otherwise | ||||||
| #        there overriding the otherwise |  | ||||||
| #        alphabetical ordering) | #        alphabetical ordering) | ||||||
| # name  ID   w/b   ins    outs | # name  ID   w/b   ins    outs | ||||||
| CCU2C   1      1   9      3 | CCU2C   1      1   9      3 | ||||||
| 
 | #A0  B0   C0    D0   A1   B1   C1   D1   CIN | ||||||
| #A0   A1   B0   B1   C0    C1  D0   D1   CIN | 379  379  275   141  -    -    -    -    257 # S0 | ||||||
| 379  -    379  -    275   -    141  -    257 | 630  630  526   392  379  379  275  141  273 # S1 | ||||||
| 630  379  630  379  526   275  392  141  273 | 516  516  412   278  516  516  412  278   43 # COUT | ||||||
| 516  516  516  516  412   412  278  278  43 |  | ||||||
| 
 | 
 | ||||||
| # Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram) | # Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram) | ||||||
| # Outputs: DO0, DO1, DO2, DO3 |  | ||||||
| # name               ID  w/b   ins   outs | # name               ID  w/b   ins   outs | ||||||
| $__ABC9_DPR16X4_COMB  2     0   8    4 | $__ABC9_DPR16X4_COMB  2     0   8    4 | ||||||
| 
 | #$DO0 $DO1 $DO2 $DO3 RAD0   RAD1   RAD2   RAD3 | ||||||
| #A0   A1   A2   A3   RAD0   RAD1   RAD2   RAD3 | 0     0    0    0    141    379    275    379 # DO0 | ||||||
| 0     0    0    0    141    379    275    379 | 0     0    0    0    141    379    275    379 # DO1 | ||||||
| 0     0    0    0    141    379    275    379 | 0     0    0    0    141    379    275    379 # DO2 | ||||||
| 0     0    0    0    141    379    275    379 | 0     0    0    0    141    379    275    379 # DO3 | ||||||
| 0     0    0    0    141    379    275    379 |  | ||||||
| 
 | 
 | ||||||
| # Box 3 : PFUMX (MUX2) | # Box 3 : PFUMX (MUX2) | ||||||
| # Outputs: Z |  | ||||||
| # name  ID   w/b   ins    outs | # name  ID   w/b   ins    outs | ||||||
| PFUMX   3    1     3      1 | PFUMX   3    1     3      1 | ||||||
| 
 |  | ||||||
| #ALUT  BLUT  C0 | #ALUT  BLUT  C0 | ||||||
| 98     98    151 | 98     98    151 # Z | ||||||
| 
 | 
 | ||||||
| # Box 4 : L6MUX21 (MUX2) | # Box 4 : L6MUX21 (MUX2) | ||||||
| # Outputs: Z |  | ||||||
| # name   ID   w/b   ins    outs | # name   ID   w/b   ins    outs | ||||||
| L6MUX21  4    1     3      1 | L6MUX21  4    1     3      1 | ||||||
| 
 |  | ||||||
| #D0    D1    SD | #D0    D1    SD | ||||||
| 140    141   148 | 140    141   148 # Z | ||||||
|  |  | ||||||
|  | @ -1,24 +1,27 @@ | ||||||
| // --------------------------------------- | // --------------------------------------- | ||||||
| 
 | 
 | ||||||
|  | // Attach a (combinatorial) black-box onto the output | ||||||
|  | //   of this LUTRAM primitive to capture its | ||||||
|  | //   asynchronous read behaviour | ||||||
| module TRELLIS_DPR16X4 ( | module TRELLIS_DPR16X4 ( | ||||||
| 	input  [3:0] DI, | 	(* techmap_autopurge *) input  [3:0] DI, | ||||||
| 	input  [3:0] WAD, | 	(* techmap_autopurge *) input  [3:0] WAD, | ||||||
| 	input        WRE, | 	(* techmap_autopurge *) input        WRE, | ||||||
| 	input        WCK, | 	(* techmap_autopurge *) input        WCK, | ||||||
| 	input  [3:0] RAD, | 	(* techmap_autopurge *) input  [3:0] RAD, | ||||||
| 	output [3:0] DO | 	output [3:0] DO | ||||||
| ); | ); | ||||||
| 	parameter WCKMUX = "WCK"; | 	parameter WCKMUX = "WCK"; | ||||||
| 	parameter WREMUX = "WRE"; | 	parameter WREMUX = "WRE"; | ||||||
| 	parameter [63:0] INITVAL = 64'h0000000000000000; | 	parameter [63:0] INITVAL = 64'h0000000000000000; | ||||||
|     wire [3:0] \$DO ; |     wire [3:0] $DO; | ||||||
| 
 | 
 | ||||||
|     TRELLIS_DPR16X4 #( |     TRELLIS_DPR16X4 #( | ||||||
|       .WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL) |       .WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL) | ||||||
|     ) _TECHMAP_REPLACE_ ( |     ) _TECHMAP_REPLACE_ ( | ||||||
|       .DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK), |       .DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK), | ||||||
|       .RAD(RAD), .DO(\$DO ) |       .RAD(RAD), .DO($DO) | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     \$__ABC9_DPR16X4_COMB do (.A(\$DO ), .S(RAD), .Y(DO)); |     $__ABC9_DPR16X4_COMB do (.$DO($DO), .RAD(RAD), .DO(DO)); | ||||||
| endmodule | endmodule | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // --------------------------------------- | // --------------------------------------- | ||||||
| 
 | 
 | ||||||
| (* abc9_box_id=2 *) | (* abc9_box_id=2 *) | ||||||
| module \$__ABC9_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); | module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO); | ||||||
| endmodule | endmodule | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // --------------------------------------- | // --------------------------------------- | ||||||
| 
 | 
 | ||||||
| module \$__ABC9_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); | module \$__ABC9_DPR16X4_COMB (input [3:0] $DO, RAD, output [3:0] DO); | ||||||
|     assign Y = A; |     assign DO = $DO; | ||||||
| endmodule | endmodule | ||||||
|  |  | ||||||
|  | @ -1,13 +1,17 @@ | ||||||
| # From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt | # From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt | ||||||
| 
 | 
 | ||||||
| # NB: Inputs/Outputs must be ordered alphabetically | # NB: Box inputs/outputs must each be in the same order | ||||||
| #     (with exceptions for carry in/out) | #     as their corresponding module definition | ||||||
|  | #     (with exceptions detailed below) | ||||||
| 
 | 
 | ||||||
| # Inputs: A B I0 I3 CI | # Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve | ||||||
| # Outputs: O CO | #                                 SB_LUT4+SB_CARRY) | ||||||
| #   (NB: carry chain input/output must be last | #   (Exception: carry chain input/output must be the | ||||||
| #        input/output and have been moved there | #        last input and output and the entire bus has been | ||||||
| #        overriding the alphabetical ordering) | #        moved there overriding the otherwise | ||||||
|  | #        alphabetical ordering) | ||||||
|  | # name                 ID  w/b ins outs | ||||||
| $__ICE40_CARRY_WRAPPER 1   1   5   2 | $__ICE40_CARRY_WRAPPER 1   1   5   2 | ||||||
| 400 379 449 316 316 | #A  B   I0  I3  CI | ||||||
| 259 231 -   -   126 | 400 379 449 316 316 # O | ||||||
|  | 259 231 -   -   126 # CO | ||||||
|  |  | ||||||
|  | @ -1,13 +1,17 @@ | ||||||
| # From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt | # From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt | ||||||
| 
 | 
 | ||||||
| # NB: Inputs/Outputs must be ordered alphabetically | # NB: Box inputs/outputs must each be in the same order | ||||||
| #     (with exceptions for carry in/out) | #     as their corresponding module definition | ||||||
|  | #     (with exceptions detailed below) | ||||||
| 
 | 
 | ||||||
| # Inputs: A B I0 I3 CI | # Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve | ||||||
| # Outputs: O CO | #                                 SB_LUT4+SB_CARRY) | ||||||
| #   (NB: carry chain input/output must be last | #   (Exception: carry chain input/output must be the | ||||||
| #        input/output and have been moved there | #        last input and output and the entire bus has been | ||||||
| #        overriding the alphabetical ordering) | #        moved there overriding the otherwise | ||||||
|  | #        alphabetical ordering) | ||||||
|  | # name                 ID  w/b ins outs | ||||||
| $__ICE40_CARRY_WRAPPER 1   1   5   2 | $__ICE40_CARRY_WRAPPER 1   1   5   2 | ||||||
| 589 558 661 465 465 | #A  B   I0  I3  CI | ||||||
| 675 609 -   -   186 | 589 558 661 465 465 # O | ||||||
|  | 675 609 -   -   186 # CO | ||||||
|  |  | ||||||
|  | @ -1,13 +1,18 @@ | ||||||
| # From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt | # From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt | ||||||
| 
 | 
 | ||||||
| # NB: Inputs/Outputs must be ordered alphabetically | # NB: Box inputs/outputs must each be in the same order | ||||||
| #     (with exceptions for carry in/out) | #     as their corresponding module definition | ||||||
|  | #     (with exceptions detailed below) | ||||||
| 
 | 
 | ||||||
| # Inputs: A B I0 I3 CI | # Box 1 : $__ICE40_CARRY_WRAPPER (private cell used to preserve | ||||||
| # Outputs: O CO | #                                 SB_LUT4+SB_CARRY) | ||||||
| #   (NB: carry chain input/output must be last | # Outputs: O, CO | ||||||
| #        input/output and have been moved there | #   (Exception: carry chain input/output must be the | ||||||
| #        overriding the alphabetical ordering) | #        last input and output and the entire bus has been | ||||||
|  | #        moved there overriding the otherwise | ||||||
|  | #        alphabetical ordering) | ||||||
|  | # name                 ID  w/b ins outs | ||||||
| $__ICE40_CARRY_WRAPPER 1   1   5   2 | $__ICE40_CARRY_WRAPPER 1   1   5   2 | ||||||
| 1231 1205 1285 874 874 | #A  B   I0  I3  CI | ||||||
| 675  609  -    -   278 | 1231 1205 1285 874 874 # O | ||||||
|  | 675  609  -    -   278 # CO | ||||||
|  |  | ||||||
|  | @ -18,8 +18,366 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| // ============================================================================ | // The following techmapping rules are intended to be run (with -max_iter 1) | ||||||
|  | //   before invoking the `abc9` pass in order to transform the design into | ||||||
|  | //   a format that it understands. | ||||||
| 
 | 
 | ||||||
|  | `ifdef DFF_MODE | ||||||
|  | // For example, (complex) flip-flops are expected to be described as an | ||||||
|  | //   combinatorial box (containing all control logic such as clock enable | ||||||
|  | //   or synchronous resets) followed by a basic D-Q flop. | ||||||
|  | // Yosys will automatically analyse the simulation model (described in | ||||||
|  | //   cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in | ||||||
|  | //   order to extract the combinatorial control logic left behind. | ||||||
|  | //   Specifically, a simulation model similar to the one below: | ||||||
|  | // | ||||||
|  | //                ++===================================++ | ||||||
|  | //                ||                        Sim model  || | ||||||
|  | //                ||      /\/\/\/\                     || | ||||||
|  | //            D -->>-----<        >     +------+       || | ||||||
|  | //            R -->>-----<  Comb. >     |$_DFF_|       || | ||||||
|  | //           CE -->>-----<  logic >-----| [NP]_|---+---->>-- Q | ||||||
|  | //                ||  +--<        >     +------+   |   || | ||||||
|  | //                ||  |   \/\/\/\/                 |   || | ||||||
|  | //                ||  |                            |   || | ||||||
|  | //                ||  +----------------------------+   || | ||||||
|  | //                ||                                   || | ||||||
|  | //                ++===================================++ | ||||||
|  | // | ||||||
|  | //   is transformed into: | ||||||
|  | // | ||||||
|  | //                ++==================++ | ||||||
|  | //                ||         Comb box || | ||||||
|  | //                ||                  || | ||||||
|  | //                ||      /\/\/\/\    || | ||||||
|  | //           D  -->>-----<        >   || | ||||||
|  | //           R  -->>-----<  Comb. >   ||        +-----------+ | ||||||
|  | //          CE  -->>-----<  logic >--->>-- $Q --|$__ABC9_FF_|--+-->> Q | ||||||
|  | //   abc9_ff.Q +-->>-----<        >   ||        +-----------+  | | ||||||
|  | //             |  ||      \/\/\/\/    ||                       | | ||||||
|  | //             |  ||                  ||                       | | ||||||
|  | //             |  ++==================++                       | | ||||||
|  | //             |                                               | | ||||||
|  | //             +-----------------------------------------------+ | ||||||
|  | // | ||||||
|  | // The purpose of the following FD* rules are to wrap the flop with: | ||||||
|  | // (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9 | ||||||
|  | //     the connectivity of its basic D-Q flop | ||||||
|  | // (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to | ||||||
|  | //     capture asynchronous behaviour | ||||||
|  | // (c) a special abc9_ff.clock wire to capture its clock domain and polarity | ||||||
|  | //     (indicated to `abc9' so that it only performs sequential synthesis | ||||||
|  | //     (with reachability analysis) correctly on one domain at a time) | ||||||
|  | // (d) a special abc9_ff.init wire to encode the flop's initial state | ||||||
|  | //     NOTE: in order to perform sequential synthesis, `abc9' also requires | ||||||
|  | //     that the initial value of all flops be zero | ||||||
|  | // (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback | ||||||
|  | //     into the (combinatorial) FD* cell to facilitate clock-enable behaviour | ||||||
|  | 
 | ||||||
|  | module FDRE (output Q, input C, CE, D, R); | ||||||
|  |   parameter [0:0] INIT = 1'b0; | ||||||
|  |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_R_INVERTED = 1'b0; | ||||||
|  |   wire QQ, $Q; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDSE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_S_INVERTED(IS_R_INVERTED) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .S(R) | ||||||
|  |     ); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDRE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_R_INVERTED(IS_R_INVERTED) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .R(R) | ||||||
|  |     ); | ||||||
|  |   end | ||||||
|  |   endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
|  | endmodule | ||||||
|  | module FDRE_1 (output Q, input C, CE, D, R); | ||||||
|  |   parameter [0:0] INIT = 1'b0; | ||||||
|  |   wire QQ, $Q; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDSE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .S(R) | ||||||
|  |     ); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDRE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .R(R) | ||||||
|  |     ); | ||||||
|  |   end | ||||||
|  |   endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module FDSE (output Q, input C, CE, D, S); | ||||||
|  |   parameter [0:0] INIT = 1'b1; | ||||||
|  |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_S_INVERTED = 1'b0; | ||||||
|  |   wire QQ, $Q; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDRE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_R_INVERTED(IS_S_INVERTED) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .R(S) | ||||||
|  |     ); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDSE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_S_INVERTED(IS_S_INVERTED) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .S(S) | ||||||
|  |     ); | ||||||
|  |   end endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
|  | endmodule | ||||||
|  | module FDSE_1 (output Q, input C, CE, D, S); | ||||||
|  |   parameter [0:0] INIT = 1'b1; | ||||||
|  |   wire QQ, $Q; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDRE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .R(S) | ||||||
|  |     ); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDSE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .S(S) | ||||||
|  |     ); | ||||||
|  |   end endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module FDCE (output Q, input C, CE, D, CLR); | ||||||
|  |   parameter [0:0] INIT = 1'b0; | ||||||
|  |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_CLR_INVERTED = 1'b0; | ||||||
|  |   wire QQ, $Q, $QQ; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDPE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_PRE_INVERTED(IS_CLR_INVERTED) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR) | ||||||
|  |                                             // ^^^ Note that async | ||||||
|  |                                             //     control is not directly | ||||||
|  |                                             //     supported by abc9 but its | ||||||
|  |                                             //     behaviour is captured by | ||||||
|  |                                             //     $__ABC9_ASYNC1 below | ||||||
|  |     ); | ||||||
|  |     // Since this is an async flop, async behaviour is dealt with here | ||||||
|  |     $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDCE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_CLR_INVERTED(IS_CLR_INVERTED) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR) | ||||||
|  |                                            // ^^^ Note that async | ||||||
|  |                                            //     control is not directly | ||||||
|  |                                            //     supported by abc9 but its | ||||||
|  |                                            //     behaviour is captured by | ||||||
|  |                                            //     $__ABC9_ASYNC0 below | ||||||
|  |     ); | ||||||
|  |     // Since this is an async flop, async behaviour is dealt with here | ||||||
|  |     $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ)); | ||||||
|  |   end endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
|  | endmodule | ||||||
|  | module FDCE_1 (output Q, input C, CE, D, CLR); | ||||||
|  |   parameter [0:0] INIT = 1'b0; | ||||||
|  |   wire QQ, $Q, $QQ; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDPE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR) | ||||||
|  |                                             // ^^^ Note that async | ||||||
|  |                                             //     control is not directly | ||||||
|  |                                             //     supported by abc9 but its | ||||||
|  |                                             //     behaviour is captured by | ||||||
|  |                                             //     $__ABC9_ASYNC1 below | ||||||
|  |     ); | ||||||
|  |     $__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ)); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDCE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR) | ||||||
|  |                                            // ^^^ Note that async | ||||||
|  |                                            //     control is not directly | ||||||
|  |                                            //     supported by abc9 but its | ||||||
|  |                                            //     behaviour is captured by | ||||||
|  |                                            //     $__ABC9_ASYNC0 below | ||||||
|  |     ); | ||||||
|  |     $__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ)); | ||||||
|  |   end endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module FDPE (output Q, input C, CE, D, PRE); | ||||||
|  |   parameter [0:0] INIT = 1'b1; | ||||||
|  |   parameter [0:0] IS_C_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_D_INVERTED = 1'b0; | ||||||
|  |   parameter [0:0] IS_PRE_INVERTED = 1'b0; | ||||||
|  |   wire QQ, $Q, $QQ; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDCE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_CLR_INVERTED(IS_PRE_INVERTED), | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE) | ||||||
|  |                                             // ^^^ Note that async | ||||||
|  |                                             //     control is not directly | ||||||
|  |                                             //     supported by abc9 but its | ||||||
|  |                                             //     behaviour is captured by | ||||||
|  |                                             //     $__ABC9_ASYNC0 below | ||||||
|  |     ); | ||||||
|  |     $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDPE #( | ||||||
|  |       .INIT(1'b0), | ||||||
|  |       .IS_C_INVERTED(IS_C_INVERTED), | ||||||
|  |       .IS_D_INVERTED(IS_D_INVERTED), | ||||||
|  |       .IS_PRE_INVERTED(IS_PRE_INVERTED), | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE) | ||||||
|  |                                            // ^^^ Note that async | ||||||
|  |                                            //     control is not directly | ||||||
|  |                                            //     supported by abc9 but its | ||||||
|  |                                            //     behaviour is captured by | ||||||
|  |                                            //     $__ABC9_ASYNC1 below | ||||||
|  |     ); | ||||||
|  |     $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ)); | ||||||
|  |   end endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
|  | endmodule | ||||||
|  | module FDPE_1 (output Q, input C, CE, D, PRE); | ||||||
|  |   parameter [0:0] INIT = 1'b1; | ||||||
|  |   wire QQ, $Q, $QQ; | ||||||
|  |   generate if (INIT == 1'b1) begin | ||||||
|  |     assign Q = ~QQ; | ||||||
|  |     FDCE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE) | ||||||
|  |                                             // ^^^ Note that async | ||||||
|  |                                             //     control is not directly | ||||||
|  |                                             //     supported by abc9 but its | ||||||
|  |                                             //     behaviour is captured by | ||||||
|  |                                             //     $__ABC9_ASYNC0 below | ||||||
|  |     ); | ||||||
|  |     $__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ)); | ||||||
|  |   end | ||||||
|  |   else begin | ||||||
|  |     assign Q = QQ; | ||||||
|  |     FDPE_1 #( | ||||||
|  |       .INIT(1'b0) | ||||||
|  |     ) _TECHMAP_REPLACE_ ( | ||||||
|  |       .D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE) | ||||||
|  |                                            // ^^^ Note that async | ||||||
|  |                                            //     control is not directly | ||||||
|  |                                            //     supported by abc9 but its | ||||||
|  |                                            //     behaviour is captured by | ||||||
|  |                                            //     $__ABC9_ASYNC1 below | ||||||
|  |     ); | ||||||
|  |     $__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ)); | ||||||
|  |   end endgenerate | ||||||
|  |   $__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ)); | ||||||
|  | 
 | ||||||
|  |   // Special signals | ||||||
|  |   wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */}; | ||||||
|  |   wire [0:0] abc9_ff.init = 1'b0; | ||||||
|  |   wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ; | ||||||
|  | endmodule | ||||||
|  | `endif | ||||||
|  | 
 | ||||||
|  | // Attach a (combinatorial) black-box onto the output | ||||||
|  | //   of thes LUTRAM primitives to capture their | ||||||
|  | //   asynchronous read behaviour | ||||||
| module RAM32X1D ( | module RAM32X1D ( | ||||||
|   output DPO, SPO, |   output DPO, SPO, | ||||||
|   (* techmap_autopurge *) input  D, |   (* techmap_autopurge *) input  D, | ||||||
|  | @ -30,17 +388,17 @@ module RAM32X1D ( | ||||||
| ); | ); | ||||||
|   parameter INIT = 32'h0; |   parameter INIT = 32'h0; | ||||||
|   parameter IS_WCLK_INVERTED = 1'b0; |   parameter IS_WCLK_INVERTED = 1'b0; | ||||||
|   wire \$DPO , \$SPO ; |   wire $DPO, $SPO; | ||||||
|   RAM32X1D #( |   RAM32X1D #( | ||||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) |     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .DPO(\$DPO ), .SPO(\$SPO ), |     .DPO($DPO), .SPO($SPO), | ||||||
|     .D(D), .WCLK(WCLK), .WE(WE), |     .D(D), .WCLK(WCLK), .WE(WE), | ||||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), |     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), | ||||||
|     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) |     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT6 spo (.A(\$SPO ), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO)); |   $__ABC9_LUT6 spo (.A($SPO), .S({1'b1, A4, A3, A2, A1, A0}), .Y(SPO)); | ||||||
|   \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); |   $__ABC9_LUT6 dpo (.A($DPO), .S({1'b1, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM64X1D ( | module RAM64X1D ( | ||||||
|  | @ -53,17 +411,17 @@ module RAM64X1D ( | ||||||
| ); | ); | ||||||
|   parameter INIT = 64'h0; |   parameter INIT = 64'h0; | ||||||
|   parameter IS_WCLK_INVERTED = 1'b0; |   parameter IS_WCLK_INVERTED = 1'b0; | ||||||
|   wire \$DPO , \$SPO ; |   wire $DPO, $SPO; | ||||||
|   RAM64X1D #( |   RAM64X1D #( | ||||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) |     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .DPO(\$DPO ), .SPO(\$SPO ), |     .DPO($DPO), .SPO($SPO), | ||||||
|     .D(D), .WCLK(WCLK), .WE(WE), |     .D(D), .WCLK(WCLK), .WE(WE), | ||||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), |     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), | ||||||
|     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) |     .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT6 spo (.A(\$SPO ), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO)); |   $__ABC9_LUT6 spo (.A($SPO), .S({A5, A4, A3, A2, A1, A0}), .Y(SPO)); | ||||||
|   \$__ABC9_LUT6 dpo (.A(\$DPO ), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); |   $__ABC9_LUT6 dpo (.A($DPO), .S({DPRA5, DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}), .Y(DPO)); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM128X1D ( | module RAM128X1D ( | ||||||
|  | @ -75,17 +433,17 @@ module RAM128X1D ( | ||||||
| ); | ); | ||||||
|   parameter INIT = 128'h0; |   parameter INIT = 128'h0; | ||||||
|   parameter IS_WCLK_INVERTED = 1'b0; |   parameter IS_WCLK_INVERTED = 1'b0; | ||||||
|   wire \$DPO , \$SPO ; |   wire $DPO, $SPO; | ||||||
|   RAM128X1D #( |   RAM128X1D #( | ||||||
|     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) |     .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .DPO(\$DPO ), .SPO(\$SPO ), |     .DPO($DPO), .SPO($SPO), | ||||||
|     .D(D), .WCLK(WCLK), .WE(WE), |     .D(D), .WCLK(WCLK), .WE(WE), | ||||||
|     .A(A), |     .A(A), | ||||||
|     .DPRA(DPRA) |     .DPRA(DPRA) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO)); |   $__ABC9_LUT7 spo (.A($SPO), .S(A), .Y(SPO)); | ||||||
|   \$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO)); |   $__ABC9_LUT7 dpo (.A($DPO), .S(DPRA), .Y(DPO)); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM32M ( | module RAM32M ( | ||||||
|  | @ -109,24 +467,24 @@ module RAM32M ( | ||||||
|   parameter [63:0] INIT_C = 64'h0000000000000000; |   parameter [63:0] INIT_C = 64'h0000000000000000; | ||||||
|   parameter [63:0] INIT_D = 64'h0000000000000000; |   parameter [63:0] INIT_D = 64'h0000000000000000; | ||||||
|   parameter [0:0] IS_WCLK_INVERTED = 1'b0; |   parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||||
|   wire [1:0] \$DOA , \$DOB , \$DOC , \$DOD ; |   wire [1:0] $DOA, $DOB, $DOC, $DOD; | ||||||
|   RAM32M #( |   RAM32M #( | ||||||
|     .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), |     .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), | ||||||
|     .IS_WCLK_INVERTED(IS_WCLK_INVERTED) |     .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ), |     .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD), | ||||||
|     .WCLK(WCLK), .WE(WE), |     .WCLK(WCLK), .WE(WE), | ||||||
|     .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), |     .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), | ||||||
|     .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) |     .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT6 doa0 (.A(\$DOA [0]), .S({1'b1, ADDRA}), .Y(DOA[0])); |   $__ABC9_LUT6 doa0 (.A($DOA[0]), .S({1'b1, ADDRA}), .Y(DOA[0])); | ||||||
|   \$__ABC9_LUT6 doa1 (.A(\$DOA [1]), .S({1'b1, ADDRA}), .Y(DOA[1])); |   $__ABC9_LUT6 doa1 (.A($DOA[1]), .S({1'b1, ADDRA}), .Y(DOA[1])); | ||||||
|   \$__ABC9_LUT6 dob0 (.A(\$DOB [0]), .S({1'b1, ADDRB}), .Y(DOB[0])); |   $__ABC9_LUT6 dob0 (.A($DOB[0]), .S({1'b1, ADDRB}), .Y(DOB[0])); | ||||||
|   \$__ABC9_LUT6 dob1 (.A(\$DOB [1]), .S({1'b1, ADDRB}), .Y(DOB[1])); |   $__ABC9_LUT6 dob1 (.A($DOB[1]), .S({1'b1, ADDRB}), .Y(DOB[1])); | ||||||
|   \$__ABC9_LUT6 doc0 (.A(\$DOC [0]), .S({1'b1, ADDRC}), .Y(DOC[0])); |   $__ABC9_LUT6 doc0 (.A($DOC[0]), .S({1'b1, ADDRC}), .Y(DOC[0])); | ||||||
|   \$__ABC9_LUT6 doc1 (.A(\$DOC [1]), .S({1'b1, ADDRC}), .Y(DOC[1])); |   $__ABC9_LUT6 doc1 (.A($DOC[1]), .S({1'b1, ADDRC}), .Y(DOC[1])); | ||||||
|   \$__ABC9_LUT6 dod0 (.A(\$DOD [0]), .S({1'b1, ADDRD}), .Y(DOD[0])); |   $__ABC9_LUT6 dod0 (.A($DOD[0]), .S({1'b1, ADDRD}), .Y(DOD[0])); | ||||||
|   \$__ABC9_LUT6 dod1 (.A(\$DOD [1]), .S({1'b1, ADDRD}), .Y(DOD[1])); |   $__ABC9_LUT6 dod1 (.A($DOD[1]), .S({1'b1, ADDRD}), .Y(DOD[1])); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module RAM64M ( | module RAM64M ( | ||||||
|  | @ -150,20 +508,20 @@ module RAM64M ( | ||||||
|   parameter [63:0] INIT_C = 64'h0000000000000000; |   parameter [63:0] INIT_C = 64'h0000000000000000; | ||||||
|   parameter [63:0] INIT_D = 64'h0000000000000000; |   parameter [63:0] INIT_D = 64'h0000000000000000; | ||||||
|   parameter [0:0] IS_WCLK_INVERTED = 1'b0; |   parameter [0:0] IS_WCLK_INVERTED = 1'b0; | ||||||
|   wire \$DOA , \$DOB , \$DOC , \$DOD ; |   wire $DOA, $DOB, $DOC, $DOD; | ||||||
|   RAM64M #( |   RAM64M #( | ||||||
|     .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), |     .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), | ||||||
|     .IS_WCLK_INVERTED(IS_WCLK_INVERTED) |     .IS_WCLK_INVERTED(IS_WCLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ), |     .DOA($DOA), .DOB($DOB), .DOC($DOC), .DOD($DOD), | ||||||
|     .WCLK(WCLK), .WE(WE), |     .WCLK(WCLK), .WE(WE), | ||||||
|     .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), |     .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), | ||||||
|     .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) |     .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT6 doa (.A(\$DOA ), .S(ADDRA), .Y(DOA)); |   $__ABC9_LUT6 doa (.A($DOA), .S(ADDRA), .Y(DOA)); | ||||||
|   \$__ABC9_LUT6 dob (.A(\$DOB ), .S(ADDRB), .Y(DOB)); |   $__ABC9_LUT6 dob (.A($DOB), .S(ADDRB), .Y(DOB)); | ||||||
|   \$__ABC9_LUT6 doc (.A(\$DOC ), .S(ADDRC), .Y(DOC)); |   $__ABC9_LUT6 doc (.A($DOC), .S(ADDRC), .Y(DOC)); | ||||||
|   \$__ABC9_LUT6 dod (.A(\$DOD ), .S(ADDRD), .Y(DOD)); |   $__ABC9_LUT6 dod (.A($DOD), .S(ADDRD), .Y(DOD)); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module SRL16E ( | module SRL16E ( | ||||||
|  | @ -172,14 +530,14 @@ module SRL16E ( | ||||||
| ); | ); | ||||||
|   parameter [15:0] INIT = 16'h0000; |   parameter [15:0] INIT = 16'h0000; | ||||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; |   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||||
|   wire \$Q ; |   wire $Q; | ||||||
|   SRL16E #( |   SRL16E #( | ||||||
|     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) |     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .Q(\$Q ), |     .Q($Q), | ||||||
|     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) |     .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); |   $__ABC9_LUT6 q (.A($Q), .S({1'b1, A3, A2, A1, A0, 1'b1}), .Y(Q)); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module SRLC32E ( | module SRLC32E ( | ||||||
|  | @ -190,14 +548,14 @@ module SRLC32E ( | ||||||
| ); | ); | ||||||
|   parameter [31:0] INIT = 32'h00000000; |   parameter [31:0] INIT = 32'h00000000; | ||||||
|   parameter [0:0] IS_CLK_INVERTED = 1'b0; |   parameter [0:0] IS_CLK_INVERTED = 1'b0; | ||||||
|   wire \$Q ; |   wire $Q; | ||||||
|   SRLC32E #( |   SRLC32E #( | ||||||
|     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) |     .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) | ||||||
|   ) _TECHMAP_REPLACE_ ( |   ) _TECHMAP_REPLACE_ ( | ||||||
|     .Q(\$Q ), .Q31(Q31), |     .Q($Q), .Q31(Q31), | ||||||
|     .A(A), .CE(CE), .CLK(CLK), .D(D) |     .A(A), .CE(CE), .CLK(CLK), .D(D) | ||||||
|   ); |   ); | ||||||
|   \$__ABC9_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q)); |   $__ABC9_LUT6 q (.A($Q), .S({1'b1, A}), .Y(Q)); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module DSP48E1 ( | module DSP48E1 ( | ||||||
|  |  | ||||||
|  | @ -30,7 +30,22 @@ module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1); | ||||||
|                 : (S0 ? I1 : I0); |                 : (S0 ? I1 : I0); | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| // Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} | module \$__ABC9_FF_ (input D, output Q); | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | // Box to emulate async behaviour of FDC* | ||||||
|  | (* abc9_box_id = 1000, lib_whitebox *) | ||||||
|  | module \$__ABC9_ASYNC0 (input A, S, output Y); | ||||||
|  |   assign Y = S ? 1'b0 : A; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | // Box to emulate async behaviour of FDP* | ||||||
|  | (* abc9_box_id = 1001, lib_whitebox *) | ||||||
|  | module \$__ABC9_ASYNC1 (input A, S, output Y); | ||||||
|  |   assign Y = S ? 1'b0 : A; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | // Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32} | ||||||
| //   Necessary since RAMD* and SRL* have both combinatorial (i.e. | //   Necessary since RAMD* and SRL* have both combinatorial (i.e. | ||||||
| //   same-cycle read operation) and sequential (write operation | //   same-cycle read operation) and sequential (write operation | ||||||
| //   is only committed on the next clock edge). | //   is only committed on the next clock edge). | ||||||
|  | @ -39,7 +54,7 @@ endmodule | ||||||
| (* abc9_box_id=2000 *) | (* abc9_box_id=2000 *) | ||||||
| module \$__ABC9_LUT6 (input A, input [5:0] S, output Y); | module \$__ABC9_LUT6 (input A, input [5:0] S, output Y); | ||||||
| endmodule | endmodule | ||||||
| // Box to emulate comb/seq behaviour of RAMD128 | // Box to emulate comb/seq behaviour of RAM128 | ||||||
| (* abc9_box_id=2001 *) | (* abc9_box_id=2001 *) | ||||||
| module \$__ABC9_LUT7 (input A, input [6:0] S, output Y); | module \$__ABC9_LUT7 (input A, input [6:0] S, output Y); | ||||||
| endmodule | endmodule | ||||||
|  |  | ||||||
|  | @ -20,6 +20,15 @@ | ||||||
| 
 | 
 | ||||||
| // ============================================================================ | // ============================================================================ | ||||||
| 
 | 
 | ||||||
|  | (* techmap_celltype = "$__ABC9_ASYNC0 $__ABC9_ASYNC1" *) | ||||||
|  | module $__ABC9_ASYNC01(input A, S, output Y); | ||||||
|  |   assign Y = A; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module $__ABC9_FF_(input D, output Q); | ||||||
|  |   assign Q = D; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
| module $__ABC9_LUT6(input A, input [5:0] S, output Y); | module $__ABC9_LUT6(input A, input [5:0] S, output Y); | ||||||
|   assign Y = A; |   assign Y = A; | ||||||
| endmodule | endmodule | ||||||
|  |  | ||||||
|  | @ -1,64 +1,142 @@ | ||||||
| # Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf | # Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf | ||||||
| #                 https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf | #                 https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf | ||||||
| 
 | 
 | ||||||
| # NB: Inputs/Outputs must be ordered alphabetically | # NB: Box inputs/outputs must each be in the same order | ||||||
| #     (with exceptions for carry in/out) | #     as their corresponding module definition | ||||||
|  | #     (with exceptions detailed below) | ||||||
| 
 | 
 | ||||||
| # Average across F7[AB]MUX | # Box 1 : MUXF7 | ||||||
| # Inputs: I0 I1 S0 | #   Max delays from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L451-L453 | ||||||
| # Outputs: O | # name ID w/b ins outs | ||||||
| MUXF7  1  1   3   1 | MUXF7  1  1   3   1 | ||||||
| 204 208 286 | #I0 I1  S0 | ||||||
|  | 204 208 286 # O | ||||||
| 
 | 
 | ||||||
| # Inputs: I0 I1 S0 | # Box 2 : MUXF8 | ||||||
| # Outputs: O | #   Max delays from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L462-L464 | ||||||
|  | # name ID w/b ins outs | ||||||
| MUXF8  2  1   3   1 | MUXF8  2  1   3   1 | ||||||
| 104 94 273 | #I0 I1 S0 | ||||||
|  | 104 94 273 # O | ||||||
| 
 | 
 | ||||||
| # Box containing MUXF7.[AB] + MUXF8, | # Box 3 : $__MUXF78 | ||||||
| #   Necessary to make these an atomic unit so that | #         (private cell used to preserve 2xMUXF7 + 1xMUXF8 | ||||||
| #   ABC cannot optimise just one of the MUXF7 away | #          an atomic unit so that ABC cannot optimise just | ||||||
| #   and expect to save on its delay | #          one of the MUXF7 away and expect to save on its | ||||||
| # Inputs: I0 I1 I2 I3 S0 S1 | #          delay, since MUXF8 is only reachable through an | ||||||
| # Outputs: O | #          MUXF7) | ||||||
|  | # name    ID w/b ins outs | ||||||
| $__MUXF78 3  1   6   1 | $__MUXF78 3  1   6   1 | ||||||
| 294 297 311 317 390 273 | #I0 I1  I2  I3  S0  S1 | ||||||
|  | 294 297 311 317 390 273 # O | ||||||
| 
 | 
 | ||||||
| # CARRY4 + CARRY4_[ABCD]X | # Box 4 : CARRY4 + CARRY4_[ABCD]X | ||||||
| # Inputs: CYINIT DI0 DI1 DI2 DI3 S0 S1 S2 S3 CI | #   (Exception: carry chain input/output must be the | ||||||
| # Outputs:  O0 O1 O2 O3 CO0 CO1 CO2 CO3 | #        last input and output and the entire bus has been | ||||||
| #   (NB: carry chain input/output must be last |  | ||||||
| #        input/output and the entire bus has been |  | ||||||
| #        moved there overriding the otherwise | #        moved there overriding the otherwise | ||||||
| #        alphabetical ordering) | #        alphabetical ordering) | ||||||
|  | #   Max delays from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L11-L46 | ||||||
|  | # name ID w/b ins outs | ||||||
| CARRY4 4  1   10  8 | CARRY4 4  1   10  8 | ||||||
| 482 -   -   -   -   223 -   -   -   222 | #CYINIT DI0 DI1 DI2 DI3 S0  S1  S2  S3  CI | ||||||
| 598 407 -   -   -   400 205 -   -   334 | 482     -   -   -   -   223 -   -   -   222 # O0 | ||||||
| 584 556 537 -   -   523 558 226 -   239 | 598     407 -   -   -   400 205 -   -   334 # O1 | ||||||
| 642 615 596 438 -   582 618 330 227 313 | 584     556 537 -   -   523 558 226 -   239 # O2 | ||||||
| 536 379 -   -   -   340 -   -   -   271 | 642     615 596 438 -   582 618 330 227 313 # O3 | ||||||
| 494 465 445 -   -   433 469 -   -   157 | 536     379 -   -   -   340 -   -   -   271 # CO0 | ||||||
| 592 540 520 356 -   512 548 292 -   228 | 494     465 445 -   -   433 469 -   -   157 # CO1 | ||||||
| 580 526 507 398 385 508 528 378 380 114 | 592     540 520 356 -   512 548 292 -   228 # CO2 | ||||||
|  | 580     526 507 398 385 508 528 378 380 114 # CO3 | ||||||
| 
 | 
 | ||||||
|  | # Box 1000 : $__ABC9_ASYNC0 | ||||||
|  | #            (private cell to emulate async behaviour of FDC*) | ||||||
|  | # name         ID   w/b ins outs | ||||||
|  | $__ABC9_ASYNC0 1000 1   2   1 | ||||||
|  | #A S | ||||||
|  | 0  764 # Y | ||||||
|  | 
 | ||||||
|  | # Box 1001 : $__ABC9_ASYNC1 | ||||||
|  | #            (private cell to emulate async behaviour of FDP*) | ||||||
|  | # name         ID   w/b ins outs | ||||||
|  | $__ABC9_ASYNC1 1001 1   2   1 | ||||||
|  | #A S | ||||||
|  | 0  764 # Y | ||||||
|  | 
 | ||||||
|  | # Flop boxes: | ||||||
|  | # * Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251 | ||||||
|  | #                   https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277 | ||||||
|  | # * Exception: $abc9_currQ is a special input (located last) necessary for clock-enable functionality | ||||||
|  | 
 | ||||||
|  | # Box 1100 : FDRE | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDRE   1100 1   5   1 | ||||||
|  | #C CE  D   R   $abc9_currQ | ||||||
|  | #0 109 -46 404 0 | ||||||
|  | 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1101 : FDRE_1 | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDRE_1 1101 1   5   1 | ||||||
|  | #C CE  D   R   $abc9_currQ | ||||||
|  | #0 109 -46 404 0 | ||||||
|  | 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1102 : FDSE | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDSE   1102 1   5   1 | ||||||
|  | #C CE  D   R   $abc9_currQ | ||||||
|  | #0 109 -46 404 0 | ||||||
|  | 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1103 : FDSE_1 | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDSE_1 1103 1   5   1 | ||||||
|  | #C CE  D   R   $abc9_currQ | ||||||
|  | #0 109 -46 404 0 | ||||||
|  | 0 109 0   404 0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1104 : FDCE | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDCE   1104 1   5   1 | ||||||
|  | #C CE  CLR D   $abc9_currQ | ||||||
|  | #0 109 764 -46 0 | ||||||
|  | 0 109 764 0   0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1105 : FDCE_1 | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDCE_1 1105 1   5   1 | ||||||
|  | #C CE  CLR D   $abc9_currQ | ||||||
|  | #0 109 764 -46 0 | ||||||
|  | 0 109 764 0   0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1106 : FDPE | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDPE   1106 1   5   1 | ||||||
|  | #C CE  D   PRE $abc9_currQ | ||||||
|  | #0 109 -46 764 0 | ||||||
|  | 0 109 0   764 0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 1107 : FDPE_1 | ||||||
|  | # name ID   w/b ins outs | ||||||
|  | FDPE_1 1107 1   5   1 | ||||||
|  | #C CE  D   PRE $abc9_currQ | ||||||
|  | #0 109 -46 764 0 | ||||||
|  | 0 109 0   764 0 # Q (-46ps Tsu clamped to 0) | ||||||
|  | 
 | ||||||
|  | # Box 2000 : $__ABC9_LUT6 | ||||||
|  | #            (private cell to emulate async behaviour of LUTRAMs) | ||||||
| # SLICEM/A6LUT | # SLICEM/A6LUT | ||||||
| # Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} | # name       ID   w/b ins outs | ||||||
| #   Necessary since RAMD* and SRL* have both combinatorial (i.e. |  | ||||||
| #   same-cycle read operation) and sequential (write operation |  | ||||||
| #   is only committed on the next clock edge). |  | ||||||
| #   To model the combinatorial path, such cells have to be split |  | ||||||
| #   into comb and seq parts, with this box modelling only the former. |  | ||||||
| # Inputs: A S0 S1 S2 S3 S4 S5 |  | ||||||
| # Outputs: Y |  | ||||||
| $__ABC9_LUT6 2000 0   7   1 | $__ABC9_LUT6 2000 0   7   1 | ||||||
| 0 642 631 472 407 238 127 | #A S0  S1  S2  S3  S4  S5 | ||||||
|  | 0  642 631 472 407 238 127 # Y | ||||||
| 
 | 
 | ||||||
| # SLICEM/A6LUT + F7BMUX | # Box 2001 : $__ABC9_LUT6 | ||||||
| # Box to emulate comb/seq behaviour of RAMD128 | #            (private cell to emulate async behaviour of LUITRAMs) | ||||||
| # Inputs: A S0 S1 S2 S3 S4 S5 S6 | # name       ID   w/b ins outs | ||||||
| # Outputs: DPO SPO |  | ||||||
| $__ABC9_LUT7 2001 0 8 1 | $__ABC9_LUT7 2001 0 8 1 | ||||||
| 0 1047 1036 877 812 643 532 478 | #A S0   S1   S2  S3  S4  S5  S6 | ||||||
|  | 0  1047 1036 877 812 643 532 478 # Y | ||||||
| 
 | 
 | ||||||
| # Boxes used to represent the comb behaviour of various modes | # Boxes used to represent the comb behaviour of various modes | ||||||
| #   of DSP48E1 | #   of DSP48E1 | ||||||
|  |  | ||||||
|  | @ -325,6 +325,7 @@ 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 *) | ||||||
| module FDRE ( | module FDRE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|  | @ -348,6 +349,20 @@ module FDRE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | (* abc9_box_id=1101, lib_whitebox, abc9_flop *) | ||||||
|  | module FDRE_1 ( | ||||||
|  |   (* abc9_arrival=303 *) | ||||||
|  |   output reg Q, | ||||||
|  |   (* clkbuf_sink *) | ||||||
|  |   input C, | ||||||
|  |   input CE, D, R | ||||||
|  | ); | ||||||
|  |   parameter [0:0] INIT = 1'b0; | ||||||
|  |   initial Q <= INIT; | ||||||
|  |   always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | (* abc9_box_id=1102, lib_whitebox, abc9_flop *) | ||||||
| module FDSE ( | module FDSE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|  | @ -371,6 +386,19 @@ module FDSE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | (* abc9_box_id=1103, lib_whitebox, abc9_flop *) | ||||||
|  | module FDSE_1 ( | ||||||
|  |   (* abc9_arrival=303 *) | ||||||
|  |   output reg Q, | ||||||
|  |   (* clkbuf_sink *) | ||||||
|  |   input C, | ||||||
|  |   input CE, D, S | ||||||
|  | ); | ||||||
|  |   parameter [0:0] INIT = 1'b1; | ||||||
|  |   initial Q <= INIT; | ||||||
|  |   always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
| module FDRSE ( | module FDRSE ( | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|  | @ -406,6 +434,7 @@ module FDRSE ( | ||||||
|       Q <= d; |       Q <= d; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | (* abc9_box_id=1104, lib_whitebox, abc9_flop *) | ||||||
| module FDCE ( | module FDCE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|  | @ -413,10 +442,10 @@ module FDCE ( | ||||||
|   (* invertible_pin = "IS_C_INVERTED" *) |   (* invertible_pin = "IS_C_INVERTED" *) | ||||||
|   input C, |   input C, | ||||||
|   input CE, |   input CE, | ||||||
|   (* invertible_pin = "IS_D_INVERTED" *) |  | ||||||
|   input D, |  | ||||||
|   (* invertible_pin = "IS_CLR_INVERTED" *) |   (* invertible_pin = "IS_CLR_INVERTED" *) | ||||||
|   input CLR |   input CLR, | ||||||
|  |   (* invertible_pin = "IS_D_INVERTED" *) | ||||||
|  |   input D | ||||||
| ); | ); | ||||||
|   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; | ||||||
|  | @ -431,6 +460,20 @@ module FDCE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | (* abc9_box_id=1105, lib_whitebox, abc9_flop *) | ||||||
|  | module FDCE_1 ( | ||||||
|  |   (* abc9_arrival=303 *) | ||||||
|  |   output reg Q, | ||||||
|  |   (* clkbuf_sink *) | ||||||
|  |   input C, | ||||||
|  |   input CE, D, CLR | ||||||
|  | ); | ||||||
|  |   parameter [0:0] INIT = 1'b0; | ||||||
|  |   initial Q <= INIT; | ||||||
|  |   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | (* abc9_box_id=1106, lib_whitebox, abc9_flop *) | ||||||
| module FDPE ( | module FDPE ( | ||||||
|   (* abc9_arrival=303 *) |   (* abc9_arrival=303 *) | ||||||
|   output reg Q, |   output reg Q, | ||||||
|  | @ -456,6 +499,19 @@ module FDPE ( | ||||||
|   endcase endgenerate |   endcase endgenerate | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
|  | (* abc9_box_id=1107, lib_whitebox, abc9_flop *) | ||||||
|  | module FDPE_1 ( | ||||||
|  |   (* abc9_arrival=303 *) | ||||||
|  |   output reg Q, | ||||||
|  |   (* clkbuf_sink *) | ||||||
|  |   input C, | ||||||
|  |   input CE, D, PRE | ||||||
|  | ); | ||||||
|  |   parameter [0:0] INIT = 1'b1; | ||||||
|  |   initial Q <= INIT; | ||||||
|  |   always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
| module FDCPE ( | module FDCPE ( | ||||||
|   output wire Q, |   output wire Q, | ||||||
|   (* clkbuf_sink *) |   (* clkbuf_sink *) | ||||||
|  | @ -501,54 +557,6 @@ module FDCPE ( | ||||||
|   assign Q = qs ? qp : qc; |   assign Q = qs ? qp : qc; | ||||||
| endmodule | endmodule | ||||||
| 
 | 
 | ||||||
| module FDRE_1 ( |  | ||||||
|   (* abc9_arrival=303 *) |  | ||||||
|   output reg Q, |  | ||||||
|   (* clkbuf_sink *) |  | ||||||
|   input C, |  | ||||||
|   input CE, D, R |  | ||||||
| ); |  | ||||||
|   parameter [0:0] INIT = 1'b0; |  | ||||||
|   initial Q <= INIT; |  | ||||||
|   always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; |  | ||||||
| endmodule |  | ||||||
| 
 |  | ||||||
| module FDSE_1 ( |  | ||||||
|   (* abc9_arrival=303 *) |  | ||||||
|   output reg Q, |  | ||||||
|   (* clkbuf_sink *) |  | ||||||
|   input C, |  | ||||||
|   input CE, D, S |  | ||||||
| ); |  | ||||||
|   parameter [0:0] INIT = 1'b1; |  | ||||||
|   initial Q <= INIT; |  | ||||||
|   always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; |  | ||||||
| endmodule |  | ||||||
| 
 |  | ||||||
| module FDCE_1 ( |  | ||||||
|   (* abc9_arrival=303 *) |  | ||||||
|   output reg Q, |  | ||||||
|   (* clkbuf_sink *) |  | ||||||
|   input C, |  | ||||||
|   input CE, D, CLR |  | ||||||
| ); |  | ||||||
|   parameter [0:0] INIT = 1'b0; |  | ||||||
|   initial Q <= INIT; |  | ||||||
|   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; |  | ||||||
| endmodule |  | ||||||
| 
 |  | ||||||
| module FDPE_1 ( |  | ||||||
|   (* abc9_arrival=303 *) |  | ||||||
|   output reg Q, |  | ||||||
|   (* clkbuf_sink *) |  | ||||||
|   input C, |  | ||||||
|   input CE, D, PRE |  | ||||||
| ); |  | ||||||
|   parameter [0:0] INIT = 1'b1; |  | ||||||
|   initial Q <= INIT; |  | ||||||
|   always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; |  | ||||||
| endmodule |  | ||||||
| 
 |  | ||||||
| module LDCE ( | module LDCE ( | ||||||
|   output reg Q, |   output reg Q, | ||||||
|   (* invertible_pin = "IS_CLR_INVERTED" *) |   (* invertible_pin = "IS_CLR_INVERTED" *) | ||||||
|  | @ -2388,8 +2396,8 @@ module DSP48E1 ( | ||||||
|                     if (CEB2) Br2 <= Br1; |                     if (CEB2) Br2 <= Br1; | ||||||
|                 end |                 end | ||||||
|         end else if (BREG == 1) begin |         end else if (BREG == 1) begin | ||||||
|             //initial Br1 = 25'b0; |             //initial Br1 = 18'b0; | ||||||
|             initial Br2 = 25'b0; |             initial Br2 = 18'b0; | ||||||
|             always @(posedge CLK) |             always @(posedge CLK) | ||||||
|                 if (RSTB) begin |                 if (RSTB) begin | ||||||
|                     Br1 <= 18'b0; |                     Br1 <= 18'b0; | ||||||
|  | @ -2436,7 +2444,7 @@ module DSP48E1 ( | ||||||
|     endgenerate |     endgenerate | ||||||
| 
 | 
 | ||||||
|     // A/D input selection and pre-adder |     // A/D input selection and pre-adder | ||||||
|     wire signed [29:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2; |     wire signed [24:0] Ar12_muxed = INMODEr[0] ? Ar1 : Ar2; | ||||||
|     wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed; |     wire signed [24:0] Ar12_gated = INMODEr[1] ? 25'b0 : Ar12_muxed; | ||||||
|     wire signed [24:0] Dr_gated   = INMODEr[2] ? Dr : 25'b0; |     wire signed [24:0] Dr_gated   = INMODEr[2] ? Dr : 25'b0; | ||||||
|     wire signed [24:0] AD_result  = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated); |     wire signed [24:0] AD_result  = INMODEr[3] ? (Dr_gated - Ar12_gated) : (Dr_gated + Ar12_gated); | ||||||
|  |  | ||||||
|  | @ -107,8 +107,12 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 		log("    -flatten\n"); | 		log("    -flatten\n"); | ||||||
| 		log("        flatten design before synthesis\n"); | 		log("        flatten design before synthesis\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    -dff\n"); | ||||||
|  | 		log("        run 'abc'/'abc9' with -dff option\n"); | ||||||
|  | 		log("\n"); | ||||||
| 		log("    -retime\n"); | 		log("    -retime\n"); | ||||||
| 		log("        run 'abc' with '-dff -D 1' options\n"); | 		log("        run 'abc' with '-D 1' option to enable flip-flop retiming.\n"); | ||||||
|  | 		log("        implies -dff.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -abc9\n"); | 		log("    -abc9\n"); | ||||||
| 		log("        use new ABC9 flow (EXPERIMENTAL)\n"); | 		log("        use new ABC9 flow (EXPERIMENTAL)\n"); | ||||||
|  | @ -120,7 +124,8 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	std::string top_opt, edif_file, blif_file, family; | 	std::string top_opt, edif_file, blif_file, family; | ||||||
| 	bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9; | 	bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram; | ||||||
|  | 	bool abc9, dff_mode; | ||||||
| 	bool flatten_before_abc; | 	bool flatten_before_abc; | ||||||
| 	int widemux; | 	int widemux; | ||||||
| 
 | 
 | ||||||
|  | @ -145,6 +150,7 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 		nodsp = false; | 		nodsp = false; | ||||||
| 		uram = false; | 		uram = false; | ||||||
| 		abc9 = false; | 		abc9 = false; | ||||||
|  | 		dff_mode = false; | ||||||
| 		flatten_before_abc = false; | 		flatten_before_abc = false; | ||||||
| 		widemux = 0; | 		widemux = 0; | ||||||
| 	} | 	} | ||||||
|  | @ -190,6 +196,7 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (args[argidx] == "-retime") { | 			if (args[argidx] == "-retime") { | ||||||
|  | 				dff_mode = true; | ||||||
| 				retime = true; | 				retime = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | @ -252,6 +259,10 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 				uram = true; | 				uram = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-dff") { | ||||||
|  | 				dff_mode = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
|  | @ -287,10 +298,11 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 			ff_map_file = "+/xilinx/xc7_ff_map.v"; | 			ff_map_file = "+/xilinx/xc7_ff_map.v"; | ||||||
| 
 | 
 | ||||||
| 		if (check_label("begin")) { | 		if (check_label("begin")) { | ||||||
|  | 			std::string read_args; | ||||||
| 			if (vpr) | 			if (vpr) | ||||||
| 				run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); | 				read_args += " -D_EXPLICIT_CARRY"; | ||||||
| 			else | 			read_args += " -lib +/xilinx/cells_sim.v"; | ||||||
| 				run("read_verilog -lib +/xilinx/cells_sim.v"); | 			run("read_verilog" + read_args); | ||||||
| 
 | 
 | ||||||
| 			run("read_verilog -lib +/xilinx/cells_xtra.v"); | 			run("read_verilog -lib +/xilinx/cells_xtra.v"); | ||||||
| 
 | 
 | ||||||
|  | @ -532,12 +544,15 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 			if (flatten_before_abc) | 			if (flatten_before_abc) | ||||||
| 				run("flatten"); | 				run("flatten"); | ||||||
| 			if (help_mode) | 			if (help_mode) | ||||||
| 				run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut'; option for '-retime')"); | 				run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for 'nowidelut', '-dff', '-retime')"); | ||||||
| 			else if (abc9) { | 			else if (abc9) { | ||||||
| 				if (family != "xc7") | 				if (family != "xc7") | ||||||
| 					log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " | 					log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, " | ||||||
| 							"will use timing for 'xc7' instead.\n", family.c_str()); | 							"will use timing for 'xc7' instead.\n", family.c_str()); | ||||||
| 				run("techmap -map +/xilinx/abc9_map.v -max_iter 1"); | 				std::string techmap_args = "-map +/xilinx/abc9_map.v -max_iter 1"; | ||||||
|  | 				if (dff_mode) | ||||||
|  | 					techmap_args += " -D DFF_MODE"; | ||||||
|  | 				run("techmap " + techmap_args); | ||||||
| 				run("read_verilog -icells -lib +/xilinx/abc9_model.v"); | 				run("read_verilog -icells -lib +/xilinx/abc9_model.v"); | ||||||
| 				std::string abc9_opts = " -box +/xilinx/abc9_xc7.box"; | 				std::string abc9_opts = " -box +/xilinx/abc9_xc7.box"; | ||||||
| 				abc9_opts += stringf(" -W %d", XC7_WIRE_DELAY); | 				abc9_opts += stringf(" -W %d", XC7_WIRE_DELAY); | ||||||
|  | @ -545,13 +560,22 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 					abc9_opts += " -lut +/xilinx/abc9_xc7_nowide.lut"; | 					abc9_opts += " -lut +/xilinx/abc9_xc7_nowide.lut"; | ||||||
| 				else | 				else | ||||||
| 					abc9_opts += " -lut +/xilinx/abc9_xc7.lut"; | 					abc9_opts += " -lut +/xilinx/abc9_xc7.lut"; | ||||||
|  | 				if (dff_mode) | ||||||
|  | 					abc9_opts += " -dff"; | ||||||
| 				run("abc9" + abc9_opts); | 				run("abc9" + abc9_opts); | ||||||
|  | 				run("techmap -map +/xilinx/abc9_unmap.v"); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
|  | 				std::string abc_opts; | ||||||
| 				if (nowidelut) | 				if (nowidelut) | ||||||
| 					run("abc -luts 2:2,3,6:5" + string(retime ? " -dff -D 1" : "")); | 					abc_opts += " -luts 2:2,3,6:5"; | ||||||
| 				else | 				else | ||||||
| 					run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff -D 1" : "")); | 					abc_opts += " -luts 2:2,3,6:5,10,20"; | ||||||
|  | 				if (dff_mode) | ||||||
|  | 					abc_opts += " -dff"; | ||||||
|  | 				if (retime) | ||||||
|  | 					abc_opts += " -D 1"; | ||||||
|  | 				run("abc" + abc_opts); | ||||||
| 			} | 			} | ||||||
| 			run("clean"); | 			run("clean"); | ||||||
| 
 | 
 | ||||||
|  | @ -561,14 +585,11 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 				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) | ||||||
| 				techmap_args += " [-map " + ff_map_file + "]"; | 				techmap_args += stringf("[-map %s]", ff_map_file.c_str()); | ||||||
| 			else if (abc9) | 			else if (!abc9) | ||||||
| 				techmap_args += " -map +/xilinx/abc9_unmap.v"; | 				techmap_args += stringf(" -map %s", ff_map_file.c_str()); | ||||||
| 			else | 			run("techmap " + techmap_args, "(only if '-abc9')"); | ||||||
| 				techmap_args += " -map " + ff_map_file; |  | ||||||
| 			run("techmap " + techmap_args); |  | ||||||
| 			run("xilinx_dffopt"); | 			run("xilinx_dffopt"); | ||||||
| 			run("clean"); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("finalize")) { | 		if (check_label("finalize")) { | ||||||
|  | @ -576,6 +597,7 @@ struct SynthXilinxPass : public ScriptPass | ||||||
| 				run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')"); | 				run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')"); | ||||||
| 			if (help_mode || ise) | 			if (help_mode || ise) | ||||||
| 				run("extractinv -inv INV O:I", "(only if '-ise')"); | 				run("extractinv -inv INV O:I", "(only if '-ise')"); | ||||||
|  | 			run("clean"); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (check_label("check")) { | 		if (check_label("check")) { | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ design -import gold -as gold | ||||||
| design -import gate -as gate | 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 -seq 16 miter | sat -verify -prove-asserts -show-ports -seq 16 miter | ||||||
| " | " -l ${aag}.log | ||||||
| done | done | ||||||
| 
 | 
 | ||||||
| for aig in *.aig; do | for aig in *.aig; do | ||||||
|  | @ -50,5 +50,5 @@ design -import gold -as gold | ||||||
| design -import gate -as gate | 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 -seq 16 miter | sat -verify -prove-asserts -show-ports -seq 16 miter | ||||||
| " | " -l ${aig}.log | ||||||
| done | done | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								tests/aiger/symbols.aag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/aiger/symbols.aag
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | aag 2 1 1 1 0 | ||||||
|  | 2 | ||||||
|  | 4 2 1 | ||||||
|  | 4 | ||||||
|  | i0 d | ||||||
|  | l0 q | ||||||
|  | o0 q | ||||||
|  | c | ||||||
|  | Generated by Yosys 0.9+932 (git sha1 baba33fb, clang 9.0.0-2 -fPIC -Os) | ||||||
							
								
								
									
										8
									
								
								tests/aiger/symbols.aig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								tests/aiger/symbols.aig
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | aig 2 1 1 1 0 | ||||||
|  | 2 1 | ||||||
|  | 4 | ||||||
|  | i0 d | ||||||
|  | l0 q | ||||||
|  | o0 q | ||||||
|  | c | ||||||
|  | Generated by Yosys 0.9+932 (git sha1 baba33fb, clang 9.0.0-2 -fPIC -Os) | ||||||
							
								
								
									
										32
									
								
								tests/arch/xilinx/abc9_dff.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tests/arch/xilinx/abc9_dff.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | read_verilog <<EOT | ||||||
|  | module top(input C, D, output [7:0] Q); | ||||||
|  | FDRE   fd1(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[0])); | ||||||
|  | FDSE   fd2(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[1])); | ||||||
|  | FDCE   fd3(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[2])); | ||||||
|  | FDPE   fd4(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[3])); | ||||||
|  | FDRE_1 fd5(.C(C), .CE(1'b1), .D(D), .R(1'b1), .Q(Q[4])); | ||||||
|  | FDSE_1 fd6(.C(C), .CE(1'b1), .D(D), .S(1'b1), .Q(Q[5])); | ||||||
|  | FDCE_1 fd7(.C(C), .CE(1'b1), .D(D), .CLR(1'b1), .Q(Q[6])); | ||||||
|  | FDPE_1 fd8(.C(C), .CE(1'b1), .D(D), .PRE(1'b1), .Q(Q[7])); | ||||||
|  | endmodule | ||||||
|  | EOT | ||||||
|  | equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf | ||||||
|  | design -load postopt | ||||||
|  | select -assert-none t:FD* | ||||||
|  | 
 | ||||||
|  | design -reset | ||||||
|  | read_verilog <<EOT | ||||||
|  | module top(input C, D, output [7:0] Q); | ||||||
|  | FDRE   fd1(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[0])); | ||||||
|  | FDSE   fd2(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[1])); | ||||||
|  | FDCE   fd3(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[2])); | ||||||
|  | FDPE   fd4(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[3])); | ||||||
|  | FDRE_1 fd5(.C(C), .CE(1'b0), .D(D), .R(1'b0), .Q(Q[4])); | ||||||
|  | FDSE_1 fd6(.C(C), .CE(1'b0), .D(D), .S(1'b0), .Q(Q[5])); | ||||||
|  | FDCE_1 fd7(.C(C), .CE(1'b0), .D(D), .CLR(1'b0), .Q(Q[6])); | ||||||
|  | FDPE_1 fd8(.C(C), .CE(1'b0), .D(D), .PRE(1'b0), .Q(Q[7])); | ||||||
|  | endmodule | ||||||
|  | EOT | ||||||
|  | equiv_opt -assert -multiclock -map +/xilinx/cells_sim.v synth_xilinx -abc9 -dff -noiopad -noclkbuf | ||||||
|  | design -load postopt | ||||||
|  | select -assert-none t:FD* | ||||||
							
								
								
									
										91
									
								
								tests/arch/xilinx/abc9_map.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								tests/arch/xilinx/abc9_map.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | ||||||
|  | read_verilog <<EOT | ||||||
|  | module top(input C, CE, D, R, output [1:0] Q); | ||||||
|  | FDRE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[0])); | ||||||
|  | FDRE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[1])); | ||||||
|  | endmodule | ||||||
|  | EOT | ||||||
|  | design -save gold | ||||||
|  | 
 | ||||||
|  | techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE | ||||||
|  | techmap -map +/xilinx/abc9_unmap.v | ||||||
|  | select -assert-count 1 t:FDSE | ||||||
|  | select -assert-count 1 t:FDSE_1 | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | 
 | ||||||
|  | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
|  | sat -seq 2 -verify -prove-asserts -show-ports miter | ||||||
|  | 
 | ||||||
|  | design -reset | ||||||
|  | read_verilog <<EOT | ||||||
|  | module top(input C, CE, D, S, output [1:0] Q); | ||||||
|  | FDSE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[0])); | ||||||
|  | FDSE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[1])); | ||||||
|  | endmodule | ||||||
|  | EOT | ||||||
|  | design -save gold | ||||||
|  | 
 | ||||||
|  | techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE | ||||||
|  | techmap -map +/xilinx/abc9_unmap.v | ||||||
|  | select -assert-count 1 t:FDRE | ||||||
|  | select -assert-count 1 t:FDRE_1 | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | 
 | ||||||
|  | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
|  | sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter | ||||||
|  | 
 | ||||||
|  | design -reset | ||||||
|  | read_verilog <<EOT | ||||||
|  | module top(input C, CE, D, PRE, output [1:0] Q); | ||||||
|  | FDPE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[0])); | ||||||
|  | FDPE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[1])); | ||||||
|  | endmodule | ||||||
|  | EOT | ||||||
|  | design -save gold | ||||||
|  | 
 | ||||||
|  | techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE | ||||||
|  | techmap -map +/xilinx/abc9_unmap.v | ||||||
|  | select -assert-count 1 t:FDCE | ||||||
|  | select -assert-count 1 t:FDCE_1 | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | clk2fflogic | ||||||
|  | 
 | ||||||
|  | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
|  | sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter | ||||||
|  | 
 | ||||||
|  | design -reset | ||||||
|  | read_verilog <<EOT | ||||||
|  | module top(input C, CE, D, CLR, output [1:0] Q); | ||||||
|  | FDCE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[0])); | ||||||
|  | FDCE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[1])); | ||||||
|  | endmodule | ||||||
|  | EOT | ||||||
|  | design -save gold | ||||||
|  | 
 | ||||||
|  | techmap -map +/xilinx/abc9_map.v -max_iter 1 -D DFF_MODE | ||||||
|  | techmap -map +/xilinx/abc9_unmap.v | ||||||
|  | select -assert-count 1 t:FDPE | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | techmap -autoproc -map +/xilinx/cells_sim.v | ||||||
|  | clk2fflogic | ||||||
|  | 
 | ||||||
|  | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
|  | sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter | ||||||
|  | @ -264,3 +264,30 @@ always @* | ||||||
|   if (en) |   if (en) | ||||||
|     q <= d; |     q <= d; | ||||||
| endmodule | endmodule | ||||||
|  | 
 | ||||||
|  | module abc9_test031(input clk1, clk2, d, output reg q1, q2); | ||||||
|  | always @(posedge clk1) q1 <= d; | ||||||
|  | always @(negedge clk2) q2 <= q1; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module abc9_test032(input clk, d, r, output reg q); | ||||||
|  | always @(posedge clk or posedge r) | ||||||
|  |     if (r) q <= 1'b0; | ||||||
|  |     else q <= d; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module abc9_test033(input clk, d, r, output reg q); | ||||||
|  | always @(negedge clk or posedge r) | ||||||
|  |     if (r) q <= 1'b1; | ||||||
|  |     else q <= d; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module abc9_test034(input clk, d, output reg q1, q2); | ||||||
|  | always @(posedge clk) q1 <= d; | ||||||
|  | always @(posedge clk) q2 <= q1; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module abc9_test035(input clk, d, output reg [1:0] q); | ||||||
|  | always @(posedge clk) q[0] <= d; | ||||||
|  | always @(negedge clk) q[1] <= q[0]; | ||||||
|  | endmodule | ||||||
|  |  | ||||||
|  | @ -20,10 +20,12 @@ fi | ||||||
| cp ../simple/*.v . | cp ../simple/*.v . | ||||||
| cp ../simple/*.sv . | cp ../simple/*.sv . | ||||||
| DOLLAR='?' | DOLLAR='?' | ||||||
| exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p '\ | exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p '\ | ||||||
|     hierarchy; \ |     hierarchy; \ | ||||||
|     synth -run coarse; \ |     synth -run coarse; \ | ||||||
|     opt -full; \ |     opt -full; \ | ||||||
|     techmap; abc9 -lut 4 -box ../abc.box; \ |     techmap; \ | ||||||
|  |     abc9 -lut 4 -box ../abc.box; \ | ||||||
|  |     clean; \ | ||||||
|     check -assert; \ |     check -assert; \ | ||||||
|     select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'" |     select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'" | ||||||
|  |  | ||||||
|  | @ -9,3 +9,10 @@ wire w; | ||||||
| unknown u(~i, w); | unknown u(~i, w); | ||||||
| unknown2 u2(w, o); | unknown2 u2(w, o); | ||||||
| endmodule | endmodule | ||||||
|  | 
 | ||||||
|  | module abc9_test032(input clk, d, r, output reg q); | ||||||
|  | initial q = 1'b0; | ||||||
|  | always @(negedge clk or negedge r) | ||||||
|  |     if (!r) q <= 1'b0; | ||||||
|  |     else q <= d; | ||||||
|  | endmodule | ||||||
|  |  | ||||||
|  | @ -22,3 +22,19 @@ abc9 -lut 4 | ||||||
| select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i | 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 | ||||||
|  | hierarchy -top abc9_test032 | ||||||
|  | proc | ||||||
|  | clk2fflogic | ||||||
|  | design -save gold | ||||||
|  | 
 | ||||||
|  | abc9 -lut 4 | ||||||
|  | check | ||||||
|  | design -stash gate | ||||||
|  | 
 | ||||||
|  | design -import gold -as gold | ||||||
|  | design -import gate -as gate | ||||||
|  | 
 | ||||||
|  | miter -equiv -flatten -make_assert -make_outputs gold gate miter | ||||||
|  | sat -seq 10 -verify -prove-asserts -show-ports miter | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue