mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			201 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
	
		
			6.5 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/register.h"
 | |
| #include "kernel/sigtools.h"
 | |
| #include "kernel/rtlil.h"
 | |
| #include "kernel/log.h"
 | |
| 
 | |
| USING_YOSYS_NAMESPACE
 | |
| PRIVATE_NAMESPACE_BEGIN
 | |
| 
 | |
| struct ConnwrappersWorker
 | |
| {
 | |
| 	struct portdecl_t {
 | |
| 		// key: celltype, portname;
 | |
| 		std::string widthparam, signparam;
 | |
| 		bool is_signed;
 | |
| 	};
 | |
| 
 | |
| 	std::set<RTLIL::IdString> decl_celltypes;
 | |
| 	std::map<std::pair<RTLIL::IdString, RTLIL::IdString>, portdecl_t> decls;
 | |
| 
 | |
| 	void add_port(std::string celltype, std::string portname, std::string widthparam, std::string signparam)
 | |
| 	{
 | |
| 		std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
 | |
| 		decl_celltypes.insert(key.first);
 | |
| 
 | |
| 		if (decls.count(key))
 | |
| 			log_cmd_error("Duplicate port decl: %s %s\n", celltype, portname);
 | |
| 
 | |
| 		portdecl_t decl;
 | |
| 		decl.widthparam = RTLIL::escape_id(widthparam);
 | |
| 		decl.signparam = RTLIL::escape_id(signparam);
 | |
| 		decl.is_signed = false;
 | |
| 		decls[key] = decl;
 | |
| 	}
 | |
| 
 | |
| 	void add_port(std::string celltype, std::string portname, std::string widthparam, bool is_signed)
 | |
| 	{
 | |
| 		std::pair<std::string, std::string> key(RTLIL::escape_id(celltype), RTLIL::escape_id(portname));
 | |
| 		decl_celltypes.insert(key.first);
 | |
| 
 | |
| 		if (decls.count(key))
 | |
| 			log_cmd_error("Duplicate port decl: %s %s\n", celltype, portname);
 | |
| 
 | |
| 		portdecl_t decl;
 | |
| 		decl.widthparam = RTLIL::escape_id(widthparam);
 | |
| 		decl.is_signed = is_signed;
 | |
| 		decls[key] = decl;
 | |
| 	}
 | |
| 
 | |
| 	void work(RTLIL::Module *module)
 | |
| 	{
 | |
| 		std::map<RTLIL::SigBit, std::pair<bool, RTLIL::SigSpec>> extend_map;
 | |
| 		SigMap sigmap(module);
 | |
| 
 | |
| 		for (auto cell : module->cells())
 | |
| 		{
 | |
| 			if (!decl_celltypes.count(cell->type))
 | |
| 				continue;
 | |
| 
 | |
| 			for (auto &conn : cell->connections())
 | |
| 			{
 | |
| 				std::pair<RTLIL::IdString, RTLIL::IdString> key(cell->type, conn.first);
 | |
| 
 | |
| 				if (!decls.count(key))
 | |
| 					continue;
 | |
| 
 | |
| 				portdecl_t &decl = decls.at(key);
 | |
| 
 | |
| 				if (!cell->parameters.count(decl.widthparam))
 | |
| 					continue;
 | |
| 
 | |
| 				if (!decl.signparam.empty() && !cell->parameters.count(decl.signparam))
 | |
| 					continue;
 | |
| 
 | |
| 				int inner_width = cell->parameters.at(decl.widthparam).as_int();
 | |
| 				int outer_width = conn.second.size();
 | |
| 				bool is_signed = decl.signparam.empty() ? decl.is_signed : cell->parameters.at(decl.signparam).as_bool();
 | |
| 
 | |
| 				if (inner_width >= outer_width)
 | |
| 					continue;
 | |
| 
 | |
| 				RTLIL::SigSpec sig = sigmap(conn.second);
 | |
| 				extend_map[sig.extract(inner_width - 1, 1)] = std::pair<bool, RTLIL::SigSpec>(is_signed,
 | |
| 						sig.extract(inner_width, outer_width - inner_width));
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for (auto cell : module->selected_cells())
 | |
| 		{
 | |
| 			for (auto &conn : cell->connections_)
 | |
| 			{
 | |
| 				std::vector<RTLIL::SigBit> sigbits = sigmap(conn.second).to_sigbit_vector();
 | |
| 				RTLIL::SigSpec old_sig;
 | |
| 
 | |
| 				for (size_t i = 0; i < sigbits.size(); i++)
 | |
| 				{
 | |
| 					if (!extend_map.count(sigbits[i]))
 | |
| 						continue;
 | |
| 
 | |
| 					bool is_signed = extend_map.at(sigbits[i]).first;
 | |
| 					RTLIL::SigSpec extend_sig = extend_map.at(sigbits[i]).second;
 | |
| 
 | |
| 					int extend_width = 0;
 | |
| 					RTLIL::SigBit extend_bit = is_signed ? sigbits[i] : RTLIL::SigBit(RTLIL::State::S0);
 | |
| 					while (extend_width < extend_sig.size() && i + extend_width + 1 < sigbits.size() &&
 | |
| 							sigbits[i + extend_width + 1] == extend_bit) extend_width++;
 | |
| 
 | |
| 					if (extend_width == 0)
 | |
| 						continue;
 | |
| 
 | |
| 					if (old_sig.size() == 0)
 | |
| 						old_sig = conn.second;
 | |
| 
 | |
| 					conn.second.replace(i+1, extend_sig.extract(0, extend_width));
 | |
| 					i += extend_width;
 | |
| 				}
 | |
| 
 | |
| 				if (old_sig.size())
 | |
| 					log("Connected extended bits of %s.%s:%s: %s -> %s\n", log_id(module->name), log_id(cell->name),
 | |
| 							log_id(conn.first), log_signal(old_sig), log_signal(conn.second));
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| };
 | |
| 
 | |
| struct ConnwrappersPass : public Pass {
 | |
| 	ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { }
 | |
| 	void help() override
 | |
| 	{
 | |
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
| 		log("\n");
 | |
| 		log("    connwrappers [options] [selection]\n");
 | |
| 		log("\n");
 | |
| 		log("Wrappers are used in coarse-grain synthesis to wrap cells with smaller ports\n");
 | |
| 		log("in wrapper cells with a (larger) constant port size. I.e. the upper bits\n");
 | |
| 		log("of the wrapper output are signed/unsigned bit extended. This command uses this\n");
 | |
| 		log("knowledge to rewire the inputs of the driven cells to match the output of\n");
 | |
| 		log("the driving cell.\n");
 | |
| 		log("\n");
 | |
| 		log("    -signed <cell_type> <port_name> <width_param>\n");
 | |
| 		log("    -unsigned <cell_type> <port_name> <width_param>\n");
 | |
| 		log("        consider the specified signed/unsigned wrapper output\n");
 | |
| 		log("\n");
 | |
| 		log("    -port <cell_type> <port_name> <width_param> <sign_param>\n");
 | |
| 		log("        use the specified parameter to decide if signed or unsigned\n");
 | |
| 		log("\n");
 | |
| 		log("The options -signed, -unsigned, and -port can be specified multiple times.\n");
 | |
| 		log("\n");
 | |
| 	}
 | |
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | |
| 	{
 | |
| 		ConnwrappersWorker worker;
 | |
| 
 | |
| 		size_t argidx;
 | |
| 		for (argidx = 1; argidx < args.size(); argidx++)
 | |
| 		{
 | |
| 			if (args[argidx] == "-signed" && argidx+3 < args.size()) {
 | |
| 				worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], true);
 | |
| 				argidx += 3;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (args[argidx] == "-unsigned" && argidx+3 < args.size()) {
 | |
| 				worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], false);
 | |
| 				argidx += 3;
 | |
| 				continue;
 | |
| 			}
 | |
| 			if (args[argidx] == "-port" && argidx+4 < args.size()) {
 | |
| 				worker.add_port(args[argidx+1], args[argidx+2], args[argidx+3], args[argidx+4]);
 | |
| 				argidx += 4;
 | |
| 				continue;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 		extra_args(args, argidx, design);
 | |
| 
 | |
| 		log_header(design, "Executing CONNWRAPPERS pass (connect extended ports of wrapper cells).\n");
 | |
| 
 | |
| 		for (auto module : design->selected_modules())
 | |
| 			worker.work(module);
 | |
| 	}
 | |
| } ConnwrappersPass;
 | |
| 
 | |
| PRIVATE_NAMESPACE_END
 |