spaces -> tabs
[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 = 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 return lexer(str);
163 f.unget();
164 return '\\';
165 }
166
167 // check for a new line
168 if (c == '\n') {
169 line++;
170 return 'n';
171 }
172
173 // anything else, such as ';' will get passed
174 // through as literal items.
175
176 // if (c >= 32 && c < 255)
177 // fprintf(stderr, "LEX: char >>%c<<\n", c);
178 // else
179 // fprintf(stderr, "LEX: char %d\n", c);
180 return c;
181 }
182
183 LibertyAst *LibertyParser::parse()
184 {
185 std::string str;
186
187 int tok = lexer(str);
188
189 while (tok == 'n')
190 tok = lexer(str);
191
192 if (tok == '}' || tok < 0)
193 return NULL;
194
195 if (tok != 'v')
196 error();
197
198 LibertyAst *ast = new LibertyAst;
199 ast->id = str;
200
201 while (1)
202 {
203 tok = lexer(str);
204
205 // allow both ';' and new lines to
206 // terminate a statement.
207 if ((tok == ';') || (tok == 'n'))
208 break;
209
210 if (tok == ':' && ast->value.empty()) {
211 tok = lexer(ast->value);
212 if (tok != 'v')
213 error();
214 tok = lexer(str);
215 while (tok == '+' || tok == '-' || tok == '*' || tok == '/') {
216 ast->value += tok;
217 tok = lexer(str);
218 if (tok != 'v')
219 error();
220 ast->value += str;
221 tok = lexer(str);
222 }
223
224 // In a liberty file, all key : value pairs should end in ';'
225 // However, there are some liberty files in the wild that
226 // just have a newline. We'll be kind and accept a newline
227 // instead of the ';' too..
228 if ((tok == ';') || (tok == 'n'))
229 break;
230 else
231 error();
232 continue;
233 }
234
235 if (tok == '(') {
236 while (1) {
237 std::string arg;
238 tok = lexer(arg);
239 if (tok == ',')
240 continue;
241 if (tok == ')')
242 break;
243
244 // FIXME: the AST needs to be extended to store
245 // these vector ranges.
246 if (tok == '[')
247 {
248 // parse vector range [A] or [A:B]
249 std::string arg;
250 tok = lexer(arg);
251 if (tok != 'v')
252 {
253 // expected a vector array index
254 error("Expected a number.");
255 }
256 else
257 {
258 // fixme: check for number A
259 }
260 tok = lexer(arg);
261 // optionally check for : in case of [A:B]
262 // if it isn't we just expect ']'
263 // as we have [A]
264 if (tok == ':')
265 {
266 tok = lexer(arg);
267 if (tok != 'v')
268 {
269 // expected a vector array index
270 error("Expected a number.");
271 }
272 else
273 {
274 // fixme: check for number B
275 tok = lexer(arg);
276 }
277 }
278 // expect a closing bracket of array range
279 if (tok != ']')
280 {
281 error("Expected ']' on array range.");
282 }
283 continue;
284 }
285 if (tok != 'v')
286 error();
287 ast->args.push_back(arg);
288 }
289 continue;
290 }
291
292 if (tok == '{') {
293 while (1) {
294 LibertyAst *child = parse();
295 if (child == NULL)
296 break;
297 ast->children.push_back(child);
298 }
299 break;
300 }
301
302 error();
303 }
304
305 return ast;
306 }
307
308 #ifndef FILTERLIB
309
310 void LibertyParser::error()
311 {
312 log_error("Syntax error in liberty file on line %d.\n", line);
313 }
314
315 void LibertyParser::error(const std::string &str)
316 {
317 std::stringstream ss;
318 ss << "Syntax error in liberty file on line " << line << ".\n";
319 ss << " " << str << "\n";
320 log_error("%s", ss.str().c_str());
321 }
322
323 #else
324
325 void LibertyParser::error()
326 {
327 fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
328 exit(1);
329 }
330
331 void LibertyParser::error(const std::string &str)
332 {
333 std::stringstream ss;
334 ss << "Syntax error in liberty file on line " << line << ".\n";
335 ss << " " << str << "\n";
336 printf("%s", ss.str().c_str());
337 exit(1);
338 }
339
340 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
341
342 #define CHECK_NV(result, check) \
343 do { \
344 auto _R = (result); \
345 if (!(_R check)) { \
346 fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
347 #result, (long int)_R, #check, __FILE__, __LINE__); \
348 abort(); \
349 } \
350 } while(0)
351
352 #define CHECK_COND(result) \
353 do { \
354 if (!(result)) { \
355 fprintf(stderr, "Error from '%s' in %s:%d.\n", \
356 #result, __FILE__, __LINE__); \
357 abort(); \
358 } \
359 } while(0)
360
361 /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
362
363 LibertyAst *find_non_null(LibertyAst *node, const char *name)
364 {
365 LibertyAst *ret = node->find(name);
366 if (ret == NULL)
367 fprintf(stderr, "Error: expected to find `%s' node.\n", name);
368 return ret;
369 }
370
371 std::string func2vl(std::string str)
372 {
373 for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
374 char c_left = pos > 0 ? str[pos-1] : ' ';
375 char c_right = pos+1 < str.size() ? str[pos+1] : ' ';
376 if (std::string("\" \t*+").find(c_left) != std::string::npos)
377 str.erase(pos, 1);
378 else if (std::string("\" \t*+").find(c_right) != std::string::npos)
379 str.erase(pos, 1);
380 else
381 str[pos] = '*';
382 }
383
384 std::vector<size_t> group_start;
385 for (size_t pos = 0; pos < str.size(); pos++) {
386 if (str[pos] == '(')
387 group_start.push_back(pos);
388 if (str[pos] == ')' && group_start.size() > 0) {
389 if (pos+1 < str.size() && str[pos+1] == '\'') {
390 std::string group = str.substr(group_start.back(), pos-group_start.back()+1);
391 str[group_start.back()] = '~';
392 str.replace(group_start.back()+1, group.size(), group);
393 pos++;
394 }
395 group_start.pop_back();
396 }
397 if (str[pos] == '\'' && pos > 0) {
398 size_t start = str.find_last_of("()'*+^&| ", pos-1)+1;
399 std::string group = str.substr(start, pos-start);
400 str[start] = '~';
401 str.replace(start+1, group.size(), group);
402 }
403 if (str[pos] == '*')
404 str[pos] = '&';
405 if (str[pos] == '+')
406 str[pos] = '|';
407 }
408
409 return str;
410 }
411
412 void event2vl(LibertyAst *ast, std::string &edge, std::string &expr)
413 {
414 edge.clear();
415 expr.clear();
416
417 if (ast != NULL) {
418 expr = func2vl(ast->value);
419 if (expr.size() > 0 && expr[0] == '~')
420 edge = "negedge " + expr.substr(1);
421 else
422 edge = "posedge " + expr;
423 }
424 }
425
426 void clear_preset_var(std::string var, std::string type)
427 {
428 if (type.find('L') != std::string::npos) {
429 printf(" %s <= 0;\n", var.c_str());
430 return;
431 }
432 if (type.find('H') != std::string::npos) {
433 printf(" %s <= 1;\n", var.c_str());
434 return;
435 }
436 if (type.find('T') != std::string::npos) {
437 printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
438 return;
439 }
440 if (type.find('X') != std::string::npos) {
441 printf(" %s <= 'bx;\n", var.c_str());
442 return;
443 }
444 }
445
446 void gen_verilogsim_cell(LibertyAst *ast)
447 {
448 if (ast->find("statetable") != NULL)
449 return;
450
451 CHECK_NV(ast->args.size(), == 1);
452 printf("module %s (", ast->args[0].c_str());
453 bool first = true;
454 for (auto child : ast->children) {
455 if (child->id != "pin")
456 continue;
457 CHECK_NV(child->args.size(), == 1);
458 printf("%s%s", first ? "" : ", ", child->args[0].c_str());
459 first = false;
460 }
461 printf(");\n");
462
463 for (auto child : ast->children) {
464 if (child->id != "ff" && child->id != "latch")
465 continue;
466 printf(" reg ");
467 first = true;
468 for (auto arg : child->args) {
469 printf("%s%s", first ? "" : ", ", arg.c_str());
470 first = false;
471 }
472 printf(";\n");
473 }
474
475 for (auto child : ast->children) {
476 if (child->id != "pin")
477 continue;
478 CHECK_NV(child->args.size(), == 1);
479 LibertyAst *dir = find_non_null(child, "direction");
480 LibertyAst *func = child->find("function");
481 printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str());
482 if (func != NULL)
483 printf(" assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str());
484 }
485
486 for (auto child : ast->children)
487 {
488 if (child->id != "ff" || child->args.size() != 2)
489 continue;
490
491 std::string iq_var = child->args[0];
492 std::string iqn_var = child->args[1];
493
494 std::string clock_edge, clock_expr;
495 event2vl(child->find("clocked_on"), clock_edge, clock_expr);
496
497 std::string clear_edge, clear_expr;
498 event2vl(child->find("clear"), clear_edge, clear_expr);
499
500 std::string preset_edge, preset_expr;
501 event2vl(child->find("preset"), preset_edge, preset_expr);
502
503 std::string edge = "";
504 if (!clock_edge.empty())
505 edge += (edge.empty() ? "" : ", ") + clock_edge;
506 if (!clear_edge.empty())
507 edge += (edge.empty() ? "" : ", ") + clear_edge;
508 if (!preset_edge.empty())
509 edge += (edge.empty() ? "" : ", ") + preset_edge;
510
511 if (edge.empty())
512 continue;
513
514 printf(" always @(%s) begin\n", edge.c_str());
515
516 const char *else_prefix = "";
517 if (!clear_expr.empty() && !preset_expr.empty()) {
518 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
519 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
520 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
521 printf(" end\n");
522 else_prefix = "else ";
523 }
524 if (!clear_expr.empty()) {
525 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
526 printf(" %s <= 0;\n", iq_var.c_str());
527 printf(" %s <= 1;\n", iqn_var.c_str());
528 printf(" end\n");
529 else_prefix = "else ";
530 }
531 if (!preset_expr.empty()) {
532 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
533 printf(" %s <= 1;\n", iq_var.c_str());
534 printf(" %s <= 0;\n", iqn_var.c_str());
535 printf(" end\n");
536 else_prefix = "else ";
537 }
538 if (*else_prefix)
539 printf(" %sbegin\n", else_prefix);
540 std::string expr = find_non_null(child, "next_state")->value;
541 printf(" // %s\n", expr.c_str());
542 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
543 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
544 if (*else_prefix)
545 printf(" end\n");
546
547 printf(" end\n");
548 }
549
550 for (auto child : ast->children)
551 {
552 if (child->id != "latch" || child->args.size() != 2)
553 continue;
554
555 std::string iq_var = child->args[0];
556 std::string iqn_var = child->args[1];
557
558 std::string enable_edge, enable_expr;
559 event2vl(child->find("enable"), enable_edge, enable_expr);
560
561 std::string clear_edge, clear_expr;
562 event2vl(child->find("clear"), clear_edge, clear_expr);
563
564 std::string preset_edge, preset_expr;
565 event2vl(child->find("preset"), preset_edge, preset_expr);
566
567 printf(" always @* begin\n");
568
569 const char *else_prefix = "";
570 if (!clear_expr.empty() && !preset_expr.empty()) {
571 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
572 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
573 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
574 printf(" end\n");
575 else_prefix = "else ";
576 }
577 if (!clear_expr.empty()) {
578 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
579 printf(" %s <= 0;\n", iq_var.c_str());
580 printf(" %s <= 1;\n", iqn_var.c_str());
581 printf(" end\n");
582 else_prefix = "else ";
583 }
584 if (!preset_expr.empty()) {
585 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
586 printf(" %s <= 1;\n", iq_var.c_str());
587 printf(" %s <= 0;\n", iqn_var.c_str());
588 printf(" end\n");
589 else_prefix = "else ";
590 }
591 if (!enable_expr.empty()) {
592 printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str());
593 std::string expr = find_non_null(child, "data_in")->value;
594 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
595 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
596 printf(" end\n");
597 else_prefix = "else ";
598 }
599
600 printf(" end\n");
601 }
602
603 printf("endmodule\n");
604 }
605
606 void gen_verilogsim(LibertyAst *ast)
607 {
608 CHECK_COND(ast->id == "library");
609
610 for (auto child : ast->children)
611 if (child->id == "cell" && !child->find("dont_use"))
612 gen_verilogsim_cell(child);
613 }
614
615 void usage()
616 {
617 fprintf(stderr, "Usage: filterlib [rules-file [liberty-file]]\n");
618 fprintf(stderr, " or: filterlib -verilogsim [liberty-file]\n");
619 exit(1);
620 }
621
622 int main(int argc, char **argv)
623 {
624 bool flag_verilogsim = false;
625
626 if (argc > 3)
627 usage();
628
629 if (argc > 1)
630 {
631 if (!strcmp(argv[1], "-verilogsim"))
632 flag_verilogsim = true;
633 if (!strcmp(argv[1], "-") || !strcmp(argv[1], "-verilogsim"))
634 {
635 LibertyAst::whitelist.insert("/library");
636 LibertyAst::whitelist.insert("/library/cell");
637 LibertyAst::whitelist.insert("/library/cell/area");
638 LibertyAst::whitelist.insert("/library/cell/cell_footprint");
639 LibertyAst::whitelist.insert("/library/cell/dont_touch");
640 LibertyAst::whitelist.insert("/library/cell/dont_use");
641 LibertyAst::whitelist.insert("/library/cell/ff");
642 LibertyAst::whitelist.insert("/library/cell/ff/*");
643 LibertyAst::whitelist.insert("/library/cell/latch");
644 LibertyAst::whitelist.insert("/library/cell/latch/*");
645 LibertyAst::whitelist.insert("/library/cell/pin");
646 LibertyAst::whitelist.insert("/library/cell/pin/clock");
647 LibertyAst::whitelist.insert("/library/cell/pin/direction");
648 LibertyAst::whitelist.insert("/library/cell/pin/driver_type");
649 LibertyAst::whitelist.insert("/library/cell/pin/function");
650 LibertyAst::whitelist.insert("/library/cell/pin_opposite");
651 LibertyAst::whitelist.insert("/library/cell/pin/state_function");
652 LibertyAst::whitelist.insert("/library/cell/pin/three_state");
653 LibertyAst::whitelist.insert("/library/cell/statetable");
654 LibertyAst::whitelist.insert("/library/cell/statetable/*");
655 }
656 else
657 {
658 FILE *f = fopen(argv[1], "r");
659 if (f == NULL) {
660 fprintf(stderr, "Can't open rules file `%s'.\n", argv[1]);
661 usage();
662 }
663
664 char buffer[1024];
665 while (fgets(buffer, 1024, f) != NULL)
666 {
667 char mode = 0;
668 std::string id;
669 for (char *p = buffer; *p; p++)
670 {
671 if (*p == '-' || *p == '+') {
672 if (mode != 0)
673 goto syntax_error;
674 mode = *p;
675 continue;
676 }
677 if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#') {
678 if (!id.empty()) {
679 if (mode == '-')
680 LibertyAst::blacklist.insert(id);
681 else
682 if (mode == '+')
683 LibertyAst::whitelist.insert(id);
684 else
685 goto syntax_error;
686 }
687 id.clear();
688 if (*p == '#')
689 break;
690 continue;
691 }
692 id += *p;
693 continue;
694
695 syntax_error:
696 fprintf(stderr, "Syntax error in rules file:\n%s", buffer);
697 exit(1);
698 }
699 }
700 }
701 }
702
703 std::istream *f = &std::cin;
704
705 if (argc == 3) {
706 std::ifstream *ff = new std::ifstream;
707 ff->open(argv[2]);
708 if (ff->fail()) {
709 delete ff;
710 fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
711 usage();
712 }
713 f = ff;
714 }
715
716 LibertyParser parser(*f);
717 if (parser.ast) {
718 if (flag_verilogsim)
719 gen_verilogsim(parser.ast);
720 else
721 parser.ast->dump(stdout);
722 }
723
724 if (argc == 3)
725 delete f;
726
727 return 0;
728 }
729
730 #endif
731