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/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
27 extern void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
);
31 PRIVATE_NAMESPACE_BEGIN
33 bool check_signal(RTLIL::Module
*mod
, RTLIL::SigSpec signal
, RTLIL::SigSpec ref
, bool &polarity
)
35 if (signal
.size() != 1)
40 for (auto cell
: mod
->cells())
42 if (cell
->type
== "$reduce_or" && cell
->getPort("\\Y") == signal
)
43 return check_signal(mod
, cell
->getPort("\\A"), ref
, polarity
);
45 if (cell
->type
== "$reduce_bool" && cell
->getPort("\\Y") == signal
)
46 return check_signal(mod
, cell
->getPort("\\A"), ref
, polarity
);
48 if (cell
->type
== "$logic_not" && cell
->getPort("\\Y") == signal
) {
50 return check_signal(mod
, cell
->getPort("\\A"), ref
, polarity
);
53 if (cell
->type
== "$not" && cell
->getPort("\\Y") == signal
) {
55 return check_signal(mod
, cell
->getPort("\\A"), ref
, polarity
);
58 if ((cell
->type
== "$eq" || cell
->type
== "$eqx") && cell
->getPort("\\Y") == signal
) {
59 if (cell
->getPort("\\A").is_fully_const()) {
60 if (!cell
->getPort("\\A").as_bool())
62 return check_signal(mod
, cell
->getPort("\\B"), ref
, polarity
);
64 if (cell
->getPort("\\B").is_fully_const()) {
65 if (!cell
->getPort("\\B").as_bool())
67 return check_signal(mod
, cell
->getPort("\\A"), ref
, polarity
);
71 if ((cell
->type
== "$ne" || cell
->type
== "$nex") && cell
->getPort("\\Y") == signal
) {
72 if (cell
->getPort("\\A").is_fully_const()) {
73 if (cell
->getPort("\\A").as_bool())
75 return check_signal(mod
, cell
->getPort("\\B"), ref
, polarity
);
77 if (cell
->getPort("\\B").is_fully_const()) {
78 if (cell
->getPort("\\B").as_bool())
80 return check_signal(mod
, cell
->getPort("\\A"), ref
, polarity
);
88 void apply_const(RTLIL::Module
*mod
, const RTLIL::SigSpec rspec
, RTLIL::SigSpec
&rval
, RTLIL::CaseRule
*cs
, RTLIL::SigSpec const_sig
, bool polarity
, bool unknown
)
90 for (auto &action
: cs
->actions
) {
92 rspec
.replace(action
.first
, RTLIL::SigSpec(RTLIL::State::Sm
, action
.second
.size()), &rval
);
94 rspec
.replace(action
.first
, action
.second
, &rval
);
97 for (auto sw
: cs
->switches
) {
98 if (sw
->signal
.size() == 0) {
99 for (auto cs2
: sw
->cases
)
100 apply_const(mod
, rspec
, rval
, cs2
, const_sig
, polarity
, unknown
);
102 bool this_polarity
= polarity
;
103 if (check_signal(mod
, sw
->signal
, const_sig
, this_polarity
)) {
104 for (auto cs2
: sw
->cases
) {
105 for (auto comp
: cs2
->compare
)
106 if (comp
== RTLIL::SigSpec(this_polarity
, 1))
108 if (cs2
->compare
.size() == 0) {
110 apply_const(mod
, rspec
, rval
, cs2
, const_sig
, polarity
, false);
115 for (auto cs2
: sw
->cases
)
116 apply_const(mod
, rspec
, rval
, cs2
, const_sig
, polarity
, true);
121 void eliminate_const(RTLIL::Module
*mod
, RTLIL::CaseRule
*cs
, RTLIL::SigSpec const_sig
, bool polarity
)
123 for (auto sw
: cs
->switches
) {
124 bool this_polarity
= polarity
;
125 if (check_signal(mod
, sw
->signal
, const_sig
, this_polarity
)) {
126 bool found_rem_path
= false;
127 for (size_t i
= 0; i
< sw
->cases
.size(); i
++) {
128 RTLIL::CaseRule
*cs2
= sw
->cases
[i
];
129 for (auto comp
: cs2
->compare
)
130 if (comp
== RTLIL::SigSpec(this_polarity
, 1))
132 if (found_rem_path
) {
134 sw
->cases
.erase(sw
->cases
.begin() + (i
--));
138 found_rem_path
= true;
139 cs2
->compare
.clear();
141 sw
->signal
= RTLIL::SigSpec();
143 for (auto cs2
: sw
->cases
)
144 eliminate_const(mod
, cs2
, const_sig
, polarity
);
149 bool did_something
= true;
150 while (did_something
) {
151 did_something
= false;
152 proc_clean_case(cs
, did_something
, dummy_count
, 1);
156 void proc_arst(RTLIL::Module
*mod
, RTLIL::Process
*proc
, SigMap
&assign_map
)
159 if (proc
->root_case
.switches
.size() != 1)
162 RTLIL::SigSpec root_sig
= proc
->root_case
.switches
[0]->signal
;
164 for (auto &sync
: proc
->syncs
) {
165 if (sync
->type
== RTLIL::SyncType::STp
|| sync
->type
== RTLIL::SyncType::STn
) {
166 bool polarity
= sync
->type
== RTLIL::SyncType::STp
;
167 if (check_signal(mod
, root_sig
, sync
->signal
, polarity
)) {
168 if (proc
->syncs
.size() == 1) {
169 log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync
->signal
), mod
->name
.c_str(), proc
->name
.c_str());
171 log("Found async reset %s in `%s.%s'.\n", log_signal(sync
->signal
), mod
->name
.c_str(), proc
->name
.c_str());
172 sync
->type
= sync
->type
== RTLIL::SyncType::STp
? RTLIL::SyncType::ST1
: RTLIL::SyncType::ST0
;
174 for (auto &action
: sync
->actions
) {
175 RTLIL::SigSpec rspec
= action
.second
;
176 RTLIL::SigSpec rval
= RTLIL::SigSpec(RTLIL::State::Sm
, rspec
.size());
177 for (int i
= 0; i
< GetSize(rspec
); i
++)
178 if (rspec
[i
].wire
== NULL
)
180 RTLIL::SigSpec last_rval
;
181 for (int count
= 0; rval
!= last_rval
; count
++) {
183 apply_const(mod
, rspec
, rval
, &proc
->root_case
, root_sig
, polarity
, false);
184 assign_map
.apply(rval
);
185 if (rval
.is_fully_const())
188 log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
189 log_signal(sync
->signal
), log_signal(rval
), log_signal(action
.first
));
192 if (rval
.has_marked_bits())
193 log_error("Async reset %s yields non-constant value %s for signal %s.\n",
194 log_signal(sync
->signal
), log_signal(rval
), log_signal(action
.first
));
195 action
.second
= rval
;
197 eliminate_const(mod
, &proc
->root_case
, root_sig
, polarity
);
198 goto restart_proc_arst
;
204 struct ProcArstPass
: public Pass
{
205 ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { }
208 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
210 log(" proc_arst [-global_arst [!]<netname>] [selection]\n");
212 log("This pass identifies asynchronous resets in the processes and converts them\n");
213 log("to a different internal representation that is suitable for generating\n");
214 log("flip-flop cells with asynchronous resets.\n");
216 log(" -global_arst [!]<netname>\n");
217 log(" In modules that have a net with the given name, use this net as async\n");
218 log(" reset for registers that have been assign initial values in their\n");
219 log(" declaration ('reg foobar = constant_value;'). Use the '!' modifier for\n");
220 log(" active low reset signals. Note: the frontend stores the default value\n");
221 log(" in the 'init' attribute on the net.\n");
224 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
226 std::string global_arst
;
227 bool global_arst_neg
= false;
229 log_header(design
, "Executing PROC_ARST pass (detect async resets in processes).\n");
232 for (argidx
= 1; argidx
< args
.size(); argidx
++)
234 if (args
[argidx
] == "-global_arst" && argidx
+1 < args
.size()) {
235 global_arst
= args
[++argidx
];
236 if (!global_arst
.empty() && global_arst
[0] == '!') {
237 global_arst_neg
= true;
238 global_arst
= global_arst
.substr(1);
240 global_arst
= RTLIL::escape_id(global_arst
);
246 extra_args(args
, argidx
, design
);
247 pool
<Wire
*> delete_initattr_wires
;
249 for (auto mod
: design
->modules())
250 if (design
->selected(mod
)) {
251 SigMap
assign_map(mod
);
252 for (auto &proc_it
: mod
->processes
) {
253 if (!design
->selected(mod
, proc_it
.second
))
255 proc_arst(mod
, proc_it
.second
, assign_map
);
256 if (global_arst
.empty() || mod
->wire(global_arst
) == nullptr)
258 std::vector
<RTLIL::SigSig
> arst_actions
;
259 for (auto sync
: proc_it
.second
->syncs
)
260 if (sync
->type
== RTLIL::SyncType::STp
|| sync
->type
== RTLIL::SyncType::STn
)
261 for (auto &act
: sync
->actions
) {
262 RTLIL::SigSpec arst_sig
, arst_val
;
263 for (auto &chunk
: act
.first
.chunks())
264 if (chunk
.wire
&& chunk
.wire
->attributes
.count("\\init")) {
265 RTLIL::SigSpec value
= chunk
.wire
->attributes
.at("\\init");
266 value
.extend_u0(chunk
.wire
->width
, false);
267 arst_sig
.append(chunk
);
268 arst_val
.append(value
.extract(chunk
.offset
, chunk
.width
));
269 delete_initattr_wires
.insert(chunk
.wire
);
271 if (arst_sig
.size()) {
272 log("Added global reset to process %s: %s <- %s\n",
273 proc_it
.first
.c_str(), log_signal(arst_sig
), log_signal(arst_val
));
274 arst_actions
.push_back(RTLIL::SigSig(arst_sig
, arst_val
));
277 if (!arst_actions
.empty()) {
278 RTLIL::SyncRule
*sync
= new RTLIL::SyncRule
;
279 sync
->type
= global_arst_neg
? RTLIL::SyncType::ST0
: RTLIL::SyncType::ST1
;
280 sync
->signal
= mod
->wire(global_arst
);
281 sync
->actions
= arst_actions
;
282 proc_it
.second
->syncs
.push_back(sync
);
287 for (auto wire
: delete_initattr_wires
)
288 wire
->attributes
.erase("\\init");
292 PRIVATE_NAMESPACE_END