Merge pull request #480 from Fatsie/liberty_value_expression
[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 == '.') {
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 == '.')
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 ';';
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 == ';')
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 == ':' && ast->value.empty()) {
198 tok = lexer(ast->value);
199 if (tok != 'v')
200 error();
201 tok = lexer(str);
202 while (tok == '+' || tok == '-' || tok == '*' || tok == '/') {
203 ast->value += tok;
204 tok = lexer(str);
205 if (tok != 'v')
206 error();
207 ast->value += str;
208 tok = lexer(str);
209 }
210 if (tok == ';')
211 break;
212 else
213 error();
214 continue;
215 }
216
217 if (tok == '(') {
218 while (1) {
219 std::string arg;
220 tok = lexer(arg);
221 if (tok == ',')
222 continue;
223 if (tok == ')')
224 break;
225 if (tok != 'v')
226 error();
227 ast->args.push_back(arg);
228 }
229 continue;
230 }
231
232 if (tok == '{') {
233 while (1) {
234 LibertyAst *child = parse();
235 if (child == NULL)
236 break;
237 ast->children.push_back(child);
238 }
239 break;
240 }
241
242 error();
243 }
244
245 return ast;
246 }
247
248 #ifndef FILTERLIB
249
250 void LibertyParser::error()
251 {
252 log_error("Syntax error in line %d.\n", line);
253 }
254
255 #else
256
257 void LibertyParser::error()
258 {
259 fprintf(stderr, "Syntax error in line %d.\n", line);
260 exit(1);
261 }
262
263 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
264
265 #define CHECK_NV(result, check) \
266 do { \
267 auto _R = (result); \
268 if (!(_R check)) { \
269 fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
270 #result, (long int)_R, #check, __FILE__, __LINE__); \
271 abort(); \
272 } \
273 } while(0)
274
275 #define CHECK_COND(result) \
276 do { \
277 if (!(result)) { \
278 fprintf(stderr, "Error from '%s' in %s:%d.\n", \
279 #result, __FILE__, __LINE__); \
280 abort(); \
281 } \
282 } while(0)
283
284 /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
285
286 LibertyAst *find_non_null(LibertyAst *node, const char *name)
287 {
288 LibertyAst *ret = node->find(name);
289 if (ret == NULL)
290 fprintf(stderr, "Error: expected to find `%s' node.\n", name);
291 return ret;
292 }
293
294 std::string func2vl(std::string str)
295 {
296 for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) {
297 char c_left = pos > 0 ? str[pos-1] : ' ';
298 char c_right = pos+1 < str.size() ? str[pos+1] : ' ';
299 if (std::string("\" \t*+").find(c_left) != std::string::npos)
300 str.erase(pos, 1);
301 else if (std::string("\" \t*+").find(c_right) != std::string::npos)
302 str.erase(pos, 1);
303 else
304 str[pos] = '*';
305 }
306
307 std::vector<size_t> group_start;
308 for (size_t pos = 0; pos < str.size(); pos++) {
309 if (str[pos] == '(')
310 group_start.push_back(pos);
311 if (str[pos] == ')' && group_start.size() > 0) {
312 if (pos+1 < str.size() && str[pos+1] == '\'') {
313 std::string group = str.substr(group_start.back(), pos-group_start.back()+1);
314 str[group_start.back()] = '~';
315 str.replace(group_start.back()+1, group.size(), group);
316 pos++;
317 }
318 group_start.pop_back();
319 }
320 if (str[pos] == '\'' && pos > 0) {
321 size_t start = str.find_last_of("()'*+^&| ", pos-1)+1;
322 std::string group = str.substr(start, pos-start);
323 str[start] = '~';
324 str.replace(start+1, group.size(), group);
325 }
326 if (str[pos] == '*')
327 str[pos] = '&';
328 if (str[pos] == '+')
329 str[pos] = '|';
330 }
331
332 return str;
333 }
334
335 void event2vl(LibertyAst *ast, std::string &edge, std::string &expr)
336 {
337 edge.clear();
338 expr.clear();
339
340 if (ast != NULL) {
341 expr = func2vl(ast->value);
342 if (expr.size() > 0 && expr[0] == '~')
343 edge = "negedge " + expr.substr(1);
344 else
345 edge = "posedge " + expr;
346 }
347 }
348
349 void clear_preset_var(std::string var, std::string type)
350 {
351 if (type.find('L') != std::string::npos) {
352 printf(" %s <= 0;\n", var.c_str());
353 return;
354 }
355 if (type.find('H') != std::string::npos) {
356 printf(" %s <= 1;\n", var.c_str());
357 return;
358 }
359 if (type.find('T') != std::string::npos) {
360 printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
361 return;
362 }
363 if (type.find('X') != std::string::npos) {
364 printf(" %s <= 'bx;\n", var.c_str());
365 return;
366 }
367 }
368
369 void gen_verilogsim_cell(LibertyAst *ast)
370 {
371 if (ast->find("statetable") != NULL)
372 return;
373
374 CHECK_NV(ast->args.size(), == 1);
375 printf("module %s (", ast->args[0].c_str());
376 bool first = true;
377 for (auto child : ast->children) {
378 if (child->id != "pin")
379 continue;
380 CHECK_NV(child->args.size(), == 1);
381 printf("%s%s", first ? "" : ", ", child->args[0].c_str());
382 first = false;
383 }
384 printf(");\n");
385
386 for (auto child : ast->children) {
387 if (child->id != "ff" && child->id != "latch")
388 continue;
389 printf(" reg ");
390 first = true;
391 for (auto arg : child->args) {
392 printf("%s%s", first ? "" : ", ", arg.c_str());
393 first = false;
394 }
395 printf(";\n");
396 }
397
398 for (auto child : ast->children) {
399 if (child->id != "pin")
400 continue;
401 CHECK_NV(child->args.size(), == 1);
402 LibertyAst *dir = find_non_null(child, "direction");
403 LibertyAst *func = child->find("function");
404 printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str());
405 if (func != NULL)
406 printf(" assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str());
407 }
408
409 for (auto child : ast->children)
410 {
411 if (child->id != "ff" || child->args.size() != 2)
412 continue;
413
414 std::string iq_var = child->args[0];
415 std::string iqn_var = child->args[1];
416
417 std::string clock_edge, clock_expr;
418 event2vl(child->find("clocked_on"), clock_edge, clock_expr);
419
420 std::string clear_edge, clear_expr;
421 event2vl(child->find("clear"), clear_edge, clear_expr);
422
423 std::string preset_edge, preset_expr;
424 event2vl(child->find("preset"), preset_edge, preset_expr);
425
426 std::string edge = "";
427 if (!clock_edge.empty())
428 edge += (edge.empty() ? "" : ", ") + clock_edge;
429 if (!clear_edge.empty())
430 edge += (edge.empty() ? "" : ", ") + clear_edge;
431 if (!preset_edge.empty())
432 edge += (edge.empty() ? "" : ", ") + preset_edge;
433
434 if (edge.empty())
435 continue;
436
437 printf(" always @(%s) begin\n", edge.c_str());
438
439 const char *else_prefix = "";
440 if (!clear_expr.empty() && !preset_expr.empty()) {
441 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
442 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
443 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
444 printf(" end\n");
445 else_prefix = "else ";
446 }
447 if (!clear_expr.empty()) {
448 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
449 printf(" %s <= 0;\n", iq_var.c_str());
450 printf(" %s <= 1;\n", iqn_var.c_str());
451 printf(" end\n");
452 else_prefix = "else ";
453 }
454 if (!preset_expr.empty()) {
455 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
456 printf(" %s <= 1;\n", iq_var.c_str());
457 printf(" %s <= 0;\n", iqn_var.c_str());
458 printf(" end\n");
459 else_prefix = "else ";
460 }
461 if (*else_prefix)
462 printf(" %sbegin\n", else_prefix);
463 std::string expr = find_non_null(child, "next_state")->value;
464 printf(" // %s\n", expr.c_str());
465 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
466 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
467 if (*else_prefix)
468 printf(" end\n");
469
470 printf(" end\n");
471 }
472
473 for (auto child : ast->children)
474 {
475 if (child->id != "latch" || child->args.size() != 2)
476 continue;
477
478 std::string iq_var = child->args[0];
479 std::string iqn_var = child->args[1];
480
481 std::string enable_edge, enable_expr;
482 event2vl(child->find("enable"), enable_edge, enable_expr);
483
484 std::string clear_edge, clear_expr;
485 event2vl(child->find("clear"), clear_edge, clear_expr);
486
487 std::string preset_edge, preset_expr;
488 event2vl(child->find("preset"), preset_edge, preset_expr);
489
490 printf(" always @* begin\n");
491
492 const char *else_prefix = "";
493 if (!clear_expr.empty() && !preset_expr.empty()) {
494 printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
495 clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
496 clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
497 printf(" end\n");
498 else_prefix = "else ";
499 }
500 if (!clear_expr.empty()) {
501 printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
502 printf(" %s <= 0;\n", iq_var.c_str());
503 printf(" %s <= 1;\n", iqn_var.c_str());
504 printf(" end\n");
505 else_prefix = "else ";
506 }
507 if (!preset_expr.empty()) {
508 printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
509 printf(" %s <= 1;\n", iq_var.c_str());
510 printf(" %s <= 0;\n", iqn_var.c_str());
511 printf(" end\n");
512 else_prefix = "else ";
513 }
514 if (!enable_expr.empty()) {
515 printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str());
516 std::string expr = find_non_null(child, "data_in")->value;
517 printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
518 printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
519 printf(" end\n");
520 else_prefix = "else ";
521 }
522
523 printf(" end\n");
524 }
525
526 printf("endmodule\n");
527 }
528
529 void gen_verilogsim(LibertyAst *ast)
530 {
531 CHECK_COND(ast->id == "library");
532
533 for (auto child : ast->children)
534 if (child->id == "cell" && !child->find("dont_use"))
535 gen_verilogsim_cell(child);
536 }
537
538 void usage()
539 {
540 fprintf(stderr, "Usage: filterlib [rules-file [liberty-file]]\n");
541 fprintf(stderr, " or: filterlib -verilogsim [liberty-file]\n");
542 exit(1);
543 }
544
545 int main(int argc, char **argv)
546 {
547 bool flag_verilogsim = false;
548
549 if (argc > 3)
550 usage();
551
552 if (argc > 1)
553 {
554 if (!strcmp(argv[1], "-verilogsim"))
555 flag_verilogsim = true;
556 if (!strcmp(argv[1], "-") || !strcmp(argv[1], "-verilogsim"))
557 {
558 LibertyAst::whitelist.insert("/library");
559 LibertyAst::whitelist.insert("/library/cell");
560 LibertyAst::whitelist.insert("/library/cell/area");
561 LibertyAst::whitelist.insert("/library/cell/cell_footprint");
562 LibertyAst::whitelist.insert("/library/cell/dont_touch");
563 LibertyAst::whitelist.insert("/library/cell/dont_use");
564 LibertyAst::whitelist.insert("/library/cell/ff");
565 LibertyAst::whitelist.insert("/library/cell/ff/*");
566 LibertyAst::whitelist.insert("/library/cell/latch");
567 LibertyAst::whitelist.insert("/library/cell/latch/*");
568 LibertyAst::whitelist.insert("/library/cell/pin");
569 LibertyAst::whitelist.insert("/library/cell/pin/clock");
570 LibertyAst::whitelist.insert("/library/cell/pin/direction");
571 LibertyAst::whitelist.insert("/library/cell/pin/driver_type");
572 LibertyAst::whitelist.insert("/library/cell/pin/function");
573 LibertyAst::whitelist.insert("/library/cell/pin_opposite");
574 LibertyAst::whitelist.insert("/library/cell/pin/state_function");
575 LibertyAst::whitelist.insert("/library/cell/pin/three_state");
576 LibertyAst::whitelist.insert("/library/cell/statetable");
577 LibertyAst::whitelist.insert("/library/cell/statetable/*");
578 }
579 else
580 {
581 FILE *f = fopen(argv[1], "r");
582 if (f == NULL) {
583 fprintf(stderr, "Can't open rules file `%s'.\n", argv[1]);
584 usage();
585 }
586
587 char buffer[1024];
588 while (fgets(buffer, 1024, f) != NULL)
589 {
590 char mode = 0;
591 std::string id;
592 for (char *p = buffer; *p; p++)
593 {
594 if (*p == '-' || *p == '+') {
595 if (mode != 0)
596 goto syntax_error;
597 mode = *p;
598 continue;
599 }
600 if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '#') {
601 if (!id.empty()) {
602 if (mode == '-')
603 LibertyAst::blacklist.insert(id);
604 else
605 if (mode == '+')
606 LibertyAst::whitelist.insert(id);
607 else
608 goto syntax_error;
609 }
610 id.clear();
611 if (*p == '#')
612 break;
613 continue;
614 }
615 id += *p;
616 continue;
617
618 syntax_error:
619 fprintf(stderr, "Syntax error in rules file:\n%s", buffer);
620 exit(1);
621 }
622 }
623 }
624 }
625
626 std::istream *f = &std::cin;
627
628 if (argc == 3) {
629 std::ifstream *ff = new std::ifstream;
630 ff->open(argv[2]);
631 if (ff->fail()) {
632 delete ff;
633 fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]);
634 usage();
635 }
636 f = ff;
637 }
638
639 LibertyParser parser(*f);
640 if (parser.ast) {
641 if (flag_verilogsim)
642 gen_verilogsim(parser.ast);
643 else
644 parser.ast->dump(stdout);
645 }
646
647 if (argc == 3)
648 delete f;
649
650 return 0;
651 }
652
653 #endif
654