Using log_assert() instead of assert()
[yosys.git] / passes / proc / proc_dff.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/consteval.h"
23 #include "kernel/log.h"
24 #include <sstream>
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 static RTLIL::SigSpec find_any_lvalue(const RTLIL::Process *proc)
29 {
30 RTLIL::SigSpec lvalue;
31
32 for (auto sync : proc->syncs)
33 for (auto &action : sync->actions)
34 if (action.first.size() > 0) {
35 lvalue = action.first;
36 lvalue.sort_and_unify();
37 break;
38 }
39
40 for (auto sync : proc->syncs) {
41 RTLIL::SigSpec this_lvalue;
42 for (auto &action : sync->actions)
43 this_lvalue.append(action.first);
44 this_lvalue.sort_and_unify();
45 RTLIL::SigSpec common_sig = this_lvalue.extract(lvalue);
46 if (common_sig.size() > 0)
47 lvalue = common_sig;
48 }
49
50 return lvalue;
51 }
52
53 static void gen_dffsr_complex(RTLIL::Module *mod, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::SigSpec clk, bool clk_polarity,
54 std::map<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> &async_rules, RTLIL::Process *proc)
55 {
56 RTLIL::SigSpec sig_sr_set = RTLIL::SigSpec(0, sig_d.size());
57 RTLIL::SigSpec sig_sr_clr = RTLIL::SigSpec(0, sig_d.size());
58
59 for (auto &it : async_rules)
60 {
61 RTLIL::SigSpec sync_value = it.first;
62 RTLIL::SigSpec sync_value_inv;
63 RTLIL::SigSpec sync_high_signals;
64 RTLIL::SigSpec sync_low_signals;
65
66 for (auto &it2 : it.second)
67 if (it2->type == RTLIL::SyncType::ST0)
68 sync_low_signals.append(it2->signal);
69 else if (it2->type == RTLIL::SyncType::ST1)
70 sync_high_signals.append(it2->signal);
71 else
72 log_abort();
73
74 if (sync_low_signals.size() > 1) {
75 RTLIL::Cell *cell = mod->addCell(NEW_ID, "$reduce_or");
76 cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
77 cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.size());
78 cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
79 cell->set("\\A", sync_low_signals);
80 cell->set("\\Y", sync_low_signals = mod->addWire(NEW_ID));
81 }
82
83 if (sync_low_signals.size() > 0) {
84 RTLIL::Cell *cell = mod->addCell(NEW_ID, "$not");
85 cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
86 cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_low_signals.size());
87 cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
88 cell->set("\\A", sync_low_signals);
89 cell->set("\\Y", mod->addWire(NEW_ID));
90 sync_high_signals.append(cell->get("\\Y"));
91 }
92
93 if (sync_high_signals.size() > 1) {
94 RTLIL::Cell *cell = mod->addCell(NEW_ID, "$reduce_or");
95 cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
96 cell->parameters["\\A_WIDTH"] = RTLIL::Const(sync_high_signals.size());
97 cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
98 cell->set("\\A", sync_high_signals);
99 cell->set("\\Y", sync_high_signals = mod->addWire(NEW_ID));
100 }
101
102 RTLIL::Cell *inv_cell = mod->addCell(NEW_ID, "$not");
103 inv_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0);
104 inv_cell->parameters["\\A_WIDTH"] = RTLIL::Const(sig_d.size());
105 inv_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_d.size());
106 inv_cell->set("\\A", sync_value);
107 inv_cell->set("\\Y", sync_value_inv = mod->addWire(NEW_ID, sig_d.size()));
108
109 RTLIL::Cell *mux_set_cell = mod->addCell(NEW_ID, "$mux");
110 mux_set_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
111 mux_set_cell->set("\\A", sig_sr_set);
112 mux_set_cell->set("\\B", sync_value);
113 mux_set_cell->set("\\S", sync_high_signals);
114 mux_set_cell->set("\\Y", sig_sr_set = mod->addWire(NEW_ID, sig_d.size()));
115
116 RTLIL::Cell *mux_clr_cell = mod->addCell(NEW_ID, "$mux");
117 mux_clr_cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
118 mux_clr_cell->set("\\A", sig_sr_clr);
119 mux_clr_cell->set("\\B", sync_value_inv);
120 mux_clr_cell->set("\\S", sync_high_signals);
121 mux_clr_cell->set("\\Y", sig_sr_clr = mod->addWire(NEW_ID, sig_d.size()));
122 }
123
124 std::stringstream sstr;
125 sstr << "$procdff$" << (RTLIL::autoidx++);
126
127 RTLIL::Cell *cell = mod->addCell(sstr.str(), "$dffsr");
128 cell->attributes = proc->attributes;
129 cell->parameters["\\WIDTH"] = RTLIL::Const(sig_d.size());
130 cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
131 cell->parameters["\\SET_POLARITY"] = RTLIL::Const(true, 1);
132 cell->parameters["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
133 cell->set("\\D", sig_d);
134 cell->set("\\Q", sig_q);
135 cell->set("\\CLK", clk);
136 cell->set("\\SET", sig_sr_set);
137 cell->set("\\CLR", sig_sr_clr);
138
139 log(" created %s cell `%s' with %s edge clock and multiple level-sensitive resets.\n",
140 cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
141 }
142
143 static void gen_dffsr(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_out,
144 bool clk_polarity, bool set_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec set, RTLIL::Process *proc)
145 {
146 std::stringstream sstr;
147 sstr << "$procdff$" << (RTLIL::autoidx++);
148
149 RTLIL::SigSpec sig_set_inv = mod->addWire(NEW_ID, sig_in.size());
150 RTLIL::SigSpec sig_sr_set = mod->addWire(NEW_ID, sig_in.size());
151 RTLIL::SigSpec sig_sr_clr = mod->addWire(NEW_ID, sig_in.size());
152
153 RTLIL::Cell *inv_set = mod->addCell(NEW_ID, "$not");
154 inv_set->parameters["\\A_SIGNED"] = RTLIL::Const(0);
155 inv_set->parameters["\\A_WIDTH"] = RTLIL::Const(sig_in.size());
156 inv_set->parameters["\\Y_WIDTH"] = RTLIL::Const(sig_in.size());
157 inv_set->set("\\A", sig_set);
158 inv_set->set("\\Y", sig_set_inv);
159
160 RTLIL::Cell *mux_sr_set = mod->addCell(NEW_ID, "$mux");
161 mux_sr_set->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
162 mux_sr_set->set(set_polarity ? "\\A" : "\\B", RTLIL::Const(0, sig_in.size()));
163 mux_sr_set->set(set_polarity ? "\\B" : "\\A", sig_set);
164 mux_sr_set->set("\\Y", sig_sr_set);
165 mux_sr_set->set("\\S", set);
166
167 RTLIL::Cell *mux_sr_clr = mod->addCell(NEW_ID, "$mux");
168 mux_sr_clr->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
169 mux_sr_clr->set(set_polarity ? "\\A" : "\\B", RTLIL::Const(0, sig_in.size()));
170 mux_sr_clr->set(set_polarity ? "\\B" : "\\A", sig_set_inv);
171 mux_sr_clr->set("\\Y", sig_sr_clr);
172 mux_sr_clr->set("\\S", set);
173
174 RTLIL::Cell *cell = mod->addCell(sstr.str(), "$dffsr");
175 cell->attributes = proc->attributes;
176 cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
177 cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
178 cell->parameters["\\SET_POLARITY"] = RTLIL::Const(true, 1);
179 cell->parameters["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
180 cell->set("\\D", sig_in);
181 cell->set("\\Q", sig_out);
182 cell->set("\\CLK", clk);
183 cell->set("\\SET", sig_sr_set);
184 cell->set("\\CLR", sig_sr_clr);
185
186 log(" created %s cell `%s' with %s edge clock and %s level non-const reset.\n", cell->type.c_str(), cell->name.c_str(),
187 clk_polarity ? "positive" : "negative", set_polarity ? "positive" : "negative");
188 }
189
190 static void gen_dff(RTLIL::Module *mod, RTLIL::SigSpec sig_in, RTLIL::Const val_rst, RTLIL::SigSpec sig_out,
191 bool clk_polarity, bool arst_polarity, RTLIL::SigSpec clk, RTLIL::SigSpec *arst, RTLIL::Process *proc)
192 {
193 std::stringstream sstr;
194 sstr << "$procdff$" << (RTLIL::autoidx++);
195
196 RTLIL::Cell *cell = mod->addCell(sstr.str(), arst ? "$adff" : "$dff");
197 cell->attributes = proc->attributes;
198
199 cell->parameters["\\WIDTH"] = RTLIL::Const(sig_in.size());
200 if (arst) {
201 cell->parameters["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity, 1);
202 cell->parameters["\\ARST_VALUE"] = val_rst;
203 }
204 cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity, 1);
205
206 cell->set("\\D", sig_in);
207 cell->set("\\Q", sig_out);
208 if (arst)
209 cell->set("\\ARST", *arst);
210 cell->set("\\CLK", clk);
211
212 log(" created %s cell `%s' with %s edge clock", cell->type.c_str(), cell->name.c_str(), clk_polarity ? "positive" : "negative");
213 if (arst)
214 log(" and %s level reset", arst_polarity ? "positive" : "negative");
215 log(".\n");
216 }
217
218 static void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce)
219 {
220 while (1)
221 {
222 RTLIL::SigSpec sig = find_any_lvalue(proc);
223 bool free_sync_level = false;
224
225 if (sig.size() == 0)
226 break;
227
228 log("Creating register for signal `%s.%s' using process `%s.%s'.\n",
229 mod->name.c_str(), log_signal(sig), mod->name.c_str(), proc->name.c_str());
230
231 RTLIL::SigSpec insig = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
232 RTLIL::SigSpec rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
233 RTLIL::SyncRule *sync_level = NULL;
234 RTLIL::SyncRule *sync_edge = NULL;
235 RTLIL::SyncRule *sync_always = NULL;
236
237 std::map<RTLIL::SigSpec, std::set<RTLIL::SyncRule*>> many_async_rules;
238
239 for (auto sync : proc->syncs)
240 for (auto &action : sync->actions)
241 {
242 if (action.first.extract(sig).size() == 0)
243 continue;
244
245 if (sync->type == RTLIL::SyncType::ST0 || sync->type == RTLIL::SyncType::ST1) {
246 if (sync_level != NULL && sync_level != sync) {
247 // log_error("Multiple level sensitive events found for this signal!\n");
248 many_async_rules[rstval].insert(sync_level);
249 rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
250 }
251 rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
252 sig.replace(action.first, action.second, &rstval);
253 sync_level = sync;
254 }
255 else if (sync->type == RTLIL::SyncType::STp || sync->type == RTLIL::SyncType::STn) {
256 if (sync_edge != NULL && sync_edge != sync)
257 log_error("Multiple edge sensitive events found for this signal!\n");
258 sig.replace(action.first, action.second, &insig);
259 sync_edge = sync;
260 }
261 else if (sync->type == RTLIL::SyncType::STa) {
262 if (sync_always != NULL && sync_always != sync)
263 log_error("Multiple always events found for this signal!\n");
264 sig.replace(action.first, action.second, &insig);
265 sync_always = sync;
266 }
267 else {
268 log_error("Event with any-edge sensitivity found for this signal!\n");
269 }
270
271 action.first.remove2(sig, &action.second);
272 }
273
274 if (many_async_rules.size() > 0)
275 {
276 many_async_rules[rstval].insert(sync_level);
277 if (many_async_rules.size() == 1)
278 {
279 sync_level = new RTLIL::SyncRule;
280 sync_level->type = RTLIL::SyncType::ST1;
281 sync_level->signal = mod->addWire(NEW_ID);
282 sync_level->actions.push_back(RTLIL::SigSig(sig, rstval));
283 free_sync_level = true;
284
285 RTLIL::SigSpec inputs, compare;
286 for (auto &it : many_async_rules[rstval]) {
287 inputs.append(it->signal);
288 compare.append(it->type == RTLIL::SyncType::ST0 ? RTLIL::State::S1 : RTLIL::State::S0);
289 }
290 log_assert(inputs.size() == compare.size());
291
292 RTLIL::Cell *cell = mod->addCell(NEW_ID, "$ne");
293 cell->parameters["\\A_SIGNED"] = RTLIL::Const(false, 1);
294 cell->parameters["\\B_SIGNED"] = RTLIL::Const(false, 1);
295 cell->parameters["\\A_WIDTH"] = RTLIL::Const(inputs.size());
296 cell->parameters["\\B_WIDTH"] = RTLIL::Const(inputs.size());
297 cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1);
298 cell->set("\\A", inputs);
299 cell->set("\\B", compare);
300 cell->set("\\Y", sync_level->signal);
301
302 many_async_rules.clear();
303 }
304 else
305 {
306 rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
307 sync_level = NULL;
308 }
309 }
310
311 ce.assign_map.apply(insig);
312 ce.assign_map.apply(rstval);
313 ce.assign_map.apply(sig);
314
315 if (rstval == sig) {
316 rstval = RTLIL::SigSpec(RTLIL::State::Sz, sig.size());
317 sync_level = NULL;
318 }
319
320 if (sync_always) {
321 if (sync_edge || sync_level || many_async_rules.size() > 0)
322 log_error("Mixed always event with edge and/or level sensitive events!\n");
323 log(" created direct connection (no actual register cell created).\n");
324 mod->connect(RTLIL::SigSig(sig, insig));
325 continue;
326 }
327
328 if (!sync_edge)
329 log_error("Missing edge-sensitive event for this signal!\n");
330
331 if (many_async_rules.size() > 0)
332 {
333 log("WARNING: Complex async reset for dff `%s'.\n", log_signal(sig));
334 gen_dffsr_complex(mod, insig, sig, sync_edge->signal, sync_edge->type == RTLIL::SyncType::STp, many_async_rules, proc);
335 }
336 else if (!rstval.is_fully_const() && !ce.eval(rstval))
337 {
338 log("WARNING: Async reset value `%s' is not constant!\n", log_signal(rstval));
339 gen_dffsr(mod, insig, rstval, sig,
340 sync_edge->type == RTLIL::SyncType::STp,
341 sync_level && sync_level->type == RTLIL::SyncType::ST1,
342 sync_edge->signal, sync_level->signal, proc);
343 }
344 else
345 gen_dff(mod, insig, rstval.as_const(), sig,
346 sync_edge->type == RTLIL::SyncType::STp,
347 sync_level && sync_level->type == RTLIL::SyncType::ST1,
348 sync_edge->signal, sync_level ? &sync_level->signal : NULL, proc);
349
350 if (free_sync_level)
351 delete sync_level;
352 }
353 }
354
355 struct ProcDffPass : public Pass {
356 ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { }
357 virtual void help()
358 {
359 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
360 log("\n");
361 log(" proc_dff [selection]\n");
362 log("\n");
363 log("This pass identifies flip-flops in the processes and converts them to\n");
364 log("d-type flip-flop cells.\n");
365 log("\n");
366 }
367 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
368 {
369 log_header("Executing PROC_DFF pass (convert process syncs to FFs).\n");
370
371 extra_args(args, 1, design);
372
373 for (auto mod : design->modules())
374 if (design->selected(mod)) {
375 ConstEval ce(mod);
376 for (auto &proc_it : mod->processes)
377 if (design->selected(mod, proc_it.second))
378 proc_dff(mod, proc_it.second, ce);
379 }
380 }
381 } ProcDffPass;
382