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.
25 #include "kernel/log.h"
28 using namespace PASS_DFFLIBMAP
;
30 std::set
<std::string
> LibertyAst::blacklist
;
31 std::set
<std::string
> LibertyAst::whitelist
;
33 LibertyAst::~LibertyAst()
35 for (auto child
: children
)
40 LibertyAst
*LibertyAst::find(std::string name
)
44 for (auto child
: children
)
45 if (child
->id
== name
)
50 void LibertyAst::dump(FILE *f
, std::string indent
, std::string path
, bool path_ok
)
52 if (whitelist
.count(path
+ "/*") > 0)
57 if (blacklist
.count(id
) > 0 || blacklist
.count(path
) > 0)
59 if (whitelist
.size() > 0 && whitelist
.count(id
) == 0 && whitelist
.count(path
) == 0 && !path_ok
) {
60 fprintf(stderr
, "Automatically added to blacklist: %s\n", path
.c_str());
65 fprintf(f
, "%s%s", indent
.c_str(), id
.c_str());
66 if (!args
.empty() || !children
.empty()) {
68 for (size_t i
= 0; i
< args
.size(); i
++)
69 fprintf(f
, "%s%s", i
> 0 ? ", " : "", args
[i
].c_str());
73 fprintf(f
, " : %s", value
.c_str());
74 if (!children
.empty()) {
76 for (size_t i
= 0; i
< children
.size(); i
++)
77 children
[i
]->dump(f
, indent
+ " ", path
, path_ok
);
78 fprintf(f
, "%s}\n", indent
.c_str());
83 int LibertyParser::lexer(std::string
&str
)
89 } while (c
== ' ' || c
== '\t' || c
== '\r');
91 if (('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z') || ('0' <= c
&& c
<= '9') || c
== '_' || c
== '-' || c
== '+' || c
== '.') {
95 if (('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z') || ('0' <= c
&& c
<= '9') || c
== '_' || c
== '-' || c
== '+' || c
== '.')
101 // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
115 // fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
123 while (c
> 0 && (last_c
!= '*' || c
!= '/')) {
130 } else if (c
== '/') {
131 while (c
> 0 && c
!= '\n')
137 // fprintf(stderr, "LEX: char >>/<<\n");
156 // if (c >= 32 && c < 255)
157 // fprintf(stderr, "LEX: char >>%c<<\n", c);
159 // fprintf(stderr, "LEX: char %d\n", c);
163 LibertyAst
*LibertyParser::parse()
167 int tok
= lexer(str
);
172 if (tok
== '}' || tok
< 0)
178 LibertyAst
*ast
= new LibertyAst
;
188 if (tok
== ':' && ast
->value
.empty()) {
189 tok
= lexer(ast
->value
);
205 ast
->args
.push_back(arg
);
212 LibertyAst
*child
= parse();
215 ast
->children
.push_back(child
);
228 void LibertyParser::error()
230 log_error("Syntax error in line %d.\n", line
);
235 void LibertyParser::error()
237 fprintf(stderr
, "Syntax error in line %d.\n", line
);
241 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
243 // This is to not confuse the VIM syntax highlighting
244 #define CHECK_VAL_OPEN (
245 #define CHECK_VAL_CLOSE )
247 #define CHECK(result, check) \
249 auto _R = (result); \
251 fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
252 #result, (long int)_R, #check, __FILE__, __LINE__); \
258 #define CHECK_NV(result, check) \
260 auto _R = (result); \
262 fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
263 #result, (long int)_R, #check, __FILE__, __LINE__); \
268 #define CHECK_COND(result) \
271 fprintf(stderr, "Error from '%s' in %s:%d.\n", \
272 #result, __FILE__, __LINE__); \
277 /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
279 std::string
func2vl(std::string str
)
281 for (size_t pos
= str
.find_first_of("\" \t"); pos
!= std::string::npos
; pos
= str
.find_first_of("\" \t")) {
282 char c_left
= pos
> 0 ? str
[pos
-1] : ' ';
283 char c_right
= pos
+1 < str
.size() ? str
[pos
+1] : ' ';
284 if (std::string("\" \t*+").find(c_left
) != std::string::npos
)
286 else if (std::string("\" \t*+").find(c_right
) != std::string::npos
)
292 std::vector
<size_t> group_start
;
293 for (size_t pos
= 0; pos
< str
.size(); pos
++) {
295 group_start
.push_back(pos
);
296 if (str
[pos
] == ')' && group_start
.size() > 0) {
297 if (pos
+1 < str
.size() && str
[pos
+1] == '\'') {
298 std::string group
= str
.substr(group_start
.back(), pos
-group_start
.back()+1);
299 str
[group_start
.back()] = '~';
300 str
.replace(group_start
.back()+1, group
.size(), group
);
303 group_start
.pop_back();
305 if (str
[pos
] == '\'' && pos
> 0) {
306 size_t start
= str
.find_last_of("()'*+^&| ", pos
-1)+1;
307 std::string group
= str
.substr(start
, pos
-start
);
309 str
.replace(start
+1, group
.size(), group
);
320 void event2vl(LibertyAst
*ast
, std::string
&edge
, std::string
&expr
)
326 expr
= func2vl(ast
->value
);
327 if (expr
.size() > 0 && expr
[0] == '~')
328 edge
= "negedge " + expr
.substr(1);
330 edge
= "posedge " + expr
;
334 void clear_preset_var(std::string var
, std::string type
)
336 if (type
.find('L') != std::string::npos
) {
337 printf(" %s <= 0;\n", var
.c_str());
340 if (type
.find('H') != std::string::npos
) {
341 printf(" %s <= 1;\n", var
.c_str());
344 if (type
.find('T') != std::string::npos
) {
345 printf(" %s <= ~%s;\n", var
.c_str(), var
.c_str());
348 if (type
.find('X') != std::string::npos
) {
349 printf(" %s <= 'bx;\n", var
.c_str());
354 void gen_verilogsim_cell(LibertyAst
*ast
)
356 if (ast
->find("statetable") != NULL
)
359 CHECK_NV(ast
->args
.size(), == 1);
360 printf("module %s (", ast
->args
[0].c_str());
362 for (auto child
: ast
->children
) {
363 if (child
->id
!= "pin")
365 CHECK_NV(child
->args
.size(), == 1);
366 printf("%s%s", first
? "" : ", ", child
->args
[0].c_str());
371 for (auto child
: ast
->children
) {
372 if (child
->id
!= "ff" && child
->id
!= "latch")
376 for (auto arg
: child
->args
) {
377 printf("%s%s", first
? "" : ", ", arg
.c_str());
383 for (auto child
: ast
->children
) {
384 if (child
->id
!= "pin")
386 CHECK_NV(child
->args
.size(), == 1);
387 LibertyAst
*dir
= CHECK(child
->find("direction"), != NULL
);
388 LibertyAst
*func
= child
->find("function");
389 printf(" %s %s;\n", dir
->value
.c_str(), child
->args
[0].c_str());
391 printf(" assign %s = %s; // %s\n", child
->args
[0].c_str(), func2vl(func
->value
).c_str(), func
->value
.c_str());
394 for (auto child
: ast
->children
)
396 if (child
->id
!= "ff" || child
->args
.size() != 2)
399 std::string iq_var
= child
->args
[0];
400 std::string iqn_var
= child
->args
[1];
402 std::string clock_edge
, clock_expr
;
403 event2vl(child
->find("clocked_on"), clock_edge
, clock_expr
);
405 std::string clear_edge
, clear_expr
;
406 event2vl(child
->find("clear"), clear_edge
, clear_expr
);
408 std::string preset_edge
, preset_expr
;
409 event2vl(child
->find("preset"), preset_edge
, preset_expr
);
411 std::string edge
= "";
412 if (!clock_edge
.empty())
413 edge
+= (edge
.empty() ? "" : ", ") + clock_edge
;
414 if (!clear_edge
.empty())
415 edge
+= (edge
.empty() ? "" : ", ") + clear_edge
;
416 if (!preset_edge
.empty())
417 edge
+= (edge
.empty() ? "" : ", ") + preset_edge
;
422 printf(" always @(%s) begin\n", edge
.c_str());
424 const char *else_prefix
= "";
425 if (!clear_expr
.empty() && !preset_expr
.empty()) {
426 printf(" %sif ((%s) && (%s)) begin\n", else_prefix
, clear_expr
.c_str(), preset_expr
.c_str());
427 clear_preset_var(iq_var
, CHECK(child
->find("clear_preset_var1"), != NULL
)->value
);
428 clear_preset_var(iqn_var
, CHECK(child
->find("clear_preset_var2"), != NULL
)->value
);
430 else_prefix
= "else ";
432 if (!clear_expr
.empty()) {
433 printf(" %sif (%s) begin\n", else_prefix
, clear_expr
.c_str());
434 printf(" %s <= 0;\n", iq_var
.c_str());
435 printf(" %s <= 1;\n", iqn_var
.c_str());
437 else_prefix
= "else ";
439 if (!preset_expr
.empty()) {
440 printf(" %sif (%s) begin\n", else_prefix
, preset_expr
.c_str());
441 printf(" %s <= 1;\n", iq_var
.c_str());
442 printf(" %s <= 0;\n", iqn_var
.c_str());
444 else_prefix
= "else ";
447 printf(" %sbegin\n", else_prefix
);
448 std::string expr
= CHECK(child
->find("next_state"), != NULL
)->value
;
449 printf(" // %s\n", expr
.c_str());
450 printf(" %s <= %s;\n", iq_var
.c_str(), func2vl(expr
).c_str());
451 printf(" %s <= ~(%s);\n", iqn_var
.c_str(), func2vl(expr
).c_str());
458 for (auto child
: ast
->children
)
460 if (child
->id
!= "latch" || child
->args
.size() != 2)
463 std::string iq_var
= child
->args
[0];
464 std::string iqn_var
= child
->args
[1];
466 std::string enable_edge
, enable_expr
;
467 event2vl(child
->find("enable"), enable_edge
, enable_expr
);
469 std::string clear_edge
, clear_expr
;
470 event2vl(child
->find("clear"), clear_edge
, clear_expr
);
472 std::string preset_edge
, preset_expr
;
473 event2vl(child
->find("preset"), preset_edge
, preset_expr
);
475 printf(" always @* begin\n");
477 const char *else_prefix
= "";
478 if (!clear_expr
.empty() && !preset_expr
.empty()) {
479 printf(" %sif ((%s) && (%s)) begin\n", else_prefix
, clear_expr
.c_str(), preset_expr
.c_str());
480 clear_preset_var(iq_var
, CHECK(child
->find("clear_preset_var1"), != NULL
)->value
);
481 clear_preset_var(iqn_var
, CHECK(child
->find("clear_preset_var2"), != NULL
)->value
);
483 else_prefix
= "else ";
485 if (!clear_expr
.empty()) {
486 printf(" %sif (%s) begin\n", else_prefix
, clear_expr
.c_str());
487 printf(" %s <= 0;\n", iq_var
.c_str());
488 printf(" %s <= 1;\n", iqn_var
.c_str());
490 else_prefix
= "else ";
492 if (!preset_expr
.empty()) {
493 printf(" %sif (%s) begin\n", else_prefix
, preset_expr
.c_str());
494 printf(" %s <= 1;\n", iq_var
.c_str());
495 printf(" %s <= 0;\n", iqn_var
.c_str());
497 else_prefix
= "else ";
499 if (!enable_expr
.empty()) {
500 printf(" %sif (%s) begin\n", else_prefix
, enable_expr
.c_str());
501 std::string expr
= CHECK(child
->find("data_in"), != NULL
)->value
;
502 printf(" %s <= %s;\n", iq_var
.c_str(), func2vl(expr
).c_str());
503 printf(" %s <= ~(%s);\n", iqn_var
.c_str(), func2vl(expr
).c_str());
505 else_prefix
= "else ";
511 printf("endmodule\n");
514 void gen_verilogsim(LibertyAst
*ast
)
516 CHECK_COND(ast
->id
== "library");
518 for (auto child
: ast
->children
)
519 if (child
->id
== "cell" && !child
->find("dont_use"))
520 gen_verilogsim_cell(child
);
525 fprintf(stderr
, "Usage: filterlib [rules-file [liberty-file]]\n");
526 fprintf(stderr
, " or: filterlib -verilogsim [liberty-file]\n");
530 int main(int argc
, char **argv
)
532 bool flag_verilogsim
= false;
539 if (!strcmp(argv
[1], "-verilogsim"))
540 flag_verilogsim
= true;
541 if (!strcmp(argv
[1], "-") || !strcmp(argv
[1], "-verilogsim"))
543 LibertyAst::whitelist
.insert("/library");
544 LibertyAst::whitelist
.insert("/library/cell");
545 LibertyAst::whitelist
.insert("/library/cell/area");
546 LibertyAst::whitelist
.insert("/library/cell/cell_footprint");
547 LibertyAst::whitelist
.insert("/library/cell/dont_touch");
548 LibertyAst::whitelist
.insert("/library/cell/dont_use");
549 LibertyAst::whitelist
.insert("/library/cell/ff");
550 LibertyAst::whitelist
.insert("/library/cell/ff/*");
551 LibertyAst::whitelist
.insert("/library/cell/latch");
552 LibertyAst::whitelist
.insert("/library/cell/latch/*");
553 LibertyAst::whitelist
.insert("/library/cell/pin");
554 LibertyAst::whitelist
.insert("/library/cell/pin/clock");
555 LibertyAst::whitelist
.insert("/library/cell/pin/direction");
556 LibertyAst::whitelist
.insert("/library/cell/pin/driver_type");
557 LibertyAst::whitelist
.insert("/library/cell/pin/function");
558 LibertyAst::whitelist
.insert("/library/cell/pin_opposite");
559 LibertyAst::whitelist
.insert("/library/cell/pin/state_function");
560 LibertyAst::whitelist
.insert("/library/cell/pin/three_state");
561 LibertyAst::whitelist
.insert("/library/cell/statetable");
562 LibertyAst::whitelist
.insert("/library/cell/statetable/*");
566 FILE *f
= fopen(argv
[1], "r");
568 fprintf(stderr
, "Can't open rules file `%s'.\n", argv
[1]);
573 while (fgets(buffer
, 1024, f
) != NULL
)
577 for (char *p
= buffer
; *p
; p
++)
579 if (*p
== '-' || *p
== '+') {
585 if (*p
== ' ' || *p
== '\t' || *p
== '\r' || *p
== '\n' || *p
== '#') {
588 LibertyAst::blacklist
.insert(id
);
591 LibertyAst::whitelist
.insert(id
);
604 fprintf(stderr
, "Syntax error in rules file:\n%s", buffer
);
613 f
= fopen(argv
[2], "r");
615 fprintf(stderr
, "Can't open liberty file `%s'.\n", argv
[2]);
620 LibertyParser
parser(f
);
623 gen_verilogsim(parser
.ast
);
625 parser
.ast
->dump(stdout
);