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