mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Added splice command
This commit is contained in:
		
							parent
							
								
									08aa1062b4
								
							
						
					
					
						commit
						244e8ce1f4
					
				
					 4 changed files with 281 additions and 0 deletions
				
			
		|  | @ -12,4 +12,5 @@ OBJS += passes/cmds/splitnets.o | ||||||
| OBJS += passes/cmds/stat.o | OBJS += passes/cmds/stat.o | ||||||
| OBJS += passes/cmds/setattr.o | OBJS += passes/cmds/setattr.o | ||||||
| OBJS += passes/cmds/copy.o | OBJS += passes/cmds/copy.o | ||||||
|  | OBJS += passes/cmds/splice.o | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										252
									
								
								passes/cmds/splice.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								passes/cmds/splice.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,252 @@ | ||||||
|  | /*
 | ||||||
|  |  *  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/celltypes.h" | ||||||
|  | #include "kernel/sigtools.h" | ||||||
|  | #include "kernel/rtlil.h" | ||||||
|  | #include "kernel/log.h" | ||||||
|  | #include <tuple> | ||||||
|  | 
 | ||||||
|  | struct SpliceWorker | ||||||
|  | { | ||||||
|  | 	RTLIL::Design *design; | ||||||
|  | 	RTLIL::Module *module; | ||||||
|  | 
 | ||||||
|  | 	CellTypes ct; | ||||||
|  | 	SigMap sigmap; | ||||||
|  | 
 | ||||||
|  | 	std::vector<RTLIL::SigBit> driven_bits; | ||||||
|  | 	std::map<RTLIL::SigBit, int> driven_bits_map; | ||||||
|  | 
 | ||||||
|  | 	std::set<RTLIL::SigSpec> driven_chunks; | ||||||
|  | 	std::map<RTLIL::SigSpec, RTLIL::SigSpec> spliced_signals_cache; | ||||||
|  | 	std::map<RTLIL::SigSpec, RTLIL::SigSpec> sliced_signals_cache; | ||||||
|  | 
 | ||||||
|  | 	SpliceWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), ct(design), sigmap(module) | ||||||
|  | 	{ | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	RTLIL::SigSpec get_sliced_signal(RTLIL::SigSpec sig) | ||||||
|  | 	{ | ||||||
|  | 		if (sig.width == 0 || sig.is_fully_const()) | ||||||
|  | 			return sig; | ||||||
|  | 
 | ||||||
|  | 		if (sliced_signals_cache.count(sig)) | ||||||
|  | 			return sliced_signals_cache.at(sig); | ||||||
|  | 
 | ||||||
|  | 		int offset = 0; | ||||||
|  | 		int p = driven_bits_map.at(sig.extract(0, 1).to_single_sigbit()) - 1; | ||||||
|  | 		while (driven_bits.at(p) != RTLIL::State::Sm) | ||||||
|  | 			p--, offset++; | ||||||
|  | 
 | ||||||
|  | 		RTLIL::SigSpec sig_a; | ||||||
|  | 		for (p++; driven_bits.at(p) != RTLIL::State::Sm; p++) | ||||||
|  | 			sig_a.append(driven_bits.at(p)); | ||||||
|  | 
 | ||||||
|  | 		RTLIL::SigSpec new_sig = sig; | ||||||
|  | 
 | ||||||
|  | 		if (sig_a.width != sig.width) { | ||||||
|  | 			RTLIL::Cell *cell = new RTLIL::Cell; | ||||||
|  | 			cell->name = NEW_ID; | ||||||
|  | 			cell->type = "$slice"; | ||||||
|  | 			cell->parameters["\\OFFSET"] = offset; | ||||||
|  | 			cell->parameters["\\A_WIDTH"] = sig_a.width; | ||||||
|  | 			cell->parameters["\\Y_WIDTH"] = sig.width; | ||||||
|  | 			cell->connections["\\A"] = sig_a; | ||||||
|  | 			cell->connections["\\Y"] = module->new_wire(sig.width, NEW_ID); | ||||||
|  | 			new_sig = cell->connections["\\Y"]; | ||||||
|  | 			module->add(cell); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		new_sig.optimize(); | ||||||
|  | 		sliced_signals_cache[sig] = new_sig; | ||||||
|  | 
 | ||||||
|  | 		return new_sig; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	RTLIL::SigSpec get_spliced_signal(RTLIL::SigSpec sig) | ||||||
|  | 	{ | ||||||
|  | 		if (sig.width == 0) | ||||||
|  | 			return sig; | ||||||
|  | 
 | ||||||
|  | 		if (spliced_signals_cache.count(sig)) | ||||||
|  | 			return spliced_signals_cache.at(sig); | ||||||
|  | 
 | ||||||
|  | 		int last_bit = -1; | ||||||
|  | 		std::vector<RTLIL::SigSpec> chunks; | ||||||
|  | 
 | ||||||
|  | 		for (auto &bit : sig.to_sigbit_vector()) | ||||||
|  | 		{ | ||||||
|  | 			if (bit.wire == NULL) | ||||||
|  | 			{ | ||||||
|  | 				if (last_bit == 0) | ||||||
|  | 					chunks.back().append(bit); | ||||||
|  | 				else | ||||||
|  | 					chunks.push_back(bit); | ||||||
|  | 				last_bit = 0; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (driven_bits_map.count(bit)) | ||||||
|  | 			{ | ||||||
|  | 				int this_bit = driven_bits_map.at(bit); | ||||||
|  | 				if (last_bit+1 == this_bit) | ||||||
|  | 					chunks.back().append(bit); | ||||||
|  | 				else | ||||||
|  | 					chunks.push_back(bit); | ||||||
|  | 				last_bit = this_bit; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			log("  Failed to generate spliced signal %s.\n", log_signal(sig)); | ||||||
|  | 			spliced_signals_cache[sig] = sig; | ||||||
|  | 			return sig; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 		RTLIL::SigSpec new_sig = get_sliced_signal(chunks.front()); | ||||||
|  | 		for (size_t i = 1; i < chunks.size(); i++) { | ||||||
|  | 			RTLIL::SigSpec sig2 = get_sliced_signal(chunks[i]); | ||||||
|  | 			RTLIL::Cell *cell = new RTLIL::Cell; | ||||||
|  | 			cell->name = NEW_ID; | ||||||
|  | 			cell->type = "$concat"; | ||||||
|  | 			cell->parameters["\\A_WIDTH"] = new_sig.width; | ||||||
|  | 			cell->parameters["\\B_WIDTH"] = sig2.width; | ||||||
|  | 			cell->connections["\\A"] = new_sig; | ||||||
|  | 			cell->connections["\\B"] = sig2; | ||||||
|  | 			cell->connections["\\Y"] = module->new_wire(new_sig.width + sig2.width, NEW_ID); | ||||||
|  | 			new_sig = cell->connections["\\Y"]; | ||||||
|  | 			module->add(cell); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		new_sig.optimize(); | ||||||
|  | 		spliced_signals_cache[sig] = new_sig; | ||||||
|  | 
 | ||||||
|  | 		log("  Created spliced signal: %s -> %s\n", log_signal(sig), log_signal(new_sig)); | ||||||
|  | 		return new_sig; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void run() | ||||||
|  | 	{ | ||||||
|  | 		log("Splicing signals in module %s:\n", RTLIL::id2cstr(module->name)); | ||||||
|  | 
 | ||||||
|  | 		driven_bits.push_back(RTLIL::State::Sm); | ||||||
|  | 		driven_bits.push_back(RTLIL::State::Sm); | ||||||
|  | 
 | ||||||
|  | 		for (auto &it : module->wires) | ||||||
|  | 			if (it.second->port_input) { | ||||||
|  | 				RTLIL::SigSpec sig = sigmap(it.second); | ||||||
|  | 				driven_chunks.insert(sig); | ||||||
|  | 				for (auto &bit : sig.to_sigbit_vector()) | ||||||
|  | 					driven_bits.push_back(bit); | ||||||
|  | 				driven_bits.push_back(RTLIL::State::Sm); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		for (auto &it : module->cells) | ||||||
|  | 		for (auto &conn : it.second->connections) | ||||||
|  | 			if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) { | ||||||
|  | 				RTLIL::SigSpec sig = sigmap(conn.second); | ||||||
|  | 				driven_chunks.insert(sig); | ||||||
|  | 				for (auto &bit : sig.to_sigbit_vector()) | ||||||
|  | 					driven_bits.push_back(bit); | ||||||
|  | 				driven_bits.push_back(RTLIL::State::Sm); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		driven_bits.push_back(RTLIL::State::Sm); | ||||||
|  | 
 | ||||||
|  | 		for (size_t i = 0; i < driven_bits.size(); i++) | ||||||
|  | 			driven_bits_map[driven_bits[i]] = i; | ||||||
|  | 
 | ||||||
|  | 		for (auto &it : module->cells) { | ||||||
|  | 			if (!design->selected(module, it.second)) | ||||||
|  | 				continue; | ||||||
|  | 			for (auto &conn : it.second->connections) | ||||||
|  | 				if (ct.cell_input(it.second->type, conn.first)) { | ||||||
|  | 					RTLIL::SigSpec sig = sigmap(conn.second); | ||||||
|  | 					if (driven_chunks.count(sig) > 0) | ||||||
|  | 						continue; | ||||||
|  | 					conn.second = get_spliced_signal(sig); | ||||||
|  | 				} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_outputs; | ||||||
|  | 
 | ||||||
|  | 		for (auto &it : module->wires) | ||||||
|  | 			if (it.second->port_output) { | ||||||
|  | 				if (!design->selected(module, it.second)) | ||||||
|  | 					continue; | ||||||
|  | 				RTLIL::SigSpec sig = sigmap(it.second); | ||||||
|  | 				if (driven_chunks.count(sig) > 0) | ||||||
|  | 					continue; | ||||||
|  | 				RTLIL::SigSpec new_sig = get_spliced_signal(sig); | ||||||
|  | 				if (new_sig != sig) | ||||||
|  | 					rework_outputs.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(it.second, new_sig)); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		for (auto &it : rework_outputs) | ||||||
|  | 		{ | ||||||
|  | 			module->wires.erase(it.first->name); | ||||||
|  | 			RTLIL::Wire *new_port = new RTLIL::Wire(*it.first); | ||||||
|  | 			it.first->name = NEW_ID; | ||||||
|  | 			it.first->port_id = 0; | ||||||
|  | 			it.first->port_input = false; | ||||||
|  | 			it.first->port_output = false; | ||||||
|  | 			module->add(it.first); | ||||||
|  | 			module->add(new_port); | ||||||
|  | 			module->connections.push_back(RTLIL::SigSig(new_port, it.second)); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct SplicePass : public Pass { | ||||||
|  | 	SplicePass() : Pass("splice", "create explicit splicing cells") { } | ||||||
|  | 	virtual void help() | ||||||
|  | 	{ | ||||||
|  | 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("    splice [selection]\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 		log("This command adds $slice and $concat cells to the design to make the splicing\n"); | ||||||
|  | 		log("of multi-bit signals explicit. This for example is useful for coarse grain\n"); | ||||||
|  | 		log("synthesis, where dedidacted hardware is needed to splice signals.\n"); | ||||||
|  | 		log("\n"); | ||||||
|  | 	} | ||||||
|  | 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||||
|  | 	{ | ||||||
|  | 		extra_args(args, 1, design); | ||||||
|  | 
 | ||||||
|  | 		log_header("Executing SPLICE pass (creating cells for signal splicing).\n"); | ||||||
|  | 
 | ||||||
|  | 		for (auto &mod_it : design->modules) | ||||||
|  | 		{ | ||||||
|  | 			if (!design->selected(mod_it.second)) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			if (mod_it.second->processes.size()) { | ||||||
|  | 				log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str()); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			SpliceWorker worker(design, mod_it.second); | ||||||
|  | 			worker.run(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } SplicePass; | ||||||
|  |   | ||||||
							
								
								
									
										14
									
								
								tests/sat/splice.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/sat/splice.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | module test(a, b, y); | ||||||
|  | 
 | ||||||
|  | input [15:0] a, b; | ||||||
|  | output [15:0] y; | ||||||
|  | 
 | ||||||
|  | wire [7:0] ah = a[15:8], al = a[7:0]; | ||||||
|  | wire [7:0] bh = b[15:8], bl = b[7:0]; | ||||||
|  | 
 | ||||||
|  | wire [7:0] th = ah + bh, tl = al + bl; | ||||||
|  | wire [15:0] t = {th, tl}, k = t ^ 16'hcd; | ||||||
|  | 
 | ||||||
|  | assign y = { k[7:0], k[15:8] }; | ||||||
|  | 
 | ||||||
|  | endmodule | ||||||
							
								
								
									
										14
									
								
								tests/sat/splice.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/sat/splice.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | read_verilog splice.v | ||||||
|  | hierarchy -check; opt | ||||||
|  | copy test gold | ||||||
|  | 
 | ||||||
|  | cd test | ||||||
|  | splice | ||||||
|  | # show | ||||||
|  | 
 | ||||||
|  | cd .. | ||||||
|  | rename test gate | ||||||
|  | miter -equiv -make_assert -make_outputs gold gate miter | ||||||
|  | 
 | ||||||
|  | flatten miter | ||||||
|  | sat -verify -prove-asserts -show-inputs -show-outputs miter | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue