mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	Add splitfanout first pass
This commit is contained in:
		
							parent
							
								
									fd53f4ab1b
								
							
						
					
					
						commit
						5777bed8ed
					
				
					 2 changed files with 195 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -15,6 +15,7 @@ OBJS += passes/cmds/scatter.o
 | 
			
		|||
OBJS += passes/cmds/setundef.o
 | 
			
		||||
OBJS += passes/cmds/splitnets.o
 | 
			
		||||
OBJS += passes/cmds/splitcells.o
 | 
			
		||||
OBJS += passes/cmds/splitfanout.o
 | 
			
		||||
OBJS += passes/cmds/stat.o
 | 
			
		||||
OBJS += passes/cmds/setattr.o
 | 
			
		||||
OBJS += passes/cmds/copy.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										194
									
								
								passes/cmds/splitfanout.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								passes/cmds/splitfanout.cc
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,194 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  yosys -- Yosys Open SYnthesis Suite
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.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/yosys.h"
 | 
			
		||||
#include "kernel/sigtools.h"
 | 
			
		||||
 | 
			
		||||
USING_YOSYS_NAMESPACE
 | 
			
		||||
PRIVATE_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
struct SplitfanoutWorker
 | 
			
		||||
{
 | 
			
		||||
	Module *module;
 | 
			
		||||
	SigMap sigmap;
 | 
			
		||||
	dict<SigBit, tuple<IdString,IdString,int>> bit_drivers_db;
 | 
			
		||||
	dict<SigBit, pool<tuple<IdString,IdString,int>>> bit_users_db;
 | 
			
		||||
 | 
			
		||||
	SplitfanoutWorker(Module *module) : module(module), sigmap(module)
 | 
			
		||||
	{
 | 
			
		||||
		for (auto cell : module->cells()) {
 | 
			
		||||
			for (auto conn : cell->connections()) {
 | 
			
		||||
				if (!cell->output(conn.first)) continue;
 | 
			
		||||
				for (int i = 0; i < GetSize(conn.second); i++) {
 | 
			
		||||
					SigBit bit(sigmap(conn.second[i]));
 | 
			
		||||
					bit_drivers_db[bit] = tuple<IdString,IdString,int>(cell->name, conn.first, i);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto cell : module->cells()) {
 | 
			
		||||
			for (auto conn : cell->connections()) {
 | 
			
		||||
				if (!cell->input(conn.first)) continue;
 | 
			
		||||
				for (int i = 0; i < GetSize(conn.second); i++) {
 | 
			
		||||
					SigBit bit(sigmap(conn.second[i]));
 | 
			
		||||
					if (!bit_drivers_db.count(bit)) continue;
 | 
			
		||||
					bit_users_db[bit].insert(tuple<IdString,IdString,int>(cell->name,
 | 
			
		||||
							conn.first, i-std::get<2>(bit_drivers_db[bit])));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (auto wire : module->wires()) {
 | 
			
		||||
			if (!wire->port_output) continue;
 | 
			
		||||
			SigSpec sig(sigmap(wire));
 | 
			
		||||
			for (int i = 0; i < GetSize(sig); i++) {
 | 
			
		||||
				SigBit bit(sig[i]);
 | 
			
		||||
				if (!bit_drivers_db.count(bit)) continue;
 | 
			
		||||
				bit_users_db[bit].insert(tuple<IdString,IdString,int>(wire->name,
 | 
			
		||||
						IdString(), i-std::get<2>(bit_drivers_db[bit])));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int split(Cell *cell)
 | 
			
		||||
	{
 | 
			
		||||
		// Get output signal/port
 | 
			
		||||
		SigSpec outsig;
 | 
			
		||||
		IdString outport;
 | 
			
		||||
		if (cell->hasPort(ID::Y)) {
 | 
			
		||||
			outsig = sigmap(cell->getPort(ID::Y));
 | 
			
		||||
			outport = ID::Y;
 | 
			
		||||
		}
 | 
			
		||||
		else if (cell->hasPort(ID::Q)) {
 | 
			
		||||
			outsig = sigmap(cell->getPort(ID::Q));
 | 
			
		||||
			outport = ID::Q;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		// Check if output signal is "bit-split", skip if so
 | 
			
		||||
		pool<tuple<IdString,IdString,int>> bit_users = bit_users_db[outsig[0]];
 | 
			
		||||
		for (int i = 0; i < GetSize(outsig); i++) {
 | 
			
		||||
			if (bit_users_db[outsig[i]] != bit_users) {
 | 
			
		||||
				log("  Skipping %s cell %s/%s with bit-split output.\n", log_id(cell->type), log_id(module), log_id(cell));
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Skip if output signal has only one user
 | 
			
		||||
		if (GetSize(bit_users) <= 1)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		// Iterate over bit users and create a new cell for each one
 | 
			
		||||
		log("Splitting %s cell %s/%s into %d copies based on fanout:\n", log_id(cell->type), log_id(module), log_id(cell), GetSize(bit_users)-1);
 | 
			
		||||
		int foi = 0;
 | 
			
		||||
		cell->setPort(outport, module->addWire(NEW_ID, GetSize(outsig)));
 | 
			
		||||
		for (auto user : bit_users)
 | 
			
		||||
		{
 | 
			
		||||
			// Create a new cell
 | 
			
		||||
			IdString new_name = module->uniquify(cell->name.str());
 | 
			
		||||
			Cell *new_cell = module->addCell(new_name, cell);
 | 
			
		||||
 | 
			
		||||
			// Connect the new cell to the user
 | 
			
		||||
			if (std::get<1>(user) == IdString()) {
 | 
			
		||||
				Wire *old_wire = module->wire(std::get<0>(user));
 | 
			
		||||
				Wire *new_wire = module->addWire(NEW_ID, old_wire);
 | 
			
		||||
				module->swap_names(old_wire, new_wire);
 | 
			
		||||
				old_wire->port_id = 0;
 | 
			
		||||
				old_wire->port_input = false;
 | 
			
		||||
				old_wire->port_output = false;
 | 
			
		||||
				new_cell->setPort(outport, new_wire);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				Wire *new_wire = module->addWire(NEW_ID, GetSize(outsig));
 | 
			
		||||
				module->cell(std::get<0>(user))->setPort(std::get<1>(user), new_wire);
 | 
			
		||||
				new_cell->setPort(outport, new_wire);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Log the new cell
 | 
			
		||||
			log("  slice %d: %s => %s\n", foi, log_id(new_name), log_signal(new_cell->getPort(outport)));
 | 
			
		||||
 | 
			
		||||
			// Increment the fanout index
 | 
			
		||||
			foi++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Remove the original cell
 | 
			
		||||
		module->remove(cell);
 | 
			
		||||
 | 
			
		||||
		// Fix up ports
 | 
			
		||||
		module->fixup_ports();
 | 
			
		||||
 | 
			
		||||
		// Return the number of new cells created
 | 
			
		||||
		return GetSize(bit_users)-1;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SplitfanoutPass : public Pass {
 | 
			
		||||
	SplitfanoutPass() : Pass("splitfanout", "split up cells with >1 fanout into copies") { }
 | 
			
		||||
	void help() override
 | 
			
		||||
	{
 | 
			
		||||
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("    splitfanout [options] [selection]\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("This command copies selected cells with >1 fanout into cells with fanout 1. It\n");
 | 
			
		||||
		log("is effectively the opposite of the opt_merge pass.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
		log("This command operates only on cells with 1 output and no \"bit split\" on that\n");
 | 
			
		||||
		log("output.\n");
 | 
			
		||||
		log("\n");
 | 
			
		||||
	}
 | 
			
		||||
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | 
			
		||||
	{
 | 
			
		||||
		log_header(design, "Executing SPLITFANOUT pass (splitting up cells with >1 fanout into copies).\n");
 | 
			
		||||
 | 
			
		||||
		size_t argidx;
 | 
			
		||||
		for (argidx = 1; argidx < args.size(); argidx++)
 | 
			
		||||
		{
 | 
			
		||||
			// No arguments currently supported
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		extra_args(args, argidx, design);
 | 
			
		||||
 | 
			
		||||
		for (auto module : design->selected_modules())
 | 
			
		||||
		{
 | 
			
		||||
			int count_split_pre = 0;
 | 
			
		||||
			int count_split_post = 0;
 | 
			
		||||
 | 
			
		||||
			while (1) {
 | 
			
		||||
				SplitfanoutWorker worker(module);
 | 
			
		||||
				bool did_something = false;
 | 
			
		||||
				for (auto cell : module->selected_cells()) {
 | 
			
		||||
					int n = worker.split(cell);
 | 
			
		||||
					did_something |= (n != 0);
 | 
			
		||||
					count_split_pre += (n != 0);
 | 
			
		||||
					count_split_post += n;
 | 
			
		||||
				}
 | 
			
		||||
				if (!did_something)
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (count_split_pre)
 | 
			
		||||
				log("Split %d cells in module '%s' into %d copies based on fanout.\n",
 | 
			
		||||
					count_split_pre, log_id(module), count_split_post);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
} SplitfanoutPass;
 | 
			
		||||
 | 
			
		||||
PRIVATE_NAMESPACE_END
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue