diff options
| -rw-r--r-- | backends/aiger/xaiger.cc | 37 | ||||
| -rw-r--r-- | passes/techmap/abc9.cc | 22 | ||||
| -rw-r--r-- | passes/techmap/abc9_exe.cc | 13 | ||||
| -rw-r--r-- | passes/techmap/abc9_ops.cc | 360 | ||||
| -rw-r--r-- | techlibs/xilinx/abc9_model.v | 5 | ||||
| -rw-r--r-- | techlibs/xilinx/abc9_xc7.box | 61 | ||||
| -rw-r--r-- | techlibs/xilinx/cells_sim.v | 338 | ||||
| -rw-r--r-- | techlibs/xilinx/cells_xtra.py | 40 | ||||
| -rw-r--r-- | techlibs/xilinx/cells_xtra.v | 16 | 
9 files changed, 669 insertions, 223 deletions
| diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 93e0ebc8c..d934a9aa9 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -184,6 +184,7 @@ struct XAigerWriter  				}  			} +		std::vector<int> arrivals;  		for (auto cell : module->cells()) {  			if (cell->type == "$_NOT_")  			{ @@ -223,13 +224,15 @@ struct XAigerWriter  			}  			RTLIL::Module* inst_module = module->design->module(cell->type); -			if (inst_module) { +			if (inst_module && inst_module->get_blackbox_attribute()) {  				auto it = cell->attributes.find("\\abc9_box_seq");  				if (it != cell->attributes.end()) {  					int abc9_box_seq = it->second.as_int();  					if (GetSize(box_list) <= abc9_box_seq)  						box_list.resize(abc9_box_seq+1);  					box_list[abc9_box_seq] = cell; +					// Only flop boxes may have arrival times +					//   (all others are combinatorial)  					if (!inst_module->get_bool_attribute("\\abc9_flop"))  						continue;  				} @@ -237,16 +240,32 @@ struct XAigerWriter  				for (const auto &conn : cell->connections()) {  					auto port_wire = inst_module->wire(conn.first);  					if (port_wire->port_output) { -						int arrival = 0; +						arrivals.clear();  						auto it = port_wire->attributes.find("\\abc9_arrival"); -						if (it != port_wire->attributes.end()) { -							if (it->second.flags != 0) -								log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); -							arrival = it->second.as_int(); +						if (it == port_wire->attributes.end()) +							continue; +						if (it->second.flags == 0) +							arrivals.emplace_back(it->second.as_int()); +						else +							for (const auto &tok : split_tokens(it->second.decode_string())) +								arrivals.push_back(atoi(tok.c_str())); +						if (GetSize(arrivals) > 1 && GetSize(arrivals) != GetSize(port_wire)) +							log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), +									GetSize(port_wire), log_signal(it->second), GetSize(arrivals)); +						auto jt = arrivals.begin(); + +#ifndef NDEBUG +						if (ys_debug(1)) { +							static std::set<std::pair<IdString,IdString>> seen; +							if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_arrival = %d\n", log_id(cell->type), log_id(conn.first), *jt); +						} +#endif + +						for (auto bit : sigmap(conn.second)) { +							arrival_times[bit] = *jt; +							if (arrivals.size() > 1) +								jt++;  						} -						if (arrival) -							for (auto bit : sigmap(conn.second)) -								arrival_times[bit] = arrival;  					}  				}  			} diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 5d6d8904c..1be7519b7 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -121,6 +121,7 @@ struct Abc9Pass : public ScriptPass  	std::stringstream exe_cmd;  	bool dff_mode, cleanup; +	std::string box_file;  	void clear_flags() YS_OVERRIDE  	{ @@ -128,6 +129,7 @@ struct Abc9Pass : public ScriptPass  		exe_cmd << "abc9_exe";  		dff_mode = false;  		cleanup = true; +		box_file.clear();  	}  	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -144,7 +146,7 @@ struct Abc9Pass : public ScriptPass  			std::string arg = args[argidx];  			if ((arg == "-exe" || arg == "-script" || arg == "-D" ||  						/* arg == "-S" || */ arg == "-lut" || arg == "-luts" || -						arg == "-box" || arg == "-W") && +						/*arg == "-box" ||*/ arg == "-W") &&  					argidx+1 < args.size()) {  				exe_cmd << " " << arg << " " << args[++argidx];  				continue; @@ -163,6 +165,10 @@ struct Abc9Pass : public ScriptPass  				cleanup = false;  				continue;  			} +			if (arg == "-box" && argidx+1 < args.size()) { +				box_file = args[++argidx]; +				continue; +			}  			break;  		}  		extra_args(args, argidx, design); @@ -175,11 +181,12 @@ struct Abc9Pass : public ScriptPass  	void script() YS_OVERRIDE  	{  		if (check_label("pre")) { +			run("abc9_ops -check");  			run("scc -set_attr abc9_scc_id {}");  			if (help_mode) -				run("abc9_ops -break_scc -prep_holes [-dff]", "(option for -dff)"); +				run("abc9_ops -break_scc -prep_times -prep_holes [-dff]", "(option for -dff)");  			else -				run("abc9_ops -break_scc -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)"); +				run("abc9_ops -break_scc -prep_times -prep_holes" + std::string(dff_mode ? " -dff" : ""), "(option for -dff)");  			run("select -set abc9_holes A:abc9_holes");  			run("flatten -wb @abc9_holes");  			run("techmap @abc9_holes"); @@ -193,8 +200,9 @@ struct Abc9Pass : public ScriptPass  		if (check_label("map")) {  			if (help_mode) {  				run("foreach module in selection"); +				run("    abc9_ops -write_box [(-box value)|(null)] <abc-temp-dir>/input.box");  				run("    write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig"); -				run("    abc9_exe -cwd <abc-temp-dir> [options]"); +				run("    abc9_exe [options] -cwd <abc-temp-dir> -box <abc-temp-dir>/input.box");  				run("    read_aiger -xaiger -wideports -module_name <module-name>$abc9 -map <abc-temp-dir>/input.sym <abc-temp-dir>/output.aig");  				run("    abc9_ops -reintegrate");  			} @@ -219,6 +227,10 @@ struct Abc9Pass : public ScriptPass  						tempdir_name[0] = tempdir_name[4] = '_';  					tempdir_name = make_temp_dir(tempdir_name); +					if (box_file.empty()) +						run(stringf("abc9_ops -write_box (null) %s/input.box", tempdir_name.c_str())); +					else +						run(stringf("abc9_ops -write_box %s %s/input.box", box_file.c_str(), tempdir_name.c_str()));  					run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()));  					int num_outputs = active_design->scratchpad_get_int("write_xaiger.num_outputs"); @@ -228,7 +240,7 @@ struct Abc9Pass : public ScriptPass  							active_design->scratchpad_get_int("write_xaiger.num_inputs"),  							num_outputs);  					if (num_outputs) { -						run(stringf("%s -cwd %s", exe_cmd.str().c_str(), tempdir_name.c_str())); +						run(stringf("%s -cwd %s -box %s/input.box", exe_cmd.str().c_str(), tempdir_name.c_str(), tempdir_name.c_str()));  						run(stringf("read_aiger -xaiger -wideports -module_name %s$abc9 -map %s/input.sym %s/output.aig", log_id(mod->name), tempdir_name.c_str(), tempdir_name.c_str()));  						run("abc9_ops -reintegrate");  					} diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 3108765a1..d92285a51 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -188,20 +188,15 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe  	std::string abc9_script; -	if (!lut_costs.empty()) { +	if (!lut_costs.empty())  		abc9_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); -		if (!box_file.empty()) -			abc9_script += stringf("read_box %s; ", box_file.c_str()); -	}  	else -	if (!lut_file.empty()) { +	if (!lut_file.empty())  		abc9_script += stringf("read_lut %s; ", lut_file.c_str()); -		if (!box_file.empty()) -			abc9_script += stringf("read_box %s; ", box_file.c_str()); -	}  	else  		log_abort(); +	abc9_script += stringf("read_box %s; ", box_file.c_str());  	abc9_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());  	if (!script_file.empty()) { @@ -350,7 +345,7 @@ struct Abc9ExePass : public Pass {  		log("        command output is identical across runs.\n");  		log("\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.\n");  		log("\n");  		log("    -cwd <dir>\n");  		log("        use this as the current working directory, inside which the 'input.xaig'\n"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cc22fd474..7f3bbc7ad 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -23,6 +23,8 @@  #include "kernel/utils.h"  #include "kernel/celltypes.h" +#define ABC9_DELAY_BASE_ID 9000 +  USING_YOSYS_NAMESPACE  PRIVATE_NAMESPACE_BEGIN @@ -33,6 +35,62 @@ inline std::string remap_name(RTLIL::IdString abc9_name)  	return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);  } +void check(RTLIL::Design *design) +{ +	dict<IdString,IdString> box_lookup; +	for (auto m : design->modules()) { +		auto flop = m->get_bool_attribute(ID(abc9_flop)); +		auto it = m->attributes.find(ID(abc9_box_id)); +		if (it == m->attributes.end()) { +			if (flop) +				log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id=<int> *).\n", log_id(m)); +			continue; +		} +		if (m->name.begins_with("$paramod")) +			continue; +		auto id = it->second.as_int(); +		auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", 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)); + +		// 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 : m->ports) { +			auto w = m->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(m)); +					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(m)); +					carry_out = 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(m)); +		if (carry_in == IdString() && carry_out != IdString()) +			log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m)); + +		if (flop) { +			int num_outputs = 0; +			for (auto port_name : m->ports) { +				auto wire = m->wire(port_name); +				if (wire->port_output) num_outputs++; +			} +			if (num_outputs != 1) +				log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); +		} +	} +} +  void break_scc(RTLIL::Module *module)  {  	// For every unique SCC found, (arbitrarily) find the first @@ -302,6 +360,7 @@ void prep_holes(RTLIL::Module *module, bool dff)  		}  		cell->attributes["\\abc9_box_seq"] = box_list.size(); +		//log_debug("%s.%s is box %d\n", log_id(module), log_id(cell), box_list.size());  		box_list.emplace_back(cell);  	}  	log_assert(!box_list.empty()); @@ -319,13 +378,12 @@ void prep_holes(RTLIL::Module *module, bool dff)  		log_assert(orig_box_module);  		IdString derived_name = orig_box_module->derive(design, cell->parameters);  		RTLIL::Module* box_module = design->module(derived_name); +		//cell->type = derived_name; +		//cell->parameters.clear();  		auto r = cell_cache.insert(derived_name);  		auto &holes_cell = r.first->second;  		if (r.second) { -			if (box_module->has_processes()) -				Pass::call_on_module(design, box_module, "proc"); -  			auto r2 = box_ports.insert(cell->type);  			if (r2.second) {  				// Make carry in the last PI, and carry out the last PO @@ -335,25 +393,15 @@ void prep_holes(RTLIL::Module *module, bool dff)  					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)); +						if (w->port_input)  							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)); +						if (w->port_output)  							carry_out = port_name; -						}  					}  					else  						r2.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()) {  					r2.first->second.push_back(carry_in);  					r2.first->second.push_back(carry_out); @@ -363,6 +411,9 @@ void prep_holes(RTLIL::Module *module, bool dff)  			if (box_module->get_bool_attribute("\\whitebox")) {  				holes_cell = holes_module->addCell(cell->name, derived_name); +				if (box_module->has_processes()) +					Pass::call_on_module(design, box_module, "proc"); +  				int box_inputs = 0;  				for (auto port_name : box_ports.at(cell->type)) {  					RTLIL::Wire *w = box_module->wire(port_name); @@ -422,6 +473,159 @@ void prep_holes(RTLIL::Module *module, bool dff)  	}  } +void prep_times(RTLIL::Design *design) +{ +	std::set<int> delays; +	pool<Module*> flops; +	std::vector<Cell*> boxes; +	std::map<int,std::vector<int>> requireds; +	for (auto module : design->selected_modules()) { +		if (module->processes.size() > 0) { +			log("Skipping module %s as it contains processes.\n", log_id(module)); +			continue; +		} + +		boxes.clear(); +		for (auto cell : module->cells()) { +			if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) +				continue; + +			RTLIL::Module* inst_module = module->design->module(cell->type); +			if (!inst_module) +				continue; +			if (!inst_module->get_blackbox_attribute()) +				continue; +			if (inst_module->get_bool_attribute(ID(abc9_flop))) { +				flops.insert(inst_module); +				continue; +			} +			// All remaining boxes are combinatorial and cannot +			//   contain a required time +			if (inst_module->attributes.count(ID(abc9_box_id))) +				continue; +			boxes.emplace_back(cell); +		} + +		delays.clear(); +		requireds.clear(); +		for (auto cell : boxes) { +			RTLIL::Module* inst_module = module->design->module(cell->type); +			log_assert(inst_module); +			for (auto &conn : cell->connections_) { +				auto port_wire = inst_module->wire(conn.first); +				if (!port_wire->port_input) +					continue; + +				auto it = port_wire->attributes.find("\\abc9_required"); +				if (it == port_wire->attributes.end()) +					continue; + +				int count = 0; +				requireds.clear(); +				if (it->second.flags == 0) { +					count = 1; +					requireds[it->second.as_int()].push_back(0); +				} +				else +					for (const auto &tok : split_tokens(it->second.decode_string())) +						requireds[atoi(tok.c_str())].push_back(count++); +				if (count > 1 && count != GetSize(port_wire)) +					log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), +							GetSize(port_wire), log_signal(it->second), count); + +				SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); +				for (const auto &i : requireds) { +#ifndef NDEBUG +					if (ys_debug(1)) { +						static std::set<std::pair<IdString,IdString>> seen; +						if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i.first); +					} +#endif +					delays.insert(i.first); +					for (auto offset : i.second) { +						auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); +						box->setPort(ID(I), conn.second[offset]); +						box->setPort(ID(O), O[offset]); +						box->setParam(ID(DELAY), i.first); +						conn.second[offset] = O[offset]; +					} +				} +			} +		} + +		std::stringstream ss; +		bool first = true; +		for (auto d : delays) { +			if (first) +				first = false; +			else +				ss << " "; +			ss << d; +		} +		module->attributes[ID(abc9_delays)] = ss.str(); +	} + +	std::stringstream ss; +	for (auto flop_module : flops) { +		// Skip parameterised flop_modules for now (since we do not +		//   dynamically generate the abc9_box_id) +		if (flop_module->name.begins_with("$paramod")) +			continue; + +		int num_inputs = 0, num_outputs = 0; +		for (auto port_name : flop_module->ports) { +			auto wire = flop_module->wire(port_name); +			if (wire->port_input) num_inputs++; +			if (wire->port_output) num_outputs++; +		} +		log_assert(num_outputs == 1); + +		ss << log_id(flop_module) << " " << flop_module->attributes.at(ID(abc9_box_id)).as_int(); +		ss << " 1 " << num_inputs+1 << " " << num_outputs << std::endl; +		bool first = true; +		for (auto port_name : flop_module->ports) { +			auto wire = flop_module->wire(port_name); +			if (!wire->port_input) +				continue; +			if (first) +				first = false; +			else +				ss << " "; +			ss << wire->attributes.at("\\abc9_required", 0).as_int(); +		} +		// Last input is 'abc9_ff.Q' +		ss << " 0" << std::endl << std::endl; +	} +	design->scratchpad_set_string("abc9_ops.box.flops", ss.str()); +} + +void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) { +	std::ofstream ofs(dst); +	log_assert(ofs.is_open()); + +	// Since ABC can only accept one box file, we have to copy +	//   over the existing box file +	if (src != "(null)") { +		std::ifstream ifs(src); +		ofs << ifs.rdbuf() << std::endl; +		ifs.close(); +	} + +	ofs << module->design->scratchpad_get_string("abc9_ops.box.flops"); + +	auto it = module->attributes.find(ID(abc9_delays)); +	if (it != module->attributes.end()) { +		for (const auto &tok : split_tokens(it->second.decode_string())) { +			int d = atoi(tok.c_str()); +			ofs << "$__ABC9_DELAY@" << d << " " << ABC9_DELAY_BASE_ID + d << " 0 1 1" << std::endl; +			ofs << d << std::endl; +		} +		module->attributes.erase(it); +	} + +	ofs.close(); +} +  void reintegrate(RTLIL::Module *module)  {  	auto design = module->design; @@ -437,8 +641,6 @@ void reintegrate(RTLIL::Module *module)  		module->addWire(remap_name(w->name), GetSize(w));  	dict<IdString,IdString> box_lookup; -	dict<IdString,std::vector<IdString>> box_ports; -  	for (auto m : design->modules()) {  		auto it = m->attributes.find(ID(abc9_box_id));  		if (it == m->attributes.end()) @@ -446,51 +648,19 @@ void reintegrate(RTLIL::Module *module)  		if (m->name.begins_with("$paramod"))  			continue;  		auto id = it->second.as_int(); -		auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", 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)); +		auto r YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name));  		log_assert(r.second); - -		auto r2 = box_ports.insert(m->name); -		if (r2.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 : m->ports) { -				auto w = m->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(m)); -						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(m)); -						carry_out = port_name; -					} -				} -				else -					r2.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(m)); -			if (carry_in == IdString() && carry_out != IdString()) -				log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); -			if (carry_in != IdString()) { -				r2.first->second.push_back(carry_in); -				r2.first->second.push_back(carry_out); -			} -		}  	} +	pool<IdString> delay_boxes;  	std::vector<Cell*> boxes;  	for (auto cell : module->cells().to_vector()) {  		if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_)))  			module->remove(cell); +		else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { +			delay_boxes.insert(cell->name); +			module->remove(cell); +		}  		else if (cell->attributes.erase("\\abc9_box_seq"))  			boxes.emplace_back(cell);  	} @@ -500,6 +670,7 @@ void reintegrate(RTLIL::Module *module)  	dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers;  	dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks; +	dict<IdString,std::vector<IdString>> box_ports;  	std::map<IdString, int> cell_stats;  	for (auto mapped_cell : mapped_mod->cells())  	{ @@ -550,16 +721,6 @@ void reintegrate(RTLIL::Module *module)  		}  		if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { -			// Convert buffer into direct connection -			if (mapped_cell->type == ID($lut) && -					GetSize(mapped_cell->getPort(ID::A)) == 1 && -					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); -				log_abort(); -				continue; -			}  			RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);  			cell->parameters = mapped_cell->parameters;  			cell->attributes = mapped_cell->attributes; @@ -587,6 +748,16 @@ void reintegrate(RTLIL::Module *module)  						bit_drivers[i].insert(mapped_cell->name);  			}  		} +		else if (delay_boxes.count(mapped_cell->name)) { +			SigBit I = mapped_cell->getPort(ID(i)); +			SigBit O = mapped_cell->getPort(ID(o)); +			if (I.wire) +				I.wire = module->wires_.at(remap_name(I.wire->name)); +			log_assert(O.wire); +			O.wire = module->wires_.at(remap_name(O.wire->name)); +			module->connect(O, I); +			continue; +		}  		else {  			RTLIL::Cell *existing_cell = module->cell(mapped_cell->name);  			log_assert(existing_cell); @@ -620,6 +791,30 @@ void reintegrate(RTLIL::Module *module)  					bit_drivers[i].insert(mapped_cell->name);  			} +			auto r2 = box_ports.insert(cell->type); +			if (r2.second) { +				// Make carry in the last PI, and carry out the last PO +				//   since ABC requires it this way +				IdString carry_in, carry_out; +				for (const auto &port_name : box_module->ports) { +					auto w = box_module->wire(port_name); +					log_assert(w); +					if (w->get_bool_attribute("\\abc9_carry")) { +						if (w->port_input) +							carry_in = port_name; +						if (w->port_output) +							carry_out = port_name; +					} +					else +						r2.first->second.push_back(port_name); +				} + +				if (carry_in != IdString()) { +					r2.first->second.push_back(carry_in); +					r2.first->second.push_back(carry_out); +				} +			} +  			int input_count = 0, output_count = 0;  			for (const auto &port_name : box_ports.at(cell->type)) {  				RTLIL::Wire *w = box_module->wire(port_name); @@ -806,16 +1001,23 @@ struct Abc9OpsPass : public Pass {  	{  		log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); +		bool check_mode = false; +		bool prep_times_mode = false;  		bool break_scc_mode = false;  		bool unbreak_scc_mode = false; -		bool prep_dff_mode = false;  		bool prep_holes_mode = false; +		bool prep_dff_mode = false; +		std::string write_box_src, write_box_dst;  		bool reintegrate_mode = false;  		bool dff_mode = false;  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) {  			std::string arg = args[argidx]; +			if (arg == "-check") { +				check_mode = true; +				continue; +			}  			if (arg == "-break_scc") {  				break_scc_mode = true;  				continue; @@ -832,6 +1034,17 @@ struct Abc9OpsPass : public Pass {  				prep_holes_mode = true;  				continue;  			} +			if (arg == "-prep_times") { +				prep_times_mode = true; +				continue; +			} +			if (arg == "-write_box" && argidx+2 < args.size()) { +				write_box_src = args[++argidx]; +				write_box_dst = args[++argidx]; +				rewrite_filename(write_box_src); +				rewrite_filename(write_box_dst); +				continue; +			}  			if (arg == "-reintegrate") {  				reintegrate_mode = true;  				continue; @@ -844,12 +1057,17 @@ struct Abc9OpsPass : public Pass {  		}  		extra_args(args, argidx, design); -		if (!(break_scc_mode || unbreak_scc_mode || prep_dff_mode || reintegrate_mode)) -			log_cmd_error("At least one of -{,un}break_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); +		if (!(check_mode || break_scc_mode || unbreak_scc_mode || prep_times_mode || prep_holes_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) +			log_cmd_error("At least one of -check, -{,un}break_scc, -prep_{times,holes,dff}, -write_box, -reintegrate must be specified.\n");  		if (dff_mode && !prep_holes_mode)  			log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); +		if (check_mode) +			check(design); +		if (prep_times_mode) +			prep_times(design); +  		for (auto mod : design->selected_modules()) {  			if (mod->get_bool_attribute("\\abc9_holes"))  				continue; @@ -866,10 +1084,12 @@ struct Abc9OpsPass : public Pass {  				break_scc(mod);  			if (unbreak_scc_mode)  				unbreak_scc(mod); -			if (prep_dff_mode) -				prep_dff(mod);  			if (prep_holes_mode)  				prep_holes(mod, dff_mode); +			if (prep_dff_mode) +				prep_dff(mod); +			if (!write_box_src.empty()) +				write_box(mod, write_box_src, write_box_dst);  			if (reintegrate_mode)  				reintegrate(mod);  		} diff --git a/techlibs/xilinx/abc9_model.v b/techlibs/xilinx/abc9_model.v index 204fa883f..25530acf8 100644 --- a/techlibs/xilinx/abc9_model.v +++ b/techlibs/xilinx/abc9_model.v @@ -33,6 +33,11 @@ endmodule  module \$__ABC9_FF_ (input D, output Q);  endmodule +(* abc9_box_id = (9000+DELAY) *) +module \$__ABC9_DELAY (input I, output O); +  parameter DELAY = 0; +endmodule +  // Box to emulate async behaviour of FDC*  (* abc9_box_id = 1000, lib_whitebox *)  module \$__ABC9_ASYNC0 (input A, S, output Y); diff --git a/techlibs/xilinx/abc9_xc7.box b/techlibs/xilinx/abc9_xc7.box index 13f4f0e61..48d492801 100644 --- a/techlibs/xilinx/abc9_xc7.box +++ b/techlibs/xilinx/abc9_xc7.box @@ -62,67 +62,6 @@ $__ABC9_ASYNC1 1001 1   2   1  #A S  0  764 # Y -# Flop boxes: -# * Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251 -#                   https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277 -# * Exception: $abc9_currQ is a special input (located last) necessary for clock-enable functionality - -# Box 1100 : FDRE -# name ID   w/b ins outs -FDRE   1100 1   5   1 -#C CE  D   R   $abc9_currQ -#0 109 -46 404 0 -0 109 0   404 0 # Q (-46ps Tsu clamped to 0) - -# Box 1101 : FDRE_1 -# name ID   w/b ins outs -FDRE_1 1101 1   5   1 -#C CE  D   R   $abc9_currQ -#0 109 -46 404 0 -0 109 0   404 0 # Q (-46ps Tsu clamped to 0) - -# Box 1102 : FDSE -# name ID   w/b ins outs -FDSE   1102 1   5   1 -#C CE  D   R   $abc9_currQ -#0 109 -46 404 0 -0 109 0   404 0 # Q (-46ps Tsu clamped to 0) - -# Box 1103 : FDSE_1 -# name ID   w/b ins outs -FDSE_1 1103 1   5   1 -#C CE  D   R   $abc9_currQ -#0 109 -46 404 0 -0 109 0   404 0 # Q (-46ps Tsu clamped to 0) - -# Box 1104 : FDCE -# name ID   w/b ins outs -FDCE   1104 1   5   1 -#C CE  CLR D   $abc9_currQ -#0 109 764 -46 0 -0 109 764 0   0 # Q (-46ps Tsu clamped to 0) - -# Box 1105 : FDCE_1 -# name ID   w/b ins outs -FDCE_1 1105 1   5   1 -#C CE  CLR D   $abc9_currQ -#0 109 764 -46 0 -0 109 764 0   0 # Q (-46ps Tsu clamped to 0) - -# Box 1106 : FDPE -# name ID   w/b ins outs -FDPE   1106 1   5   1 -#C CE  D   PRE $abc9_currQ -#0 109 -46 764 0 -0 109 0   764 0 # Q (-46ps Tsu clamped to 0) - -# Box 1107 : FDPE_1 -# name ID   w/b ins outs -FDPE_1 1107 1   5   1 -#C CE  D   PRE $abc9_currQ -#0 109 -46 764 0 -0 109 0   764 0 # Q (-46ps Tsu clamped to 0) -  # Box 2000 : $__ABC9_LUT6  #            (private cell to emulate async behaviour of LUTRAMs)  # SLICEM/A6LUT diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 22dca3c47..08380ddca 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -1120,15 +1120,33 @@ module RAM16X1D_1 (  endmodule  module RAM32X1D ( -  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 -  (* abc9_arrival=1188 *) +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 +  (* abc9_arrival=1153 *)    output DPO, SPO, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 +  (* abc9_required=453 *)    input  D,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *)    input  WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *)    input  WE, -  input  A0, A1, A2, A3, A4, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800 +  (* abc9_required=245 *) +  input  A0, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798 +  (* abc9_required=208 *) +  input  A1, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796 +  (* abc9_required=147 *) +  input  A2, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794 +  (* abc9_required=68 *) +  input  A3, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792 +  (* abc9_required=66 *) +  input  A4,    input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4  );    parameter INIT = 32'h0; @@ -1143,15 +1161,33 @@ module RAM32X1D (  endmodule  module RAM32X1D_1 ( -  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 -  (* abc9_arrival=1188 *) +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 +  (* abc9_arrival=1153 *)    output DPO, SPO, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 +  (* abc9_required=453 *)    input  D,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *)    input  WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *)    input  WE, -  input  A0, A1, A2, A3, A4, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800 +  (* abc9_required=245 *) +  input  A0, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798 +  (* abc9_required=208 *) +  input  A1, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796 +  (* abc9_required=147 *) +  input  A2, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794 +  (* abc9_required=68 *) +  input  A3, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792 +  (* abc9_required=66 *) +  input  A4,    input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4  );    parameter INIT = 32'h0; @@ -1166,15 +1202,36 @@ module RAM32X1D_1 (  endmodule  module RAM64X1D ( -  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981    (* abc9_arrival=1153 *)    output DPO, SPO, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 +  (* abc9_required=453 *)    input  D,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *)    input  WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *)    input  WE, -  input  A0, A1, A2, A3, A4, A5, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828 +  (* abc9_required=362 *) +  input  A0, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826 +  (* abc9_required=245 *) +  input  A1, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824 +  (* abc9_required=208 *) +  input  A2, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822 +  (* abc9_required=147 *) +  input  A3, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820 +  (* abc9_required=68 *) +  input  A4, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818 +  (* abc9_required=66 *) +  input  A5,    input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5  );    parameter INIT = 64'h0; @@ -1189,15 +1246,36 @@ module RAM64X1D (  endmodule  module RAM64X1D_1 ( -  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981    (* abc9_arrival=1153 *)    output DPO, SPO, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 +  (* abc9_required=453 *)    input  D,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *)    input  WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *)    input  WE, -  input  A0, A1, A2, A3, A4, A5, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828 +  (* abc9_required=362 *) +  input  A0, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826 +  (* abc9_required=245 *) +  input  A1, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824 +  (* abc9_required=208 *) +  input  A2, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822 +  (* abc9_required=147 *) +  input  A3, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820 +  (* abc9_required=68 *) +  input  A4, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818 +  (* abc9_required=66 *) +  input  A5,    input  DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5  );    parameter INIT = 64'h0; @@ -1212,16 +1290,23 @@ module RAM64X1D_1 (  endmodule  module RAM128X1D ( -  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889 -  //   plus 204ps to cross MUXF7 -  (* abc9_arrival=1357 *) -  output DPO, SPO, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981 +  //   plus 208ps to cross MUXF7 +  (* abc9_arrival=1359 *) +  output       DPO, SPO, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986 +  (* abc9_required=453 *)    input        D,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *)    input        WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *)    input        WE, -  input  [6:0] A, DPRA +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830 +  (* abc9_required="616 362 245 208 147 68 66" *) +  input  [6:0] A, +  input  [6:0] DPRA  );    parameter INIT = 128'h0;    parameter IS_WCLK_INVERTED = 1'b0; @@ -1253,24 +1338,44 @@ endmodule  // Multi port.  module RAM32M ( +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 -  (* abc9_arrival=1188 *) +  (* abc9_arrival="1153 1188" *)    output [1:0] DOA, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925 -  (* abc9_arrival=1187 *) +  (* abc9_arrival="1161 1187" *)    output [1:0] DOB, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993 -  (* abc9_arrival=1180 *) +  (* abc9_arrival="1158 1180" *)    output [1:0] DOC, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061 -  (* abc9_arrival=1190 *) +  (* abc9_arrival="1163 1190" *)    output [1:0] DOD, -  input [4:0] ADDRA, ADDRB, ADDRC, ADDRD, -  input [1:0] DIA, DIB, DIC, DID, +  input  [4:0] ADDRA, ADDRB, ADDRC, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792-L802 +  (* abc9_required="245 208 147 68 66" *) +  input  [4:0] ADDRD, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988 +  (* abc9_required="453 384" *) +  input  [1:0] DIA, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056 +  (* abc9_required="461 354" *) +  input  [1:0] DIB, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124 +  (* abc9_required="457 375" *) +  input  [1:0] DIC, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192 +  (* abc9_required="310 334" *) +  input  [1:0] DID,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *) -  input WCLK, -  input WE +  input        WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *) +  input        WE  );    parameter [63:0] INIT_A = 64'h0000000000000000;    parameter [63:0] INIT_B = 64'h0000000000000000; @@ -1367,22 +1472,38 @@ endmodule  module RAM64M (    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889    (* abc9_arrival=1153 *) -  output DOA, +  output       DOA,    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957    (* abc9_arrival=1161 *) -  output DOB, +  output       DOB,    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025    (* abc9_arrival=1158 *) -  output DOC, +  output       DOC,    // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093    (* abc9_arrival=1163 *) -  output DOD, -  input [5:0] ADDRA, ADDRB, ADDRC, ADDRD, -  input DIA, DIB, DIC, DID, +  output       DOD, +  input  [5:0] ADDRA, ADDRB, ADDRC, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830 +  (* abc9_required="362 245 208 147 68 66" *) +  input  [5:0] ADDRD, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988 +  (* abc9_required=384 *) +  input        DIA, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056 +  (* abc9_required=354 *) +  input        DIB, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124 +  (* abc9_required=375 *) +  input        DIC, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192 +  (* abc9_required=310 *) +  input        DID,    (* clkbuf_sink *)    (* invertible_pin = "IS_WCLK_INVERTED" *) -  input WCLK, -  input WE +  input        WCLK, +  // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834 +  (* abc9_required=654 *) +  input        WE  );    parameter [63:0] INIT_A = 64'h0000000000000000;    parameter [63:0] INIT_B = 64'h0000000000000000; @@ -2169,21 +2290,30 @@ module DSP48E1 (      output reg MULTSIGNOUT,      output OVERFLOW,  `ifdef YOSYS -    (* abc9_arrival = \DSP48E1.P_arrival () *) +    (* abc9_arrival = \P.abc9_arrival () *)  `endif      output reg signed [47:0] P,      output reg PATTERNBDETECT,      output reg PATTERNDETECT,  `ifdef YOSYS -    (* abc9_arrival = \DSP48E1.PCOUT_arrival () *) +    (* abc9_arrival = \PCOUT.abc9_arrival () *)  `endif      output [47:0] PCOUT,      output UNDERFLOW, +`ifdef YOSYS +    (* abc9_required = \A.abc9_required () *) +`endif      input signed [29:0] A,      input [29:0] ACIN,      input [3:0] ALUMODE, +`ifdef YOSYS +    (* abc9_required = \B.abc9_required () *) +`endif      input signed [17:0] B,      input [17:0] BCIN, +`ifdef YOSYS +    (* abc9_required = \C.abc9_required () *) +`endif      input [47:0] C,      input CARRYCASCIN,      input CARRYIN, @@ -2202,10 +2332,16 @@ module DSP48E1 (      input CEM,      input CEP,      (* clkbuf_sink *) input CLK, +`ifdef YOSYS +    (* abc9_required = \D.abc9_required () *) +`endif      input [24:0] D,      input [4:0] INMODE,      input MULTSIGNIN,      input [6:0] OPMODE, +`ifdef YOSYS +    (* abc9_required = \PCIN.abc9_required () *) +`endif      input [47:0] PCIN,      input RSTA,      input RSTALLCARRYIN, @@ -2250,69 +2386,133 @@ module DSP48E1 (      parameter [6:0] IS_OPMODE_INVERTED = 7'b0;  `ifdef YOSYS -    function integer \DSP48E1.P_arrival ; +    function integer \A.abc9_required ; +    begin +        \A.abc9_required = 0; +        if (AREG != 0)           \A.abc9_required =  254; +        else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin +            if (MREG != 0)       \A.abc9_required = 1416; +            else if (PREG != 0)  \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3030 : 2739) ; +        end +        else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin +            // Worst-case from ADREG and MREG +            if (MREG != 0)       \A.abc9_required = 2400; +            else if (ADREG != 0) \A.abc9_required = 1283; +            else if (PREG != 0)  \A.abc9_required = 3723; +            else if (PREG != 0)  \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 4014 : 3723) ; +        end +        else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin +            if (PREG != 0)       \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1730 : 1441) ; +        end +    end +    endfunction +    function integer \B.abc9_required ; +    begin +        \B.abc9_required = 0; +        if (BREG != 0)      \B.abc9_required =  324; +        else if (MREG != 0) \B.abc9_required = 1285; +        else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin +            if (PREG != 0)  \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ; +        end +        else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin +            if (PREG != 0)  \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ; +        end +        else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin +            if (PREG != 0)  \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1718 : 1428) ; +        end +    end +    endfunction +    function integer \C.abc9_required ; +    begin +        \C.abc9_required = 0; +        if (CREG != 0)      \C.abc9_required =  168; +        else if (PREG != 0) \C.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1534 : 1244) ; +    end +    endfunction +    function integer \D.abc9_required ; +    begin +        \D.abc9_required = 0; +        if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin +        end +        else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin +            if (DREG != 0)       \D.abc9_required =  248; +            else if (ADREG != 0) \D.abc9_required = 1195; +            else if (MREG != 0)  \D.abc9_required = 2310; +            else if (PREG != 0)  \D.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3925 : 3635) ; +        end +        else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin +        end +    end +    endfunction +    function integer \PCIN.abc9_required ; +    begin +        \PCIN.abc9_required = 0; +        if (PREG != 0) \PCIN.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1315 : 1025) ; +    end +    endfunction +    function integer \P.abc9_arrival ;      begin -        \DSP48E1.P_arrival = 0; +        \P.abc9_arrival = 0;          if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin -            if (PREG != 0)      \DSP48E1.P_arrival =  329; +            if (PREG != 0)       \P.abc9_arrival =  329;              // Worst-case from CREG and MREG -            else if (CREG != 0) \DSP48E1.P_arrival = 1687; -            else if (MREG != 0) \DSP48E1.P_arrival = 1671; +            else if (CREG != 0)  \P.abc9_arrival = 1687; +            else if (MREG != 0)  \P.abc9_arrival = 1671;              // Worst-case from AREG and BREG -            else if (AREG != 0) \DSP48E1.P_arrival = 2952; -            else if (BREG != 0) \DSP48E1.P_arrival = 2813; +            else if (AREG != 0)  \P.abc9_arrival = 2952; +            else if (BREG != 0)  \P.abc9_arrival = 2813;          end          else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin -            if (PREG != 0)      \DSP48E1.P_arrival =  329; +            if (PREG != 0)       \P.abc9_arrival =  329;              // Worst-case from CREG and MREG -            else if (CREG != 0) \DSP48E1.P_arrival = 1687; -            else if (MREG != 0) \DSP48E1.P_arrival = 1671; +            else if (CREG != 0)  \P.abc9_arrival = 1687; +            else if (MREG != 0)  \P.abc9_arrival = 1671;              // Worst-case from AREG, ADREG, BREG, DREG -            else if (AREG != 0)  \DSP48E1.P_arrival = 3935; -            else if (DREG != 0)  \DSP48E1.P_arrival = 3908; -            else if (ADREG != 0) \DSP48E1.P_arrival = 2958; -            else if (BREG != 0)  \DSP48E1.P_arrival = 2813; +            else if (AREG != 0)  \P.abc9_arrival = 3935; +            else if (DREG != 0)  \P.abc9_arrival = 3908; +            else if (ADREG != 0) \P.abc9_arrival = 2958; +            else if (BREG != 0)  \P.abc9_arrival = 2813;          end          else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin -            if (PREG != 0)      \DSP48E1.P_arrival =  329; +            if (PREG != 0)       \P.abc9_arrival =  329;              // Worst-case from AREG, BREG, CREG -            else if (CREG != 0) \DSP48E1.P_arrival = 1687; -            else if (AREG != 0) \DSP48E1.P_arrival = 1632; -            else if (BREG != 0) \DSP48E1.P_arrival = 1616; +            else if (CREG != 0)  \P.abc9_arrival = 1687; +            else if (AREG != 0)  \P.abc9_arrival = 1632; +            else if (BREG != 0)  \P.abc9_arrival = 1616;          end          //else          //    $error("Invalid DSP48E1 configuration");      end      endfunction -    function integer \DSP48E1.PCOUT_arrival ; +    function integer \PCOUT.abc9_arrival ;      begin -        \DSP48E1.PCOUT_arrival = 0; +        \PCOUT.abc9_arrival = 0;          if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin -            if (PREG != 0)      \DSP48E1.PCOUT_arrival =  435; +            if (PREG != 0)       \PCOUT.abc9_arrival =  435;              // Worst-case from CREG and MREG -            else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; -            else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819; +            else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; +            else if (MREG != 0)  \PCOUT.abc9_arrival = 1819;              // Worst-case from AREG and BREG -            else if (AREG != 0) \DSP48E1.PCOUT_arrival = 3098; -            else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960; +            else if (AREG != 0)  \PCOUT.abc9_arrival = 3098; +            else if (BREG != 0)  \PCOUT.abc9_arrival = 2960;          end          else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin -            if (PREG != 0)      \DSP48E1.PCOUT_arrival =  435; +            if (PREG != 0)       \PCOUT.abc9_arrival =  435;              // Worst-case from CREG and MREG -            else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; -            else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819; +            else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; +            else if (MREG != 0)  \PCOUT.abc9_arrival = 1819;              // Worst-case from AREG, ADREG, BREG, DREG -            else if (AREG != 0)  \DSP48E1.PCOUT_arrival = 4083; -            else if (DREG != 0)  \DSP48E1.PCOUT_arrival = 4056; -            else if (BREG != 0)  \DSP48E1.PCOUT_arrival = 2960; -            else if (ADREG != 0) \DSP48E1.PCOUT_arrival = 2859; +            else if (AREG != 0)  \PCOUT.abc9_arrival = 4083; +            else if (DREG != 0)  \PCOUT.abc9_arrival = 4056; +            else if (BREG != 0)  \PCOUT.abc9_arrival = 2960; +            else if (ADREG != 0) \PCOUT.abc9_arrival = 2859;          end          else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin -            if (PREG != 0)      \DSP48E1.PCOUT_arrival =  435; +            if (PREG != 0)       \PCOUT.abc9_arrival =  435;              // Worst-case from AREG, BREG, CREG -            else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835; -            else if (AREG != 0) \DSP48E1.PCOUT_arrival = 1780; -            else if (BREG != 0) \DSP48E1.PCOUT_arrival = 1765; +            else if (CREG != 0)  \PCOUT.abc9_arrival = 1835; +            else if (AREG != 0)  \PCOUT.abc9_arrival = 1780; +            else if (BREG != 0)  \PCOUT.abc9_arrival = 1765;          end          //else          //    $error("Invalid DSP48E1 configuration"); diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py index d5c58c5d7..cb873a044 100644 --- a/techlibs/xilinx/cells_xtra.py +++ b/techlibs/xilinx/cells_xtra.py @@ -180,18 +180,58 @@ CELLS = [      Cell('RAMB18E1', port_attrs={          'CLKARDCLK': ['clkbuf_sink'],          'CLKBWRCLK': ['clkbuf_sink'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143          'DOADO': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163          'DOBDO': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144          'DOPADOP': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164          'DOPBDOP': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13 +        'ADDRARDADDR': ['abc9_required=566'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17 +        'ADDRBWRADDR': ['abc9_required=566'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19 +        'WEA': ['abc9_required=532'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21 +        'WEBWE': ['abc9_required=532'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123 +        'DIADI': ['abc9_required=737'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133 +        'DIBDI': ['abc9_required=737'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125 +        'DIPADIP': ['abc9_required=737'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135 +        'DIPBDIP': ['abc9_required=737'],      }),      Cell('RAMB36E1', port_attrs={          'CLKARDCLK': ['clkbuf_sink'],          'CLKBWRCLK': ['clkbuf_sink'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143          'DOADO': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163          'DOBDO': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144          'DOPADOP': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164          'DOPBDOP': ['abc9_arrival=2454'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13 +        'ADDRARDADDR': ['abc9_required=566'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17 +        'ADDRBWRADDR': ['abc9_required=566'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19 +        'WEA': ['abc9_required=532'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21 +        'WEBWE': ['abc9_required=532'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123 +        'DIADI': ['abc9_required=737'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133 +        'DIBDI': ['abc9_required=737'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125 +        'DIPADIP': ['abc9_required=737'], +        # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135 +        'DIPBDIP': ['abc9_required=737'],      }),      # Ultrascale.      Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index c3e5c72f9..beed07e0a 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -4518,13 +4518,21 @@ module RAMB18E1 (...);      input RSTREGARSTREG;      (* invertible_pin = "IS_RSTREGB_INVERTED" *)      input RSTREGB; +    (* abc9_required=566 *)      input [13:0] ADDRARDADDR; +    (* abc9_required=566 *)      input [13:0] ADDRBWRADDR; +    (* abc9_required=737 *)      input [15:0] DIADI; +    (* abc9_required=737 *)      input [15:0] DIBDI; +    (* abc9_required=737 *)      input [1:0] DIPADIP; +    (* abc9_required=737 *)      input [1:0] DIPBDIP; +    (* abc9_required=532 *)      input [1:0] WEA; +    (* abc9_required=532 *)      input [3:0] WEBWE;  endmodule @@ -4742,13 +4750,21 @@ module RAMB36E1 (...);      input REGCEB;      input INJECTDBITERR;      input INJECTSBITERR; +    (* abc9_required=566 *)      input [15:0] ADDRARDADDR; +    (* abc9_required=566 *)      input [15:0] ADDRBWRADDR; +    (* abc9_required=737 *)      input [31:0] DIADI; +    (* abc9_required=737 *)      input [31:0] DIBDI; +    (* abc9_required=737 *)      input [3:0] DIPADIP; +    (* abc9_required=737 *)      input [3:0] DIPBDIP; +    (* abc9_required=532 *)      input [3:0] WEA; +    (* abc9_required=532 *)      input [7:0] WEBWE;  endmodule | 
