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
== ID($tribuf
))
67 tribuf_cells
[sigmap(cell
->getPort(ID::Y
))].push_back(cell
);
69 if (cell
->type
== ID($_TBUF_
))
70 tribuf_cells
[sigmap(cell
->getPort(ID::Y
))].push_back(cell
);
72 if (cell
->type
.in(ID($mux
), ID($_MUX_
)))
74 IdString en_port
= cell
->type
== ID($mux
) ? ID::EN
: ID::E
;
75 IdString tri_type
= cell
->type
== ID($mux
) ? ID($tribuf
) : ID($_TBUF_
);
77 if (is_all_z(cell
->getPort(ID::A
)) && is_all_z(cell
->getPort(ID::B
))) {
82 if (is_all_z(cell
->getPort(ID::A
))) {
83 cell
->setPort(ID::A
, cell
->getPort(ID::B
));
84 cell
->setPort(en_port
, cell
->getPort(ID::S
));
85 cell
->unsetPort(ID::B
);
86 cell
->unsetPort(ID::S
);
87 cell
->type
= tri_type
;
88 tribuf_cells
[sigmap(cell
->getPort(ID::Y
))].push_back(cell
);
89 module
->design
->scratchpad_set_bool("tribuf.added_something", true);
93 if (is_all_z(cell
->getPort(ID::B
))) {
94 cell
->setPort(en_port
, module
->Not(NEW_ID
, cell
->getPort(ID::S
)));
95 cell
->unsetPort(ID::B
);
96 cell
->unsetPort(ID::S
);
97 cell
->type
= tri_type
;
98 tribuf_cells
[sigmap(cell
->getPort(ID::Y
))].push_back(cell
);
99 module
->design
->scratchpad_set_bool("tribuf.added_something", true);
105 if (config
.merge_mode
|| config
.logic_mode
)
107 for (auto &it
: tribuf_cells
)
109 bool no_tribuf
= false;
111 if (config
.logic_mode
) {
113 for (auto bit
: it
.first
)
114 if (output_bits
.count(bit
))
118 if (GetSize(it
.second
) <= 1 && !no_tribuf
)
121 SigSpec pmux_b
, pmux_s
;
122 for (auto cell
: it
.second
) {
123 if (cell
->type
== ID($tribuf
))
124 pmux_s
.append(cell
->getPort(ID::EN
));
126 pmux_s
.append(cell
->getPort(ID::E
));
127 pmux_b
.append(cell
->getPort(ID::A
));
128 module
->remove(cell
);
131 SigSpec muxout
= GetSize(pmux_s
) > 1 ? module
->Pmux(NEW_ID
, SigSpec(State::Sx
, GetSize(it
.first
)), pmux_b
, pmux_s
) : pmux_b
;
134 module
->connect(it
.first
, muxout
);
136 module
->addTribuf(NEW_ID
, muxout
, module
->ReduceOr(NEW_ID
, pmux_s
), it
.first
);
137 module
->design
->scratchpad_set_bool("tribuf.added_something", true);
144 struct TribufPass
: public Pass
{
145 TribufPass() : Pass("tribuf", "infer tri-state buffers") { }
146 void help() YS_OVERRIDE
148 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
150 log(" tribuf [options] [selection]\n");
152 log("This pass transforms $mux cells with 'z' inputs to tristate buffers.\n");
155 log(" merge multiple tri-state buffers driving the same net\n");
156 log(" into a single buffer.\n");
159 log(" convert tri-state buffers that do not drive output ports\n");
160 log(" to non-tristate logic. this option implies -merge.\n");
163 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
167 log_header(design
, "Executing TRIBUF pass.\n");
170 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
171 if (args
[argidx
] == "-merge") {
172 config
.merge_mode
= true;
175 if (args
[argidx
] == "-logic") {
176 config
.logic_mode
= true;
181 extra_args(args
, argidx
, design
);
183 for (auto module
: design
->selected_modules()) {
184 TribufWorker
worker(module
, config
);
190 PRIVATE_NAMESPACE_END