abc9_ops: still emit delay table even box has no timing
[yosys.git] / passes / techmap / libparse.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 "libparse.h"
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <istream>
25 #include <fstream>
26 #include <iostream>
27 #include <sstream>
28
29 #ifndef FILTERLIB
30 #include "kernel/log.h"
31 #endif
32
33 using namespace Yosys;
34
35 std::set<std::string> LibertyAst::blacklist;
36 std::set<std::string> LibertyAst::whitelist;
37
38 LibertyAst::~LibertyAst()
39 {
40 for (auto child : children)
41 delete child;
42 children.clear();
43 }
44
45 LibertyAst *LibertyAst::find(std::string name)
46 {
47 for (auto child : children)
48 if (child->id == name)
49 return child;
50 return NULL;
51 }
52
53 void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_ok)
54 {
55 if (whitelist.count(path + "/*") > 0)
56 path_ok = true;
57
58 path += "/" + id;
59
60 if (blacklist.count(id) > 0 || blacklist.count(path) > 0)
61 return;
62 if (whitelist.size() > 0 && whitelist.count(id) == 0 && whitelist.count(path) == 0 && !path_ok) {
63 fprintf(stderr, "Automatically added to blacklist: %s\n", path.c_str());
64 blacklist.insert(id);
65 return;
66 }
67
68 fprintf(f, "%s%s", indent.c_str(), id.c_str());
69 if (!args.empty() || !children.empty()) {
70 fprintf(f, "(");
71 for (size_t i = 0; i < args.size(); i++)
72 fprintf(f, "%s%s", i > 0 ? ", " : "", args[i].c_str());
73 fprintf(f, ")");
74 }
75 if (!value.empty())
76 fprintf(f, " : %s", value.c_str());
77 if (!children.empty()) {
78 fprintf(f, " {\n");
79 for (size_t i = 0; i < children.size(); i++)
80 children[i]->dump(f, indent + " ", path, path_ok);
81 fprintf(f, "%s}\n", indent.c_str());
82 } else
83 fprintf(f, " ;\n");
84 }
85
86 int LibertyParser::lexer(std::string &str)
87 {
88 int c;
89
90 // eat whitespace
91 do {
92 c = f.get();
93 } while (c == ' ' || c == '\t' || c == '\r');
94
95 // search for identifiers, numbers, plus or minus.
96 if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
97 str = static_cast<char>(c);
98 while (1) {
99 c = f.get();
100 if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
101 str += c;
102 else
103 break;
104 }
105 f.unget();
106 if (str == "+" || str == "-") {
107 /* Single operator is not an identifier */
108 // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str());
109 return str[0];
110 }
111 else {
112 // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
113 return 'v';
114 }
115 }
116
117 // if it wasn't an identifer, number of array range,
118 // maybe it's a string?
119 if (c == '"') {
120 str = "";
121 while (1) {
122 c = f.get();
123 if (c == '\n')
124 line++;
125 if (c == '"')
126 break;
127 str += c;
128 }
129 // fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
130 return 'v';
131 }
132
133 // if it wasn't a string, perhaps it's a comment or a forward slash?
134 if (c == '/') {
135 c = f.get();
136 if (c == '*') { // start of '/*' block comment
137 int last_c = 0;
138 while (c > 0 && (last_c != '*' || c != '/')) {
139 last_c = c;
140 c = f.get();
141 if (c == '\n')
142 line++;
143 }
144 return lexer(str);
145 } else if (c == '/') { // start of '//' line comment
146 while (c > 0 && c != '\n')
147 c = f.get();
148 line++;
149 return lexer(str);
150 }
151 f.unget();
152 // fprintf(stderr, "LEX: char >>/<<\n");
153 return '/'; // a single '/' charater.
154 }
155
156 // check for a backslash
157 if (c == '\\') {
158 c = f.get();
159 if (c == '\r')
160 c = f.get();
161 if (c == '\n') {
162 line++;
163 return lexer(str);
164 }
165 f.unget();
166 return '\\';
167 }
168
169 // check for a new line
170 if (c == '\n') {
171 line++;
172 return 'n';
173 }
174
175 // anything else, such as ';' will get passed
176 // through as literal items.
177
178 // if (c >= 32 && c < 255)
179 // fprintf(stderr, "LEX: char >>%c<<\n", c);
180 // else
181 // fprintf(stderr, "LEX: char %d\n", c);
182 return c;
183 }
184
185 LibertyAst *LibertyParser::parse()
186 {
187 std::string str;
188
189 int tok = lexer(str);
190
191 // there are liberty files in the wild that
192 // have superfluous ';' at the end of
193 // a { ... }. We simply ignore a ';' here.
194 // and get to the next statement.
195
196 while ((tok == 'n') || (tok == ';'))
197 tok = lexer(str);
198
199 if (tok == '}' || tok < 0)
200 return NULL;
201
202 if (tok != 'v') {
203 std::string eReport;
204 switch(tok)
205 {
206 case 'n':
207 error("Unexpected newline.");
208 break;
209 case '[':
210 case ']':
211 case '}':
212 case '{':
213 case '\"':
214 case ':':
215 eReport = "Unexpected '";
216 eReport += static_cast<char>(tok);
217 eReport += "'.";
218 error(eReport);
219 break;
220 default:
221 error();
222 }
223 }
224
225 LibertyAst *ast = new LibertyAst;
226 ast->id = str;
227
228 while (1)
229 {
230 tok = lexer(str);
231
232 // allow both ';' and new lines to
233 // terminate a statement.
234 if ((tok == ';') || (tok == 'n'))
235 break;
236
237 if (tok == ':' && ast->value.empty()) {
238 tok = lexer(ast->value);
239 if (tok != 'v')
240 error();
241 tok = lexer(str);
242 while (tok == '+' || tok == '-' || tok == '*' || tok == '/') {
243 ast->value += tok;
244 tok = lexer(str);
245 if (tok != 'v')
246 error();
247 ast->value += str;
248 tok = lexer(str);
249 }
250
251 // In a liberty file, all key : value pairs should end in ';'
252 // However, there are some liberty files in the wild that
253 // just have a newline. We'll be kind and accept a newline
254 // instead of the ';' too..
255 if ((tok == ';') || (tok == 'n'))
256 break;
257 else
258 error();
259 continue;
260 }
261
262 if (tok == '(') {
263 while (1) {
264 std::string arg;
265 tok = lexer(arg);
266 if (tok == ',')
267 continue;
268 if (tok == ')')
269 break;
270
271 // FIXME: the AST needs to be extended to store
272 // these vector ranges.
273 if (tok == '[')
274 {
275 // parse vector range [A] or [A:B]
276 std::string arg;
277 tok = lexer(arg);
278 if (tok != 'v')
279 {
280 // expected a vector array index
281 error("Expected a number.");
282 }
283 else
284 {
285 // fixme: check for number A
286 }
287 tok = lexer(arg);
288 // optionally check for : in case of [A:B]
289 // if it isn't we just expect ']'
290 // as we have [A]
291 if (tok == ':')
292 {
293 tok = lexer(arg);
294 if (tok != 'v')
295 {
296 // expected a vector array index
297 error("Expected a number.");
298 }
299 else
300 {
301 // fixme: check for number B
302 tok = lexer(arg);
303 }
304 }
305 // expect a closing bracket of array range
306 if (tok != ']')
307 {
308 error("Expected ']' on array range.");
309 }
310 continue;
311 }
312 if (tok != 'v') {
313 std::string eReport;
314 switch(tok)
315 {
316 case 'n':
317 error("Unexpected newline.");
318 break;
319 case '[':
320 case ']':
321 case '}':
322 case '{':
323 case '\"':
324 case ':':
325 eReport = "Unexpected '";
326 eReport += static_cast<char>(tok);
327 eReport += "'.";
328 error(eReport);
329 break;
330 default:
331 error();
332 }
333 }
334 ast->args.push_back(arg);
335 }
336 continue;
337 }
338
339 if (tok == '{') {
340 while (1) {
341 LibertyAst *child = parse();
342 if (child == NULL)
343 break;
344 ast->children.push_back(child);
345 }
346 break;
347 }
348
349 error();
350 }
351
352 return ast;
353 }
354
355 #ifndef FILTERLIB
356
357 void LibertyParser::error()
358 {
359 log_error("Syntax error in liberty file on line %d.\n", line);
360 }
361
362 void LibertyParser::error(const std::string &str)
363 {
364 std::stringstream ss;
365 ss << "Syntax error in liberty file on line " << line << ".\n";
366 ss << " " << str << "\n";
367 log_error("%s", ss.str().c_str());
368 }
369
370 #else
371
372 void LibertyParser::error()
373 {
374 fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
375 exit(1);
376 }
377
378 void LibertyParser::error(const std::string &str)
379 {
380 std::stringstream ss;
381 ss << "Syntax error in liberty file on line " << line << ".\n";
382 ss << " " << str << "\n";
383 printf("%s", ss.str().c_str());
384 exit(1);
385 }
386
387 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
388
389 #define CHECK_NV(result, check) \
390 do { \
391 auto _R = (result); \
392 if (!(_R check)) { \
393 fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
394 #result, (long int)_R, #check, __FILE__, __LINE__); \
395 abort(); \
396 } \
397 } while(0)
398
399 #define CHECK_COND(result) \
400 do { \
401 if (!(result)) { \
402 fprintf(stderr, "Error from '%s' in %s:%d.\n", \
403 #result, __FILE__, __LINE__); \
404 abort(); \
405 } \
406 } while(0)
407
408 /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
409
410 LibertyAst *find_non_null(LibertyAst *node, const char *name)
411 {
412 LibertyAst *ret = node->find(name);
413 if (ret == NULL)
414 fprintf(stderr, "Error: expected to find `%s' node.\n", name);
415 return ret;
416 }
417
418 std::string func2vl(std::string str)
419 {
420 for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
421 char c_left = pos > 0 ? str[pos-1] : ' ';
422 char c_right = pos+1 < str.size() ? str[pos+1] : ' ';
423 if (std::string("\" \t*+").find(c_left) != std::string::npos)
424 str.erase(pos, 1);
425 else if (std::string("\" \t*+").find(c_right) != std::string::npos)
426 str.erase(pos, 1);
427 else
428 str[pos] = '*';
429 }
430
431 std::vector<size_t> group_start;
432 for (size_t pos = 0; pos < str.size(); pos++) {
433 if (str[pos] == '(')
434 group_start.push_back(pos);
435 if (str[pos] == ')' && group_start.size() > 0) {
436 if (pos+1 < str.size() && str[pos+1] == '\'') {
437 std::string group = str.substr(group_start.back(), pos-group_start.back()+1);
438 str[group_start.back()] = '~';
439 str.replace(group_start.back()+1, group.size(), group);
440 pos++;
441 }
442 group_start.pop_back();
443 }
444 if (str[pos] == '\'' && pos > 0) {
445 size_t start = str.find_last_of("()'*+^&| ", pos-1)+1;
446 std::string group = str.substr(start, pos-start);
447 str[start] = '~';
448 str.replace(start+1, group.size(), group);
449 }
450 if (str[pos] == '*')
451 str[pos] = '&';
452 if (str[pos] == '+')
453 str[pos] = '|';
454 }
455
456 return str;
457 }
458
459 void event2vl(LibertyAst *ast, std::string &edge, std::string &expr)
460 {
461 edge.clear();
462 expr.clear();
463
464 if (ast != NULL) {
465 expr = func2vl(ast->value);
466 if (expr.size() > 0 && expr[0] == '~')
467 edge = "negedge " + expr.substr(1);
468 else
469 edge = "posedge " + expr;
470 }
471 }
472
473 void clear_preset_var(std::string var, std::string type)
474 {
475 if (type.find('L') != std::string::npos) {
476 printf(" %s <= 0;\n", var.c_str());
477 return;
478 }
479 if (type.find('H') != std::string::npos) {
480 printf(" %s <= 1;\n", var.c_str());
481 return;
482 }
483 if (type.find('T') != std::string::npos) {
484 printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
485 return;
486 }
487 if (type.find('X') != std::string::npos) {
488 printf(" %s <= 'bx;\n", var.c_str());
489 return;
490 }
491 }
492
493 void gen_verilogsim_cell(LibertyAst *ast)
494 {
495 if (ast->find("statetable") != NULL)
496 return;
497
498 CHECK_NV(ast->args.size(), == 1);
499 printf("module %s (", ast->args[0].c_str());
500 bool first = true;
501 for (auto child : ast->children) {
502 if (child->id != "pin")
503 continue;
504 CHECK_NV(child->args.size(), == 1);
505 printf("%s%s", first ? "" : ", ", child->args[0].c_str());
506 first = false;
507 }
508 printf(");\n");
509
510 for (auto child : ast->children) {
511 if (child->id != "ff" && child->id != "latch")
512 continue;
513 printf(" reg ");
514 first = true;
515 for (auto arg : child->args) {
516 printf("%s%s", first ? "" : ", ", arg.c_str());
517 first = false;
518 }
519 printf(";\n");
520 }
521
522 for (auto child : ast->children) {
523 if (child->id != "pin")
524 continue;
525 CHECK_NV(child->args.size(), == 1);
526 LibertyAst *dir = find_non_null(child, "direction");
527 LibertyAst *func = child->find("function");
528 printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str());
529 if (func != NULL)
530 printf(" assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str());
531 }
532
533 for (auto child : ast->children)
534 {
535 if (child->id != "ff" || child->args.size() != 2)
536 continue;
537
538 std::string iq_var = child->args[0];
539 std::string iqn_var = child->args[1];
540
541 std::string clock_edge, clock_expr;
542 event2vl(child->find("clocked_on"), clock_edge, clock_expr);
543
544 std::string clear_edge, clear_expr;
545 event2vl(child->find("clear"), clear_edge, clear_expr);
546
547 std::string preset_edge, preset_expr;
548 event2vl(child->find("preset"), preset_edge, preset_expr);
549
550 std::string edge = "";
551 if (!clock_edge.empty())
552 edge += (edge.empty() ? "" : ", ") + clock_edge;
553 if (!clear_edge.empty())
554 edge += (edge.empty() ? "" : ", ") + clear_edge;
555 if (!preset_edge.empty())
556 edge += (edge.empty() ? "" : ", ") + preset_edge;
557
558 if (edge.empty())
559 continue;
560
561 printf(" always @(%s) begin\n", edge.c_str());
562
563 const char *else_prefix = "";
564 if (!clear_expr.empty() && !preset_expr.empty()) {
565 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
566 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
567 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
568 printf(" end\n");
569 else_prefix = "else ";
570 }
571 if (!clear_expr.empty()) {
572 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
573 printf(" %s <= 0;\n", iq_var.c_str());
574 printf(" %s <= 1;\n", iqn_var.c_str());
575 printf(" end\n");
576 else_prefix = "else ";
577 }
578 if (!preset_expr.empty()) {
579 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
580 printf(" %s <= 1;\n", iq_var.c_str());
581 printf(" %s <= 0;\n", iqn_var.c_str());
582 printf(" end\n");
583 else_prefix = "else ";
584 }
585 if (*else_prefix)
586 printf(" %sbegin\n", else_prefix);
587 std::string expr = find_non_null(child, "next_state")->value;
588 printf(" // %s\n", expr.c_str());
589 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
590 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
591 if (*else_prefix)
592 printf(" end\n");
593
594 printf(" end\n");
595 }
596
597 for (auto child : ast->children)
598 {
599 if (child->id != "latch" || child->args.size() != 2)
600 continue;
601
602 std::string iq_var = child->args[0];
603 std::string iqn_var = child->args[1];
604
605 std::string enable_edge, enable_expr;
606 event2vl(child->find("enable"), enable_edge, enable_expr);
607
608 std::string clear_edge, clear_expr;
609 event2vl(child->find("clear"), clear_edge, clear_expr);
610
611 std::string preset_edge, preset_expr;
612 event2vl(child->find("preset"), preset_edge, preset_expr);
613
614 printf(" always @* begin\n");
615
616 const char *else_prefix = "";
617 if (!clear_expr.empty() && !preset_expr.empty()) {
618 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
619 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
620 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
621 printf(" end\n");
622 else_prefix = "else ";
623 }
624 if (!clear_expr.empty()) {
625 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
626 printf(" %s <= 0;\n", iq_var.c_str());
627 printf(" %s <= 1;\n", iqn_var.c_str());
628 printf(" end\n");
629 else_prefix = "else ";
630 }
631 if (!preset_expr.empty()) {
632 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
633 printf(" %s <= 1;\n", iq_var.c_str());
634 printf(" %s <= 0;\n", iqn_var.c_str());
635 printf(" end\n");
636 else_prefix = "else ";
637 }
638 if (!enable_expr.empty()) {
639 printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str());
640 std::string expr = find_non_null(child, "data_in")->value;
641 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
642 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
643 printf(" end\n");
644 else_prefix = "else ";
645 }
646
647 printf(" end\n");
648 }
649
650 printf("endmodule\n");
651 }
652
653 void gen_verilogsim(LibertyAst *ast)
654 {
655 CHECK_COND(ast->id == "library");
656
657 for (auto child : ast->children)
658 if (child->id == "cell" && !child->find("dont_use"))
659 gen_verilogsim_cell(child);
660 }
661
662 void usage()
663 {
664 fprintf(stderr, "Usage: filterlib [rules-file [liberty-file]]\n");
665 fprintf(stderr, " or: filterlib -verilogsim [liberty-file]\n");
666 exit(1);
667 }
668
669 int main(int argc, char **argv)
670 {
671 bool flag_verilogsim = false;
672
673 if (argc > 3)
674 usage();
675
676 if (argc > 1)
677 {
678 if (!strcmp(argv[1], "-verilogsim"))
679 flag_verilogsim = true;
680 if (!strcmp(argv[1], "-") || !strcmp(argv[1], "-verilogsim"))
681 {
682 LibertyAst::whitelist.insert("/library");
683 LibertyAst::whitelist.insert("/library/cell");
684 LibertyAst::whitelist.insert("/library/cell/area");
685 LibertyAst::whitelist.insert("/library/cell/cell_footprint");
686 LibertyAst::whitelist.insert("/library/cell/dont_touch");
687 LibertyAst::whitelist.insert("/library/cell/dont_use");
688 LibertyAst::whitelist.insert("/library/cell/ff");
689 LibertyAst::whitelist.insert("/library/cell/ff/*");
690 LibertyAst::whitelist.insert("/library/cell/latch");
691 LibertyAst::whitelist.insert("/library/cell/latch/*");
692 LibertyAst::whitelist.insert("/library/cell/pin");
693 LibertyAst::whitelist.insert("/library/cell/pin/clock");
694 LibertyAst::whitelist.insert("/library/cell/pin/direction");
695 LibertyAst::whitelist.insert("/library/cell/pin/driver_type");
696 LibertyAst::whitelist.insert("/library/cell/pin/function");
697 LibertyAst::whitelist.insert("/library/cell/pin_opposite");
698 LibertyAst::whitelist.insert("/library/cell/pin/state_function");
699 LibertyAst::whitelist.insert("/library/cell/pin/three_state");
700 LibertyAst::whitelist.insert("/library/cell/statetable");
701 LibertyAst::whitelist.insert("/library/cell/statetable/*");
702 }
703 else
704 {
705 FILE *f = fopen(argv[1], "r");
706 if (f == NULL) {
707 fprintf(stderr, "Can't open rules file `%s'.\n", argv[1]);
708 usage();
709 }
710
711 char buffer[1024];
712 while (fgets(buffer, 1024, f) != NULL)
713 {
714 char mode = 0;
715 std::string id;
716 for (char *p = buffer; *p; p++)
717 {
718 if (*p == '-' || *p == '+') {
719 if (mode != 0)
720 goto syntax_error;
721 mode = *p;
722 continue;
723 }
724 if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#') {
725 if (!id.empty()) {
726 if (mode == '-')
727 LibertyAst::blacklist.insert(id);
728 else
729 if (mode == '+')
730 LibertyAst::whitelist.insert(id);
731 else
732 goto syntax_error;
733 }
734 id.clear();
735 if (*p == '#')
736 break;
737 continue;
738 }
739 id += *p;
740 continue;
741
742 syntax_error:
743 fprintf(stderr, "Syntax error in rules file:\n%s", buffer);
744 exit(1);
745 }
746 }
747 }
748 }
749
750 std::istream *f = &std::cin;
751
752 if (argc == 3) {
753 std::ifstream *ff = new std::ifstream;
754 ff->open(argv[2]);
755 if (ff->fail()) {
756 delete ff;
757 fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
758 usage();
759 }
760 f = ff;
761 }
762
763 LibertyParser parser(*f);
764 if (parser.ast) {
765 if (flag_verilogsim)
766 gen_verilogsim(parser.ast);
767 else
768 parser.ast->dump(stdout);
769 }
770
771 if (argc == 3)
772 delete f;
773
774 return 0;
775 }
776
777 #endif
778