diff options
Diffstat (limited to 'passes/techmap')
| -rw-r--r-- | passes/techmap/Makefile.inc | 1 | ||||
| -rw-r--r-- | passes/techmap/abc9.cc | 277 | ||||
| -rw-r--r-- | passes/techmap/clkpart.cc | 269 | 
3 files changed, 389 insertions, 158 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index cd357d72a..13992315e 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -41,6 +41,7 @@ OBJS += passes/techmap/zinit.o  OBJS += passes/techmap/dff2dffs.o  OBJS += passes/techmap/flowmap.o  OBJS += passes/techmap/extractinv.o +OBJS += passes/techmap/clkpart.o  endif  GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 27106cc5d..4b6ec6e11 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -65,20 +65,15 @@ PRIVATE_NAMESPACE_BEGIN  bool markgroups;  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)  {  	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  	// cell in the component, and select (and mark) all its output @@ -243,49 +238,15 @@ struct abc9_output_filter  	}  }; -void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, -		bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, +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 /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,  		bool show_tempdir, std::string box_file, std::string lut_file,  		std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs  )  { -	module = current_module;  	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";  	if (!cleanup)  		tempdir_name[0] = tempdir_name[4] = '_'; @@ -361,18 +322,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  	fprintf(f, "%s\n", abc9_script.c_str());  	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); @@ -387,13 +336,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  	if (count_output)  	{ -		design->selection_stack.emplace_back(false); -		RTLIL::Selection& sel = design->selection_stack.back(); -		sel.select(module); - -		handle_loops(design); +		handle_loops(design, module); -		Pass::call(design, "aigmap"); +		Pass::call(design, "aigmap -select");  		//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); @@ -418,8 +363,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  		design->remove(design->module(ID($__abc9__)));  #endif -		design->selection_stack.pop_back(); -  		// Now 'unexpose' those wires by undoing  		// the expose operation -- remove them from PO/PI  		// and re-connecting them back together @@ -519,9 +462,8 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  		dict<IdString, bool> abc9_box;  		vector<RTLIL::Cell*> boxes; -		for (const auto &it : module->cells_) { -			auto cell = it.second; -			if (cell->type.in(ID($_AND_), ID($_NOT_))) { +		for (auto cell : module->selected_cells()) { +			if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) {  				module->remove(cell);  				continue;  			} @@ -540,19 +482,19 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  		dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;  		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; -			if (c->type == ID($_NOT_)) { -				RTLIL::SigBit a_bit = c->getPort(ID::A); -				RTLIL::SigBit y_bit = c->getPort(ID::Y); -				bit_users[a_bit].insert(c->name); -				bit_drivers[y_bit].insert(c->name); +			if (mapped_cell->type == ID($_NOT_)) { +				RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); +				RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); +				bit_users[a_bit].insert(mapped_cell->name); +				bit_drivers[y_bit].insert(mapped_cell->name);  				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));  					log_assert(wire);  					module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); @@ -576,7 +518,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  					if (!driver_lut) {  						// If a driver couldn't be found (could be from PI or box CI)  						// 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(y_bit.wire->name)), y_bit.offset),  								RTLIL::Const::from_string("01")); @@ -584,7 +526,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  						cell_stats[ID($lut)]++;  					}  					else -						not2drivers[c] = driver_lut; +						not2drivers[mapped_cell] = driver_lut;  					continue;  				}  				else @@ -592,24 +534,26 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  				if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;  				continue;  			} -			cell_stats[c->type]++; +			cell_stats[mapped_cell->type]++;  			RTLIL::Cell *existing_cell = nullptr; -			if (c->type == ID($lut)) { -				if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { -					SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); -					SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); +			if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { +				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); -					if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; +					if (markgroups) mapped_cell->attributes[ID(abcgroup)] = map_autoidx;  					log_abort();  					continue;  				} -				cell = module->addCell(remap_name(c->name), c->type); +				cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);  			}  			else { -				existing_cell = module->cell(c->name); +				existing_cell = module->cell(mapped_cell->name);  				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; @@ -618,10 +562,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  				cell->attributes = existing_cell->attributes;  			}  			else { -				cell->parameters = c->parameters; -				cell->attributes = c->attributes; +				cell->parameters = mapped_cell->parameters; +				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->attributes.count("\\abc9_flop"); +			for (auto &conn : mapped_cell->connections()) {  				RTLIL::SigSpec newsig;  				for (auto c : conn.second.chunks()) {  					if (c.width == 0) @@ -633,15 +580,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  				}  				cell->setPort(conn.first, newsig); -				if (cell->input(conn.first)) { -					for (auto i : newsig) -						bit2sinks[i].push_back(cell); -					for (auto i : conn.second) -						bit_users[i].insert(c->name); +				if (!abc9_flop) { +					if (cell->input(conn.first)) { +						for (auto i : newsig) +							bit2sinks[i].push_back(cell); +						for (auto i : conn.second) +							bit_users[i].insert(mapped_cell->name); +					} +					if (cell->output(conn.first)) +						for (auto i : conn.second) +							bit_drivers[i].insert(mapped_cell->name);  				} -				if (cell->output(conn.first)) -					for (auto i : conn.second) -						bit_drivers[i].insert(c->name);  			}  		} @@ -903,8 +852,17 @@ struct Abc9Pass : public Pass {  		log("internally. This is not going to \"run ABC on your design\". It will instead run\n");  		log("ABC on logic snippets extracted from your design. You will not get any useful\n");  		log("output when passing an ABC script that writes a file. Instead write your full\n"); -		log("design as BLIF file with write_blif and then load that into ABC externally if\n"); -		log("you want to use ABC to convert your design into another format.\n"); +		log("design as an XAIGER file with write_xaiger and then load that into ABC externally\n"); +		log("if you want to use ABC to convert your design into another format.\n"); +		log("\n"); +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("Delay targets can also be specified on a per clock basis by attaching a\n"); +		log("'(* abc9_period = <int> *)' attribute onto clock wires (specifically, onto wires\n"); +		log("that appear inside any special '$abc9_clock' wires inserted by abc9_map.v). This\n"); +		log("can be achieved by modifying the source directly, or through a `setattr`\n"); +		log("invocation. Since such attributes cannot yet be propagated through a\n"); +		log("hierarchical design (whether or not it has been uniquified) it is recommended\n"); +		log("that the design be flattened when using this feature.\n");  		log("\n");  		log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");  		log("\n"); @@ -914,8 +872,6 @@ struct Abc9Pass : public Pass {  		log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");  		log_push(); -		assign_map.clear(); -  #ifdef ABCEXTERNAL  		std::string exe_file = ABCEXTERNAL;  #else @@ -923,7 +879,7 @@ struct Abc9Pass : public Pass {  #endif  		std::string script_file, clk_str, box_file, lut_file;  		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,*/ keepff = false, cleanup = true;  		bool show_tempdir = false;  		bool nomfs = false;  		vector<int> lut_costs; @@ -1125,48 +1081,39 @@ struct Abc9Pass : public Pass {  			}  		} -		for (auto mod : design->selected_modules()) +		for (auto module : design->selected_modules())  		{ -			if (mod->attributes.count(ID(abc9_box_id))) +			if (module->attributes.count(ID(abc9_box_id)))  				continue; -			if (mod->processes.size() > 0) { -				log("Skipping module %s as it contains processes.\n", log_id(mod)); +			if (module->processes.size() > 0) { +				log("Skipping module %s as it contains processes.\n", log_id(module));  				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; -			} +			SigMap assign_map(module);  			CellTypes ct(design); -			std::vector<RTLIL::Cell*> all_cells = mod->selected_cells(); +			std::vector<RTLIL::Cell*> all_cells = module->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<SigSpec, pool<RTLIL::IdString>> assigned_cells; +			std::map<RTLIL::Cell*, SigSpec> 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; +			typedef std::pair<IdString, SigSpec> ctrldomain_t; +			std::map<ctrldomain_t, int> mergeability_class; +			for (auto cell : all_cells) {  				for (auto &conn : cell->connections()) -				for (auto bit : conn.second) { -					bit = assign_map(bit); +				for (auto bit : assign_map(conn.second))  					if (bit.wire != nullptr) {  						cell_to_bit[cell].insert(bit);  						bit_to_cell[bit].insert(cell); @@ -1179,29 +1126,33 @@ struct Abc9Pass : public Pass {  							bit_to_cell_up[bit].insert(cell);  						}  					} -				} -				if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) -				{ -					key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); -				} -				else -				if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) -				{ -					bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); -					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 +				auto inst_module = design->module(cell->type); +				if (!inst_module || !inst_module->attributes.count("\\abc9_flop"))  					continue; +				Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str())); +				if (abc9_clock_wire == NULL) +					log_error("'%s$abc9_clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); +				SigSpec abc9_clock = assign_map(abc9_clock_wire); + +				Wire *abc9_control_wire = module->wire(stringf("%s.$abc9_control", cell->name.c_str())); +				if (abc9_control_wire == NULL) +					log_error("'%s$abc9_control' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); +				SigSpec abc9_control = assign_map(abc9_control_wire); +  				unassigned_cells.erase(cell);  				expand_queue.insert(cell);  				expand_queue_up.insert(cell);  				expand_queue_down.insert(cell); -				assigned_cells[key].push_back(cell); -				assigned_cells_reverse[cell] = key; +				assigned_cells[abc9_clock].insert(cell->name); +				assigned_cells_reverse[cell] = abc9_clock; + +				ctrldomain_t key(cell->type, abc9_control); +				auto r = mergeability_class.emplace(key, mergeability_class.size() + 1); +				auto YS_ATTRIBUTE(unused) r2 = cell->attributes.insert(std::make_pair(ID(abc9_mergeability),  r.first->second)); +				log_assert(r2.second);  			}  			while (!expand_queue_up.empty() || !expand_queue_down.empty()) @@ -1209,15 +1160,15 @@ struct Abc9Pass : public Pass {  				if (!expand_queue_up.empty())  				{  					RTLIL::Cell *cell = *expand_queue_up.begin(); -					clkdomain_t key = assigned_cells_reverse.at(cell); +					SigSpec 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)) { +						if (unassigned_cells.count(c) && !c->type.in("$__ABC9_FF_", "$__ABC9_ASYNC_")) {  							unassigned_cells.erase(c);  							next_expand_queue_up.insert(c); -							assigned_cells[key].push_back(c); +							assigned_cells[key].insert(c->name);  							assigned_cells_reverse[c] = key;  							expand_queue.insert(c);  						} @@ -1226,7 +1177,7 @@ struct Abc9Pass : public Pass {  				if (!expand_queue_down.empty())  				{  					RTLIL::Cell *cell = *expand_queue_down.begin(); -					clkdomain_t key = assigned_cells_reverse.at(cell); +					SigSpec key = assigned_cells_reverse.at(cell);  					expand_queue_down.erase(cell);  					for (auto bit : cell_to_bit_down[cell]) @@ -1234,7 +1185,7 @@ struct Abc9Pass : public Pass {  						if (unassigned_cells.count(c)) {  							unassigned_cells.erase(c);  							next_expand_queue_up.insert(c); -							assigned_cells[key].push_back(c); +							assigned_cells[key].insert(c->name);  							assigned_cells_reverse[c] = key;  							expand_queue.insert(c);  						} @@ -1249,7 +1200,7 @@ struct Abc9Pass : public Pass {  			while (!expand_queue.empty())  			{  				RTLIL::Cell *cell = *expand_queue.begin(); -				clkdomain_t key = assigned_cells_reverse.at(cell); +				SigSpec key = assigned_cells_reverse.at(cell);  				expand_queue.erase(cell);  				for (auto bit : cell_to_bit.at(cell)) { @@ -1257,7 +1208,7 @@ struct Abc9Pass : public Pass {  						if (unassigned_cells.count(c)) {  							unassigned_cells.erase(c);  							next_expand_queue.insert(c); -							assigned_cells[key].push_back(c); +							assigned_cells[key].insert(c->name);  							assigned_cells_reverse[c] = key;  						}  					bit_to_cell[bit].clear(); @@ -1267,32 +1218,42 @@ struct Abc9Pass : public Pass {  					expand_queue.swap(next_expand_queue);  			} -			clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); +			SigSpec key;  			for (auto cell : unassigned_cells) { -				assigned_cells[key].push_back(cell); +				assigned_cells[key].insert(cell->name);  				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))); +				log("  %d cells in clk=%s\n", GetSize(it.second), log_signal(it.first)); +			design->selection_stack.emplace_back(false); +			design->selected_active_module = module->name.str();  			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, +				std::string target = delay_target; +				if (target.empty()) { +					for (auto b : assign_map(it.first)) +						if (b.wire) { +							auto jt = b.wire->attributes.find("\\abc9_period"); +							if (jt != b.wire->attributes.end()) { +								target = stringf("-D %d", jt->second.as_int()); +								log("Target period = %s ps for clock domain %s\n", target.c_str(), log_signal(it.first)); +								break; +							} +						} +				} +				RTLIL::Selection& sel = design->selection_stack.back(); +				sel.selected_members[module->name] = std::move(it.second); +				abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, false, "$", +						keepff, target, lutin_shared, fast_mode, show_tempdir,  						box_file, lut_file, wire_delay, box_lookup, nomfs); -				assign_map.set(mod); +				assign_map.set(module);  			} +			design->selection_stack.pop_back(); +			design->selected_active_module.clear();  		} -		assign_map.clear(); -  		log_pop();  	}  } Abc9Pass; diff --git a/passes/techmap/clkpart.cc b/passes/techmap/clkpart.cc new file mode 100644 index 000000000..8f671c175 --- /dev/null +++ b/passes/techmap/clkpart.cc @@ -0,0 +1,269 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + *                2019  Eddie Hung <eddie@fpgeh.com> + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ClkPartPass : public Pass { +	ClkPartPass() : Pass("clkpart", "partition design according to clock domain") { } +	void help() YS_OVERRIDE +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("    clkpart [options] [selection]\n"); +		log("\n"); +		log("Partition the contents of selected modules according to the clock (and optionally\n"); +		log("the enable) domains of its $_DFF* cells by extracting them into sub-modules,\n"); +		log("using the `submod` command.\n"); +		log("Sub-modules created by this command are marked with a 'clkpart' attribute.\n"); +		log("\n"); +		log("    -unpart\n"); +		log("        undo this operation within the selected modules, by flattening those with\n"); +		log("        a 'clkpart' attribute into those modules without this attribute.\n"); +		log("\n"); +		log("    -enable\n"); +		log("        also consider enable domains.\n"); +		log("\n"); +	} + +	bool unpart_mode, enable_mode; + +	void clear_flags() YS_OVERRIDE +	{ +		unpart_mode = false; +		enable_mode = false; +	} +	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE +	{ +		log_header(design, "Executing CLKPART pass (partition design according to clock domain).\n"); +		log_push(); + +		clear_flags(); + +		size_t argidx; +		for (argidx = 1; argidx < args.size(); argidx++) +		{ +			if (args[argidx] == "-unpart") { +				unpart_mode = true; +				continue; +			} +			if (args[argidx] == "-enable") { +				enable_mode = true; +				continue; +			} +			break; +		} +		extra_args(args, argidx, design); + +		if (unpart_mode) +			unpart(design); +		else +			part(design); + +		log_pop(); +	} + +	void part(RTLIL::Design *design) +	{ +		CellTypes ct(design); +		SigMap assign_map; + +		for (auto mod : design->selected_modules()) +		{ +			if (mod->processes.size() > 0) { +				log("Skipping module %s as it contains processes.\n", log_id(mod)); +				continue; +			} + +			assign_map.set(mod); + +			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, vector<RTLIL::IdString>> 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; + +				for (auto &conn : cell->connections()) +				for (auto bit : conn.second) { +					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_))) +				{ +					key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); +				} +				else +				if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) +				{ +					bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); +					bool this_en_pol = !enable_mode || cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); +					key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, enable_mode ? assign_map(cell->getPort(ID(E))) : RTLIL::SigSpec()); +				} +				else +					continue; + +				unassigned_cells.erase(cell); +				expand_queue.insert(cell); +				expand_queue_up.insert(cell); +				expand_queue_down.insert(cell); + +				assigned_cells[key].push_back(cell->name); +				assigned_cells_reverse[cell] = key; +			} + +			while (!expand_queue_up.empty() || !expand_queue_down.empty()) +			{ +				if (!expand_queue_up.empty()) +				{ +					RTLIL::Cell *cell = *expand_queue_up.begin(); +					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->name); +							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->name); +							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->name); +							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->name); +				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))); + +			if (assigned_cells.size() > 1) +				for (auto &it : assigned_cells) { +					RTLIL::Selection sel(false); +					sel.selected_members[mod->name] = pool<IdString>(it.second.begin(), it.second.end()); + +					RTLIL::IdString submod = stringf("%s.%s", mod->name.c_str(), NEW_ID.c_str()); +					Pass::call_on_selection(design, sel, stringf("submod -name %s", submod.c_str())); + +					design->module(submod)->set_bool_attribute(ID(clkpart)); +				} +		} +	} + +	void unpart(RTLIL::Design *design) +	{ +		vector<Module*> keeped; +		for (auto mod : design->selected_modules()) { +			if (mod->get_bool_attribute(ID(clkpart))) +				continue; +			if (mod->get_bool_attribute(ID(keep_hierarchy))) +				continue; +			keeped.push_back(mod); +			mod->set_bool_attribute(ID(keep_hierarchy)); +		} + +		Pass::call(design, "flatten"); + +		for (auto mod : keeped) +			mod->set_bool_attribute(ID(keep_hierarchy), false); + +	} +} ClkPartPass; + +PRIVATE_NAMESPACE_END  | 
