Fix "tee" handling of log_streams
[yosys.git] / passes / cmds / connect.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/register.h"
21 #include "kernel/rtlil.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/celltypes.h"
24 #include "kernel/log.h"
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap &sigmap, RTLIL::SigSpec &sig)
30 {
31 CellTypes ct(design);
32
33 RTLIL::Wire *dummy_wire = module->addWire(NEW_ID, sig.size());
34
35 for (auto &it : module->cells_)
36 for (auto &port : it.second->connections_)
37 if (ct.cell_output(it.second->type, port.first))
38 sigmap(port.second).replace(sig, dummy_wire, &port.second);
39
40 for (auto &conn : module->connections_)
41 sigmap(conn.first).replace(sig, dummy_wire, &conn.first);
42 }
43
44 struct ConnectPass : public Pass {
45 ConnectPass() : Pass("connect", "create or remove connections") { }
46 void help() YS_OVERRIDE
47 {
48 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
49 log("\n");
50 log(" connect [-nomap] [-nounset] -set <lhs-expr> <rhs-expr>\n");
51 log("\n");
52 log("Create a connection. This is equivalent to adding the statement 'assign\n");
53 log("<lhs-expr> = <rhs-expr>;' to the Verilog input. Per default, all existing\n");
54 log("drivers for <lhs-expr> are unconnected. This can be overwritten by using\n");
55 log("the -nounset option.\n");
56 log("\n");
57 log("\n");
58 log(" connect [-nomap] -unset <expr>\n");
59 log("\n");
60 log("Unconnect all existing drivers for the specified expression.\n");
61 log("\n");
62 log("\n");
63 log(" connect [-nomap] -port <cell> <port> <expr>\n");
64 log("\n");
65 log("Connect the specified cell port to the specified cell port.\n");
66 log("\n");
67 log("\n");
68 log("Per default signal alias names are resolved and all signal names are mapped\n");
69 log("the the signal name of the primary driver. Using the -nomap option deactivates\n");
70 log("this behavior.\n");
71 log("\n");
72 log("The connect command operates in one module only. Either only one module must\n");
73 log("be selected or an active module must be set using the 'cd' command.\n");
74 log("\n");
75 log("This command does not operate on module with processes.\n");
76 log("\n");
77 }
78 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
79 {
80 RTLIL::Module *module = NULL;
81 for (auto &it : design->modules_) {
82 if (!design->selected(it.second))
83 continue;
84 if (module != NULL)
85 log_cmd_error("Multiple modules selected: %s, %s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.first));
86 module = it.second;
87 }
88 if (module == NULL)
89 log_cmd_error("No modules selected.\n");
90 if (!module->processes.empty())
91 log_cmd_error("Found processes in selected module.\n");
92
93 bool flag_nounset = false, flag_nomap = false;
94 std::string set_lhs, set_rhs, unset_expr;
95 std::string port_cell, port_port, port_expr;
96
97 size_t argidx;
98 for (argidx = 1; argidx < args.size(); argidx++)
99 {
100 std::string arg = args[argidx];
101 if (arg == "-nounset") {
102 flag_nounset = true;
103 continue;
104 }
105 if (arg == "-nomap") {
106 flag_nomap = true;
107 continue;
108 }
109 if (arg == "-set" && argidx+2 < args.size()) {
110 set_lhs = args[++argidx];
111 set_rhs = args[++argidx];
112 continue;
113 }
114 if (arg == "-unset" && argidx+1 < args.size()) {
115 unset_expr = args[++argidx];
116 continue;
117 }
118 if (arg == "-port" && argidx+3 < args.size()) {
119 port_cell = args[++argidx];
120 port_port = args[++argidx];
121 port_expr = args[++argidx];
122 continue;
123 }
124 break;
125 }
126
127 SigMap sigmap;
128 if (!flag_nomap)
129 for (auto &it : module->connections()) {
130 std::vector<RTLIL::SigBit> lhs = it.first.to_sigbit_vector();
131 std::vector<RTLIL::SigBit> rhs = it.first.to_sigbit_vector();
132 for (size_t i = 0; i < lhs.size(); i++)
133 if (rhs[i].wire != NULL)
134 sigmap.add(lhs[i], rhs[i]);
135 }
136
137 if (!set_lhs.empty())
138 {
139 if (!unset_expr.empty() || !port_cell.empty())
140 log_cmd_error("Can't use -set together with -unset and/or -port.\n");
141
142 RTLIL::SigSpec sig_lhs, sig_rhs;
143 if (!RTLIL::SigSpec::parse_sel(sig_lhs, design, module, set_lhs))
144 log_cmd_error("Failed to parse set lhs expression `%s'.\n", set_lhs.c_str());
145 if (!RTLIL::SigSpec::parse_rhs(sig_lhs, sig_rhs, module, set_rhs))
146 log_cmd_error("Failed to parse set rhs expression `%s'.\n", set_rhs.c_str());
147
148 sigmap.apply(sig_lhs);
149 sigmap.apply(sig_rhs);
150
151 if (!flag_nounset)
152 unset_drivers(design, module, sigmap, sig_lhs);
153
154 module->connect(RTLIL::SigSig(sig_lhs, sig_rhs));
155 }
156 else
157 if (!unset_expr.empty())
158 {
159 if (!port_cell.empty() || flag_nounset)
160 log_cmd_error("Can't use -unset together with -port and/or -nounset.\n");
161
162 RTLIL::SigSpec sig;
163 if (!RTLIL::SigSpec::parse_sel(sig, design, module, unset_expr))
164 log_cmd_error("Failed to parse unset expression `%s'.\n", unset_expr.c_str());
165
166 sigmap.apply(sig);
167 unset_drivers(design, module, sigmap, sig);
168 }
169 else
170 if (!port_cell.empty())
171 {
172 if (flag_nounset)
173 log_cmd_error("Can't use -port together with -nounset.\n");
174
175 if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0)
176 log_cmd_error("Can't find cell %s.\n", port_cell.c_str());
177
178 RTLIL::SigSpec sig;
179 if (!RTLIL::SigSpec::parse_sel(sig, design, module, port_expr))
180 log_cmd_error("Failed to parse port expression `%s'.\n", port_expr.c_str());
181
182 module->cells_.at(RTLIL::escape_id(port_cell))->setPort(RTLIL::escape_id(port_port), sigmap(sig));
183 }
184 else
185 log_cmd_error("Expected -set, -unset, or -port.\n");
186 }
187 } ConnectPass;
188
189 PRIVATE_NAMESPACE_END