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