Consistent use of 'override' for virtual methods in derived classes.
[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 if (cell->type.in("$dff", "$adff", "$dffsr"))
218 {
219 bool clkpol = cell->parameters["\\CLK_POLARITY"].as_bool();
220
221 SigSpec clk = cell->getPort("\\CLK");
222 Wire *past_clk = module->addWire(NEW_ID);
223 past_clk->attributes["\\init"] = clkpol ? State::S1 : State::S0;
224 module->addFf(NEW_ID, clk, past_clk);
225
226 SigSpec sig_d = cell->getPort("\\D");
227 SigSpec sig_q = cell->getPort("\\Q");
228
229 log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
230 log_id(module), log_id(cell), log_id(cell->type),
231 log_signal(clk), log_signal(sig_d), log_signal(sig_q));
232
233 SigSpec clock_edge_pattern;
234
235 if (clkpol) {
236 clock_edge_pattern.append_bit(State::S0);
237 clock_edge_pattern.append_bit(State::S1);
238 } else {
239 clock_edge_pattern.append_bit(State::S1);
240 clock_edge_pattern.append_bit(State::S0);
241 }
242
243 SigSpec clock_edge = module->Eqx(NEW_ID, {clk, SigSpec(past_clk)}, clock_edge_pattern);
244
245 Wire *past_d = module->addWire(NEW_ID, GetSize(sig_d));
246 Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q));
247 module->addFf(NEW_ID, sig_d, past_d);
248 module->addFf(NEW_ID, sig_q, past_q);
249
250 if (cell->type == "$adff")
251 {
252 SigSpec arst = cell->getPort("\\ARST");
253 SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
254 Const rstval = cell->parameters["\\ARST_VALUE"];
255
256 if (cell->parameters["\\ARST_POLARITY"].as_bool())
257 module->addMux(NEW_ID, qval, rstval, arst, sig_q);
258 else
259 module->addMux(NEW_ID, rstval, qval, arst, sig_q);
260 }
261 else
262 if (cell->type == "$dffsr")
263 {
264 SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge);
265 SigSpec setval = cell->getPort("\\SET");
266 SigSpec clrval = cell->getPort("\\CLR");
267
268 if (!cell->parameters["\\SET_POLARITY"].as_bool())
269 setval = module->Not(NEW_ID, setval);
270
271 if (cell->parameters["\\CLR_POLARITY"].as_bool())
272 clrval = module->Not(NEW_ID, clrval);
273
274 qval = module->Or(NEW_ID, qval, setval);
275 module->addAnd(NEW_ID, qval, clrval, sig_q);
276 }
277 else
278 {
279 module->addMux(NEW_ID, past_q, past_d, clock_edge, sig_q);
280 }
281
282 Const initval;
283 bool assign_initval = false;
284 for (int i = 0; i < GetSize(sig_d); i++) {
285 SigBit qbit = sigmap(sig_q[i]);
286 if (initbits.count(qbit)) {
287 initval.bits.push_back(initbits.at(qbit));
288 del_initbits.insert(qbit);
289 } else
290 initval.bits.push_back(State::Sx);
291 if (initval.bits.back() != State::Sx)
292 assign_initval = true;
293 }
294
295 if (assign_initval) {
296 past_d->attributes["\\init"] = initval;
297 past_q->attributes["\\init"] = initval;
298 }
299
300 module->remove(cell);
301 continue;
302 }
303 }
304
305 for (auto wire : module->wires())
306 if (wire->attributes.count("\\init") > 0)
307 {
308 bool delete_initattr = true;
309 Const initval = wire->attributes.at("\\init");
310 SigSpec initsig = sigmap(wire);
311
312 for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
313 if (del_initbits.count(initsig[i]) > 0)
314 initval[i] = State::Sx;
315 else if (initval[i] != State::Sx)
316 delete_initattr = false;
317
318 if (delete_initattr)
319 wire->attributes.erase("\\init");
320 else
321 wire->attributes.at("\\init") = initval;
322 }
323 }
324
325 }
326 } Clk2fflogicPass;
327
328 PRIVATE_NAMESPACE_END