Merge pull request #695 from daveshah1/ecp5_bb
[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
28 #ifndef FILTERLIB
29 #include "kernel/log.h"
30 #endif
31
32 using namespace Yosys;
33
34 std::set<std::string> LibertyAst::blacklist;
35 std::set<std::string> LibertyAst::whitelist;
36
37 LibertyAst::~LibertyAst()
38 {
39 for (auto child : children)
40 delete child;
41 children.clear();
42 }
43
44 LibertyAst *LibertyAst::find(std::string name)
45 {
46 for (auto child : children)
47 if (child->id == name)
48 return child;
49 return NULL;
50 }
51
52 void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_ok)
53 {
54 if (whitelist.count(path + "/*") > 0)
55 path_ok = true;
56
57 path += "/" + id;
58
59 if (blacklist.count(id) > 0 || blacklist.count(path) > 0)
60 return;
61 if (whitelist.size() > 0 && whitelist.count(id) == 0 && whitelist.count(path) == 0 && !path_ok) {
62 fprintf(stderr, "Automatically added to blacklist: %s\n", path.c_str());
63 blacklist.insert(id);
64 return;
65 }
66
67 fprintf(f, "%s%s", indent.c_str(), id.c_str());
68 if (!args.empty() || !children.empty()) {
69 fprintf(f, "(");
70 for (size_t i = 0; i < args.size(); i++)
71 fprintf(f, "%s%s", i > 0 ? ", " : "", args[i].c_str());
72 fprintf(f, ")");
73 }
74 if (!value.empty())
75 fprintf(f, " : %s", value.c_str());
76 if (!children.empty()) {
77 fprintf(f, " {\n");
78 for (size_t i = 0; i < children.size(); i++)
79 children[i]->dump(f, indent + " ", path, path_ok);
80 fprintf(f, "%s}\n", indent.c_str());
81 } else
82 fprintf(f, " ;\n");
83 }
84
85 int LibertyParser::lexer(std::string &str)
86 {
87 int c;
88
89 do {
90 c = f.get();
91 } while (c == ' ' || c == '\t' || c == '\r');
92
93 if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') {
94 str = c;
95 while (1) {
96 c = f.get();
97 if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']')
98 str += c;
99 else
100 break;
101 }
102 f.unget();
103 if (str == "+" || str == "-") {
104 /* Single operator is not an identifier */
105 // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str());
106 return str[0];
107 }
108 else {
109 // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str());
110 return 'v';
111 }
112 }
113
114 if (c == '"') {
115 str = "";
116 while (1) {
117 c = f.get();
118 if (c == '\n')
119 line++;
120 if (c == '"')
121 break;
122 str += c;
123 }
124 // fprintf(stderr, "LEX: string >>%s<<\n", str.c_str());
125 return 'v';
126 }
127
128 if (c == '/') {
129 c = f.get();
130 if (c == '*') {
131 int last_c = 0;
132 while (c > 0 && (last_c != '*' || c != '/')) {
133 last_c = c;
134 c = f.get();
135 if (c == '\n')
136 line++;
137 }
138 return lexer(str);
139 } else if (c == '/') {
140 while (c > 0 && c != '\n')
141 c = f.get();
142 line++;
143 return lexer(str);
144 }
145 f.unget();
146 // fprintf(stderr, "LEX: char >>/<<\n");
147 return '/';
148 }
149
150 if (c == '\\') {
151 c = f.get();
152 if (c == '\r')
153 c = f.get();
154 if (c == '\n')
155 return lexer(str);
156 f.unget();
157 return '\\';
158 }
159
160 if (c == '\n') {
161 line++;
162 return 'n';
163 }
164
165 // if (c >= 32 && c < 255)
166 // fprintf(stderr, "LEX: char >>%c<<\n", c);
167 // else
168 // fprintf(stderr, "LEX: char %d\n", c);
169 return c;
170 }
171
172 LibertyAst *LibertyParser::parse()
173 {
174 std::string str;
175
176 int tok = lexer(str);
177
178 while (tok == 'n')
179 tok = lexer(str);
180
181 if (tok == '}' || tok < 0)
182 return NULL;
183
184 if (tok != 'v')
185 error();
186
187 LibertyAst *ast = new LibertyAst;
188 ast->id = str;
189
190 while (1)
191 {
192 tok = lexer(str);
193
194 if (tok == ';')
195 break;
196
197 if (tok == 'n')
198 continue;
199
200 if (tok == ':' && ast->value.empty()) {
201 tok = lexer(ast->value);
202 if (tok != 'v')
203 error();
204 tok = lexer(str);
205 while (tok == '+' || tok == '-' || tok == '*' || tok == '/') {
206 ast->value += tok;
207 tok = lexer(str);
208 if (tok != 'v')
209 error();
210 ast->value += str;
211 tok = lexer(str);
212 }
213 if (tok == ';')
214 break;
215 else
216 error();
217 continue;
218 }
219
220 if (tok == '(') {
221 while (1) {
222 std::string arg;
223 tok = lexer(arg);
224 if (tok == ',')
225 continue;
226 if (tok == ')')
227 break;
228 if (tok != 'v')
229 error();
230 ast->args.push_back(arg);
231 }
232 continue;
233 }
234
235 if (tok == '{') {
236 while (1) {
237 LibertyAst *child = parse();
238 if (child == NULL)
239 break;
240 ast->children.push_back(child);
241 }
242 break;
243 }
244
245 error();
246 }
247
248 return ast;
249 }
250
251 #ifndef FILTERLIB
252
253 void LibertyParser::error()
254 {
255 log_error("Syntax error in liberty file on line %d.\n", line);
256 }
257
258 #else
259
260 void LibertyParser::error()
261 {
262 fprintf(stderr, "Syntax error in liberty file on line %d.\n", line);
263 exit(1);
264 }
265
266 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
267
268 #define CHECK_NV(result, check) \
269 do { \
270 auto _R = (result); \
271 if (!(_R check)) { \
272 fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
273 #result, (long int)_R, #check, __FILE__, __LINE__); \
274 abort(); \
275 } \
276 } while(0)
277
278 #define CHECK_COND(result) \
279 do { \
280 if (!(result)) { \
281 fprintf(stderr, "Error from '%s' in %s:%d.\n", \
282 #result, __FILE__, __LINE__); \
283 abort(); \
284 } \
285 } while(0)
286
287 /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
288
289 LibertyAst *find_non_null(LibertyAst *node, const char *name)
290 {
291 LibertyAst *ret = node->find(name);
292 if (ret == NULL)
293 fprintf(stderr, "Error: expected to find `%s' node.\n", name);
294 return ret;
295 }
296
297 std::string func2vl(std::string str)
298 {
299 for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
300 char c_left = pos > 0 ? str[pos-1] : ' ';
301 char c_right = pos+1 < str.size() ? str[pos+1] : ' ';
302 if (std::string("\" \t*+").find(c_left) != std::string::npos)
303 str.erase(pos, 1);
304 else if (std::string("\" \t*+").find(c_right) != std::string::npos)
305 str.erase(pos, 1);
306 else
307 str[pos] = '*';
308 }
309
310 std::vector<size_t> group_start;
311 for (size_t pos = 0; pos < str.size(); pos++) {
312 if (str[pos] == '(')
313 group_start.push_back(pos);
314 if (str[pos] == ')' && group_start.size() > 0) {
315 if (pos+1 < str.size() && str[pos+1] == '\'') {
316 std::string group = str.substr(group_start.back(), pos-group_start.back()+1);
317 str[group_start.back()] = '~';
318 str.replace(group_start.back()+1, group.size(), group);
319 pos++;
320 }
321 group_start.pop_back();
322 }
323 if (str[pos] == '\'' && pos > 0) {
324 size_t start = str.find_last_of("()'*+^&| ", pos-1)+1;
325 std::string group = str.substr(start, pos-start);
326 str[start] = '~';
327 str.replace(start+1, group.size(), group);
328 }
329 if (str[pos] == '*')
330 str[pos] = '&';
331 if (str[pos] == '+')
332 str[pos] = '|';
333 }
334
335 return str;
336 }
337
338 void event2vl(LibertyAst *ast, std::string &edge, std::string &expr)
339 {
340 edge.clear();
341 expr.clear();
342
343 if (ast != NULL) {
344 expr = func2vl(ast->value);
345 if (expr.size() > 0 && expr[0] == '~')
346 edge = "negedge " + expr.substr(1);
347 else
348 edge = "posedge " + expr;
349 }
350 }
351
352 void clear_preset_var(std::string var, std::string type)
353 {
354 if (type.find('L') != std::string::npos) {
355 printf(" %s <= 0;\n", var.c_str());
356 return;
357 }
358 if (type.find('H') != std::string::npos) {
359 printf(" %s <= 1;\n", var.c_str());
360 return;
361 }
362 if (type.find('T') != std::string::npos) {
363 printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
364 return;
365 }
366 if (type.find('X') != std::string::npos) {
367 printf(" %s <= 'bx;\n", var.c_str());
368 return;
369 }
370 }
371
372 void gen_verilogsim_cell(LibertyAst *ast)
373 {
374 if (ast->find("statetable") != NULL)
375 return;
376
377 CHECK_NV(ast->args.size(), == 1);
378 printf("module %s (", ast->args[0].c_str());
379 bool first = true;
380 for (auto child : ast->children) {
381 if (child->id != "pin")
382 continue;
383 CHECK_NV(child->args.size(), == 1);
384 printf("%s%s", first ? "" : ", ", child->args[0].c_str());
385 first = false;
386 }
387 printf(");\n");
388
389 for (auto child : ast->children) {
390 if (child->id != "ff" && child->id != "latch")
391 continue;
392 printf(" reg ");
393 first = true;
394 for (auto arg : child->args) {
395 printf("%s%s", first ? "" : ", ", arg.c_str());
396 first = false;
397 }
398 printf(";\n");
399 }
400
401 for (auto child : ast->children) {
402 if (child->id != "pin")
403 continue;
404 CHECK_NV(child->args.size(), == 1);
405 LibertyAst *dir = find_non_null(child, "direction");
406 LibertyAst *func = child->find("function");
407 printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str());
408 if (func != NULL)
409 printf(" assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str());
410 }
411
412 for (auto child : ast->children)
413 {
414 if (child->id != "ff" || child->args.size() != 2)
415 continue;
416
417 std::string iq_var = child->args[0];
418 std::string iqn_var = child->args[1];
419
420 std::string clock_edge, clock_expr;
421 event2vl(child->find("clocked_on"), clock_edge, clock_expr);
422
423 std::string clear_edge, clear_expr;
424 event2vl(child->find("clear"), clear_edge, clear_expr);
425
426 std::string preset_edge, preset_expr;
427 event2vl(child->find("preset"), preset_edge, preset_expr);
428
429 std::string edge = "";
430 if (!clock_edge.empty())
431 edge += (edge.empty() ? "" : ", ") + clock_edge;
432 if (!clear_edge.empty())
433 edge += (edge.empty() ? "" : ", ") + clear_edge;
434 if (!preset_edge.empty())
435 edge += (edge.empty() ? "" : ", ") + preset_edge;
436
437 if (edge.empty())
438 continue;
439
440 printf(" always @(%s) begin\n", edge.c_str());
441
442 const char *else_prefix = "";
443 if (!clear_expr.empty() && !preset_expr.empty()) {
444 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
445 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
446 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
447 printf(" end\n");
448 else_prefix = "else ";
449 }
450 if (!clear_expr.empty()) {
451 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
452 printf(" %s <= 0;\n", iq_var.c_str());
453 printf(" %s <= 1;\n", iqn_var.c_str());
454 printf(" end\n");
455 else_prefix = "else ";
456 }
457 if (!preset_expr.empty()) {
458 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
459 printf(" %s <= 1;\n", iq_var.c_str());
460 printf(" %s <= 0;\n", iqn_var.c_str());
461 printf(" end\n");
462 else_prefix = "else ";
463 }
464 if (*else_prefix)
465 printf(" %sbegin\n", else_prefix);
466 std::string expr = find_non_null(child, "next_state")->value;
467 printf(" // %s\n", expr.c_str());
468 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
469 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
470 if (*else_prefix)
471 printf(" end\n");
472
473 printf(" end\n");
474 }
475
476 for (auto child : ast->children)
477 {
478 if (child->id != "latch" || child->args.size() != 2)
479 continue;
480
481 std::string iq_var = child->args[0];
482 std::string iqn_var = child->args[1];
483
484 std::string enable_edge, enable_expr;
485 event2vl(child->find("enable"), enable_edge, enable_expr);
486
487 std::string clear_edge, clear_expr;
488 event2vl(child->find("clear"), clear_edge, clear_expr);
489
490 std::string preset_edge, preset_expr;
491 event2vl(child->find("preset"), preset_edge, preset_expr);
492
493 printf(" always @* begin\n");
494
495 const char *else_prefix = "";
496 if (!clear_expr.empty() && !preset_expr.empty()) {
497 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
498 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
499 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
500 printf(" end\n");
501 else_prefix = "else ";
502 }
503 if (!clear_expr.empty()) {
504 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
505 printf(" %s <= 0;\n", iq_var.c_str());
506 printf(" %s <= 1;\n", iqn_var.c_str());
507 printf(" end\n");
508 else_prefix = "else ";
509 }
510 if (!preset_expr.empty()) {
511 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
512 printf(" %s <= 1;\n", iq_var.c_str());
513 printf(" %s <= 0;\n", iqn_var.c_str());
514 printf(" end\n");
515 else_prefix = "else ";
516 }
517 if (!enable_expr.empty()) {
518 printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str());
519 std::string expr = find_non_null(child, "data_in")->value;
520 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
521 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
522 printf(" end\n");
523 else_prefix = "else ";
524 }
525
526 printf(" end\n");
527 }
528
529 printf("endmodule\n");
530 }
531
532 void gen_verilogsim(LibertyAst *ast)
533 {
534 CHECK_COND(ast->id == "library");
535
536 for (auto child : ast->children)
537 if (child->id == "cell" && !child->find("dont_use"))
538 gen_verilogsim_cell(child);
539 }
540
541 void usage()
542 {
543 fprintf(stderr, "Usage: filterlib [rules-file [liberty-file]]\n");
544 fprintf(stderr, " or: filterlib -verilogsim [liberty-file]\n");
545 exit(1);
546 }
547
548 int main(int argc, char **argv)
549 {
550 bool flag_verilogsim = false;
551
552 if (argc > 3)
553 usage();
554
555 if (argc > 1)
556 {
557 if (!strcmp(argv[1], "-verilogsim"))
558 flag_verilogsim = true;
559 if (!strcmp(argv[1], "-") || !strcmp(argv[1], "-verilogsim"))
560 {
561 LibertyAst::whitelist.insert("/library");
562 LibertyAst::whitelist.insert("/library/cell");
563 LibertyAst::whitelist.insert("/library/cell/area");
564 LibertyAst::whitelist.insert("/library/cell/cell_footprint");
565 LibertyAst::whitelist.insert("/library/cell/dont_touch");
566 LibertyAst::whitelist.insert("/library/cell/dont_use");
567 LibertyAst::whitelist.insert("/library/cell/ff");
568 LibertyAst::whitelist.insert("/library/cell/ff/*");
569 LibertyAst::whitelist.insert("/library/cell/latch");
570 LibertyAst::whitelist.insert("/library/cell/latch/*");
571 LibertyAst::whitelist.insert("/library/cell/pin");
572 LibertyAst::whitelist.insert("/library/cell/pin/clock");
573 LibertyAst::whitelist.insert("/library/cell/pin/direction");
574 LibertyAst::whitelist.insert("/library/cell/pin/driver_type");
575 LibertyAst::whitelist.insert("/library/cell/pin/function");
576 LibertyAst::whitelist.insert("/library/cell/pin_opposite");
577 LibertyAst::whitelist.insert("/library/cell/pin/state_function");
578 LibertyAst::whitelist.insert("/library/cell/pin/three_state");
579 LibertyAst::whitelist.insert("/library/cell/statetable");
580 LibertyAst::whitelist.insert("/library/cell/statetable/*");
581 }
582 else
583 {
584 FILE *f = fopen(argv[1], "r");
585 if (f == NULL) {
586 fprintf(stderr, "Can't open rules file `%s'.\n", argv[1]);
587 usage();
588 }
589
590 char buffer[1024];
591 while (fgets(buffer, 1024, f) != NULL)
592 {
593 char mode = 0;
594 std::string id;
595 for (char *p = buffer; *p; p++)
596 {
597 if (*p == '-' || *p == '+') {
598 if (mode != 0)
599 goto syntax_error;
600 mode = *p;
601 continue;
602 }
603 if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#') {
604 if (!id.empty()) {
605 if (mode == '-')
606 LibertyAst::blacklist.insert(id);
607 else
608 if (mode == '+')
609 LibertyAst::whitelist.insert(id);
610 else
611 goto syntax_error;
612 }
613 id.clear();
614 if (*p == '#')
615 break;
616 continue;
617 }
618 id += *p;
619 continue;
620
621 syntax_error:
622 fprintf(stderr, "Syntax error in rules file:\n%s", buffer);
623 exit(1);
624 }
625 }
626 }
627 }
628
629 std::istream *f = &std::cin;
630
631 if (argc == 3) {
632 std::ifstream *ff = new std::ifstream;
633 ff->open(argv[2]);
634 if (ff->fail()) {
635 delete ff;
636 fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
637 usage();
638 }
639 f = ff;
640 }
641
642 LibertyParser parser(*f);
643 if (parser.ast) {
644 if (flag_verilogsim)
645 gen_verilogsim(parser.ast);
646 else
647 parser.ast->dump(stdout);
648 }
649
650 if (argc == 3)
651 delete f;
652
653 return 0;
654 }
655
656 #endif
657