/*
 *  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/rtlil.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, RTLIL::SigSpec &sig)
{
	CellTypes ct(design);

	RTLIL::Wire *dummy_wire = module->addWire(NEW_ID, sig.size());

	for (auto &it : module->cells_)
	for (auto &port : it.second->connections_)
		if (ct.cell_output(it.second->type, port.first))
			sigmap(port.second).replace(sig, dummy_wire, &port.second);

	for (auto &conn : module->connections_)
		sigmap(conn.first).replace(sig, dummy_wire, &conn.first);
}

struct ConnectPass : public Pass {
	ConnectPass() : Pass("connect", "create or remove connections") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    connect [-nomap] [-nounset] -set <lhs-expr> <rhs-expr>\n");
		log("\n");
		log("Create a connection. This is equivalent to adding the statement 'assign\n");
		log("<lhs-expr> = <rhs-expr>;' to the Verilog input. Per default, all existing\n");
		log("drivers for <lhs-expr> are unconnected. This can be overwritten by using\n");
		log("the -nounset option.\n");
		log("\n");
		log("\n");
		log("    connect [-nomap] -unset <expr>\n");
		log("\n");
		log("Unconnect all existing drivers for the specified expression.\n");
		log("\n");
		log("\n");
		log("    connect [-nomap] -port <cell> <port> <expr>\n");
		log("\n");
		log("Connect the specified cell port to the specified cell port.\n");
		log("\n");
		log("\n");
		log("Per default signal alias names are resolved and all signal names are mapped\n");
		log("the the signal name of the primary driver. Using the -nomap option deactivates\n");
		log("this behavior.\n");
		log("\n");
		log("The connect command operates in one module only. Either only one module must\n");
		log("be selected or an active module must be set using the 'cd' command.\n");
		log("\n");
		log("This command does not operate on module with processes.\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		RTLIL::Module *module = NULL;
		for (auto &it : design->modules_) {
			if (!design->selected(it.second))
				continue;
			if (module != NULL)
				log_cmd_error("Multiple modules selected: %s, %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.first));
			module = it.second;
		}
		if (module == NULL)
			log_cmd_error("No modules selected.\n");
		if (!module->processes.empty())
			log_cmd_error("Found processes in selected module.\n");

		bool flag_nounset = false, flag_nomap = false;
		std::string set_lhs, set_rhs, unset_expr;
		std::string port_cell, port_port, port_expr;

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			std::string arg = args[argidx];
			if (arg == "-nounset") {
				flag_nounset = true;
				continue;
			}
			if (arg == "-nomap") {
				flag_nomap = true;
				continue;
			}
			if (arg == "-set" && argidx+2 < args.size()) {
				set_lhs = args[++argidx];
				set_rhs = args[++argidx];
				continue;
			}
			if (arg == "-unset" && argidx+1 < args.size()) {
				unset_expr = args[++argidx];
				continue;
			}
			if (arg == "-port" && argidx+3 < args.size()) {
				port_cell = args[++argidx];
				port_port = args[++argidx];
				port_expr = args[++argidx];
				continue;
			}
			break;
		}

		SigMap sigmap;
		if (!flag_nomap)
			for (auto &it : module->connections()) {
				std::vector<RTLIL::SigBit> lhs = it.first.to_sigbit_vector();
				std::vector<RTLIL::SigBit> rhs = it.first.to_sigbit_vector();
				for (size_t i = 0; i < lhs.size(); i++)
					if (rhs[i].wire != NULL)
						sigmap.add(lhs[i], rhs[i]);
			}

		if (!set_lhs.empty())
		{
			if (!unset_expr.empty() || !port_cell.empty())
				log_cmd_error("Can't use -set together with -unset and/or -port.\n");

			RTLIL::SigSpec sig_lhs, sig_rhs;
			if (!RTLIL::SigSpec::parse_sel(sig_lhs, design, module, set_lhs))
				log_cmd_error("Failed to parse set lhs expression `%s'.\n", set_lhs.c_str());
			if (!RTLIL::SigSpec::parse_rhs(sig_lhs, sig_rhs, module, set_rhs))
				log_cmd_error("Failed to parse set rhs expression `%s'.\n", set_rhs.c_str());

			sigmap.apply(sig_lhs);
			sigmap.apply(sig_rhs);

			if (!flag_nounset)
				unset_drivers(design, module, sigmap, sig_lhs);

			module->connect(RTLIL::SigSig(sig_lhs, sig_rhs));
		}
		else
		if (!unset_expr.empty())
		{
			if (!port_cell.empty() || flag_nounset)
				log_cmd_error("Can't use -unset together with -port and/or -nounset.\n");

			RTLIL::SigSpec sig;
			if (!RTLIL::SigSpec::parse_sel(sig, design, module, unset_expr))
				log_cmd_error("Failed to parse unset expression `%s'.\n", unset_expr.c_str());

			sigmap.apply(sig);
			unset_drivers(design, module, sigmap, sig);
		}
		else
		if (!port_cell.empty())
		{
			if (flag_nounset)
				log_cmd_error("Can't use -port together with -nounset.\n");

			if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0)
				log_cmd_error("Can't find cell %s.\n", port_cell.c_str());

			RTLIL::SigSpec sig;
			if (!RTLIL::SigSpec::parse_sel(sig, design, module, port_expr))
				log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str());

			module->cells_.at(RTLIL::escape_id(port_cell))->setPort(RTLIL::escape_id(port_port), sigmap(sig));
		}
		else
			log_cmd_error("Expected -set, -unset, or -port.\n");
	}
} ConnectPass;

PRIVATE_NAMESPACE_END
