Merge pull request #829 from abdelrahmanhosny/master
[yosys.git] / passes / techmap / tribuf.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 TribufConfig {
27 bool merge_mode;
28 bool logic_mode;
29
30 TribufConfig() {
31 merge_mode = false;
32 logic_mode = false;
33 }
34 };
35
36 struct TribufWorker {
37 Module *module;
38 SigMap sigmap;
39 const TribufConfig &config;
40
41 TribufWorker(Module *module, const TribufConfig &config) : module(module), sigmap(module), config(config)
42 {
43 }
44
45 static bool is_all_z(SigSpec sig)
46 {
47 for (auto bit : sig)
48 if (bit != State::Sz)
49 return false;
50 return true;
51 }
52
53 void run()
54 {
55 dict<SigSpec, vector<Cell*>> tribuf_cells;
56 pool<SigBit> output_bits;
57
58 if (config.logic_mode)
59 for (auto wire : module->wires())
60 if (wire->port_output)
61 for (auto bit : sigmap(wire))
62 output_bits.insert(bit);
63
64 for (auto cell : module->selected_cells())
65 {
66 if (cell->type == "$tribuf")
67 tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
68
69 if (cell->type == "$_TBUF_")
70 tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
71
72 if (cell->type.in("$mux", "$_MUX_"))
73 {
74 IdString en_port = cell->type == "$mux" ? "\\EN" : "\\E";
75 IdString tri_type = cell->type == "$mux" ? "$tribuf" : "$_TBUF_";
76
77 if (is_all_z(cell->getPort("\\A")) && is_all_z(cell->getPort("\\B"))) {
78 module->remove(cell);
79 continue;
80 }
81
82 if (is_all_z(cell->getPort("\\A"))) {
83 cell->setPort("\\A", cell->getPort("\\B"));
84 cell->setPort(en_port, cell->getPort("\\S"));
85 cell->unsetPort("\\B");
86 cell->unsetPort("\\S");
87 cell->type = tri_type;
88 tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
89 continue;
90 }
91
92 if (is_all_z(cell->getPort("\\B"))) {
93 cell->setPort(en_port, module->Not(NEW_ID, cell->getPort("\\S")));
94 cell->unsetPort("\\B");
95 cell->unsetPort("\\S");
96 cell->type = tri_type;
97 tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell);
98 continue;
99 }
100 }
101 }
102
103 if (config.merge_mode || config.logic_mode)
104 {
105 for (auto &it : tribuf_cells)
106 {
107 bool no_tribuf = false;
108
109 if (config.logic_mode) {
110 no_tribuf = true;
111 for (auto bit : it.first)
112 if (output_bits.count(bit))
113 no_tribuf = false;
114 }
115
116 if (GetSize(it.second) <= 1 && !no_tribuf)
117 continue;
118
119 SigSpec pmux_b, pmux_s;
120 for (auto cell : it.second) {
121 if (cell->type == "$tribuf")
122 pmux_s.append(cell->getPort("\\EN"));
123 else
124 pmux_s.append(cell->getPort("\\E"));
125 pmux_b.append(cell->getPort("\\A"));
126 module->remove(cell);
127 }
128
129 SigSpec muxout = GetSize(pmux_s) > 1 ? module->Pmux(NEW_ID, SigSpec(State::Sx, GetSize(it.first)), pmux_b, pmux_s) : pmux_b;
130
131 if (no_tribuf)
132 module->connect(it.first, muxout);
133 else
134 module->addTribuf(NEW_ID, muxout, module->ReduceOr(NEW_ID, pmux_s), it.first);
135 }
136 }
137 }
138 };
139
140 struct TribufPass : public Pass {
141 TribufPass() : Pass("tribuf", "infer tri-state buffers") { }
142 void help() YS_OVERRIDE
143 {
144 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
145 log("\n");
146 log(" tribuf [options] [selection]\n");
147 log("\n");
148 log("This pass transforms $mux cells with 'z' inputs to tristate buffers.\n");
149 log("\n");
150 log(" -merge\n");
151 log(" merge multiple tri-state buffers driving the same net\n");
152 log(" into a single buffer.\n");
153 log("\n");
154 log(" -logic\n");
155 log(" convert tri-state buffers that do not drive output ports\n");
156 log(" to non-tristate logic. this option implies -merge.\n");
157 log("\n");
158 }
159 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
160 {
161 TribufConfig config;
162
163 log_header(design, "Executing TRIBUF pass.\n");
164
165 size_t argidx;
166 for (argidx = 1; argidx < args.size(); argidx++) {
167 if (args[argidx] == "-merge") {
168 config.merge_mode = true;
169 continue;
170 }
171 if (args[argidx] == "-logic") {
172 config.logic_mode = true;
173 continue;
174 }
175 break;
176 }
177 extra_args(args, argidx, design);
178
179 for (auto module : design->selected_modules()) {
180 TribufWorker worker(module, config);
181 worker.run();
182 }
183 }
184 } TribufPass;
185
186 PRIVATE_NAMESPACE_END