mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	splitnet -driver feature
Merge branch 'master' of https://github.com/cliffordwolf/yosys into btor
This commit is contained in:
		
						commit
						09f16c9d0c
					
				
					 6 changed files with 343 additions and 45 deletions
				
			
		|  | @ -1024,6 +1024,13 @@ void RTLIL::SigSpec::optimize() | ||||||
| 	check(); | 	check(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | RTLIL::SigSpec RTLIL::SigSpec::optimized() const | ||||||
|  | { | ||||||
|  | 	RTLIL::SigSpec ret = *this; | ||||||
|  | 	ret.optimize(); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool RTLIL::SigChunk::compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b) | bool RTLIL::SigChunk::compare(const RTLIL::SigChunk &a, const RTLIL::SigChunk &b) | ||||||
| { | { | ||||||
| 	if (a.wire != b.wire) { | 	if (a.wire != b.wire) { | ||||||
|  |  | ||||||
|  | @ -373,6 +373,7 @@ struct RTLIL::SigSpec { | ||||||
| 	SigSpec(std::vector<RTLIL::SigBit> bits); | 	SigSpec(std::vector<RTLIL::SigBit> bits); | ||||||
| 	void expand(); | 	void expand(); | ||||||
| 	void optimize(); | 	void optimize(); | ||||||
|  | 	RTLIL::SigSpec optimized() const; | ||||||
| 	void sort(); | 	void sort(); | ||||||
| 	void sort_and_unify(); | 	void sort_and_unify(); | ||||||
| 	void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with); | 	void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with); | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ OBJS += passes/cmds/design.o | ||||||
| OBJS += passes/cmds/select.o | OBJS += passes/cmds/select.o | ||||||
| OBJS += passes/cmds/show.o | OBJS += passes/cmds/show.o | ||||||
| OBJS += passes/cmds/rename.o | OBJS += passes/cmds/rename.o | ||||||
|  | OBJS += passes/cmds/connect.o | ||||||
| OBJS += passes/cmds/scatter.o | OBJS += passes/cmds/scatter.o | ||||||
| OBJS += passes/cmds/splitnets.o | OBJS += passes/cmds/splitnets.o | ||||||
| OBJS += passes/cmds/stat.o | OBJS += passes/cmds/stat.o | ||||||
|  |  | ||||||
							
								
								
									
										185
									
								
								passes/cmds/connect.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								passes/cmds/connect.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,185 @@ | ||||||
|  | /*
 | ||||||
|  |  *  yosys -- Yosys Open SYnthesis Suite | ||||||
|  |  * | ||||||
|  |  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> | ||||||
|  |  *   | ||||||
|  |  *  Permission to use, copy, modify, and/or distribute this software for any | ||||||
|  |  *  purpose with or without fee is hereby granted, provided that the above | ||||||
|  |  *  copyright notice and this permission notice appear in all copies. | ||||||
|  |  *   | ||||||
|  |  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||||
|  |  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||||
|  |  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||||
|  |  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||||
|  |  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||||
|  |  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||||
|  |  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include "kernel/register.h" | ||||||
|  | #include "kernel/rtlil.h" | ||||||
|  | #include "kernel/sigtools.h" | ||||||
|  | #include "kernel/celltypes.h" | ||||||
|  | #include "kernel/log.h" | ||||||
|  | 
 | ||||||
|  | static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, RTLIL::SigSpec &sig) | ||||||
|  | { | ||||||
|  | 	CellTypes ct(design); | ||||||
|  | 
 | ||||||
|  | 	RTLIL::Wire *dummy_wire = module->new_wire(sig.width, NEW_ID); | ||||||
|  | 
 | ||||||
|  | 	for (auto &it : module->cells) | ||||||
|  | 	for (auto &port : it.second->connections) | ||||||
|  | 		if (ct.cell_output(it.second->type, port.first)) | ||||||
|  | 			sigmap(port.second).replace(sig, dummy_wire, &port.second); | ||||||
|  | 
 | ||||||
|  | 	for (auto &conn : module->connections) | ||||||
|  | 		sigmap(conn.first).replace(sig, dummy_wire, &conn.first); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct ConnectPass : public Pass { | ||||||
|  | 	ConnectPass() : Pass("connect", "create or remove connections") { } | ||||||
|  | 	virtual void help() | ||||||
|  | 	{ | ||||||
|  | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    connect [-nomap] [-nounset] -set <lhs-expr> <rhs-expr>\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Create a connection. This is equivialent to adding the statement 'assign\n"); | ||||||
|  | 		log("<lhs-expr> = <rhs-expr>;' to the verilog input. Per default, all existing\n"); | ||||||
|  | 		log("drivers for <lhs-expr> are unconnected. This can be overwritten by using\n"); | ||||||
|  | 		log("the -nounset option.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    connect [-nomap] -unset <expr>\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Unconnect all existing drivers for the specified expression.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    connect [-nomap] -port <cell> <port> <expr>\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Connect the specified cell port to the specified cell port.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("Per default signal alias names are resolved and all signal names are mapped\n"); | ||||||
|  | 		log("the the signal name of the primary driver. Using the -nomap option deactivates\n"); | ||||||
|  | 		log("this behavior.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("The connect command operates in one module only. Either only one module must\n"); | ||||||
|  | 		log("be selected or an active module must be set using the 'cd' command.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("This command does not operate on module with processes.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||||
|  | 	{ | ||||||
|  | 		RTLIL::Module *module = NULL; | ||||||
|  | 		for (auto &it : design->modules) { | ||||||
|  | 			if (!design->selected(it.second)) | ||||||
|  | 				continue; | ||||||
|  | 			if (module != NULL) | ||||||
|  | 				log_cmd_error("Multiple modules selected: %s, %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.first)); | ||||||
|  | 			module = it.second; | ||||||
|  | 		} | ||||||
|  | 		if (module == NULL) | ||||||
|  | 			log_cmd_error("No modules selected.\n"); | ||||||
|  | 		if (!module->processes.empty()) | ||||||
|  | 			log_cmd_error("Found processes in selected module.\n"); | ||||||
|  | 
 | ||||||
|  | 		bool flag_nounset = false, flag_nomap = false; | ||||||
|  | 		std::string set_lhs, set_rhs, unset_expr; | ||||||
|  | 		std::string port_cell, port_port, port_expr; | ||||||
|  | 
 | ||||||
|  | 		size_t argidx; | ||||||
|  | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | 		{ | ||||||
|  | 			std::string arg = args[argidx]; | ||||||
|  | 			if (arg == "-nounset") { | ||||||
|  | 				flag_nounset = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (arg == "-nomap") { | ||||||
|  | 				flag_nomap = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (arg == "-set" && argidx+2 < args.size()) { | ||||||
|  | 				set_lhs = args[++argidx]; | ||||||
|  | 				set_rhs = args[++argidx]; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (arg == "-unset" && argidx+1 < args.size()) { | ||||||
|  | 				unset_expr = args[++argidx]; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (arg == "-port" && argidx+3 < args.size()) { | ||||||
|  | 				port_cell = args[++argidx]; | ||||||
|  | 				port_port = args[++argidx]; | ||||||
|  | 				port_expr = args[++argidx]; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		SigMap sigmap; | ||||||
|  | 		if (!flag_nomap) | ||||||
|  | 			for (auto &it : module->connections) { | ||||||
|  | 				std::vector<RTLIL::SigBit> lhs = it.first.to_sigbit_vector(); | ||||||
|  | 				std::vector<RTLIL::SigBit> rhs = it.first.to_sigbit_vector(); | ||||||
|  | 				for (size_t i = 0; i < lhs.size(); i++) | ||||||
|  | 					if (rhs[i].wire != NULL) | ||||||
|  | 						sigmap.add(lhs[i], rhs[i]); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		if (!set_lhs.empty()) | ||||||
|  | 		{ | ||||||
|  | 			if (!unset_expr.empty() || !port_cell.empty()) | ||||||
|  | 				log_cmd_error("Cant use -set together with -unset and/or -port.\n"); | ||||||
|  | 
 | ||||||
|  | 			RTLIL::SigSpec sig_lhs, sig_rhs; | ||||||
|  | 			if (!RTLIL::SigSpec::parse(sig_lhs, module, set_lhs)) | ||||||
|  | 				log_cmd_error("Failed to parse set lhs expression `%s'.\n", set_lhs.c_str()); | ||||||
|  | 			if (!RTLIL::SigSpec::parse_rhs(sig_lhs, sig_rhs, module, set_rhs)) | ||||||
|  | 				log_cmd_error("Failed to parse set rhs expression `%s'.\n", set_rhs.c_str()); | ||||||
|  | 
 | ||||||
|  | 			sigmap.apply(sig_lhs); | ||||||
|  | 			sigmap.apply(sig_rhs); | ||||||
|  | 
 | ||||||
|  | 			if (!flag_nounset) | ||||||
|  | 				unset_drivers(design, module, sigmap, sig_lhs); | ||||||
|  | 
 | ||||||
|  | 			module->connections.push_back(RTLIL::SigSig(sig_lhs, sig_rhs)); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		if (!unset_expr.empty()) | ||||||
|  | 		{ | ||||||
|  | 			if (!port_cell.empty() || flag_nounset) | ||||||
|  | 				log_cmd_error("Cant use -unset together with -port and/or -nounset.\n"); | ||||||
|  | 
 | ||||||
|  | 			RTLIL::SigSpec sig; | ||||||
|  | 			if (!RTLIL::SigSpec::parse(sig, module, unset_expr)) | ||||||
|  | 				log_cmd_error("Failed to parse unset expression `%s'.\n", unset_expr.c_str()); | ||||||
|  | 
 | ||||||
|  | 			sigmap.apply(sig); | ||||||
|  | 			unset_drivers(design, module, sigmap, sig); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		if (!port_cell.empty()) | ||||||
|  | 		{ | ||||||
|  | 			if (flag_nounset) | ||||||
|  | 				log_cmd_error("Cant use -port together with -nounset.\n"); | ||||||
|  | 
 | ||||||
|  | 			if (module->cells.count(RTLIL::escape_id(port_cell)) == 0) | ||||||
|  | 				log_cmd_error("Can't find cell %s.\n", port_cell.c_str()); | ||||||
|  | 
 | ||||||
|  | 			RTLIL::SigSpec sig; | ||||||
|  | 			if (!RTLIL::SigSpec::parse(sig, module, port_expr)) | ||||||
|  | 				log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str()); | ||||||
|  | 
 | ||||||
|  | 			module->cells.at(RTLIL::escape_id(port_cell))->connections[RTLIL::escape_id(port_port)] = sigmap(sig); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 			log_cmd_error("Expected -set, -unset, or -port.\n"); | ||||||
|  | 	} | ||||||
|  | } ConnectPass; | ||||||
|  |   | ||||||
|  | @ -24,16 +24,48 @@ | ||||||
| 
 | 
 | ||||||
| struct SplitnetsWorker | struct SplitnetsWorker | ||||||
| { | { | ||||||
| 	std::map<RTLIL::Wire*, std::vector<RTLIL::Wire*>> splitmap; | 	std::map<RTLIL::Wire*, std::vector<RTLIL::SigBit>> splitmap; | ||||||
|  | 
 | ||||||
|  | 	void append_wire(RTLIL::Module *module, RTLIL::Wire *wire, int offset, int width, std::string format) | ||||||
|  | 	{ | ||||||
|  | 		RTLIL::Wire *new_wire = new RTLIL::Wire; | ||||||
|  | 
 | ||||||
|  | 		new_wire->port_id = wire->port_id; | ||||||
|  | 		new_wire->port_input = wire->port_input; | ||||||
|  | 		new_wire->port_output = wire->port_output; | ||||||
|  | 		new_wire->name = wire->name; | ||||||
|  | 		new_wire->width = width; | ||||||
|  | 
 | ||||||
|  | 		if (format.size() > 0) | ||||||
|  | 			new_wire->name += format.substr(0, 1); | ||||||
|  | 
 | ||||||
|  | 		if (width > 1) { | ||||||
|  | 			new_wire->name += stringf("%d", offset+width-1); | ||||||
|  | 			if (format.size() > 2) | ||||||
|  | 				new_wire->name += format.substr(2, 1); | ||||||
|  | 			else | ||||||
|  | 				new_wire->name += ":"; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		new_wire->name += stringf("%d", offset); | ||||||
|  | 
 | ||||||
|  | 		if (format.size() > 1) | ||||||
|  | 			new_wire->name += format.substr(1, 1); | ||||||
|  | 
 | ||||||
|  | 		while (module->count_id(new_wire->name) > 0) | ||||||
|  | 			new_wire->name = new_wire->name + "_"; | ||||||
|  | 		module->add(new_wire); | ||||||
|  | 
 | ||||||
|  | 		std::vector<RTLIL::SigBit> sigvec = RTLIL::SigSpec(new_wire).to_sigbit_vector(); | ||||||
|  | 		splitmap[wire].insert(splitmap[wire].end(), sigvec.begin(), sigvec.end()); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	void operator()(RTLIL::SigSpec &sig) | 	void operator()(RTLIL::SigSpec &sig) | ||||||
| 	{ | 	{ | ||||||
| 		sig.expand(); | 		sig.expand(); | ||||||
| 		for (auto &c : sig.chunks) | 		for (auto &c : sig.chunks) | ||||||
| 			if (splitmap.count(c.wire) > 0) { | 			if (splitmap.count(c.wire) > 0) | ||||||
| 				c.wire = splitmap.at(c.wire).at(c.offset); | 				c = splitmap.at(c.wire).at(c.offset); | ||||||
| 				c.offset = 0; |  | ||||||
| 			} |  | ||||||
| 		sig.optimize(); | 		sig.optimize(); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  | @ -48,19 +80,25 @@ struct SplitnetsPass : public Pass { | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("This command splits multi-bit nets into single-bit nets.\n"); | 		log("This command splits multi-bit nets into single-bit nets.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -format char1[char2]\n"); | 		log("    -format char1[char2[char3]]\n"); | ||||||
| 		log("        the first char is inserted between the net name and the bit index, the\n"); | 		log("        the first char is inserted between the net name and the bit index, the\n"); | ||||||
| 		log("        second char is appended to the netname. e.g. -format () creates net\n"); | 		log("        second char is appended to the netname. e.g. -format () creates net\n"); | ||||||
| 		log("        names like 'mysignal(42)'. the default is '[]'.\n"); | 		log("        names like 'mysignal(42)'. the 3rd character is the range seperation\n"); | ||||||
|  | 		log("        character when creating multi-bit wires. the default is '[]:'.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -ports\n"); | 		log("    -ports\n"); | ||||||
| 		log("        also split module ports. per default only internal signals are split.\n"); | 		log("        also split module ports. per default only internal signals are split.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("    -driver\n"); | ||||||
|  | 		log("        don't blindly split nets in individual bits. instead look at the driver\n"); | ||||||
|  | 		log("        and split nets so that no driver drives only part of a net.\n"); | ||||||
|  | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||||
| 	{ | 	{ | ||||||
| 		bool flag_ports = false; | 		bool flag_ports = false; | ||||||
| 		std::string format = "[]"; | 		bool flag_driver = false; | ||||||
|  | 		std::string format = "[]:"; | ||||||
| 
 | 
 | ||||||
| 		size_t argidx; | 		size_t argidx; | ||||||
| 		for (argidx = 1; argidx < args.size(); argidx++) | 		for (argidx = 1; argidx < args.size(); argidx++) | ||||||
|  | @ -73,6 +111,10 @@ struct SplitnetsPass : public Pass { | ||||||
| 				flag_ports = true; | 				flag_ports = true; | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
|  | 			if (args[argidx] == "-driver") { | ||||||
|  | 				flag_driver = true; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		extra_args(args, argidx, design); | 		extra_args(args, argidx, design); | ||||||
|  | @ -85,30 +127,55 @@ struct SplitnetsPass : public Pass { | ||||||
| 
 | 
 | ||||||
| 			SplitnetsWorker worker; | 			SplitnetsWorker worker; | ||||||
| 
 | 
 | ||||||
| 			for (auto &w : module->wires) { | 			if (flag_driver) | ||||||
| 				RTLIL::Wire *wire = w.second; | 			{ | ||||||
| 				if (wire->width > 1 && (wire->port_id == 0 || flag_ports)) | 				CellTypes ct(design); | ||||||
| 					worker.splitmap[wire] = std::vector<RTLIL::Wire*>(); |  | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			for (auto &it : worker.splitmap) | 				std::map<RTLIL::Wire*, std::set<int>> split_wires_at; | ||||||
| 				for (int i = 0; i < it.first->width; i++) { | 
 | ||||||
| 					RTLIL::Wire *wire = new RTLIL::Wire; | 				for (auto &c : module->cells) | ||||||
| 					wire->port_id = it.first->port_id; | 				for (auto &p : c.second->connections) | ||||||
| 					wire->port_input = it.first->port_input; | 				{ | ||||||
| 					wire->port_output = it.first->port_output; | 					if (!ct.cell_known(c.second->type)) | ||||||
| 					wire->name = it.first->name; | 						continue; | ||||||
| 					if (format.size() > 0) | 					if (!ct.cell_output(c.second->type, p.first)) | ||||||
| 						wire->name += format.substr(0, 1); | 						continue; | ||||||
| 					wire->name += stringf("%d", i); | 
 | ||||||
| 					if (format.size() > 0) | 					RTLIL::SigSpec sig = p.second.optimized(); | ||||||
| 						wire->name += format.substr(1); | 					for (auto &chunk : sig.chunks) { | ||||||
| 					while (module->count_id(wire->name) > 0) | 						if (chunk.wire == NULL) | ||||||
| 						wire->name = wire->name + "_"; | 							continue; | ||||||
| 					module->add(wire); | 						if (chunk.wire->port_id == 0 || flag_ports) { | ||||||
| 					it.second.push_back(wire); | 							if (chunk.offset != 0) | ||||||
|  | 								split_wires_at[chunk.wire].insert(chunk.offset); | ||||||
|  | 							if (chunk.offset + chunk.width < chunk.wire->width) | ||||||
|  | 								split_wires_at[chunk.wire].insert(chunk.offset + chunk.width); | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				for (auto &it : split_wires_at) { | ||||||
|  | 					int cursor = 0; | ||||||
|  | 					for (int next_cursor : it.second) { | ||||||
|  | 						worker.append_wire(module, it.first, cursor, next_cursor - cursor, format); | ||||||
|  | 						cursor = next_cursor; | ||||||
|  | 					} | ||||||
|  | 					worker.append_wire(module, it.first, cursor, it.first->width - cursor, format); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				for (auto &w : module->wires) { | ||||||
|  | 					RTLIL::Wire *wire = w.second; | ||||||
|  | 					if (wire->width > 1 && (wire->port_id == 0 || flag_ports)) | ||||||
|  | 						worker.splitmap[wire] = std::vector<RTLIL::SigBit>(); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				for (auto &it : worker.splitmap) | ||||||
|  | 					for (int i = 0; i < it.first->width; i++) | ||||||
|  | 						worker.append_wire(module, it.first, i, 1, format); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			module->rewrite_sigspecs(worker); | 			module->rewrite_sigspecs(worker); | ||||||
| 
 | 
 | ||||||
| 			for (auto &it : worker.splitmap) { | 			for (auto &it : worker.splitmap) { | ||||||
|  |  | ||||||
|  | @ -231,9 +231,7 @@ struct PerformReduction | ||||||
| 			std::vector<RTLIL::SigBit> bucket_sigbits; | 			std::vector<RTLIL::SigBit> bucket_sigbits; | ||||||
| 			for (int idx : bucket) | 			for (int idx : bucket) | ||||||
| 				bucket_sigbits.push_back(out_bits[idx]); | 				bucket_sigbits.push_back(out_bits[idx]); | ||||||
| 			RTLIL::SigSpec bucket_sig(bucket_sigbits); | 			log("%*s  Trying to shatter bucket with %d signals: %s\n", 2*level, "", int(bucket.size()), log_signal(RTLIL::SigSpec(bucket_sigbits).optimized())); | ||||||
| 			bucket_sig.optimize(); |  | ||||||
| 			log("%*s  Trying to shatter bucket with %d signals: %s\n", 2*level, "", int(bucket.size()), log_signal(bucket_sig)); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		std::vector<int> sat_list, sat_inv_list; | 		std::vector<int> sat_list, sat_inv_list; | ||||||
|  | @ -340,6 +338,34 @@ struct PerformReduction | ||||||
| 			if (r.size() <= 1) | 			if (r.size() <= 1) | ||||||
| 				continue; | 				continue; | ||||||
| 
 | 
 | ||||||
|  | 			if (verbose_level >= 1) { | ||||||
|  | 				std::vector<RTLIL::SigBit> r_sigbits; | ||||||
|  | 				for (int idx : r) | ||||||
|  | 					r_sigbits.push_back(out_bits[idx]); | ||||||
|  | 				log("  Found group of %d equivialent signals: %s\n", int(r.size()), log_signal(RTLIL::SigSpec(r_sigbits).optimized())); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			std::vector<int> undef_slaves; | ||||||
|  | 
 | ||||||
|  | 			for (int idx : r) { | ||||||
|  | 				std::vector<int> sat_def_list; | ||||||
|  | 				for (int idx2 : r) | ||||||
|  | 					if (idx != idx2) | ||||||
|  | 						sat_def_list.push_back(sat_def[idx2]); | ||||||
|  | 				if (ez.solve(ez.NOT(sat_def[idx]), ez.expression(ezSAT::OpOr, sat_def_list))) | ||||||
|  | 					undef_slaves.push_back(idx); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (undef_slaves.size() == bucket.size()) { | ||||||
|  | 				if (verbose_level >= 1) | ||||||
|  | 					log("    Complex undef overlap. None of the signals covers the others.\n"); | ||||||
|  | 				// FIXME: We could try to further shatter a group with complex undef overlaps
 | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			for (int idx : undef_slaves) | ||||||
|  | 				out_depth[idx] = std::numeric_limits<int>::max(); | ||||||
|  | 
 | ||||||
| 			std::vector<equiv_bit_t> result; | 			std::vector<equiv_bit_t> result; | ||||||
| 
 | 
 | ||||||
| 			for (int idx : r) { | 			for (int idx : r) { | ||||||
|  | @ -371,13 +397,14 @@ struct PerformReduction | ||||||
| 
 | 
 | ||||||
| struct FreduceWorker | struct FreduceWorker | ||||||
| { | { | ||||||
|  | 	RTLIL::Design *design; | ||||||
| 	RTLIL::Module *module; | 	RTLIL::Module *module; | ||||||
| 
 | 
 | ||||||
| 	SigMap sigmap; | 	SigMap sigmap; | ||||||
| 	drivers_t drivers; | 	drivers_t drivers; | ||||||
| 	std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> inv_pairs; | 	std::set<std::pair<RTLIL::SigBit, RTLIL::SigBit>> inv_pairs; | ||||||
| 
 | 
 | ||||||
| 	FreduceWorker(RTLIL::Module *module) : module(module), sigmap(module) | 	FreduceWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), sigmap(module) | ||||||
| 	{ | 	{ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -418,10 +445,14 @@ struct FreduceWorker | ||||||
| 		buckets[std::vector<RTLIL::SigBit>()].push_back(RTLIL::SigBit(RTLIL::State::S1)); | 		buckets[std::vector<RTLIL::SigBit>()].push_back(RTLIL::SigBit(RTLIL::State::S1)); | ||||||
| 		for (auto &batch : batches) | 		for (auto &batch : batches) | ||||||
| 		{ | 		{ | ||||||
| 			RTLIL::SigSpec batch_sig(std::vector<RTLIL::SigBit>(batch.begin(), batch.end())); | 			for (auto &bit : batch) | ||||||
| 			batch_sig.optimize(); | 				if (bit.wire != NULL && design->selected(module, bit.wire)) | ||||||
|  | 					goto found_selected_wire; | ||||||
|  | 			continue; | ||||||
| 
 | 
 | ||||||
| 			log("  Finding reduced input cone for signal batch %s%c\n", log_signal(batch_sig), verbose_level ? ':' : '.'); | 		found_selected_wire: | ||||||
|  | 			log("  Finding reduced input cone for signal batch %s%c\n", | ||||||
|  | 					log_signal(RTLIL::SigSpec(std::vector<RTLIL::SigBit>(batch.begin(), batch.end())).optimized()), verbose_level ? ':' : '.'); | ||||||
| 
 | 
 | ||||||
| 			FindReducedInputs infinder(sigmap, drivers); | 			FindReducedInputs infinder(sigmap, drivers); | ||||||
| 			for (auto &bit : batch) { | 			for (auto &bit : batch) { | ||||||
|  | @ -439,10 +470,7 @@ struct FreduceWorker | ||||||
| 			if (bucket.second.size() == 1) | 			if (bucket.second.size() == 1) | ||||||
| 				continue; | 				continue; | ||||||
| 
 | 
 | ||||||
| 			RTLIL::SigSpec bucket_sig(bucket.second); | 			log("  Trying to shatter bucket %s%c\n", log_signal(RTLIL::SigSpec(bucket.second).optimized()), verbose_level ? ':' : '.'); | ||||||
| 			bucket_sig.optimize(); |  | ||||||
| 
 |  | ||||||
| 			log("  Trying to shatter bucket %s%c\n", log_signal(bucket_sig), verbose_level ? ':' : '.'); |  | ||||||
| 			PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second); | 			PerformReduction worker(sigmap, drivers, inv_pairs, bucket.second); | ||||||
| 			worker.analyze(equiv); | 			worker.analyze(equiv); | ||||||
| 		} | 		} | ||||||
|  | @ -456,12 +484,18 @@ struct FreduceWorker | ||||||
| 			RTLIL::SigSpec inv_sig; | 			RTLIL::SigSpec inv_sig; | ||||||
| 			for (size_t i = 1; i < grp.size(); i++) | 			for (size_t i = 1; i < grp.size(); i++) | ||||||
| 			{ | 			{ | ||||||
|  | 				if (!design->selected(module, grp[i].bit.wire)) { | ||||||
|  | 					log("      Skipping not-selected slave: %s\n", log_signal(grp[i].bit)); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				log("      Connect slave%s: %s\n", grp[i].inverted ? " using inverter" : "", log_signal(grp[i].bit)); | 				log("      Connect slave%s: %s\n", grp[i].inverted ? " using inverter" : "", log_signal(grp[i].bit)); | ||||||
| 
 | 
 | ||||||
| 				RTLIL::Cell *drv = drivers.at(grp[i].bit).first; | 				RTLIL::Cell *drv = drivers.at(grp[i].bit).first; | ||||||
| 				RTLIL::Wire *dummy_wire = module->new_wire(1, NEW_ID); | 				RTLIL::Wire *dummy_wire = module->new_wire(1, NEW_ID); | ||||||
| 				for (auto &port : drv->connections) | 				for (auto &port : drv->connections) | ||||||
| 					sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second); | 					if (ct.cell_output(drv->type, port.first)) | ||||||
|  | 						sigmap(port.second).replace(grp[i].bit, dummy_wire, &port.second); | ||||||
| 
 | 
 | ||||||
| 				if (grp[i].inverted) | 				if (grp[i].inverted) | ||||||
| 				{ | 				{ | ||||||
|  | @ -505,15 +539,18 @@ struct FreducePass : public Pass { | ||||||
| 		log("equivialent, they are merged to one node and one of the redundant drivers is\n"); | 		log("equivialent, they are merged to one node and one of the redundant drivers is\n"); | ||||||
| 		log("unconnected. A subsequent call to 'clean' will remove the redundant drivers.\n"); | 		log("unconnected. A subsequent call to 'clean' will remove the redundant drivers.\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("This pass is undef-aware, i.e. it considers don't-care values for detecting\n"); |  | ||||||
| 		log("equivialent nodes.\n"); |  | ||||||
| 		log("\n"); |  | ||||||
| 		log("    -v, -vv\n"); | 		log("    -v, -vv\n"); | ||||||
| 		log("        enable verbose or very verbose output\n"); | 		log("        enable verbose or very verbose output\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
| 		log("    -inv\n"); | 		log("    -inv\n"); | ||||||
| 		log("        enable explicit handling of inverted signals\n"); | 		log("        enable explicit handling of inverted signals\n"); | ||||||
| 		log("\n"); | 		log("\n"); | ||||||
|  | 		log("This pass is undef-aware, i.e. it considers don't-care values for detecting\n"); | ||||||
|  | 		log("equivialent nodes.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("All selected wires are considered for rewiring. The selected cells cover the\n"); | ||||||
|  | 		log("circuit that is analyzed.\n"); | ||||||
|  | 		log("\n"); | ||||||
| 	} | 	} | ||||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||||
| 	{ | 	{ | ||||||
|  | @ -544,7 +581,7 @@ struct FreducePass : public Pass { | ||||||
| 		for (auto &mod_it : design->modules) { | 		for (auto &mod_it : design->modules) { | ||||||
| 			RTLIL::Module *module = mod_it.second; | 			RTLIL::Module *module = mod_it.second; | ||||||
| 			if (design->selected(module)) | 			if (design->selected(module)) | ||||||
| 				bitcount += FreduceWorker(module).run(); | 				bitcount += FreduceWorker(design, module).run(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		log("Rewired a total of %d signal bits.\n", bitcount); | 		log("Rewired a total of %d signal bits.\n", bitcount); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue