Merge pull request #1666 from Xiretza/improve-makefile
[yosys.git] / passes / sat / clk2fflogic.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/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 struct Clk2fflogicPass : public Pass {
27 Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
28 void help() YS_OVERRIDE
29 {
30 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
31 log("\n");
32 log(" clk2fflogic [options] [selection]\n");
33 log("\n");
34 log("This command replaces clocked flip-flops with generic $ff cells that use the\n");
35 log("implicit global clock. This is useful for formal verification of designs with\n");
36 log("multiple clocks.\n");
37 log("\n");
38 }
39 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
40 {
41 // bool flag_noinit = false;
42
43 log_header(design, "Executing CLK2FFLOGIC pass (convert clocked FFs to generic $ff cells).\n");
44
45 size_t argidx;
46 for (argidx = 1; argidx < args.size(); argidx++)
47 {
48 // if (args[argidx] == "-noinit") {
49 // flag_noinit = true;
50 // continue;
51 // }
52 break;
53 }
54 extra_args(args, argidx, design);
55
56 for (auto module : design->selected_modules())
57 {
58 SigMap sigmap(module);
59 dict<SigBit, State> initbits;
60 pool<SigBit> del_initbits;
61
62 for (auto wire : module->wires())
63 if (wire->attributes.count("\\init") > 0)
64 {
65 Const initval = wire->attributes.at("\\init");
66 SigSpec initsig = sigmap(wire);
67
68 for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
69 if (initval[i] == State::S0 || initval[i] == State::S1)
70 initbits[initsig[i]] = initval[i];
71 }
72
73 for (auto cell : vector<Cell*>(module->selected_cells()))
74 {
75 if (cell->type.in("$mem"))
76 {
77 int abits = cell->getParam("\\ABITS").as_int();
78 int width = cell->getParam("\\WIDTH").as_int();
79 int rd_ports = cell->getParam("\\RD_PORTS").as_int();
80 int wr_ports = cell->getParam("\\WR_PORTS").as_int();
81
82 for (int i = 0; i < rd_ports; i++) {
83 if (cell->getParam("\\RD_CLK_ENABLE").extract(i).as_bool())
84 log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
85 "Call \"memory\" with -nordff to avoid this error.\n", i, log_id(cell), log_id(module));
86 }
87
88 Const wr_clk_en_param = cell->getParam("\\WR_CLK_ENABLE");
89 Const wr_clk_pol_param = cell->getParam("\\WR_CLK_POLARITY");
90
91 SigSpec wr_clk_port = cell->getPort("\\WR_CLK");
92 SigSpec wr_en_port = cell->getPort("\\WR_EN");
93 SigSpec wr_addr_port = cell->getPort("\\WR_ADDR");
94 SigSpec wr_data_port = cell->getPort("\\WR_DATA");
95
96 for (int wport = 0; wport < wr_ports; wport++)
97 {
98 bool clken = wr_clk_en_param[wport] == State::S1;
99 bool clkpol = wr_clk_pol_param[wport] == State::S1;
100
101 if (!clken)
102 continue;
103
104 SigBit clk = wr_clk_port[wport];
105 SigSpec en = wr_en_port.extract(wport*width, width);
106 SigSpec addr = wr_addr_port.extract(wport*abits, abits);
107 SigSpec data = wr_data_port.extract(wport*width, width);
108
109 log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
110 wport, log_id(module), log_id(cell), log_signal(clk),
111 log_signal(addr), log_signal(data));
112
113 Wire *past_clk = module->addWire(NEW_ID);
114 past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
115 module->addFf(NEW_ID, clk, past_clk);
116
117 SigSpec clock_edge_pattern;
118
119 if (clkpol) {
120 clock_edge_pattern.append_bit(State::S0);
121 clock_edge_pattern.append_bit(State::S1);
122 } else {
123 clock_edge_pattern.append_bit(State::S1);
124 clock_edge_pattern.append_bit(State::S0);
125 }
126
127 SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
128
129 SigSpec en_q = module->addWire(NEW_ID, GetSize(en));
130 module->addFf(NEW_ID, en, en_q);
131
132 SigSpec addr_q = module->addWire(NEW_ID, GetSize(addr));
133 module->addFf(NEW_ID, addr, addr_q);
134
135 SigSpec data_q = module->addWire(NEW_ID, GetSize(data));
136 module->addFf(NEW_ID, data, data_q);
137
138 wr_clk_port[wport] = State::S0;
139 wr_en_port.replace(wport*width, module->Mux(NEW_ID, Const(0, GetSize(en_q)), en_q, clock_edge));
140 wr_addr_port.replace(wport*abits, addr_q);
141 wr_data_port.replace(wport*width, data_q);
142
143 wr_clk_en_param[wport] = State::S0;
144 wr_clk_pol_param[wport] = State::S0;
145 }
146
147 cell->setParam("\\WR_CLK_ENABLE", wr_clk_en_param);
148 cell->setParam("\\WR_CLK_POLARITY", wr_clk_pol_param);
149
150 cell->setPort("\\WR_CLK", wr_clk_port);
151 cell->setPort("\\WR_EN", wr_en_port);
152 cell->setPort("\\WR_ADDR", wr_addr_port);
153 cell->setPort("\\WR_DATA", wr_data_port);
154 }
155
156 if (cell->type.in("$dlatch", "$dlatchsr"))
157 {
158 bool enpol = cell->parameters["\\EN_POLARITY"].as_bool();
159
160 SigSpec sig_en = cell->getPort("\\EN");
161 SigSpec sig_d = cell->getPort("\\D");
162 SigSpec sig_q = cell->getPort("\\Q");
163
164 log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
165 log_id(module), log_id(cell), log_id(cell->type),
166 log_signal(sig_en), log_signal(sig_d), log_signal(sig_q));
167
168 Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
169 module->addFf(NEW_ID, sig_q, past_q);
170
171 if (cell->type == "$dlatch")
172 {
173 if (enpol)
174 module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q);
175 else
176 module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q);
177 }
178 else
179 {
180 SigSpec t;
181 if (enpol)
182 t = module->Mux(NEW_ID, past_q, sig_d, sig_en);
183 else
184 t = module->Mux(NEW_ID, sig_d, past_q, sig_en);
185
186 SigSpec s = cell->getPort("\\SET");
187 if (!cell->parameters["\\SET_POLARITY"].as_bool())
188 s = module->Not(NEW_ID, s);
189 t = module->Or(NEW_ID, t, s);
190
191 SigSpec c = cell->getPort("\\CLR");
192 if (cell->parameters["\\CLR_POLARITY"].as_bool())
193 c = module->Not(NEW_ID, c);
194 module->addAnd(NEW_ID, t, c, sig_q);
195 }
196
197 Const initval;
198 bool assign_initval = false;
199 for (int i = 0; i < GetSize(sig_d); i++) {
200 SigBit qbit = sigmap(sig_q[i]);
201 if (initbits.count(qbit)) {
202 initval.bits.push_back(initbits.at(qbit));
203 del_initbits.insert(qbit);
204 } else
205 initval.bits.push_back(State::Sx);
206 if (initval.bits.back() != State::Sx)
207 assign_initval = true;
208 }
209
210 if (assign_initval)
211 past_q->attributes["\\init"] = initval;
212
213 module->remove(cell);
214 continue;
215 }
216
217 bool word_dff = cell->type.in("$dff", "$adff", "$dffsr");
218 if (word_dff || cell->type.in(ID($_DFF_N_), ID($_DFF_P_),
219 ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
220 ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_),
221 ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
222 ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
223 {
224 bool clkpol;
225 SigSpec clk;
226 if (word_dff) {
227 clkpol = cell->parameters["\\CLK_POLARITY"].as_bool();
228 clk = cell->getPort("\\CLK");
229 }
230 else {
231 if (cell->type.in(ID($_DFF_P_), ID($_DFF_N_),
232 ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
233 ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
234 clkpol = cell->type[6] == 'P';
235 else if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
236 ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
237 clkpol = cell->type[8] == 'P';
238 else log_abort();
239 clk = cell->getPort("\\C");
240 }
241
242 Wire *past_clk = module->addWire(NEW_ID);
243 past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
244
245 if (word_dff)
246 module->addFf(NEW_ID, clk, past_clk);
247 else
248 module->addFfGate(NEW_ID, clk, past_clk);
249
250 SigSpec sig_d = cell->getPort("\\D");
251 SigSpec sig_q = cell->getPort("\\Q");
252
253 log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
254 log_id(module), log_id(cell), log_id(cell->type),
255 log_signal(clk), log_signal(sig_d), log_signal(sig_q));
256
257 SigSpec clock_edge_pattern;
258
259 if (clkpol) {
260 clock_edge_pattern.append_bit(State::S0);
261 clock_edge_pattern.append_bit(State::S1);
262 } else {
263 clock_edge_pattern.append_bit(State::S1);
264 clock_edge_pattern.append_bit(State::S0);
265 }
266
267 SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
268
269 Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d));
270 Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
271 if (word_dff) {
272 module->addFf(NEW_ID, sig_d, past_d);
273 module->addFf(NEW_ID, sig_q, past_q);
274 }
275 else {
276 module->addFfGate(NEW_ID, sig_d, past_d);
277 module->addFfGate(NEW_ID, sig_q, past_q);
278 }
279
280 if (cell->type == "$adff")
281 {
282 SigSpec arst = cell->getPort("\\ARST");
283 SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
284 Const rstval = cell->parameters["\\ARST_VALUE"];
285
286 Wire *past_arst = module->addWire(NEW_ID);
287 module->addFf(NEW_ID, arst, past_arst);
288 if (cell->parameters["\\ARST_POLARITY"].as_bool())
289 arst = module->LogicOr(NEW_ID, arst, past_arst);
290 else
291 arst = module->LogicAnd(NEW_ID, arst, past_arst);
292
293 if (cell->parameters["\\ARST_POLARITY"].as_bool())
294 module->addMux(NEW_ID, qval, rstval, arst, sig_q);
295 else
296 module->addMux(NEW_ID, rstval, qval, arst, sig_q);
297 }
298 else
299 if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
300 ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_)))
301 {
302 SigSpec arst = cell->getPort("\\R");
303 SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
304 SigBit rstval = (cell->type[8] == '1');
305
306 Wire *past_arst = module->addWire(NEW_ID);
307 module->addFfGate(NEW_ID, arst, past_arst);
308 if (cell->type[7] == 'P')
309 arst = module->OrGate(NEW_ID, arst, past_arst);
310 else
311 arst = module->AndGate(NEW_ID, arst, past_arst);
312
313 if (cell->type[7] == 'P')
314 module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q);
315 else
316 module->addMuxGate(NEW_ID, rstval, qval, arst, sig_q);
317 }
318 else
319 if (cell->type == "$dffsr")
320 {
321 SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
322 SigSpec setval = cell->getPort("\\SET");
323 SigSpec clrval = cell->getPort("\\CLR");
324
325 if (!cell->parameters["\\SET_POLARITY"].as_bool())
326 setval = module->Not(NEW_ID, setval);
327
328 if (cell->parameters["\\CLR_POLARITY"].as_bool())
329 clrval = module->Not(NEW_ID, clrval);
330
331 qval = module->Or(NEW_ID, qval, setval);
332 module->addAnd(NEW_ID, qval, clrval, sig_q);
333 }
334 else
335 if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
336 ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_)))
337 {
338 SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge);
339 SigSpec setval = cell->getPort("\\S");
340 SigSpec clrval = cell->getPort("\\R");
341
342 if (cell->type[9] != 'P')
343 setval = module->Not(NEW_ID, setval);
344
345 if (cell->type[10] == 'P')
346 clrval = module->Not(NEW_ID, clrval);
347
348 qval = module->OrGate(NEW_ID, qval, setval);
349 module->addAndGate(NEW_ID, qval, clrval, sig_q);
350 }
351 else if (cell->type == "$dff")
352 {
353 module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q);
354 }
355 else
356 {
357 module->addMuxGate(NEW_ID, past_q, past_d, clock_edge, sig_q);
358 }
359
360 Const initval;
361 bool assign_initval = false;
362 for (int i = 0; i < GetSize(sig_d); i++) {
363 SigBit qbit = sigmap(sig_q[i]);
364 if (initbits.count(qbit)) {
365 initval.bits.push_back(initbits.at(qbit));
366 del_initbits.insert(qbit);
367 } else
368 initval.bits.push_back(State::Sx);
369 if (initval.bits.back() != State::Sx)
370 assign_initval = true;
371 }
372
373 if (assign_initval) {
374 past_d->attributes["\\init"] = initval;
375 past_q->attributes["\\init"] = initval;
376 }
377
378 module->remove(cell);
379 continue;
380 }
381 }
382
383 for (auto wire : module->wires())
384 if (wire->attributes.count("\\init") > 0)
385 {
386 bool delete_initattr = true;
387 Const initval = wire->attributes.at("\\init");
388 SigSpec initsig = sigmap(wire);
389
390 for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
391 if (del_initbits.count(initsig[i]) > 0)
392 initval[i] = State::Sx;
393 else if (initval[i] != State::Sx)
394 delete_initattr = false;
395
396 if (delete_initattr)
397 wire->attributes.erase("\\init");
398 else
399 wire->attributes.at("\\init") = initval;
400 }
401 }
402
403 }
404 } Clk2fflogicPass;
405
406 PRIVATE_NAMESPACE_END