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"
26 // defined in proc_clean.cc
27 extern void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
);
29 static bool check_signal(RTLIL::Module
*mod
, RTLIL::SigSpec signal
, RTLIL::SigSpec ref
, bool &polarity
)
31 if (signal
.size() != 1)
36 for (auto &cell_it
: mod
->cells
) {
37 RTLIL::Cell
*cell
= cell_it
.second
;
38 if (cell
->type
== "$reduce_or" && cell
->connections
["\\Y"] == signal
)
39 return check_signal(mod
, cell
->connections
["\\A"], ref
, polarity
);
40 if (cell
->type
== "$reduce_bool" && cell
->connections
["\\Y"] == signal
)
41 return check_signal(mod
, cell
->connections
["\\A"], ref
, polarity
);
42 if (cell
->type
== "$logic_not" && cell
->connections
["\\Y"] == signal
) {
44 return check_signal(mod
, cell
->connections
["\\A"], ref
, polarity
);
46 if (cell
->type
== "$not" && cell
->connections
["\\Y"] == signal
) {
48 return check_signal(mod
, cell
->connections
["\\A"], ref
, polarity
);
50 if ((cell
->type
== "$eq" || cell
->type
== "$eqx") && cell
->connections
["\\Y"] == signal
) {
51 if (cell
->connections
["\\A"].is_fully_const()) {
52 if (!cell
->connections
["\\A"].as_bool())
54 return check_signal(mod
, cell
->connections
["\\B"], ref
, polarity
);
56 if (cell
->connections
["\\B"].is_fully_const()) {
57 if (!cell
->connections
["\\B"].as_bool())
59 return check_signal(mod
, cell
->connections
["\\A"], ref
, polarity
);
62 if ((cell
->type
== "$ne" || cell
->type
== "$nex") && cell
->connections
["\\Y"] == signal
) {
63 if (cell
->connections
["\\A"].is_fully_const()) {
64 if (cell
->connections
["\\A"].as_bool())
66 return check_signal(mod
, cell
->connections
["\\B"], ref
, polarity
);
68 if (cell
->connections
["\\B"].is_fully_const()) {
69 if (cell
->connections
["\\B"].as_bool())
71 return check_signal(mod
, cell
->connections
["\\A"], ref
, polarity
);
79 static void apply_const(RTLIL::Module
*mod
, const RTLIL::SigSpec rspec
, RTLIL::SigSpec
&rval
, RTLIL::CaseRule
*cs
, RTLIL::SigSpec const_sig
, bool polarity
, bool unknown
)
81 for (auto &action
: cs
->actions
) {
83 rspec
.replace(action
.first
, RTLIL::SigSpec(RTLIL::State::Sm
, action
.second
.size()), &rval
);
85 rspec
.replace(action
.first
, action
.second
, &rval
);
88 for (auto sw
: cs
->switches
) {
89 if (sw
->signal
.size() == 0) {
90 for (auto cs2
: sw
->cases
)
91 apply_const(mod
, rspec
, rval
, cs2
, const_sig
, polarity
, unknown
);
93 bool this_polarity
= polarity
;
94 if (check_signal(mod
, sw
->signal
, const_sig
, this_polarity
)) {
95 for (auto cs2
: sw
->cases
) {
96 for (auto comp
: cs2
->compare
)
97 if (comp
== RTLIL::SigSpec(this_polarity
, 1))
99 if (cs2
->compare
.size() == 0) {
101 apply_const(mod
, rspec
, rval
, cs2
, const_sig
, polarity
, false);
106 for (auto cs2
: sw
->cases
)
107 apply_const(mod
, rspec
, rval
, cs2
, const_sig
, polarity
, true);
112 static void eliminate_const(RTLIL::Module
*mod
, RTLIL::CaseRule
*cs
, RTLIL::SigSpec const_sig
, bool polarity
)
114 for (auto sw
: cs
->switches
) {
115 bool this_polarity
= polarity
;
116 if (check_signal(mod
, sw
->signal
, const_sig
, this_polarity
)) {
117 bool found_rem_path
= false;
118 for (size_t i
= 0; i
< sw
->cases
.size(); i
++) {
119 RTLIL::CaseRule
*cs2
= sw
->cases
[i
];
120 for (auto comp
: cs2
->compare
)
121 if (comp
== RTLIL::SigSpec(this_polarity
, 1))
123 if (found_rem_path
) {
125 sw
->cases
.erase(sw
->cases
.begin() + (i
--));
129 found_rem_path
= true;
130 cs2
->compare
.clear();
132 sw
->signal
= RTLIL::SigSpec();
134 for (auto cs2
: sw
->cases
)
135 eliminate_const(mod
, cs2
, const_sig
, polarity
);
140 bool did_something
= true;
141 while (did_something
) {
142 did_something
= false;
143 proc_clean_case(cs
, did_something
, dummy_count
, 1);
147 static void proc_arst(RTLIL::Module
*mod
, RTLIL::Process
*proc
, SigMap
&assign_map
)
150 if (proc
->root_case
.switches
.size() != 1)
153 RTLIL::SigSpec root_sig
= proc
->root_case
.switches
[0]->signal
;
155 for (auto &sync
: proc
->syncs
) {
156 if (sync
->type
== RTLIL::SyncType::STp
|| sync
->type
== RTLIL::SyncType::STn
) {
157 bool polarity
= sync
->type
== RTLIL::SyncType::STp
;
158 if (check_signal(mod
, root_sig
, sync
->signal
, polarity
)) {
159 if (proc
->syncs
.size() == 1) {
160 log("Found VHDL-style edge-trigger %s in `%s.%s'.\n", log_signal(sync
->signal
), mod
->name
.c_str(), proc
->name
.c_str());
162 log("Found async reset %s in `%s.%s'.\n", log_signal(sync
->signal
), mod
->name
.c_str(), proc
->name
.c_str());
163 sync
->type
= sync
->type
== RTLIL::SyncType::STp
? RTLIL::SyncType::ST1
: RTLIL::SyncType::ST0
;
165 for (auto &action
: sync
->actions
) {
166 RTLIL::SigSpec rspec
= action
.second
;
167 RTLIL::SigSpec rval
= RTLIL::SigSpec(RTLIL::State::Sm
, rspec
.size());
168 for (int i
= 0; i
< SIZE(rspec
); i
++)
169 if (rspec
[i
].wire
== NULL
)
171 RTLIL::SigSpec last_rval
;
172 for (int count
= 0; rval
!= last_rval
; count
++) {
174 apply_const(mod
, rspec
, rval
, &proc
->root_case
, root_sig
, polarity
, false);
175 assign_map
.apply(rval
);
176 if (rval
.is_fully_const())
179 log_error("Async reset %s yields endless loop at value %s for signal %s.\n",
180 log_signal(sync
->signal
), log_signal(rval
), log_signal(action
.first
));
183 if (rval
.has_marked_bits())
184 log_error("Async reset %s yields non-constant value %s for signal %s.\n",
185 log_signal(sync
->signal
), log_signal(rval
), log_signal(action
.first
));
186 action
.second
= rval
;
188 eliminate_const(mod
, &proc
->root_case
, root_sig
, polarity
);
189 goto restart_proc_arst
;
195 struct ProcArstPass
: public Pass
{
196 ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { }
199 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
201 log(" proc_arst [-global_arst [!]<netname>] [selection]\n");
203 log("This pass identifies asynchronous resets in the processes and converts them\n");
204 log("to a different internal representation that is suitable for generating\n");
205 log("flip-flop cells with asynchronous resets.\n");
207 log(" -global_arst [!]<netname>\n");
208 log(" In modules that have a net with the given name, use this net as async\n");
209 log(" reset for registers that have been assign initial values in their\n");
210 log(" declaration ('reg foobar = constant_value;'). Use the '!' modifier for\n");
211 log(" active low reset signals. Note: the frontend stores the default value\n");
212 log(" in the 'init' attribute on the net.\n");
215 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
217 std::string global_arst
;
218 bool global_arst_neg
= false;
220 log_header("Executing PROC_ARST pass (detect async resets in processes).\n");
223 for (argidx
= 1; argidx
< args
.size(); argidx
++)
225 if (args
[argidx
] == "-global_arst" && argidx
+1 < args
.size()) {
226 global_arst
= args
[++argidx
];
227 if (!global_arst
.empty() && global_arst
[0] == '!') {
228 global_arst_neg
= true;
229 global_arst
= global_arst
.substr(1);
231 global_arst
= RTLIL::escape_id(global_arst
);
237 extra_args(args
, argidx
, design
);
239 for (auto &mod_it
: design
->modules
)
240 if (design
->selected(mod_it
.second
)) {
241 SigMap
assign_map(mod_it
.second
);
242 for (auto &proc_it
: mod_it
.second
->processes
) {
243 if (!design
->selected(mod_it
.second
, proc_it
.second
))
245 proc_arst(mod_it
.second
, proc_it
.second
, assign_map
);
246 if (global_arst
.empty() || mod_it
.second
->wires
.count(global_arst
) == 0)
248 std::vector
<RTLIL::SigSig
> arst_actions
;
249 for (auto sync
: proc_it
.second
->syncs
)
250 if (sync
->type
== RTLIL::SyncType::STp
|| sync
->type
== RTLIL::SyncType::STn
)
251 for (auto &act
: sync
->actions
) {
252 RTLIL::SigSpec arst_sig
, arst_val
;
253 for (auto &chunk
: act
.first
.chunks())
254 if (chunk
.wire
&& chunk
.wire
->attributes
.count("\\init")) {
255 RTLIL::SigSpec value
= chunk
.wire
->attributes
.at("\\init");
256 value
.extend(chunk
.wire
->width
, false);
257 arst_sig
.append(chunk
);
258 arst_val
.append(value
.extract(chunk
.offset
, chunk
.width
));
260 if (arst_sig
.size()) {
261 log("Added global reset to process %s: %s <- %s\n",
262 proc_it
.first
.c_str(), log_signal(arst_sig
), log_signal(arst_val
));
263 arst_actions
.push_back(RTLIL::SigSig(arst_sig
, arst_val
));
266 if (!arst_actions
.empty()) {
267 RTLIL::SyncRule
*sync
= new RTLIL::SyncRule
;
268 sync
->type
= global_arst_neg
? RTLIL::SyncType::ST0
: RTLIL::SyncType::ST1
;
269 sync
->signal
= mod_it
.second
->wires
.at(global_arst
);
270 sync
->actions
= arst_actions
;
271 proc_it
.second
->syncs
.push_back(sync
);