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