mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +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/setattr.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;
 | 
			
		||||
 
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue