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