abe73c258658ae501d118676dafc81908962283b
2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
27 PRIVATE_NAMESPACE_BEGIN
31 std::map
<IdString
, char> ports
;
33 static std::map
<RTLIL::IdString
, cell_mapping
> cell_mappings
;
35 static void logmap(IdString dff
)
37 if (cell_mappings
.count(dff
) == 0) {
38 log(" unmapped dff cell: %s\n", dff
.c_str());
40 log(" %s %s (", cell_mappings
[dff
].cell_name
.c_str(), dff
.substr(1).c_str());
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] = '~';
47 arg
[1] = arg
[0], arg
[0] = ' ';
48 log("%s.%s(%s)", first
? "" : ", ", port
.first
.c_str(), arg
);
55 static void logmap_all()
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_
));
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_
));
79 static bool parse_pin(LibertyAst
*cell
, LibertyAst
*attr
, std::string
&pin_name
, bool &pin_pol
)
81 if (cell
== NULL
|| attr
== NULL
|| attr
->value
.empty())
84 std::string value
= attr
->value
;
86 for (size_t pos
= value
.find_first_of("\" \t()"); pos
!= std::string::npos
; pos
= value
.find_first_of("\" \t()"))
89 if (value
[value
.size()-1] == '\'') {
90 pin_name
= value
.substr(0, value
.size()-1);
92 } else if (value
[0] == '!') {
93 pin_name
= value
.substr(1, value
.size()-1);
100 for (auto child
: cell
->children
)
101 if (child
->id
== "pin" && child
->args
.size() == 1 && child
->args
[0] == pin_name
)
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.
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());
112 log_warning("Found unsupported expression '%s' in pin attribute of cell '%s' - skipping.\n", pin_name
.c_str(), cell
->args
[0].c_str());
118 static void find_cell(LibertyAst
*ast
, IdString cell_type
, bool clkpol
, bool has_reset
, bool rstpol
, bool rstval
, bool prepare_mode
)
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;
126 if (ast
->id
!= "library")
127 log_error("Format error in liberty file.\n");
129 for (auto cell
: ast
->children
)
131 if (cell
->id
!= "cell" || cell
->args
.size() != 1)
134 LibertyAst
*dn
= cell
->find("dont_use");
135 if (dn
!= NULL
&& dn
->value
== "true")
138 LibertyAst
*ff
= cell
->find("ff");
142 std::string cell_clk_pin
, cell_rst_pin
, cell_next_pin
;
143 bool cell_clk_pol
, cell_rst_pol
, cell_next_pol
;
145 if (!parse_pin(cell
, ff
->find("clocked_on"), cell_clk_pin
, cell_clk_pol
) || cell_clk_pol
!= clkpol
)
147 if (!parse_pin(cell
, ff
->find("next_state"), cell_next_pin
, cell_next_pol
))
149 if (has_reset
&& rstval
== false) {
150 if (!parse_pin(cell
, ff
->find("clear"), cell_rst_pin
, cell_rst_pol
) || cell_rst_pol
!= rstpol
)
153 if (has_reset
&& rstval
== true) {
154 if (!parse_pin(cell
, ff
->find("preset"), cell_rst_pin
, cell_rst_pol
) || cell_rst_pol
!= rstpol
)
158 std::map
<IdString
, char> this_cell_ports
;
159 this_cell_ports
[cell_clk_pin
] = 'C';
161 this_cell_ports
[cell_rst_pin
] = 'R';
162 this_cell_ports
[cell_next_pin
] = 'D';
165 LibertyAst
*ar
= cell
->find("area");
166 if (ar
!= NULL
&& !ar
->value
.empty())
167 area
= atof(ar
->value
.c_str());
170 bool found_output
= false;
171 bool found_noninv_output
= false;
172 for (auto pin
: cell
->children
)
174 if (pin
->id
!= "pin" || pin
->args
.size() != 1)
177 LibertyAst
*dir
= pin
->find("direction");
178 if (dir
== NULL
|| dir
->value
== "internal")
182 if (dir
->value
== "input" && this_cell_ports
.count(pin
->args
[0]) == 0)
183 goto continue_cell_loop
;
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"))
190 if (value
== ff
->args
[0]) {
191 this_cell_ports
[pin
->args
[0]] = cell_next_pol
? 'Q' : 'q';
193 found_noninv_output
= true;
196 if (value
== ff
->args
[1]) {
197 this_cell_ports
[pin
->args
[0]] = cell_next_pol
? 'q' : 'Q';
199 found_noninv_output
= true;
204 if (this_cell_ports
.count(pin
->args
[0]) == 0)
205 this_cell_ports
[pin
->args
[0]] = 0;
208 if (!found_output
|| (best_cell
!= NULL
&& (num_pins
> best_cell_pins
|| (best_cell_noninv
&& !found_noninv_output
))))
211 if (best_cell
!= NULL
&& num_pins
== best_cell_pins
&& area
> best_cell_area
)
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
);
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());
226 cell_mappings
[cell_type
].cell_name
= cell_type
;
227 cell_mappings
[cell_type
].ports
["C"] = 'C';
229 cell_mappings
[cell_type
].ports
["R"] = 'R';
230 cell_mappings
[cell_type
].ports
["D"] = 'D';
231 cell_mappings
[cell_type
].ports
["Q"] = 'Q';
233 cell_mappings
[cell_type
].cell_name
= best_cell
->args
[0];
234 cell_mappings
[cell_type
].ports
= best_cell_ports
;
239 static void find_cell_sr(LibertyAst
*ast
, IdString cell_type
, bool clkpol
, bool setpol
, bool clrpol
, bool prepare_mode
)
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;
247 if (ast
->id
!= "library")
248 log_error("Format error in liberty file.\n");
250 for (auto cell
: ast
->children
)
252 if (cell
->id
!= "cell" || cell
->args
.size() != 1)
255 LibertyAst
*dn
= cell
->find("dont_use");
256 if (dn
!= NULL
&& dn
->value
== "true")
259 LibertyAst
*ff
= cell
->find("ff");
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
;
266 if (!parse_pin(cell
, ff
->find("clocked_on"), cell_clk_pin
, cell_clk_pol
) || cell_clk_pol
!= clkpol
)
268 if (!parse_pin(cell
, ff
->find("next_state"), cell_next_pin
, cell_next_pol
))
270 if (!parse_pin(cell
, ff
->find("preset"), cell_set_pin
, cell_set_pol
) || cell_set_pol
!= setpol
)
272 if (!parse_pin(cell
, ff
->find("clear"), cell_clr_pin
, cell_clr_pol
) || cell_clr_pol
!= clrpol
)
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';
282 LibertyAst
*ar
= cell
->find("area");
283 if (ar
!= NULL
&& !ar
->value
.empty())
284 area
= atof(ar
->value
.c_str());
287 bool found_output
= false;
288 bool found_noninv_output
= false;
289 for (auto pin
: cell
->children
)
291 if (pin
->id
!= "pin" || pin
->args
.size() != 1)
294 LibertyAst
*dir
= pin
->find("direction");
295 if (dir
== NULL
|| dir
->value
== "internal")
299 if (dir
->value
== "input" && this_cell_ports
.count(pin
->args
[0]) == 0)
300 goto continue_cell_loop
;
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"))
307 if (value
== ff
->args
[0]) {
308 this_cell_ports
[pin
->args
[0]] = cell_next_pol
? 'Q' : 'q';
310 found_noninv_output
= true;
313 if (value
== ff
->args
[1]) {
314 this_cell_ports
[pin
->args
[0]] = cell_next_pol
? 'q' : 'Q';
316 found_noninv_output
= true;
321 if (this_cell_ports
.count(pin
->args
[0]) == 0)
322 this_cell_ports
[pin
->args
[0]] = 0;
325 if (!found_output
|| (best_cell
!= NULL
&& (num_pins
> best_cell_pins
|| (best_cell_noninv
&& !found_noninv_output
))))
328 if (best_cell
!= NULL
&& num_pins
== best_cell_pins
&& area
> best_cell_area
)
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
);
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());
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';
350 cell_mappings
[cell_type
].cell_name
= best_cell
->args
[0];
351 cell_mappings
[cell_type
].ports
= best_cell_ports
;
356 static bool expand_cellmap_worker(std::string from
, std::string to
, std::string inv
)
358 if (cell_mappings
.count(to
) > 0)
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
;
365 for (auto &it
: cell_mappings
[to
].ports
) {
366 char cmp_ch
= it
.second
;
367 if ('a' <= cmp_ch
&& cmp_ch
<= 'z')
369 if (inv
.find(cmp_ch
) == std::string::npos
)
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';
379 static bool expand_cellmap(std::string pattern
, std::string inv
)
381 std::vector
<std::pair
<std::string
, std::string
>> from_to_list
;
382 bool return_status
= false;
384 for (auto &it
: cell_mappings
) {
385 std::string from
= it
.first
.str(), to
= it
.first
.str();
386 if (from
.size() != pattern
.size())
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' : '*';
395 if (pattern
[i
] != '?' && pattern
[i
] != from
[i
])
398 from_to_list
.push_back(std::pair
<std::string
, std::string
>(from
, to
));
402 for (auto &it
: from_to_list
)
403 return_status
= return_status
|| expand_cellmap_worker(it
.first
, it
.second
, inv
);
404 return return_status
;
407 static void map_sr_to_arst(IdString from
, IdString to
)
409 if (!cell_mappings
.count(from
) || cell_mappings
.count(to
) > 0)
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];
419 log_assert(from_clk_pol
== to_clk_pol
);
420 log_assert(to_rst_pol
== from_set_pol
&& to_rst_pol
== from_clr_pol
);
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
;
426 for (auto &it
: cell_mappings
[to
].ports
)
428 bool is_set_pin
= it
.second
== 'S' || it
.second
== 's';
429 bool is_clr_pin
= it
.second
== 'R' || it
.second
== 'r';
431 if (!is_set_pin
&& !is_clr_pin
)
434 if ((to_rst_val
== '0' && is_set_pin
) || (to_rst_val
== '1' && is_clr_pin
))
436 // this is the unused set/clr pin -- deactivate it
438 it
.second
= (from_set_pol
== 'P') == (it
.second
== 'S') ? '0' : '1';
440 it
.second
= (from_clr_pol
== 'P') == (it
.second
== 'R') ? '0' : '1';
444 // this is the used set/clr pin -- rename it to 'reset'
445 if (it
.second
== 'S')
447 if (it
.second
== 's')
453 static void map_adff_to_dff(IdString from
, IdString to
)
455 if (!cell_mappings
.count(from
) || cell_mappings
.count(to
) > 0)
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];
462 log_assert(from_clk_pol
== to_clk_pol
);
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
;
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';
476 static void dfflibmap(RTLIL::Design
*design
, RTLIL::Module
*module
, bool prepare_mode
)
478 log("Mapping DFF cells in module `%s':\n", module
->name
.c_str());
480 dict
<SigBit
, pool
<Cell
*>> notmap
;
481 SigMap
sigmap(module
);
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
);
491 std::map
<std::string
, int> stats
;
492 for (auto cell
: cell_list
)
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();
499 module
->remove(cell
);
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());
504 new_cell
->set_src_attribute(src
);
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;
512 for (auto &port
: cm
.ports
) {
514 if ('A' <= port
.second
&& port
.second
<= 'Z') {
515 sig
= cell_connections
[std::string("\\") + port
.second
];
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
)));
526 module
->addNotGate(NEW_ID
, sig
, old_sig
);
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
);
533 if (port
.second
== '0' || port
.second
== '1') {
534 sig
= RTLIL::SigSpec(port
.second
== '0' ? 0 : 1, 1);
536 if (port
.second
== 0) {
537 sig
= module
->addWire(NEW_ID
);
540 new_cell
->setPort("\\" + port
.first
.str(), sig
);
543 stats
[stringf(" mapped %%d %s cells to %s cells.\n", cell_type
.c_str(), new_cell
->type
.c_str())]++;
546 for (auto &stat
: stats
)
547 log(stat
.first
.c_str(), stat
.second
);
550 struct DfflibmapPass
: public Pass
{
551 DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { }
552 void help() YS_OVERRIDE
555 log(" dfflibmap [-prepare] -liberty <file> [selection]\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");
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");
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");
568 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
570 log_header(design
, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
572 std::string liberty_file
;
573 bool prepare_mode
= false;
576 for (argidx
= 1; argidx
< args
.size(); argidx
++)
578 std::string arg
= args
[argidx
];
579 if (arg
== "-liberty" && argidx
+1 < args
.size()) {
580 liberty_file
= args
[++argidx
];
581 rewrite_filename(liberty_file
);
584 if (arg
== "-prepare") {
590 extra_args(args
, argidx
, design
);
592 if (liberty_file
.empty())
593 log_cmd_error("Missing `-liberty liberty_file' option!\n");
596 f
.open(liberty_file
.c_str());
598 log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file
.c_str(), strerror(errno
));
599 LibertyParser
libparser(f
);
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
);
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
);
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
);
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.
629 if (expand_cellmap("$_DFF_?*?_", "R") ||
630 expand_cellmap("$_DFFSR_?*?_", "S") ||
631 expand_cellmap("$_DFFSR_??*_", "R"))
634 if (expand_cellmap("$_DFF_??*_", "DQ"))
637 if (expand_cellmap("$_DFF_*_", "C") ||
638 expand_cellmap("$_DFF_*??_", "C") ||
639 expand_cellmap("$_DFFSR_*??_", "C"))
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_
));
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_
));
663 log(" final dff cell mappings:\n");
666 for (auto &it
: design
->modules_
)
667 if (design
->selected(it
.second
) && !it
.second
->get_blackbox_attribute())
668 dfflibmap(design
, it
.second
, prepare_mode
);
670 cell_mappings
.clear();
674 PRIVATE_NAMESPACE_END