cc6f97c7e991cbc9e8cf7a4004e6e2a42a953c01
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/register.h"
21 #include "kernel/log.h"
27 PRIVATE_NAMESPACE_BEGIN
30 std::string cell_name
;
31 std::map
<std::string
, char> ports
;
33 static std::map
<RTLIL::IdString
, cell_mapping
> cell_mappings
;
35 static void logmap(std::string 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()
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_");
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
)
106 static void find_cell(LibertyAst
*ast
, std::string cell_type
, bool clkpol
, bool has_reset
, bool rstpol
, bool rstval
, bool prepare_mode
)
108 LibertyAst
*best_cell
= NULL
;
109 std::map
<std::string
, char> best_cell_ports
;
110 int best_cell_pins
= 0;
111 double best_cell_area
= 0;
113 if (ast
->id
!= "library")
114 log_error("Format error in liberty file.\n");
116 for (auto cell
: ast
->children
)
118 if (cell
->id
!= "cell" || cell
->args
.size() != 1)
121 LibertyAst
*ff
= cell
->find("ff");
125 std::string cell_clk_pin
, cell_rst_pin
, cell_next_pin
;
126 bool cell_clk_pol
, cell_rst_pol
, cell_next_pol
;
128 if (!parse_pin(cell
, ff
->find("clocked_on"), cell_clk_pin
, cell_clk_pol
) || cell_clk_pol
!= clkpol
)
130 if (!parse_pin(cell
, ff
->find("next_state"), cell_next_pin
, cell_next_pol
))
132 if (has_reset
&& rstval
== false) {
133 if (!parse_pin(cell
, ff
->find("clear"), cell_rst_pin
, cell_rst_pol
) || cell_rst_pol
!= rstpol
)
136 if (has_reset
&& rstval
== true) {
137 if (!parse_pin(cell
, ff
->find("preset"), cell_rst_pin
, cell_rst_pol
) || cell_rst_pol
!= rstpol
)
141 std::map
<std::string
, char> this_cell_ports
;
142 this_cell_ports
[cell_clk_pin
] = 'C';
144 this_cell_ports
[cell_rst_pin
] = 'R';
145 this_cell_ports
[cell_next_pin
] = 'D';
148 LibertyAst
*ar
= cell
->find("area");
149 if (ar
!= NULL
&& !ar
->value
.empty())
150 area
= atof(ar
->value
.c_str());
153 bool found_output
= false;
154 for (auto pin
: cell
->children
)
156 if (pin
->id
!= "pin" || pin
->args
.size() != 1)
159 LibertyAst
*dir
= pin
->find("direction");
160 if (dir
== NULL
|| dir
->value
== "internal")
164 if (dir
->value
== "input" && this_cell_ports
.count(pin
->args
[0]) == 0)
165 goto continue_cell_loop
;
167 LibertyAst
*func
= pin
->find("function");
168 if (dir
->value
== "output" && func
!= NULL
) {
169 std::string value
= func
->value
;
170 for (size_t pos
= value
.find_first_of("\" \t"); pos
!= std::string::npos
; pos
= value
.find_first_of("\" \t"))
172 if ((cell_next_pol
== true && value
== ff
->args
[0]) || (cell_next_pol
== false && value
== ff
->args
[1])) {
173 this_cell_ports
[pin
->args
[0]] = 'Q';
178 if (this_cell_ports
.count(pin
->args
[0]) == 0)
179 this_cell_ports
[pin
->args
[0]] = 0;
182 if (!found_output
|| (best_cell
!= NULL
&& num_pins
> best_cell_pins
))
185 if (best_cell
!= NULL
&& num_pins
== best_cell_pins
&& area
> best_cell_area
)
189 best_cell_pins
= num_pins
;
190 best_cell_area
= area
;
191 best_cell_ports
.swap(this_cell_ports
);
195 if (best_cell
!= NULL
) {
196 log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell
->args
[0].c_str(), best_cell_pins
, best_cell_area
, cell_type
.c_str());
198 cell_mappings
[cell_type
].cell_name
= cell_type
;
199 cell_mappings
[cell_type
].ports
["C"] = 'C';
201 cell_mappings
[cell_type
].ports
["R"] = 'R';
202 cell_mappings
[cell_type
].ports
["D"] = 'D';
203 cell_mappings
[cell_type
].ports
["Q"] = 'Q';
205 cell_mappings
[cell_type
].cell_name
= best_cell
->args
[0];
206 cell_mappings
[cell_type
].ports
= best_cell_ports
;
211 static void find_cell_sr(LibertyAst
*ast
, std::string cell_type
, bool clkpol
, bool setpol
, bool clrpol
, bool prepare_mode
)
213 LibertyAst
*best_cell
= NULL
;
214 std::map
<std::string
, char> best_cell_ports
;
215 int best_cell_pins
= 0;
216 double best_cell_area
= 0;
218 if (ast
->id
!= "library")
219 log_error("Format error in liberty file.\n");
221 for (auto cell
: ast
->children
)
223 if (cell
->id
!= "cell" || cell
->args
.size() != 1)
226 LibertyAst
*ff
= cell
->find("ff");
230 std::string cell_clk_pin
, cell_set_pin
, cell_clr_pin
, cell_next_pin
;
231 bool cell_clk_pol
, cell_set_pol
, cell_clr_pol
, cell_next_pol
;
233 if (!parse_pin(cell
, ff
->find("clocked_on"), cell_clk_pin
, cell_clk_pol
) || cell_clk_pol
!= clkpol
)
235 if (!parse_pin(cell
, ff
->find("next_state"), cell_next_pin
, cell_next_pol
))
237 if (!parse_pin(cell
, ff
->find("preset"), cell_set_pin
, cell_set_pol
) || cell_set_pol
!= setpol
)
239 if (!parse_pin(cell
, ff
->find("clear"), cell_clr_pin
, cell_clr_pol
) || cell_clr_pol
!= clrpol
)
242 std::map
<std::string
, char> this_cell_ports
;
243 this_cell_ports
[cell_clk_pin
] = 'C';
244 this_cell_ports
[cell_set_pin
] = 'S';
245 this_cell_ports
[cell_clr_pin
] = 'R';
246 this_cell_ports
[cell_next_pin
] = 'D';
249 LibertyAst
*ar
= cell
->find("area");
250 if (ar
!= NULL
&& !ar
->value
.empty())
251 area
= atof(ar
->value
.c_str());
254 bool found_output
= false;
255 for (auto pin
: cell
->children
)
257 if (pin
->id
!= "pin" || pin
->args
.size() != 1)
260 LibertyAst
*dir
= pin
->find("direction");
261 if (dir
== NULL
|| dir
->value
== "internal")
265 if (dir
->value
== "input" && this_cell_ports
.count(pin
->args
[0]) == 0)
266 goto continue_cell_loop
;
268 LibertyAst
*func
= pin
->find("function");
269 if (dir
->value
== "output" && func
!= NULL
) {
270 std::string value
= func
->value
;
271 for (size_t pos
= value
.find_first_of("\" \t"); pos
!= std::string::npos
; pos
= value
.find_first_of("\" \t"))
273 if ((cell_next_pol
== true && value
== ff
->args
[0]) || (cell_next_pol
== false && value
== ff
->args
[1])) {
274 this_cell_ports
[pin
->args
[0]] = 'Q';
279 if (this_cell_ports
.count(pin
->args
[0]) == 0)
280 this_cell_ports
[pin
->args
[0]] = 0;
283 if (!found_output
|| (best_cell
!= NULL
&& num_pins
> best_cell_pins
))
286 if (best_cell
!= NULL
&& num_pins
== best_cell_pins
&& area
> best_cell_area
)
290 best_cell_pins
= num_pins
;
291 best_cell_area
= area
;
292 best_cell_ports
.swap(this_cell_ports
);
296 if (best_cell
!= NULL
) {
297 log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell
->args
[0].c_str(), best_cell_pins
, best_cell_area
, cell_type
.c_str());
299 cell_mappings
[cell_type
].cell_name
= cell_type
;
300 cell_mappings
[cell_type
].ports
["C"] = 'C';
301 cell_mappings
[cell_type
].ports
["S"] = 'S';
302 cell_mappings
[cell_type
].ports
["R"] = 'R';
303 cell_mappings
[cell_type
].ports
["D"] = 'D';
304 cell_mappings
[cell_type
].ports
["Q"] = 'Q';
306 cell_mappings
[cell_type
].cell_name
= best_cell
->args
[0];
307 cell_mappings
[cell_type
].ports
= best_cell_ports
;
312 static bool expand_cellmap_worker(std::string from
, std::string to
, std::string inv
)
314 if (cell_mappings
.count(to
) > 0)
317 log(" create mapping for %s from mapping for %s.\n", to
.c_str(), from
.c_str());
318 cell_mappings
[to
].cell_name
= cell_mappings
[from
].cell_name
;
319 cell_mappings
[to
].ports
= cell_mappings
[from
].ports
;
321 for (auto &it
: cell_mappings
[to
].ports
) {
322 char cmp_ch
= it
.second
;
323 if ('a' <= cmp_ch
&& cmp_ch
<= 'z')
325 if (inv
.find(cmp_ch
) == std::string::npos
)
327 if ('a' <= it
.second
&& it
.second
<= 'z')
328 it
.second
-= 'a' - 'A';
329 else if ('A' <= it
.second
&& it
.second
<= 'Z')
330 it
.second
+= 'a' - 'A';
335 static bool expand_cellmap(std::string pattern
, std::string inv
)
337 std::vector
<std::pair
<std::string
, std::string
>> from_to_list
;
338 bool return_status
= false;
340 for (auto &it
: cell_mappings
) {
341 std::string from
= it
.first
.str(), to
= it
.first
.str();
342 if (from
.size() != pattern
.size())
344 for (size_t i
= 0; i
< from
.size(); i
++) {
345 if (pattern
[i
] == '*') {
346 to
[i
] = from
[i
] == 'P' ? 'N' :
347 from
[i
] == 'N' ? 'P' :
348 from
[i
] == '1' ? '0' :
349 from
[i
] == '0' ? '1' : '*';
351 if (pattern
[i
] != '?' && pattern
[i
] != from
[i
])
354 from_to_list
.push_back(std::pair
<std::string
, std::string
>(from
, to
));
358 for (auto &it
: from_to_list
)
359 return_status
= return_status
|| expand_cellmap_worker(it
.first
, it
.second
, inv
);
360 return return_status
;
363 static void map_sr_to_arst(const char *from
, const char *to
)
365 if (!cell_mappings
.count(from
) || cell_mappings
.count(to
) > 0)
368 char from_clk_pol
= from
[8], from_set_pol
= from
[9], from_clr_pol
= from
[10];
369 char to_clk_pol
= to
[6], to_rst_pol
= to
[7], to_rst_val
= to
[8];
371 log_assert(from_clk_pol
== to_clk_pol
);
372 log_assert(to_rst_pol
== from_set_pol
&& to_rst_pol
== from_clr_pol
);
374 log(" create mapping for %s from mapping for %s.\n", to
, from
);
375 cell_mappings
[to
].cell_name
= cell_mappings
[from
].cell_name
;
376 cell_mappings
[to
].ports
= cell_mappings
[from
].ports
;
378 for (auto &it
: cell_mappings
[to
].ports
)
380 bool is_set_pin
= it
.second
== 'S' || it
.second
== 's';
381 bool is_clr_pin
= it
.second
== 'R' || it
.second
== 'r';
383 if (!is_set_pin
&& !is_clr_pin
)
386 if ((to_rst_val
== '0' && is_set_pin
) || (to_rst_val
== '1' && is_clr_pin
))
388 // this is the unused set/clr pin -- deactivate it
390 it
.second
= (from_set_pol
== 'P') == (it
.second
== 'S') ? '0' : '1';
392 it
.second
= (from_clr_pol
== 'P') == (it
.second
== 'R') ? '0' : '1';
396 // this is the used set/clr pin -- rename it to 'reset'
397 if (it
.second
== 'S')
399 if (it
.second
== 's')
405 static void dfflibmap(RTLIL::Design
*design
, RTLIL::Module
*module
, bool prepare_mode
)
407 log("Mapping DFF cells in module `%s':\n", module
->name
.c_str());
409 std::vector
<RTLIL::Cell
*> cell_list
;
410 for (auto &it
: module
->cells_
) {
411 if (design
->selected(module
, it
.second
) && cell_mappings
.count(it
.second
->type
) > 0)
412 cell_list
.push_back(it
.second
);
415 std::map
<std::string
, int> stats
;
416 for (auto cell
: cell_list
)
418 auto cell_type
= cell
->type
;
419 auto cell_name
= cell
->name
;
420 auto cell_connections
= cell
->connections();
421 module
->remove(cell
);
423 cell_mapping
&cm
= cell_mappings
[cell_type
];
424 RTLIL::Cell
*new_cell
= module
->addCell(cell_name
, prepare_mode
? cm
.cell_name
: "\\" + cm
.cell_name
);
426 for (auto &port
: cm
.ports
) {
428 if ('A' <= port
.second
&& port
.second
<= 'Z') {
429 sig
= cell_connections
[std::string("\\") + port
.second
];
431 if (port
.second
== 'q') {
432 RTLIL::SigSpec old_sig
= cell_connections
[std::string("\\") + char(port
.second
- ('a' - 'A'))];
433 sig
= module
->addWire(NEW_ID
, GetSize(old_sig
));
434 module
->addNotGate(NEW_ID
, sig
, old_sig
);
436 if ('a' <= port
.second
&& port
.second
<= 'z') {
437 sig
= cell_connections
[std::string("\\") + char(port
.second
- ('a' - 'A'))];
438 sig
= module
->NotGate(NEW_ID
, sig
);
440 if (port
.second
== '0' || port
.second
== '1') {
441 sig
= RTLIL::SigSpec(port
.second
== '0' ? 0 : 1, 1);
443 if (port
.second
!= 0)
445 new_cell
->setPort("\\" + port
.first
, sig
);
448 stats
[stringf(" mapped %%d %s cells to %s cells.\n", cell_type
.c_str(), new_cell
->type
.c_str())]++;
451 for (auto &stat
: stats
)
452 log(stat
.first
.c_str(), stat
.second
);
455 struct DfflibmapPass
: public Pass
{
456 DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { }
460 log(" dfflibmap [-prepare] -liberty <file> [selection]\n");
462 log("Map internal flip-flop cells to the flip-flop cells in the technology\n");
463 log("library specified in the given liberty file.\n");
465 log("This pass may add inverters as needed. Therefore it is recommended to\n");
466 log("first run this pass and then map the logic paths to the target technology.\n");
468 log("When called with -prepare, this command will convert the internal FF cells\n");
469 log("to the internal cell types that best match the cells found in the given\n");
470 log("liberty file.\n");
473 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
475 log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n");
477 std::string liberty_file
;
478 bool prepare_mode
= false;
481 for (argidx
= 1; argidx
< args
.size(); argidx
++)
483 std::string arg
= args
[argidx
];
484 if (arg
== "-liberty" && argidx
+1 < args
.size()) {
485 liberty_file
= args
[++argidx
];
488 if (arg
== "-prepare") {
494 extra_args(args
, argidx
, design
);
496 if (liberty_file
.empty())
497 log_cmd_error("Missing `-liberty liberty_file' option!\n");
500 f
.open(liberty_file
.c_str());
502 log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file
.c_str(), strerror(errno
));
503 LibertyParser
libparser(f
);
506 find_cell(libparser
.ast
, "$_DFF_N_", false, false, false, false, prepare_mode
);
507 find_cell(libparser
.ast
, "$_DFF_P_", true, false, false, false, prepare_mode
);
509 find_cell(libparser
.ast
, "$_DFF_NN0_", false, true, false, false, prepare_mode
);
510 find_cell(libparser
.ast
, "$_DFF_NN1_", false, true, false, true, prepare_mode
);
511 find_cell(libparser
.ast
, "$_DFF_NP0_", false, true, true, false, prepare_mode
);
512 find_cell(libparser
.ast
, "$_DFF_NP1_", false, true, true, true, prepare_mode
);
513 find_cell(libparser
.ast
, "$_DFF_PN0_", true, true, false, false, prepare_mode
);
514 find_cell(libparser
.ast
, "$_DFF_PN1_", true, true, false, true, prepare_mode
);
515 find_cell(libparser
.ast
, "$_DFF_PP0_", true, true, true, false, prepare_mode
);
516 find_cell(libparser
.ast
, "$_DFF_PP1_", true, true, true, true, prepare_mode
);
518 find_cell_sr(libparser
.ast
, "$_DFFSR_NNN_", false, false, false, prepare_mode
);
519 find_cell_sr(libparser
.ast
, "$_DFFSR_NNP_", false, false, true, prepare_mode
);
520 find_cell_sr(libparser
.ast
, "$_DFFSR_NPN_", false, true, false, prepare_mode
);
521 find_cell_sr(libparser
.ast
, "$_DFFSR_NPP_", false, true, true, prepare_mode
);
522 find_cell_sr(libparser
.ast
, "$_DFFSR_PNN_", true, false, false, prepare_mode
);
523 find_cell_sr(libparser
.ast
, "$_DFFSR_PNP_", true, false, true, prepare_mode
);
524 find_cell_sr(libparser
.ast
, "$_DFFSR_PPN_", true, true, false, prepare_mode
);
525 find_cell_sr(libparser
.ast
, "$_DFFSR_PPP_", true, true, true, prepare_mode
);
527 // try to implement as many cells as possible just by inverting
528 // the SET and RESET pins. If necessary, implement cell types
529 // by inverting both D and Q. Only invert clock pins if there
530 // is no other way of implementing the cell.
533 if (expand_cellmap("$_DFF_?*?_", "R") ||
534 expand_cellmap("$_DFFSR_?*?_", "S") ||
535 expand_cellmap("$_DFFSR_??*_", "R"))
538 if (expand_cellmap("$_DFF_??*_", "DQ"))
541 if (expand_cellmap("$_DFF_*_", "C") ||
542 expand_cellmap("$_DFF_*??_", "C") ||
543 expand_cellmap("$_DFFSR_*??_", "C"))
549 map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN0_");
550 map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN1_");
551 map_sr_to_arst("$_DFFSR_NPP_", "$_DFF_NP0_");
552 map_sr_to_arst("$_DFFSR_NPP_", "$_DFF_NP1_");
553 map_sr_to_arst("$_DFFSR_PNN_", "$_DFF_PN0_");
554 map_sr_to_arst("$_DFFSR_PNN_", "$_DFF_PN1_");
555 map_sr_to_arst("$_DFFSR_PPP_", "$_DFF_PP0_");
556 map_sr_to_arst("$_DFFSR_PPP_", "$_DFF_PP1_");
558 log(" final dff cell mappings:\n");
561 for (auto &it
: design
->modules_
)
562 if (design
->selected(it
.second
) && !it
.second
->get_bool_attribute("\\blackbox"))
563 dfflibmap(design
, it
.second
, prepare_mode
);
565 cell_mappings
.clear();
569 PRIVATE_NAMESPACE_END