2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
39 const TribufConfig
&config
;
41 TribufWorker(Module
*module
, const TribufConfig
&config
) : module(module
), sigmap(module
), config(config
)
45 static bool is_all_z(SigSpec sig
)
55 dict
<SigSpec
, vector
<Cell
*>> tribuf_cells
;
56 pool
<SigBit
> output_bits
;
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
);
64 for (auto cell
: module
->selected_cells())
66 if (cell
->type
== "$tribuf")
67 tribuf_cells
[sigmap(cell
->getPort("\\Y"))].push_back(cell
);
69 if (cell
->type
== "$_TBUF_")
70 tribuf_cells
[sigmap(cell
->getPort("\\Y"))].push_back(cell
);
72 if (cell
->type
.in("$mux", "$_MUX_"))
74 IdString en_port
= cell
->type
== "$mux" ? "\\EN" : "\\E";
75 IdString tri_type
= cell
->type
== "$mux" ? "$tribuf" : "$_TBUF_";
77 if (is_all_z(cell
->getPort("\\A")) && is_all_z(cell
->getPort("\\B"))) {
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
);
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
);
103 if (config
.merge_mode
|| config
.logic_mode
)
105 for (auto &it
: tribuf_cells
)
107 bool no_tribuf
= false;
109 if (config
.logic_mode
) {
111 for (auto bit
: it
.first
)
112 if (output_bits
.count(bit
))
116 if (GetSize(it
.second
) <= 1 && !no_tribuf
)
119 SigSpec pmux_b
, pmux_s
;
120 for (auto cell
: it
.second
) {
121 if (cell
->type
== "$tribuf")
122 pmux_s
.append(cell
->getPort("\\EN"));
124 pmux_s
.append(cell
->getPort("\\E"));
125 pmux_b
.append(cell
->getPort("\\A"));
126 module
->remove(cell
);
129 SigSpec muxout
= GetSize(pmux_s
) > 1 ? module
->Pmux(NEW_ID
, SigSpec(State::Sx
, GetSize(it
.first
)), pmux_b
, pmux_s
) : pmux_b
;
132 module
->connect(it
.first
, muxout
);
134 module
->addTribuf(NEW_ID
, muxout
, module
->ReduceOr(NEW_ID
, pmux_s
), it
.first
);
140 struct TribufPass
: public Pass
{
141 TribufPass() : Pass("tribuf", "infer tri-state buffers") { }
142 void help() YS_OVERRIDE
144 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
146 log(" tribuf [options] [selection]\n");
148 log("This pass transforms $mux cells with 'z' inputs to tristate buffers.\n");
151 log(" merge multiple tri-state buffers driving the same net\n");
152 log(" into a single buffer.\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");
159 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
163 log_header(design
, "Executing TRIBUF pass.\n");
166 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
167 if (args
[argidx
] == "-merge") {
168 config
.merge_mode
= true;
171 if (args
[argidx
] == "-logic") {
172 config
.logic_mode
= true;
177 extra_args(args
, argidx
, design
);
179 for (auto module
: design
->selected_modules()) {
180 TribufWorker
worker(module
, config
);
186 PRIVATE_NAMESPACE_END