Transform "$.*" to ID("$.*") in passes/techmap
[yosys.git] / passes / techmap / dfflibmap.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 #include "libparse.h"
23 #include <string.h>
24 #include <errno.h>
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct cell_mapping {
30 IdString cell_name;
31 std::map<IdString, char> ports;
32 };
33 static std::map<RTLIL::IdString, cell_mapping> cell_mappings;
34
35 static void logmap(IdString dff)
36 {
37 if (cell_mappings.count(dff) == 0) {
38 log(" unmapped dff cell: %s\n", dff.c_str());
39 } else {
40 log(" %s %s (", cell_mappings[dff].cell_name.c_str(), dff.substr(1).c_str());
41 bool first = true;
42 for (auto &port : cell_mappings[dff].ports) {
43 char arg[3] = { port.second, 0, 0 };
44 if ('a' <= arg[0] && arg[0] <= 'z')
45 arg[1] = arg[0] - ('a' - 'A'), arg[0] = '~';
46 else
47 arg[1] = arg[0], arg[0] = ' ';
48 log("%s.%s(%s)", first ? "" : ", ", port.first.c_str(), arg);
49 first = false;
50 }
51 log(");\n");
52 }
53 }
54
55 static void logmap_all()
56 {
57 logmap(ID($_DFF_N_));
58 logmap(ID($_DFF_P_));
59
60 logmap(ID($_DFF_NN0_));
61 logmap(ID($_DFF_NN1_));
62 logmap(ID($_DFF_NP0_));
63 logmap(ID($_DFF_NP1_));
64 logmap(ID($_DFF_PN0_));
65 logmap(ID($_DFF_PN1_));
66 logmap(ID($_DFF_PP0_));
67 logmap(ID($_DFF_PP1_));
68
69 logmap(ID($_DFFSR_NNN_));
70 logmap(ID($_DFFSR_NNP_));
71 logmap(ID($_DFFSR_NPN_));
72 logmap(ID($_DFFSR_NPP_));
73 logmap(ID($_DFFSR_PNN_));
74 logmap(ID($_DFFSR_PNP_));
75 logmap(ID($_DFFSR_PPN_));
76 logmap(ID($_DFFSR_PPP_));
77 }
78
79 static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, bool &pin_pol)
80 {
81 if (cell == NULL || attr == NULL || attr->value.empty())
82 return false;
83
84 std::string value = attr->value;
85
86 for (size_t pos = value.find_first_of("\" \t()"); pos != std::string::npos; pos = value.find_first_of("\" \t()"))
87 value.erase(pos, 1);
88
89 if (value[value.size()-1] == '\'') {
90 pin_name = value.substr(0, value.size()-1);
91 pin_pol = false;
92 } else if (value[0] == '!') {
93 pin_name = value.substr(1, value.size()-1);
94 pin_pol = false;
95 } else {
96 pin_name = value;
97 pin_pol = true;
98 }
99
100 for (auto child : cell->children)
101 if (child->id == "pin" && child->args.size() == 1 && child->args[0] == pin_name)
102 return true;
103
104 /* If we end up here, the pin specified in the attribute does not exist, which is an error,
105 or, the attribute contains an expression which we do not yet support.
106 For now, we'll simply produce a warning to let the user know something is up.
107 */
108 if (pin_name.find_first_of("^*|&") == std::string::npos) {
109 log_warning("Malformed liberty file - cannot find pin '%s' in cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
110 }
111 else {
112 log_warning("Found unsupported expression '%s' in pin attribute of cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str());
113 }
114
115 return false;
116 }
117
118 static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode)
119 {
120 LibertyAst *best_cell = NULL;
121 std::map<IdString, char> best_cell_ports;
122 int best_cell_pins = 0;
123 bool best_cell_noninv = false;
124 double best_cell_area = 0;
125
126 if (ast->id != "library")
127 log_error("Format error in liberty file.\n");
128
129 for (auto cell : ast->children)
130 {
131 if (cell->id != "cell" || cell->args.size() != 1)
132 continue;
133
134 LibertyAst *dn = cell->find("dont_use");
135 if (dn != NULL && dn->value == "true")
136 continue;
137
138 LibertyAst *ff = cell->find("ff");
139 if (ff == NULL)
140 continue;
141
142 std::string cell_clk_pin, cell_rst_pin, cell_next_pin;
143 bool cell_clk_pol, cell_rst_pol, cell_next_pol;
144
145 if (!parse_pin(cell, ff->find("clocked_on"), cell_clk_pin, cell_clk_pol) || cell_clk_pol != clkpol)
146 continue;
147 if (!parse_pin(cell, ff->find("next_state"), cell_next_pin, cell_next_pol))
148 continue;
149 if (has_reset && rstval == false) {
150 if (!parse_pin(cell, ff->find("clear"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol)
151 continue;
152 }
153 if (has_reset && rstval == true) {
154 if (!parse_pin(cell, ff->find("preset"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol)
155 continue;
156 }
157
158 std::map<IdString, char> this_cell_ports;
159 this_cell_ports[cell_clk_pin] = 'C';
160 if (has_reset)
161 this_cell_ports[cell_rst_pin] = 'R';
162 this_cell_ports[cell_next_pin] = 'D';
163
164 double area = 0;
165 LibertyAst *ar = cell->find("area");
166 if (ar != NULL && !ar->value.empty())
167 area = atof(ar->value.c_str());
168
169 int num_pins = 0;
170 bool found_output = false;
171 bool found_noninv_output = false;
172 for (auto pin : cell->children)
173 {
174 if (pin->id != "pin" || pin->args.size() != 1)
175 continue;
176
177 LibertyAst *dir = pin->find("direction");
178 if (dir == NULL || dir->value == "internal")
179 continue;
180 num_pins++;
181
182 if (dir->value == "input" && this_cell_ports.count(pin->args[0]) == 0)
183 goto continue_cell_loop;
184
185 LibertyAst *func = pin->find("function");
186 if (dir->value == "output" && func != NULL) {
187 std::string value = func->value;
188 for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
189 value.erase(pos, 1);
190 if (value == ff->args[0]) {
191 this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
192 if (cell_next_pol)
193 found_noninv_output = true;
194 found_output = true;
195 } else
196 if (value == ff->args[1]) {
197 this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
198 if (!cell_next_pol)
199 found_noninv_output = true;
200 found_output = true;
201 }
202 }
203
204 if (this_cell_ports.count(pin->args[0]) == 0)
205 this_cell_ports[pin->args[0]] = 0;
206 }
207
208 if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
209 continue;
210
211 if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
212 continue;
213
214 best_cell = cell;
215 best_cell_pins = num_pins;
216 best_cell_area = area;
217 best_cell_noninv = found_noninv_output;
218 best_cell_ports.swap(this_cell_ports);
219 continue_cell_loop:;
220 }
221
222 if (best_cell != NULL) {
223 log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
224 best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
225 if (prepare_mode) {
226 cell_mappings[cell_type].cell_name = cell_type;
227 cell_mappings[cell_type].ports["C"] = 'C';
228 if (has_reset)
229 cell_mappings[cell_type].ports["R"] = 'R';
230 cell_mappings[cell_type].ports["D"] = 'D';
231 cell_mappings[cell_type].ports["Q"] = 'Q';
232 } else {
233 cell_mappings[cell_type].cell_name = best_cell->args[0];
234 cell_mappings[cell_type].ports = best_cell_ports;
235 }
236 }
237 }
238
239 static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode)
240 {
241 LibertyAst *best_cell = NULL;
242 std::map<IdString, char> best_cell_ports;
243 int best_cell_pins = 0;
244 bool best_cell_noninv = false;
245 double best_cell_area = 0;
246
247 if (ast->id != "library")
248 log_error("Format error in liberty file.\n");
249
250 for (auto cell : ast->children)
251 {
252 if (cell->id != "cell" || cell->args.size() != 1)
253 continue;
254
255 LibertyAst *dn = cell->find("dont_use");
256 if (dn != NULL && dn->value == "true")
257 continue;
258
259 LibertyAst *ff = cell->find("ff");
260 if (ff == NULL)
261 continue;
262
263 std::string cell_clk_pin, cell_set_pin, cell_clr_pin, cell_next_pin;
264 bool cell_clk_pol, cell_set_pol, cell_clr_pol, cell_next_pol;
265
266 if (!parse_pin(cell, ff->find("clocked_on"), cell_clk_pin, cell_clk_pol) || cell_clk_pol != clkpol)
267 continue;
268 if (!parse_pin(cell, ff->find("next_state"), cell_next_pin, cell_next_pol))
269 continue;
270 if (!parse_pin(cell, ff->find("preset"), cell_set_pin, cell_set_pol) || cell_set_pol != setpol)
271 continue;
272 if (!parse_pin(cell, ff->find("clear"), cell_clr_pin, cell_clr_pol) || cell_clr_pol != clrpol)
273 continue;
274
275 std::map<IdString, char> this_cell_ports;
276 this_cell_ports[cell_clk_pin] = 'C';
277 this_cell_ports[cell_set_pin] = 'S';
278 this_cell_ports[cell_clr_pin] = 'R';
279 this_cell_ports[cell_next_pin] = 'D';
280
281 double area = 0;
282 LibertyAst *ar = cell->find("area");
283 if (ar != NULL && !ar->value.empty())
284 area = atof(ar->value.c_str());
285
286 int num_pins = 0;
287 bool found_output = false;
288 bool found_noninv_output = false;
289 for (auto pin : cell->children)
290 {
291 if (pin->id != "pin" || pin->args.size() != 1)
292 continue;
293
294 LibertyAst *dir = pin->find("direction");
295 if (dir == NULL || dir->value == "internal")
296 continue;
297 num_pins++;
298
299 if (dir->value == "input" && this_cell_ports.count(pin->args[0]) == 0)
300 goto continue_cell_loop;
301
302 LibertyAst *func = pin->find("function");
303 if (dir->value == "output" && func != NULL) {
304 std::string value = func->value;
305 for (size_t pos = value.find_first_of("\" \t"); pos != std::string::npos; pos = value.find_first_of("\" \t"))
306 value.erase(pos, 1);
307 if (value == ff->args[0]) {
308 this_cell_ports[pin->args[0]] = cell_next_pol ? 'Q' : 'q';
309 if (cell_next_pol)
310 found_noninv_output = true;
311 found_output = true;
312 } else
313 if (value == ff->args[1]) {
314 this_cell_ports[pin->args[0]] = cell_next_pol ? 'q' : 'Q';
315 if (!cell_next_pol)
316 found_noninv_output = true;
317 found_output = true;
318 }
319 }
320
321 if (this_cell_ports.count(pin->args[0]) == 0)
322 this_cell_ports[pin->args[0]] = 0;
323 }
324
325 if (!found_output || (best_cell != NULL && (num_pins > best_cell_pins || (best_cell_noninv && !found_noninv_output))))
326 continue;
327
328 if (best_cell != NULL && num_pins == best_cell_pins && area > best_cell_area)
329 continue;
330
331 best_cell = cell;
332 best_cell_pins = num_pins;
333 best_cell_area = area;
334 best_cell_noninv = found_noninv_output;
335 best_cell_ports.swap(this_cell_ports);
336 continue_cell_loop:;
337 }
338
339 if (best_cell != NULL) {
340 log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n",
341 best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str());
342 if (prepare_mode) {
343 cell_mappings[cell_type].cell_name = cell_type;
344 cell_mappings[cell_type].ports["C"] = 'C';
345 cell_mappings[cell_type].ports["S"] = 'S';
346 cell_mappings[cell_type].ports["R"] = 'R';
347 cell_mappings[cell_type].ports["D"] = 'D';
348 cell_mappings[cell_type].ports["Q"] = 'Q';
349 } else {
350 cell_mappings[cell_type].cell_name = best_cell->args[0];
351 cell_mappings[cell_type].ports = best_cell_ports;
352 }
353 }
354 }
355
356 static bool expand_cellmap_worker(std::string from, std::string to, std::string inv)
357 {
358 if (cell_mappings.count(to) > 0)
359 return false;
360
361 log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
362 cell_mappings[to].cell_name = cell_mappings[from].cell_name;
363 cell_mappings[to].ports = cell_mappings[from].ports;
364
365 for (auto &it : cell_mappings[to].ports) {
366 char cmp_ch = it.second;
367 if ('a' <= cmp_ch && cmp_ch <= 'z')
368 cmp_ch -= 'a' - 'A';
369 if (inv.find(cmp_ch) == std::string::npos)
370 continue;
371 if ('a' <= it.second && it.second <= 'z')
372 it.second -= 'a' - 'A';
373 else if ('A' <= it.second && it.second <= 'Z')
374 it.second += 'a' - 'A';
375 }
376 return true;
377 }
378
379 static bool expand_cellmap(std::string pattern, std::string inv)
380 {
381 std::vector<std::pair<std::string, std::string>> from_to_list;
382 bool return_status = false;
383
384 for (auto &it : cell_mappings) {
385 std::string from = it.first.str(), to = it.first.str();
386 if (from.size() != pattern.size())
387 continue;
388 for (size_t i = 0; i < from.size(); i++) {
389 if (pattern[i] == '*') {
390 to[i] = from[i] == 'P' ? 'N' :
391 from[i] == 'N' ? 'P' :
392 from[i] == '1' ? '0' :
393 from[i] == '0' ? '1' : '*';
394 } else
395 if (pattern[i] != '?' && pattern[i] != from[i])
396 goto pattern_failed;
397 }
398 from_to_list.push_back(std::pair<std::string, std::string>(from, to));
399 pattern_failed:;
400 }
401
402 for (auto &it : from_to_list)
403 return_status = return_status || expand_cellmap_worker(it.first, it.second, inv);
404 return return_status;
405 }
406
407 static void map_sr_to_arst(IdString from, IdString to)
408 {
409 if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
410 return;
411
412 char from_clk_pol YS_ATTRIBUTE(unused) = from[8];
413 char from_set_pol = from[9];
414 char from_clr_pol = from[10];
415 char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
416 char to_rst_pol YS_ATTRIBUTE(unused) = to[7];
417 char to_rst_val = to[8];
418
419 log_assert(from_clk_pol == to_clk_pol);
420 log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol);
421
422 log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
423 cell_mappings[to].cell_name = cell_mappings[from].cell_name;
424 cell_mappings[to].ports = cell_mappings[from].ports;
425
426 for (auto &it : cell_mappings[to].ports)
427 {
428 bool is_set_pin = it.second == 'S' || it.second == 's';
429 bool is_clr_pin = it.second == 'R' || it.second == 'r';
430
431 if (!is_set_pin && !is_clr_pin)
432 continue;
433
434 if ((to_rst_val == '0' && is_set_pin) || (to_rst_val == '1' && is_clr_pin))
435 {
436 // this is the unused set/clr pin -- deactivate it
437 if (is_set_pin)
438 it.second = (from_set_pol == 'P') == (it.second == 'S') ? '0' : '1';
439 else
440 it.second = (from_clr_pol == 'P') == (it.second == 'R') ? '0' : '1';
441 }
442 else
443 {
444 // this is the used set/clr pin -- rename it to 'reset'
445 if (it.second == 'S')
446 it.second = 'R';
447 if (it.second == 's')
448 it.second = 'r';
449 }
450 }
451 }
452
453 static void map_adff_to_dff(IdString from, IdString to)
454 {
455 if (!cell_mappings.count(from) || cell_mappings.count(to) > 0)
456 return;
457
458 char from_clk_pol YS_ATTRIBUTE(unused) = from[6];
459 char from_rst_pol = from[7];
460 char to_clk_pol YS_ATTRIBUTE(unused) = to[6];
461
462 log_assert(from_clk_pol == to_clk_pol);
463
464 log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str());
465 cell_mappings[to].cell_name = cell_mappings[from].cell_name;
466 cell_mappings[to].ports = cell_mappings[from].ports;
467
468 for (auto &it : cell_mappings[to].ports) {
469 if (it.second == 'S' || it.second == 'R')
470 it.second = from_rst_pol == 'P' ? '0' : '1';
471 if (it.second == 's' || it.second == 'r')
472 it.second = from_rst_pol == 'P' ? '1' : '0';
473 }
474 }
475
476 static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode)
477 {
478 log("Mapping DFF cells in module `%s':\n", module->name.c_str());
479
480 dict<SigBit, pool<Cell*>> notmap;
481 SigMap sigmap(module);
482
483 std::vector<RTLIL::Cell*> cell_list;
484 for (auto &it : module->cells_) {
485 if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0)
486 cell_list.push_back(it.second);
487 if (it.second->type == ID($_NOT_))
488 notmap[sigmap(it.second->getPort("\\A"))].insert(it.second);
489 }
490
491 std::map<std::string, int> stats;
492 for (auto cell : cell_list)
493 {
494 auto cell_type = cell->type;
495 auto cell_name = cell->name;
496 auto cell_connections = cell->connections();
497 std::string src = cell->get_src_attribute();
498
499 module->remove(cell);
500
501 cell_mapping &cm = cell_mappings[cell_type];
502 RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name.str());
503
504 new_cell->set_src_attribute(src);
505
506 bool has_q = false, has_qn = false;
507 for (auto &port : cm.ports) {
508 if (port.second == 'Q') has_q = true;
509 if (port.second == 'q') has_qn = true;
510 }
511
512 for (auto &port : cm.ports) {
513 RTLIL::SigSpec sig;
514 if ('A' <= port.second && port.second <= 'Z') {
515 sig = cell_connections[std::string("\\") + port.second];
516 } else
517 if (port.second == 'q') {
518 RTLIL::SigSpec old_sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
519 sig = module->addWire(NEW_ID, GetSize(old_sig));
520 if (has_q && has_qn) {
521 for (auto &it : notmap[sigmap(old_sig)]) {
522 module->connect(it->getPort("\\Y"), sig);
523 it->setPort("\\Y", module->addWire(NEW_ID, GetSize(old_sig)));
524 }
525 } else {
526 module->addNotGate(NEW_ID, sig, old_sig);
527 }
528 } else
529 if ('a' <= port.second && port.second <= 'z') {
530 sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))];
531 sig = module->NotGate(NEW_ID, sig);
532 } else
533 if (port.second == '0' || port.second == '1') {
534 sig = RTLIL::SigSpec(port.second == '0' ? 0 : 1, 1);
535 } else
536 if (port.second == 0) {
537 sig = module->addWire(NEW_ID);
538 } else
539 log_abort();
540 new_cell->setPort("\\" + port.first.str(), sig);
541 }
542
543 stats[stringf(" mapped %%d %s cells to %s cells.\n", cell_type.c_str(), new_cell->type.c_str())]++;
544 }
545
546 for (auto &stat: stats)
547 log(stat.first.c_str(), stat.second);
548 }
549
550 struct DfflibmapPass : public Pass {
551 DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { }
552 void help() YS_OVERRIDE
553 {
554 log("\n");
555 log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
556 log("\n");
557 log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
558 log("library specified in the given liberty file.\n");
559 log("\n");
560 log("This pass may add inverters as needed. Therefore it is recommended to\n");
561 log("first run this pass and then map the logic paths to the target technology.\n");
562 log("\n");
563 log("When called with -prepare, this command will convert the internal FF cells\n");
564 log("to the internal cell types that best match the cells found in the given\n");
565 log("liberty file.\n");
566 log("\n");
567 }
568 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
569 {
570 log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
571
572 std::string liberty_file;
573 bool prepare_mode = false;
574
575 size_t argidx;
576 for (argidx = 1; argidx < args.size(); argidx++)
577 {
578 std::string arg = args[argidx];
579 if (arg == "-liberty" && argidx+1 < args.size()) {
580 liberty_file = args[++argidx];
581 rewrite_filename(liberty_file);
582 continue;
583 }
584 if (arg == "-prepare") {
585 prepare_mode = true;
586 continue;
587 }
588 break;
589 }
590 extra_args(args, argidx, design);
591
592 if (liberty_file.empty())
593 log_cmd_error("Missing `-liberty liberty_file' option!\n");
594
595 std::ifstream f;
596 f.open(liberty_file.c_str());
597 if (f.fail())
598 log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
599 LibertyParser libparser(f);
600 f.close();
601
602 find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode);
603 find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode);
604
605 find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode);
606 find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode);
607 find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode);
608 find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode);
609 find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode);
610 find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode);
611 find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode);
612 find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode);
613
614 find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode);
615 find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode);
616 find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode);
617 find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode);
618 find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode);
619 find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode);
620 find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode);
621 find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode);
622
623 // try to implement as many cells as possible just by inverting
624 // the SET and RESET pins. If necessary, implement cell types
625 // by inverting both D and Q. Only invert clock pins if there
626 // is no other way of implementing the cell.
627 while (1)
628 {
629 if (expand_cellmap("$_DFF_?*?_", "R") ||
630 expand_cellmap("$_DFFSR_?*?_", "S") ||
631 expand_cellmap("$_DFFSR_??*_", "R"))
632 continue;
633
634 if (expand_cellmap("$_DFF_??*_", "DQ"))
635 continue;
636
637 if (expand_cellmap("$_DFF_*_", "C") ||
638 expand_cellmap("$_DFF_*??_", "C") ||
639 expand_cellmap("$_DFFSR_*??_", "C"))
640 continue;
641
642 break;
643 }
644
645 map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_));
646 map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_));
647 map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_));
648 map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_));
649 map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_));
650 map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_));
651 map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_));
652 map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_));
653
654 map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_));
655 map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_));
656 map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_));
657 map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_));
658 map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_));
659 map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_));
660 map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_));
661 map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_));
662
663 log(" final dff cell mappings:\n");
664 logmap_all();
665
666 for (auto &it : design->modules_)
667 if (design->selected(it.second) && !it.second->get_blackbox_attribute())
668 dfflibmap(design, it.second, prepare_mode);
669
670 cell_mappings.clear();
671 }
672 } DfflibmapPass;
673
674 PRIVATE_NAMESPACE_END