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