Merge branch 'opt_compare_pr' of https://github.com/C-Elegans/yosys into C-Elegans...
[yosys.git] / passes / equiv / equiv_add.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/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 struct EquivAddPass : public Pass {
27 EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { }
28 virtual void help()
29 {
30 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
31 log("\n");
32 log(" equiv_add [-try] gold_sig gate_sig\n");
33 log("\n");
34 log("This command adds an $equiv cell for the specified signals.\n");
35 log("\n");
36 log("\n");
37 log(" equiv_add [-try] -cell gold_cell gate_cell\n");
38 log("\n");
39 log("This command adds $equiv cells for the ports of the specified cells.\n");
40 log("\n");
41 }
42 virtual void execute(std::vector<std::string> args, Design *design)
43 {
44 bool try_mode = false;
45
46 if (design->selected_active_module.empty())
47 log_cmd_error("This command must be executed in module context!\n");
48
49 Module *module = design->module(design->selected_active_module);
50 log_assert(module != nullptr);
51
52 if (GetSize(args) > 1 && args[1] == "-try") {
53 args.erase(args.begin() + 1);
54 try_mode = true;
55 }
56
57 if (GetSize(args) == 4 && args[1] == "-cell")
58 {
59 Cell *gold_cell = module->cell(RTLIL::escape_id(args[2]));
60 Cell *gate_cell = module->cell(RTLIL::escape_id(args[3]));
61
62 if (gold_cell == nullptr) {
63 if (try_mode) {
64 log_warning("Can't find gold cell '%s'.\n", args[2].c_str());
65 return;
66 }
67 log_cmd_error("Can't find gold cell '%s'.\n", args[2].c_str());
68 }
69
70 if (gate_cell == nullptr) {
71 if (try_mode) {
72 log_warning("Can't find gate cell '%s'.\n", args[3].c_str());
73 return;
74 }
75 log_cmd_error("Can't find gate cell '%s'.\n", args[3].c_str());
76 }
77
78 for (auto conn : gold_cell->connections())
79 {
80 auto port = conn.first;
81 SigSpec gold_sig = gold_cell->getPort(port);
82 SigSpec gate_sig = gate_cell->getPort(port);
83 int width = min(GetSize(gold_sig), GetSize(gate_sig));
84
85 if (gold_cell->input(port) && gate_cell->input(port))
86 {
87 SigSpec combined_sig = module->addWire(NEW_ID, width);
88
89 for (int i = 0; i < width; i++) {
90 module->addEquiv(NEW_ID, gold_sig[i], gate_sig[i], combined_sig[i]);
91 gold_sig[i] = gate_sig[i] = combined_sig[i];
92 }
93
94 gold_cell->setPort(port, gold_sig);
95 gate_cell->setPort(port, gate_sig);
96 continue;
97 }
98
99 if (gold_cell->output(port) && gate_cell->output(port))
100 {
101 SigSpec new_gold_wire = module->addWire(NEW_ID, width);
102 SigSpec new_gate_wire = module->addWire(NEW_ID, width);
103 SigSig gg_conn;
104
105 for (int i = 0; i < width; i++) {
106 module->addEquiv(NEW_ID, new_gold_wire[i], new_gold_wire[i], gold_sig[i]);
107 gg_conn.first.append(gate_sig[i]);
108 gg_conn.second.append(gold_sig[i]);
109 gold_sig[i] = new_gold_wire[i];
110 gate_sig[i] = new_gate_wire[i];
111 }
112
113 module->connect(gg_conn);
114 gold_cell->setPort(port, gold_sig);
115 gate_cell->setPort(port, gate_sig);
116 continue;
117 }
118 }
119 }
120 else
121 {
122 if (GetSize(args) != 3)
123 cmd_error(args, GetSize(args)-1, "Invalid number of arguments.");
124
125 SigSpec gold_signal, gate_signal;
126
127 if (!SigSpec::parse(gate_signal, module, args[2])) {
128 if (try_mode) {
129 log_warning("Error in gate signal: %s\n", args[2].c_str());
130 return;
131 }
132 log_cmd_error("Error in gate signal: %s\n", args[2].c_str());
133 }
134
135 if (!SigSpec::parse_rhs(gate_signal, gold_signal, module, args[1])) {
136 if (try_mode) {
137 log_warning("Error in gold signal: %s\n", args[1].c_str());
138 return;
139 }
140 log_cmd_error("Error in gold signal: %s\n", args[1].c_str());
141 }
142
143 log_assert(GetSize(gold_signal) == GetSize(gate_signal));
144 SigSpec equiv_signal = module->addWire(NEW_ID, GetSize(gold_signal));
145
146 SigMap sigmap(module);
147 sigmap.apply(gold_signal);
148 sigmap.apply(gate_signal);
149
150 dict<SigBit, SigBit> to_equiv_bits;
151 pool<Cell*> added_equiv_cells;
152
153 for (int i = 0; i < GetSize(gold_signal); i++) {
154 Cell *equiv_cell = module->addEquiv(NEW_ID, gold_signal[i], gate_signal[i], equiv_signal[i]);
155 equiv_cell->set_bool_attribute("\\keep");
156 to_equiv_bits[gold_signal[i]] = equiv_signal[i];
157 to_equiv_bits[gate_signal[i]] = equiv_signal[i];
158 added_equiv_cells.insert(equiv_cell);
159 }
160
161 for (auto cell : module->cells())
162 for (auto conn : cell->connections())
163 if (!added_equiv_cells.count(cell) && cell->input(conn.first)) {
164 SigSpec new_sig;
165 for (auto bit : conn.second)
166 if (to_equiv_bits.count(sigmap(bit)))
167 new_sig.append(to_equiv_bits.at(sigmap(bit)));
168 else
169 new_sig.append(bit);
170 if (conn.second != new_sig)
171 cell->setPort(conn.first, new_sig);
172 }
173 }
174 }
175 } EquivAddPass;
176
177 PRIVATE_NAMESPACE_END