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
26 struct AssertpmuxWorker
34 // get<0> ... mux cell
35 // get<1> ... mux port index
36 // get<2> ... mux bit index
37 dict
<SigBit
, pool
<tuple
<Cell
*, int, int>>> sigbit_muxusers
;
39 dict
<SigBit
, SigBit
> sigbit_actsignals
;
40 dict
<SigSpec
, SigBit
> sigspec_actsignals
;
41 dict
<tuple
<Cell
*, int>, SigBit
> muxport_actsignal
;
43 AssertpmuxWorker(Module
*module
, bool flag_noinit
, bool flag_always
) :
44 module(module
), sigmap(module
), flag_noinit(flag_noinit
), flag_always(flag_always
)
46 for (auto wire
: module
->wires())
48 if (wire
->port_output
)
49 for (auto bit
: sigmap(wire
))
50 sigbit_actsignals
[bit
] = State::S1
;
53 for (auto cell
: module
->cells())
55 if (cell
->type
.in("$mux", "$pmux"))
57 int width
= cell
->getParam("\\WIDTH").as_int();
58 int numports
= cell
->type
== "$mux" ? 2 : cell
->getParam("\\S_WIDTH").as_int() + 1;
60 SigSpec sig_a
= sigmap(cell
->getPort("\\A"));
61 SigSpec sig_b
= sigmap(cell
->getPort("\\B"));
62 SigSpec sig_s
= sigmap(cell
->getPort("\\S"));
64 for (int i
= 0; i
< numports
; i
++) {
65 SigSpec bits
= i
== 0 ? sig_a
: sig_b
.extract(width
*(i
-1), width
);
66 for (int k
= 0; k
< width
; k
++) {
67 tuple
<Cell
*, int, int> muxuser(cell
, i
, k
);
68 sigbit_muxusers
[bits
[k
]].insert(muxuser
);
74 for (auto &conn
: cell
->connections()) {
75 if (!cell
->known() || cell
->input(conn
.first
))
76 for (auto bit
: sigmap(conn
.second
))
77 sigbit_actsignals
[bit
] = State::S1
;
83 SigBit
get_bit_activation(SigBit bit
)
87 if (sigbit_actsignals
.count(bit
) == 0)
91 for (auto muxuser
: sigbit_muxusers
.at(bit
))
93 Cell
*cell
= std::get
<0>(muxuser
);
94 int portidx
= std::get
<1>(muxuser
);
95 int bitidx
= std::get
<2>(muxuser
);
97 tuple
<Cell
*, int> muxport(cell
, portidx
);
99 if (muxport_actsignal
.count(muxport
) == 0) {
101 muxport_actsignal
[muxport
] = module
->LogicNot(NEW_ID
, cell
->getPort("\\S"));
103 muxport_actsignal
[muxport
] = cell
->getPort("\\S")[portidx
-1];
106 output
.append(module
->LogicAnd(NEW_ID
, muxport_actsignal
.at(muxport
), get_bit_activation(cell
->getPort("\\Y")[bitidx
])));
109 output
.sort_and_unify();
111 if (GetSize(output
) == 0)
113 else if (GetSize(output
) > 1)
114 output
= module
->ReduceOr(NEW_ID
, output
);
116 sigbit_actsignals
[bit
] = output
.as_bit();
119 return sigbit_actsignals
.at(bit
);
122 SigBit
get_activation(SigSpec sig
)
125 sig
.sort_and_unify();
127 if (sigspec_actsignals
.count(sig
) == 0)
132 output
.append(get_bit_activation(bit
));
134 output
.sort_and_unify();
136 if (GetSize(output
) == 0)
138 else if (GetSize(output
) > 1)
139 output
= module
->ReduceOr(NEW_ID
, output
);
141 sigspec_actsignals
[sig
] = output
.as_bit();
144 return sigspec_actsignals
.at(sig
);
149 log("Adding assert for $pmux cell %s.%s.\n", log_id(module
), log_id(pmux
));
151 int swidth
= pmux
->getParam("\\S_WIDTH").as_int();
152 int cntbits
= ceil_log2(swidth
+1);
154 SigSpec sel
= pmux
->getPort("\\S");
155 SigSpec
cnt(State::S0
, cntbits
);
157 for (int i
= 0; i
< swidth
; i
++)
158 cnt
= module
->Add(NEW_ID
, cnt
, sel
[i
]);
160 SigSpec assert_a
= module
->Le(NEW_ID
, cnt
, SigSpec(1, cntbits
));
164 assert_en
.append(module
->LogicNot(NEW_ID
, module
->Initstate(NEW_ID
)));
167 assert_en
.append(get_activation(pmux
->getPort("\\Y")));
169 if (GetSize(assert_en
) == 0)
170 assert_en
= State::S1
;
172 if (GetSize(assert_en
) == 2)
173 assert_en
= module
->LogicAnd(NEW_ID
, assert_en
[0], assert_en
[1]);
175 Cell
*assert_cell
= module
->addAssert(NEW_ID
, assert_a
, assert_en
);
177 if (pmux
->attributes
.count("\\src") != 0)
178 assert_cell
->attributes
["\\src"] = pmux
->attributes
.at("\\src");
182 struct AssertpmuxPass
: public Pass
{
183 AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { }
184 void help() YS_OVERRIDE
186 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
188 log(" assertpmux [options] [selection]\n");
190 log("This command adds asserts to the design that assert that all parallel muxes\n");
191 log("($pmux cells) have a maximum of one of their inputs enable at any time.\n");
194 log(" do not enforce the pmux condition during the init state\n");
197 log(" usually the $pmux condition is only checked when the $pmux output\n");
198 log(" is used by the mux tree it drives. this option will deactivate this\n");
199 log(" additional constraint and check the $pmux condition always.\n");
202 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
204 bool flag_noinit
= false;
205 bool flag_always
= false;
207 log_header(design
, "Executing ASSERTPMUX pass (add asserts for $pmux cells).\n");
210 for (argidx
= 1; argidx
< args
.size(); argidx
++)
212 if (args
[argidx
] == "-noinit") {
216 if (args
[argidx
] == "-always") {
222 extra_args(args
, argidx
, design
);
224 for (auto module
: design
->selected_modules())
226 AssertpmuxWorker
worker(module
, flag_noinit
, flag_always
);
227 vector
<Cell
*> pmux_cells
;
229 for (auto cell
: module
->selected_cells())
230 if (cell
->type
== "$pmux")
231 pmux_cells
.push_back(cell
);
233 for (auto cell
: pmux_cells
)
240 PRIVATE_NAMESPACE_END