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