mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			191 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *  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/celltypes.h"
 | 
						|
#include "kernel/sigtools.h"
 | 
						|
#include "kernel/log_help.h"
 | 
						|
 | 
						|
USING_YOSYS_NAMESPACE
 | 
						|
PRIVATE_NAMESPACE_BEGIN
 | 
						|
 | 
						|
struct LtpWorker
 | 
						|
{
 | 
						|
	RTLIL::Design *design;
 | 
						|
	RTLIL::Module *module;
 | 
						|
	SigMap sigmap;
 | 
						|
 | 
						|
	dict<SigBit, tuple<int, SigBit, Cell*>> bits;
 | 
						|
	dict<SigBit, dict<SigBit, Cell*>> bit2bits;
 | 
						|
	dict<SigBit, tuple<SigBit, Cell*>> bit2ff;
 | 
						|
 | 
						|
	int maxlvl;
 | 
						|
	SigBit maxbit;
 | 
						|
	pool<SigBit> busy;
 | 
						|
 | 
						|
	LtpWorker(RTLIL::Module *module, bool noff) : design(module->design), module(module), sigmap(module)
 | 
						|
	{
 | 
						|
		CellTypes ff_celltypes;
 | 
						|
 | 
						|
		if (noff) {
 | 
						|
			ff_celltypes.setup_internals_mem();
 | 
						|
			ff_celltypes.setup_stdcells_mem();
 | 
						|
		}
 | 
						|
 | 
						|
		for (auto wire : module->selected_wires())
 | 
						|
			for (auto bit : sigmap(wire))
 | 
						|
				bits[bit] = tuple<int, SigBit, Cell*>(-1, State::Sx, nullptr);
 | 
						|
 | 
						|
		for (auto cell : module->selected_cells())
 | 
						|
		{
 | 
						|
			pool<SigBit> src_bits, dst_bits;
 | 
						|
 | 
						|
			for (auto &conn : cell->connections())
 | 
						|
				for (auto bit : sigmap(conn.second)) {
 | 
						|
					if (cell->input(conn.first))
 | 
						|
						src_bits.insert(bit);
 | 
						|
					if (cell->output(conn.first))
 | 
						|
						dst_bits.insert(bit);
 | 
						|
				}
 | 
						|
 | 
						|
			if (noff && ff_celltypes.cell_known(cell->type)) {
 | 
						|
				for (auto s : src_bits)
 | 
						|
					for (auto d : dst_bits) {
 | 
						|
						bit2ff[s] = tuple<SigBit, Cell*>(d, cell);
 | 
						|
						break;
 | 
						|
					}
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			for (auto s : src_bits)
 | 
						|
				for (auto d : dst_bits)
 | 
						|
					bit2bits[s][d] = cell;
 | 
						|
		}
 | 
						|
 | 
						|
		maxlvl = -1;
 | 
						|
		maxbit = State::Sx;
 | 
						|
	}
 | 
						|
 | 
						|
	void runner(SigBit bit, int level, SigBit from, Cell *via)
 | 
						|
	{
 | 
						|
		auto &bitinfo = bits.at(bit);
 | 
						|
 | 
						|
		if (get<0>(bitinfo) >= level)
 | 
						|
			return;
 | 
						|
 | 
						|
		if (busy.count(bit) > 0) {
 | 
						|
			log_warning("Detected loop at %s in %s\n", log_signal(bit), log_id(module));
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		busy.insert(bit);
 | 
						|
		get<0>(bitinfo) = level;
 | 
						|
		get<1>(bitinfo) = from;
 | 
						|
		get<2>(bitinfo) = via;
 | 
						|
 | 
						|
		if (level > maxlvl) {
 | 
						|
			maxlvl = level;
 | 
						|
			maxbit = bit;
 | 
						|
		}
 | 
						|
 | 
						|
		if (bit2bits.count(bit)) {
 | 
						|
			for (auto &it : bit2bits.at(bit))
 | 
						|
				runner(it.first, level+1, bit, it.second);
 | 
						|
		}
 | 
						|
 | 
						|
		busy.erase(bit);
 | 
						|
	}
 | 
						|
 | 
						|
	void printpath(SigBit bit)
 | 
						|
	{
 | 
						|
		auto &bitinfo = bits.at(bit);
 | 
						|
		if (get<2>(bitinfo)) {
 | 
						|
			printpath(get<1>(bitinfo));
 | 
						|
			log("%5d: %s (via %s)\n", get<0>(bitinfo), log_signal(bit), log_id(get<2>(bitinfo)));
 | 
						|
		} else {
 | 
						|
			log("%5d: %s\n", get<0>(bitinfo), log_signal(bit));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	void run()
 | 
						|
	{
 | 
						|
		for (auto &it : bits)
 | 
						|
			if (get<0>(it.second) < 0)
 | 
						|
				runner(it.first, 0, State::Sx, nullptr);
 | 
						|
 | 
						|
		log("\n");
 | 
						|
		log("Longest topological path in %s (length=%d):\n", log_id(module), maxlvl);
 | 
						|
 | 
						|
		if (maxlvl >= 0)
 | 
						|
			printpath(maxbit);
 | 
						|
 | 
						|
		if (bit2ff.count(maxbit))
 | 
						|
			log("%5s: %s (via %s)\n", "ff", log_signal(get<0>(bit2ff.at(maxbit))), log_id(get<1>(bit2ff.at(maxbit))));
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
struct LtpPass : public Pass {
 | 
						|
	LtpPass() : Pass("ltp", "print longest topological path") { }
 | 
						|
	bool formatted_help() override {
 | 
						|
		auto *help = PrettyHelp::get_current();
 | 
						|
		help->set_group("passes/status");
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	void help() override
 | 
						|
	{
 | 
						|
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | 
						|
		log("\n");
 | 
						|
		log("    ltp [options] [selection]\n");
 | 
						|
		log("\n");
 | 
						|
		log("This command prints the longest topological path in the design. (Only considers\n");
 | 
						|
		log("paths within a single module, so the design must be flattened.)\n");
 | 
						|
		log("\n");
 | 
						|
		log("    -noff\n");
 | 
						|
		log("        automatically exclude FF cell types\n");
 | 
						|
		log("\n");
 | 
						|
	}
 | 
						|
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | 
						|
	{
 | 
						|
		bool noff = false;
 | 
						|
 | 
						|
		log_header(design, "Executing LTP pass (find longest path).\n");
 | 
						|
 | 
						|
		size_t argidx;
 | 
						|
		for (argidx = 1; argidx < args.size(); argidx++) {
 | 
						|
			if (args[argidx] == "-noff") {
 | 
						|
				noff = true;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		extra_args(args, argidx, design);
 | 
						|
 | 
						|
		for (Module *module : design->selected_modules())
 | 
						|
		{
 | 
						|
			if (module->has_processes_warn())
 | 
						|
				continue;
 | 
						|
 | 
						|
			LtpWorker worker(module, noff);
 | 
						|
			worker.run();
 | 
						|
		}
 | 
						|
	}
 | 
						|
} LtpPass;
 | 
						|
 | 
						|
PRIVATE_NAMESPACE_END
 |