diff options
| author | Eddie Hung <eddie@fpgeh.com> | 2019-12-28 05:07:46 -0800 | 
|---|---|---|
| committer | Eddie Hung <eddie@fpgeh.com> | 2019-12-28 05:07:46 -0800 | 
| commit | f348ffa44d4ec00537499ffe79ce627beeeefe85 (patch) | |
| tree | 68ca1c83c645ac3230a2170bbb29f07d4e288397 /passes/techmap | |
| parent | ec2539480867fcc05c904043747b2f3cba9a9866 (diff) | |
| download | yosys-f348ffa44d4ec00537499ffe79ce627beeeefe85.tar.gz yosys-f348ffa44d4ec00537499ffe79ce627beeeefe85.tar.bz2 yosys-f348ffa44d4ec00537499ffe79ce627beeeefe85.zip | |
abc9_techmap -> _map; called from abc9 script pass along with abc9_ops
Diffstat (limited to 'passes/techmap')
| -rw-r--r-- | passes/techmap/Makefile.inc | 3 | ||||
| -rw-r--r-- | passes/techmap/abc9.cc | 231 | ||||
| -rw-r--r-- | passes/techmap/abc9_map.cc (renamed from passes/techmap/abc9_techmap.cc) | 163 | ||||
| -rw-r--r-- | passes/techmap/abc9_ops.cc | 139 | 
4 files changed, 406 insertions, 130 deletions
| diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index a7c8d8c2b..734d6c10f 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -8,7 +8,8 @@ OBJS += passes/techmap/libparse.o  ifeq ($(ENABLE_ABC),1)  OBJS += passes/techmap/abc.o  OBJS += passes/techmap/abc9.o -OBJS += passes/techmap/abc9_techmap.o +OBJS += passes/techmap/abc9_map.o +OBJS += passes/techmap/abc9_ops.o  ifneq ($(ABCEXTERNAL),)  passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'  passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc new file mode 100644 index 000000000..e1cf188ce --- /dev/null +++ b/passes/techmap/abc9.cc @@ -0,0 +1,231 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + *            (C) 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/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate +                           // to one LUT6 (instead of a LUT5 + LUT2) + +struct Abc9Pass : public ScriptPass +{ +	Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { } + +	void help() YS_OVERRIDE +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("    abc9 [options] [selection]\n"); +		log("\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("\n"); +		log("    -exe <command>\n"); +#ifdef ABCEXTERNAL +		log("        use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else +		log("        use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n"); +#endif +		log("        This can e.g. be used to call a specific version of ABC or a wrapper.\n"); +		log("\n"); +		log("    -script <file>\n"); +		log("        use the specified ABC script file instead of the default script.\n"); +		log("\n"); +		log("        if <file> starts with a plus sign (+), then the rest of the filename\n"); +		log("        string is interpreted as the command string to be passed to ABC. The\n"); +		log("        leading plus sign is removed and all commas (,) in the string are\n"); +		log("        replaced with blanks before the string is passed to ABC.\n"); +		log("\n"); +		log("        if no -script parameter is given, the following scripts are used:\n"); +		log("\n"); +		log("        for -lut/-luts (only one LUT size):\n"); +		// FIXME +		//log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); +		log("\n"); +		log("        for -lut/-luts (different LUT sizes):\n"); +		// FIXME +		//log("%s\n", fold_abc9_cmd(ABC_COMMAND_LUT).c_str()); +		log("\n"); +		log("    -fast\n"); +		log("        use different default scripts that are slightly faster (at the cost\n"); +		log("        of output quality):\n"); +		log("\n"); +		log("        for -lut/-luts:\n"); +		// FIXME +		//log("%s\n", fold_abc9_cmd(ABC_FAST_COMMAND_LUT).c_str()); +		log("\n"); +		log("    -D <picoseconds>\n"); +		log("        set delay target. the string {D} in the default scripts above is\n"); +		log("        replaced by this option when used, and an empty string otherwise\n"); +		log("        (indicating best possible delay).\n"); +//		log("        This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); +//		log("        default scripts above.\n"); +		log("\n"); +//		log("    -S <num>\n"); +//		log("        maximum number of LUT inputs shared.\n"); +//		log("        (replaces {S} in the default scripts above, default: -S 1)\n"); +//		log("\n"); +		log("    -lut <width>\n"); +		log("        generate netlist using luts of (max) the specified width.\n"); +		log("\n"); +		log("    -lut <w1>:<w2>\n"); +		log("        generate netlist using luts of (max) the specified width <w2>. All\n"); +		log("        luts with width <= <w1> have constant cost. for luts larger than <w1>\n"); +		log("        the area cost doubles with each additional input bit. the delay cost\n"); +		log("        is still constant for all lut widths.\n"); +		log("\n"); +		log("    -lut <file>\n"); +		log("        pass this file with lut library to ABC.\n"); +		log("\n"); +		log("    -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n"); +		log("        generate netlist using luts. Use the specified costs for luts with 1,\n"); +		log("        2, 3, .. inputs.\n"); +		log("\n"); +//		log("    -dff\n"); +//		log("        also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); +//		log("        clock domains are automatically partitioned in clock domains and each\n"); +//		log("        domain is passed through ABC independently.\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("        when this option is used, the temporary files created by this pass\n"); +		log("        are not removed. this is useful for debugging.\n"); +		log("\n"); +		log("    -showtmp\n"); +		log("        print the temp dir name in log. usually this is suppressed so that the\n"); +		log("        command output is identical across runs.\n"); +		log("\n"); +		log("    -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("        pass this file with box library to ABC. Use with -lut.\n"); +		log("\n"); +		log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); +		log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); +		log("ABC on logic snippets extracted from your design. You will not get any useful\n"); +		log("output when passing an ABC script that writes a file. Instead write your full\n"); +		log("design as BLIF file with write_blif and then load that into ABC externally if\n"); +		log("you want to use ABC to convert your design into another format.\n"); +		log("\n"); +		log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); +		log("\n"); +		help_script(); +		log("\n"); +	} + +	std::stringstream map_cmd; +	bool cleanup; + +	void clear_flags() YS_OVERRIDE +	{ +		map_cmd.str(""); +		map_cmd << "abc9_map"; +		cleanup = true; +	} + +	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE +	{ +		std::string run_from, run_to; +		clear_flags(); + +		size_t argidx; +		for (argidx = 1; argidx < args.size(); argidx++) { +			std::string arg = args[argidx]; +			if ((arg == "-exe" || arg == "-script" || arg == "-D" || +						/* arg == "-S" || */ arg == "-lut" || arg == "-luts" || +						arg == "-clk" || arg == "-box" || arg == "-W") && +					argidx+1 < args.size()) { +				map_cmd << " " << arg << " " << args[++argidx]; +				continue; +			} +			if (arg == "-fast" || /*arg == "-dff" ||*/ arg == "-keepff" +					/*|| arg == "-nocleanup"*/ || arg == "-showtmp" || arg == "-markgroups" +					|| arg == "-nomfs") { +				map_cmd << " " << arg; +				continue; +			} +			if (arg == "-nocleanup") { +				cleanup = false; +				continue; +			} +			break; +		} +		extra_args(args, argidx, design); + +		log_header(design, "Executing ABC9 pass.\n"); + +		run_script(design, run_from, run_to); +	} + +	void script() YS_OVERRIDE +	{ +		auto selected_modules = active_design->selected_modules(); +		active_design->selection_stack.emplace_back(false); + +		for (auto mod : selected_modules) { +			log_push(); + +			active_design->selection().select(mod); + +			std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; +			if (!cleanup) +				tempdir_name[0] = tempdir_name[4] = '_'; +			tempdir_name = make_temp_dir(tempdir_name); + +			run("scc -set_attr abc9_scc_id {}"); +			run("abc9_ops -break_scc"); +			run("aigmap"); +			run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), +					"write_xaiger -map <abc-temp-dir>/input.sym <abc-temp-dir>/input.xaig"); +			run(stringf("%s -tempdir %s", map_cmd.str().c_str(), tempdir_name.c_str()), +					"abc9_map [options] -tempdir <abc-temp-dir>"); +			run("abc9_ops -unbreak_scc"); + +			if (cleanup) +			{ +				log("Removing temp directory.\n"); +				remove_directory(tempdir_name); +			} + +			active_design->selection().selected_modules.clear(); + +			log_pop(); +		} + +		active_design->selection_stack.pop_back(); +	} +} Abc9Pass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/abc9_techmap.cc b/passes/techmap/abc9_map.cc index 7ff68f382..40ff4bbf0 100644 --- a/passes/techmap/abc9_techmap.cc +++ b/passes/techmap/abc9_map.cc @@ -76,58 +76,6 @@ 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) -{ -	Pass::call(design, "scc -set_attr abc9_scc_id {}"); - -	// For every unique SCC found, (arbitrarily) find the first -	// cell in the component, and select (and mark) all its output -	// wires -	pool<RTLIL::Const> ids_seen; -	for (auto cell : module->cells()) { -		auto it = cell->attributes.find(ID(abc9_scc_id)); -		if (it != cell->attributes.end()) { -			auto r = ids_seen.insert(it->second); -			if (r.second) { -				for (auto &c : cell->connections_) { -					if (c.second.is_fully_const()) continue; -					if (cell->output(c.first)) { -						SigBit b = c.second.as_bit(); -						Wire *w = b.wire; -						if (w->port_input) { -							// In this case, hopefully the loop break has been already created -							// Get the non-prefixed wire -							Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); -							log_assert(wo != nullptr); -							log_assert(wo->port_output); -							log_assert(b.offset < GetSize(wo)); -							c.second = RTLIL::SigBit(wo, b.offset); -						} -						else { -							// Create a new output/input loop break -							w->port_input = true; -							w = module->wire(stringf("%s.abco", w->name.c_str())); -							if (!w) { -								w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); -								w->port_output = true; -							} -							else { -								log_assert(w->port_input); -								log_assert(b.offset < GetSize(w)); -							} -							w->set_bool_attribute(ID(abc9_scc_break)); -							c.second = RTLIL::SigBit(w, b.offset); -						} -					} -				} -			} -			cell->attributes.erase(it); -		} -	} - -	module->fixup_ports(); -} -  std::string add_echos_to_abc9_cmd(std::string str)  {  	std::string new_str, token; @@ -254,10 +202,10 @@ 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, +		/*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 +		std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs, std::string tempdir_name  )  {  	module = current_module; @@ -296,10 +244,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  	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] = '_'; -	tempdir_name = make_temp_dir(tempdir_name);  	log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",  			module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); @@ -383,33 +327,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri  		}  	} -	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(); -	if (count_output) +	//if (count_output)  	{ -		design->selection_stack.emplace_back(false); -		RTLIL::Selection& sel = design->selection_stack.back(); -		sel.select(module); - -		handle_loops(design); - -		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())); -  		std::string buffer;  		std::ifstream ifs;  #if 0 @@ -428,8 +349,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(); -  		log_header(design, "Executing ABC9_MAP.\n");  		if (!lut_costs.empty()) { @@ -773,41 +692,16 @@ clone_lut:  			}  		} -		// Now 'unexpose' those wires by undoing -		// the expose operation -- remove them from PO/PI -		// and re-connecting them back together -		for (auto wire : module->wires()) { -			auto it = wire->attributes.find(ID(abc9_scc_break)); -			if (it != wire->attributes.end()) { -				wire->attributes.erase(it); -				log_assert(wire->port_output); -				wire->port_output = false; -				std::string name = wire->name.str(); -				RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); -				log_assert(i_wire); -				log_assert(i_wire->port_input); -				i_wire->port_input = false; -				module->connect(i_wire, wire); -			} -		} -		module->fixup_ports(); -  		//log("ABC RESULTS:        internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);  		log("ABC RESULTS:           input signals: %8d\n", in_wires);  		log("ABC RESULTS:          output signals: %8d\n", out_wires);  		design->remove(mapped_mod);  	} -	else -	{ -		log("Don't call ABC as there is nothing to map.\n"); -	} - -	if (cleanup) -	{ -		log("Removing temp directory.\n"); -		remove_directory(tempdir_name); -	} +	//else +	//{ +	//	log("Don't call ABC as there is nothing to map.\n"); +	//}  	log_pop();  } @@ -894,10 +788,10 @@ struct Abc9TechmapPass : public Pass {  //		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("        when this option is used, the temporary files created by this pass\n"); -		log("        are not removed. this is useful for debugging.\n"); -		log("\n"); +//		log("    -nocleanup\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("\n");  		log("    -showtmp\n");  		log("        print the temp dir name in log. usually this is suppressed so that the\n");  		log("        command output is identical across runs.\n"); @@ -910,6 +804,9 @@ struct Abc9TechmapPass : public Pass {  		log("    -box <file>\n");  		log("        pass this file with box library to ABC. Use with -lut.\n");  		log("\n"); +		log("    -tempdir <dir>\n"); +		log("        use this as the temp dir.\n"); +		log("\n");  		log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");  		log("internally. This is not going to \"run ABC on your design\". It will instead run\n");  		log("ABC on logic snippets extracted from your design. You will not get any useful\n"); @@ -922,7 +819,7 @@ struct Abc9TechmapPass : public Pass {  	}  	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE  	{ -		log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); +		log_header(design, "Executing ABC9_MAP pass (technology mapping using ABC9).\n");  		log_push();  		assign_map.clear(); @@ -934,7 +831,8 @@ struct Abc9TechmapPass : 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; +		std::string tempdir_name; +		bool fast_mode = false, dff_mode = false, keepff = false /*, cleanup = true*/;  		bool show_tempdir = false;  		bool nomfs = false;  		vector<int> lut_costs; @@ -1038,10 +936,10 @@ struct Abc9TechmapPass : public Pass {  			//	keepff = true;  			//	continue;  			//} -			if (arg == "-nocleanup") { -				cleanup = false; -				continue; -			} +			//if (arg == "-nocleanup") { +			//	cleanup = false; +			//	continue; +			//}  			if (arg == "-showtmp") {  				show_tempdir = true;  				continue; @@ -1062,17 +960,24 @@ struct Abc9TechmapPass : public Pass {  				nomfs = true;  				continue;  			} +			if (arg == "-tempdir" && argidx+1 < args.size()) { +				tempdir_name = args[++argidx]; +				continue; +			}  			break;  		}  		extra_args(args, argidx, design);  		// ABC expects a box file for XAIG  		if (box_file.empty()) -		    box_file = "+/dummy.box"; +			box_file = "+/dummy.box";  		rewrite_filename(box_file);  		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; + +		if (tempdir_name.empty()) +			log_cmd_error("abc9_map '-tempdir' option is mandatory.\n");  		dict<int,IdString> box_lookup;  		for (auto m : design->modules()) { @@ -1148,9 +1053,9 @@ struct Abc9TechmapPass : public Pass {  			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, +				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); +						box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);  				continue;  			} @@ -1294,9 +1199,9 @@ struct Abc9TechmapPass : public Pass {  				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(), "$", +				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); +						box_file, lut_file, wire_delay, box_lookup, nomfs, tempdir_name);  				assign_map.set(mod);  			}  		} diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc new file mode 100644 index 000000000..4c30efd06 --- /dev/null +++ b/passes/techmap/abc9_ops.cc @@ -0,0 +1,139 @@ +/* + *  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" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void break_scc(RTLIL::Module *module) +{ +	// For every unique SCC found, (arbitrarily) find the first +	//   cell in the component, and convert all wires driven by +	//   its output ports into a new PO, and drive its previous +	//   sinks with a new PI +	pool<RTLIL::Const> ids_seen; +	for (auto cell : module->selected_cells()) { +		auto it = cell->attributes.find(ID(abc9_scc_id)); +		if (it == cell->attributes.end()) +			continue; +		auto r = ids_seen.insert(it->second); +		cell->attributes.erase(it); +		if (!r.second) +			continue; +		for (auto &c : cell->connections_) { +			if (c.second.is_fully_const()) continue; +			if (cell->output(c.first)) { +				SigBit b = c.second.as_bit(); +				Wire *w = b.wire; +				if (w->port_input) { +					// In this case, hopefully the loop break has been already created +					// Get the non-prefixed wire +					Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); +					log_assert(wo != nullptr); +					log_assert(wo->port_output); +					log_assert(b.offset < GetSize(wo)); +					c.second = RTLIL::SigBit(wo, b.offset); +				} +				else { +					// Create a new output/input loop break +					w->port_input = true; +					w = module->wire(stringf("%s.abco", w->name.c_str())); +					if (!w) { +						w = module->addWire(stringf("%s.abco", b.wire->name.c_str()), GetSize(b.wire)); +						w->port_output = true; +					} +					else { +						log_assert(w->port_input); +						log_assert(b.offset < GetSize(w)); +					} +					w->set_bool_attribute(ID(abc9_scc_break)); +					c.second = RTLIL::SigBit(w, b.offset); +				} +			} +		} +	} + +	module->fixup_ports(); +} + +void unbreak_scc(RTLIL::Module *module) { +	// Now 'unexpose' those wires by undoing +	// the expose operation -- remove them from PO/PI +	// and re-connecting them back together +	for (auto wire : module->wires()) { +		auto it = wire->attributes.find(ID(abc9_scc_break)); +		if (it != wire->attributes.end()) { +			wire->attributes.erase(it); +			log_assert(wire->port_output); +			wire->port_output = false; +			std::string name = wire->name.str(); +			RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); +			log_assert(i_wire); +			log_assert(i_wire->port_input); +			i_wire->port_input = false; +			module->connect(i_wire, wire); +		} +	} +	module->fixup_ports(); +} + +struct Abc9PrepPass : public Pass { +	Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } +	void help() YS_OVERRIDE +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("    abc9_ops [options] [selection]\n"); +		log("\n"); +	} +	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE +	{ +		log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); +		log_push(); + +		bool break_scc_mode = false; +		bool unbreak_scc_mode = false; + +		size_t argidx; +		for (argidx = 1; argidx < args.size(); argidx++) { +			std::string arg = args[argidx]; +			if (arg == "-break_scc") { +				break_scc_mode = true; +				continue; +			} +			if (arg == "-unbreak_scc") { +				unbreak_scc_mode = true; +				continue; +			} +			break; +		} +		extra_args(args, argidx, design); + +		for (auto mod : design->selected_modules()) { +			if (break_scc_mode) +				break_scc(mod); +			if (unbreak_scc_mode) +				unbreak_scc(mod); +		} +	} +} Abc9PrepPass; + +PRIVATE_NAMESPACE_END | 
