HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
liberty_parser.cpp
Go to the documentation of this file.
2 
7 
8 #include <fstream>
9 
10 // TODO remove LUT parsing
11 
12 namespace hal
13 {
14  Result<std::unique_ptr<GateLibrary>> LibertyParser::parse(const std::filesystem::path& file_path)
15  {
16  m_path = file_path;
17 
18  {
19  std::ifstream ifs;
20  ifs.open(m_path.string(), std::ifstream::in);
21  if (!ifs.is_open())
22  {
23  return ERR("could not parse Liberty file '" + m_path.string() + "' : unable to open file");
24  }
25  m_fs << ifs.rdbuf();
26  ifs.close();
27  }
28 
29  // tokenize file
30  tokenize();
31 
32  // parse tokens into intermediate format
33  try
34  {
35  if (auto res = parse_tokens(); res.is_error())
36  {
37  return ERR_APPEND(res.get_error(), "could not parse Liberty file '" + file_path.string() + "': unable to parse tokens");
38  }
39  }
41  {
42  if (e.line_number != (u32)-1)
43  {
44  return ERR("could not parse Liberty file '" + m_path.string() + "': " + e.message + " (line " + std::to_string(e.line_number) + ")");
45  }
46  else
47  {
48  return ERR("could not parse Liberty file '" + m_path.string() + "': " + e.message);
49  }
50  }
51 
52  return OK(std::move(m_gate_lib));
53  }
54 
55  void LibertyParser::tokenize()
56  {
57  std::string delimiters = "{}()[];:\",";
58  std::string current_token;
59  u32 line_number = 0;
60 
61  std::string line;
62  bool in_string = false;
63  bool was_in_string = false;
64  bool multi_line_comment = false;
65 
66  std::vector<Token<std::string>> parsed_tokens;
67 
68  while (std::getline(m_fs, line))
69  {
70  line_number++;
71  this->remove_comments(line, multi_line_comment);
72 
73  for (char c : line)
74  {
75  if (c == '\"')
76  {
77  was_in_string = true;
78  in_string = !in_string;
79  continue;
80  }
81 
82  if (std::isspace(c) && !in_string)
83  {
84  continue;
85  }
86 
87  if (delimiters.find(c) == std::string::npos || in_string)
88  {
89  current_token += c;
90  }
91  else
92  {
93  if (was_in_string || !current_token.empty())
94  {
95  parsed_tokens.emplace_back(line_number, current_token);
96  current_token.clear();
97  was_in_string = false;
98  }
99 
100  if (!std::isspace(c))
101  {
102  parsed_tokens.emplace_back(line_number, std::string(1, c));
103  }
104  }
105  }
106  if (!current_token.empty())
107  {
108  parsed_tokens.emplace_back(line_number, current_token);
109  current_token.clear();
110  }
111  }
112 
113  m_token_stream = TokenStream<std::string>(parsed_tokens, {"(", "{"}, {")", "}"});
114  }
115 
116  Result<std::monostate> LibertyParser::parse_tokens()
117  {
118  m_token_stream.consume("library", true);
119  m_token_stream.consume("(", true);
120  auto lib_name = m_token_stream.consume();
121  m_token_stream.consume(")", true);
122  m_token_stream.consume("{", true);
123  m_gate_lib = std::make_unique<GateLibrary>(m_path, lib_name.string);
124  auto library_str = m_token_stream.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, false);
125  m_token_stream.consume("}", false);
126 
127  do
128  {
129  auto next_token = library_str.consume();
130  if (next_token == "{")
131  {
132  library_str.consume_until("}");
133  library_str.consume("}");
134  }
135  else if (next_token == "cell" && library_str.peek() == "(")
136  {
137  if (auto cell = parse_cell(library_str); cell.is_error())
138  {
139  return ERR_APPEND(cell.get_error(), "could not parse tokens: unable to parse cell (line " + std::to_string(next_token.number) + ")");
140  }
141  else
142  {
143  if (auto res = construct_gate_type(cell.get()); res.is_error())
144  {
145  return ERR_APPEND(res.get_error(), "could not parse tokens: unable to construct gate type (line " + std::to_string(next_token.number) + ")");
146  }
147  }
148  }
149  else if (next_token == "type" && library_str.peek() == "(")
150  {
151  if (auto res = parse_type(library_str); res.is_error())
152  {
153  return ERR_APPEND(res.get_error(), "could not parse tokens: unable to parse type (line " + std::to_string(next_token.number) + ")");
154  }
155  else
156  {
157  auto type = res.get();
158  m_bus_types[type.name] = std::move(type);
159  }
160  }
161  } while (library_str.remaining() > 0);
162 
163  if (const u32 unparsed = m_token_stream.remaining(); unparsed == 0)
164  {
165  return OK({});
166  }
167  else
168  {
169  return ERR("could not parse tokens: " + std::to_string(unparsed) + " unparsed tokens remaining");
170  }
171  }
172 
173  Result<LibertyParser::type_group> LibertyParser::parse_type(TokenStream<std::string>& str)
174  {
175  type_group type;
176  type.line_number = str.peek().number;
177  str.consume("(", true);
178  type.name = str.consume().string;
179  str.consume(")", true);
180  str.consume("{", true);
181  auto type_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
182  str.consume("}", true);
183 
184  type.start_index = 0;
185  type.width = 1;
186  type.ascending = true;
187  while (type_str.remaining() > 0)
188  {
189  auto next_token = type_str.consume();
190  if (next_token == "{")
191  {
192  type_str.consume_until("}");
193  type_str.consume("}");
194  }
195  else if (next_token == "base_type")
196  {
197  type_str.consume(":", true);
198  type_str.consume("array", true);
199  }
200  else if (next_token == "data_type")
201  {
202  type_str.consume(":", true);
203  type_str.consume("bit", true);
204  }
205  else if (next_token == "bit_width")
206  {
207  type_str.consume(":", true);
208  type.width = std::stol(type_str.consume().string);
209  }
210  else if (next_token == "bit_from")
211  {
212  type_str.consume(":", true);
213  type.start_index = std::stol(type_str.consume().string);
214  }
215  else if (next_token == "bit_to")
216  {
217  // the value is implied by 'bit_from', 'bit_width', and 'downto', but must still be consumed
218  type_str.consume(":", true);
219  type_str.consume_until(";");
220  }
221  else if (next_token == "downto")
222  {
223  type_str.consume(":", true);
224  auto bval = type_str.consume();
225  if (bval == "false")
226  {
227  type.ascending = true;
228  }
229  else if (bval == "true")
230  {
231  type.ascending = false;
232  }
233  else
234  {
235  return ERR("could not parse type '" + type.name + "': invalid Boolean value '" + bval.string + "' (line " + std::to_string(bval.number) + ")");
236  }
237  }
238  else
239  {
240  return ERR("could not parse type '" + type.name + "': invalid token '" + next_token.string + "' (line " + std::to_string(next_token.number) + ")");
241  }
242  type_str.consume(";", true);
243  }
244  return OK(type);
245  }
246 
247  Result<LibertyParser::cell_group> LibertyParser::parse_cell(TokenStream<std::string>& str)
248  {
249  cell_group cell;
250 
251  cell.line_number = str.peek().number;
252  str.consume("(", true);
253  cell.name = str.consume().string;
254  str.consume(")", true);
255  str.consume("{", true);
256  auto cell_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
257  str.consume("}", true);
258 
259  if (const auto cell_it = m_cell_names.find(cell.name); cell_it != m_cell_names.end())
260  {
261  return ERR("could not parse cell '" + cell.name + "': a cell with that name already exists");
262  }
263 
264  m_cell_names.insert(cell.name);
265 
266  while (cell_str.remaining() > 0)
267  {
268  auto next_token = cell_str.consume();
269  if (next_token == "{")
270  {
271  cell_str.consume_until("}");
272  cell_str.consume("}");
273  }
274  else if (next_token == "pin")
275  {
276  if (auto pin = parse_pin(cell_str, cell); pin.is_error())
277  {
278  return ERR_APPEND(pin.get_error(), "could not parse cell '" + cell.name + "': failed to parse 'pin' group (line " + std::to_string(next_token.number) + ")");
279  }
280  else
281  {
282  cell.pins.push_back(pin.get());
283  }
284  }
285  else if (next_token == "pg_pin")
286  {
287  if (auto pin = parse_pg_pin(cell_str, cell); pin.is_ok())
288  {
289  cell.pins.push_back(pin.get());
290  }
291  }
292  else if (next_token == "bus")
293  {
294  if (auto res = parse_bus(cell_str, cell); res.is_error())
295  {
296  return ERR_APPEND(res.get_error(), "could not parse cell '" + cell.name + "': failed to parse 'bus' group (line " + std::to_string(next_token.number) + ")");
297  }
298  else
299  {
300  auto bus = res.get();
301  cell.buses[bus.name] = std::move(bus);
302  }
303  }
304  else if (next_token == "ff")
305  {
306  if (auto ff = parse_ff(cell_str); ff.is_error())
307  {
308  return ERR_APPEND(ff.get_error(), "could not parse cell '" + cell.name + "': failed to parse 'ff' group (line " + std::to_string(next_token.number) + ")");
309  }
310  else
311  {
312  cell.properties.insert(GateTypeProperty::ff);
313  cell.properties.insert(GateTypeProperty::sequential);
314  cell.ff = ff.get();
315  }
316  }
317  else if (next_token == "latch")
318  {
319  if (auto latch = parse_latch(cell_str); latch.is_error())
320  {
321  return ERR_APPEND(latch.get_error(), "could not parse cell '" + cell.name + "': failed to parse 'latch' group (line " + std::to_string(next_token.number) + ")");
322  }
323  else
324  {
325  cell.properties.insert(GateTypeProperty::latch);
326  cell.properties.insert(GateTypeProperty::sequential);
327  cell.latch = latch.get();
328  }
329  }
330  }
331 
332  return OK(cell);
333  }
334 
335  Result<LibertyParser::pin_group> LibertyParser::parse_pin(TokenStream<std::string>& str, cell_group& cell, PinDirection direction, const std::string& external_pin_name)
336  {
337  pin_group pin;
338 
339  pin.line_number = str.peek().number;
340  str.consume("(", true);
341  auto pin_names_str = str.extract_until(")", TokenStream<std::string>::END_OF_STREAM, true, true);
342  str.consume(")", true);
343  str.consume("{", true);
344  auto pin_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
345  str.consume("}", true);
346 
347  if (pin_names_str.size() == 0)
348  {
349  return ERR("could not parse pin: no pin name given (line " + std::to_string(pin.line_number) + ")");
350  }
351 
352  do
353  {
354  std::string name = pin_names_str.consume().string;
355  if (!external_pin_name.empty() && name != external_pin_name)
356  {
357  return ERR("could not parse pin '" + name + "': pin name does not match external pin name '" + external_pin_name + "' (line " + std::to_string(pin.line_number) + ")");
358  }
359 
360  if (pin_names_str.consume("["))
361  {
362  if (pin_names_str.peek(1) == ":")
363  {
364  i32 start = std::stol(pin_names_str.consume().string);
365  pin_names_str.consume(":", true);
366  i32 end = std::stol(pin_names_str.consume().string);
367  i32 dir = (start <= end) ? 1 : -1;
368 
369  for (int i = start; i != (end + dir); i += dir)
370  {
371  auto new_name = name + "(" + std::to_string(i) + ")";
372 
373  if (const auto pin_it = cell.pin_names.find(new_name); pin_it != cell.pin_names.end())
374  {
375  return ERR("could not parse pin '" + new_name + "': a pin with that name already exists (line " + std::to_string(pin.line_number) + ")");
376  }
377 
378  cell.pin_names.insert(new_name);
379  pin.pin_names.push_back(std::move(new_name));
380  }
381  }
382  else
383  {
384  u32 index = std::stoul(pin_names_str.consume().string);
385  auto new_name = name + "(" + std::to_string(index) + ")";
386 
387  if (const auto pin_it = cell.pin_names.find(new_name); pin_it != cell.pin_names.end())
388  {
389  return ERR("could not parse pin '" + new_name + "': a pin with that name already exists (line " + std::to_string(pin.line_number) + ")");
390  }
391 
392  cell.pin_names.insert(new_name);
393  pin.pin_names.push_back(std::move(new_name));
394  }
395 
396  pin_names_str.consume("]", true);
397  }
398  else
399  {
400  if (const auto pin_it = cell.pin_names.find(name); pin_it != cell.pin_names.end())
401  {
402  return ERR("could not parse pin '" + name + "': a pin with that name already exists (line " + std::to_string(pin.line_number) + ")");
403  }
404 
405  cell.pin_names.insert(name);
406  pin.pin_names.push_back(std::move(name));
407  }
408 
409  pin_names_str.consume(",", pin_names_str.remaining() > 0);
410  } while (pin_names_str.remaining() > 0);
411 
412  pin.direction = direction;
413 
414  while (pin_str.remaining() > 0)
415  {
416  auto next_token = pin_str.consume();
417  if (next_token == "direction")
418  {
419  pin_str.consume(":", true);
420  auto direction_str = pin_str.consume().string;
421  try
422  {
423  pin.direction = enum_from_string<PinDirection>(direction_str);
424  }
425  catch (const std::runtime_error&)
426  {
427  return ERR("could not parse pin: invalid pin direction '" + direction_str + "' (line " + std::to_string(pin.line_number) + ")");
428  }
429 
430  pin_str.consume(";", true);
431  }
432  else if (next_token == "function")
433  {
434  pin_str.consume(":", true);
435  pin.function = pin_str.consume().string;
436  pin_str.consume(";", true);
437  }
438  else if (next_token == "x_function")
439  {
440  pin_str.consume(":", true);
441  pin.x_function = pin_str.consume().string;
442  pin_str.consume(";", true);
443  }
444  else if (next_token == "three_state")
445  {
446  pin_str.consume(":", true);
447  pin.z_function = pin_str.consume().string;
448  pin_str.consume(";", true);
449  }
450  else if (next_token == "clock")
451  {
452  pin_str.consume(":", true);
453  if (pin_str.consume() == "true")
454  {
455  pin.clock = true;
456  }
457  pin_str.consume(";", true);
458  }
459  }
460 
461  if (pin.direction == PinDirection::none)
462  {
463  return ERR("could not parse pin: no pin direction given (line " + std::to_string(pin.line_number) + ")");
464  }
465 
466  return OK(pin);
467  }
468 
469  Result<LibertyParser::pin_group> LibertyParser::parse_pg_pin(TokenStream<std::string>& str, cell_group& cell)
470  {
471  pin_group pin;
472 
473  pin.line_number = str.peek().number;
474  str.consume("(", true);
475  TokenStream<std::string> pin_names_str = str.extract_until(")", TokenStream<std::string>::END_OF_STREAM, true, true);
476  str.consume(")", true);
477  str.consume("{", true);
478  TokenStream<std::string> pin_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
479  str.consume("}", true);
480 
481  if (pin_names_str.size() == 0)
482  {
483  return ERR("could not parse power/ground pin: no pin name given (line " + std::to_string(pin.line_number) + ")");
484  }
485  else if (pin_names_str.size() > 1)
486  {
487  return ERR("could not parse power/ground pins '" + pin_names_str.join("").string + "': more than one pin name given (line " + std::to_string(pin.line_number) + ")");
488  }
489 
490  std::string name = pin_names_str.consume().string;
491  if (const auto pin_it = cell.pin_names.find(name); pin_it != cell.pin_names.end())
492  {
493  return ERR("could not parse power/ground pin '" + name + "': a pin with that name already exists (line " + std::to_string(pin.line_number) + ")");
494  }
495 
496  while (pin_str.remaining() > 0)
497  {
498  auto next_token = pin_str.consume();
499  if (next_token == "pg_type")
500  {
501  pin_str.consume(":", true);
502  std::string type = pin_str.consume().string;
503  if (type == "primary_power")
504  {
505  pin.power = true;
506  }
507  else if (type == "primary_ground")
508  {
509  pin.ground = true;
510  }
511  else
512  {
513  return ERR("could not parse power/ground pin '" + name + "': invalid pin type '" + type + "' (line " + std::to_string(pin.line_number) + ")");
514  }
515  pin_str.consume(";", true);
516  }
517  }
518 
519  pin.direction = PinDirection::input;
520  cell.pin_names.insert(name);
521  pin.pin_names.push_back(std::move(name));
522 
523  return OK(pin);
524  }
525 
526  Result<LibertyParser::bus_group> LibertyParser::parse_bus(TokenStream<std::string>& str, cell_group& cell)
527  {
528  bus_group bus;
529  std::vector<u32> range;
530 
531  bus.line_number = str.peek().number;
532  str.consume("(", true);
533  bus.name = str.consume().string;
534  str.consume(")", true);
535  str.consume("{", true);
536  auto bus_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
537  str.consume("}", true);
538 
539  do
540  {
541  auto next_token = bus_str.consume();
542  if (next_token == "bus_type")
543  {
544  bus_str.consume(":", true);
545  auto bus_type_str = bus_str.consume().string;
546  if (const auto& it = m_bus_types.find(bus_type_str); it == m_bus_types.end())
547  {
548  return ERR("could not parse bus '" + bus.name + "': invalid bus type '" + bus_type_str + "' (line " + std::to_string(bus.line_number) + ")");
549  }
550  else
551  {
552  auto& type = it->second;
553  bus.ascending = type.ascending;
554  bus.start_index = type.start_index;
555  i32 dir = (type.ascending ? 1 : -1);
556  for (i32 i = type.start_index; i != (i32)(type.start_index + dir * type.width); i += dir)
557  {
558  range.push_back(i);
559  }
560  }
561  bus_str.consume(";", true);
562  }
563  else if (next_token == "direction")
564  {
565  bus_str.consume(":", true);
566  auto direction_str = bus_str.consume().string;
567  if (direction_str == "input")
568  {
569  bus.direction = PinDirection::input;
570  }
571  else if (direction_str == "output")
572  {
573  bus.direction = PinDirection::output;
574  }
575  else if (direction_str == "inout")
576  {
577  bus.direction = PinDirection::inout;
578  }
579  else if (direction_str == "internal")
580  {
581  bus.direction = PinDirection::internal;
582  }
583  else
584  {
585  return ERR("could not parse bus '" + bus.name + "': invalid bus direction '" + direction_str + "' (line " + std::to_string(bus.line_number) + ")");
586  }
587  bus_str.consume(";", true);
588  }
589  else if (next_token == "pin")
590  {
591  if (auto res = parse_pin(bus_str, cell, bus.direction, bus.name); res.is_error())
592  {
593  return ERR("could not parse bus '" + bus.name + "': failed to parse pin (line " + std::to_string(bus.line_number) + ")");
594  }
595  else
596  {
597  auto pin = res.get();
598  cell.pins.push_back(pin);
599  bus.pins.push_back(std::move(pin));
600  }
601  }
602  } while (bus_str.remaining() > 0);
603 
604  for (const auto& index : range)
605  {
606  auto pin_name = bus.name + "(" + std::to_string(index) + ")";
607  bus.pin_names.push_back(pin_name);
608  bus.index_to_pin[index] = pin_name;
609  }
610 
611  if (bus.direction == PinDirection::none)
612  {
613  return ERR("could not parse bus '" + bus.name + "': no bus direction given (line " + std::to_string(bus.line_number) + ")");
614  }
615 
616  return OK(bus);
617  }
618 
619  Result<LibertyParser::ff_group> LibertyParser::parse_ff(TokenStream<std::string>& str)
620  {
621  ff_group ff;
622 
623  ff.line_number = str.peek().number;
624  str.consume("(", true);
625  ff.state1 = str.consume().string;
626  str.consume(",", true);
627  ff.state2 = str.consume().string;
628  str.consume(")", true);
629  str.consume("{", true);
630  auto ff_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
631  str.consume("}", true);
632 
633  do
634  {
635  auto next_token = ff_str.consume();
636  if (next_token == "clocked_on")
637  {
638  ff_str.consume(":", true);
639  ff.clocked_on = ff_str.consume();
640  ff_str.consume(";", true);
641  }
642  else if (next_token == "next_state")
643  {
644  ff_str.consume(":", true);
645  ff.next_state = ff_str.consume();
646  ff_str.consume(";", true);
647  }
648  else if (next_token == "clear")
649  {
650  ff_str.consume(":", true);
651  ff.clear = ff_str.consume();
652  ff_str.consume(";", true);
653  }
654  else if (next_token == "preset")
655  {
656  ff_str.consume(":", true);
657  ff.preset = ff_str.consume();
658  ff_str.consume(";", true);
659  }
660  else if (next_token == "clear_preset_var1" || next_token == "clear_preset_var2")
661  {
662  ff_str.consume(":", true);
663  Token<std::string> behav_str = ff_str.consume();
664  ff_str.consume(";", true);
665 
666  if (auto behav = enum_from_string<AsyncSetResetBehavior>(behav_str, AsyncSetResetBehavior::undef); behav != AsyncSetResetBehavior::undef)
667  {
668  if (next_token == "clear_preset_var1")
669  {
670  ff.special_behavior_var1 = behav;
671  }
672  else
673  {
674  ff.special_behavior_var2 = behav;
675  }
676  }
677  else
678  {
679  return ERR("could not parse 'ff' group: invalid clear_preset behavior '" + behav_str.string + "' (line " + std::to_string(behav_str.number) + ")");
680  }
681  }
682  } while (ff_str.remaining() > 0);
683 
684  return OK(ff);
685  }
686 
687  Result<LibertyParser::latch_group> LibertyParser::parse_latch(TokenStream<std::string>& str)
688  {
689  latch_group latch;
690 
691  latch.line_number = str.peek().number;
692  str.consume("(", true);
693  latch.state1 = str.consume().string;
694  str.consume(",", true);
695  latch.state2 = str.consume().string;
696  str.consume(")", true);
697  str.consume("{", true);
698  auto latch_str = str.extract_until("}", TokenStream<std::string>::END_OF_STREAM, true, true);
699  str.consume("}", true);
700 
701  do
702  {
703  auto next_token = latch_str.consume();
704  if (next_token == "enable")
705  {
706  latch_str.consume(":", true);
707  latch.enable = latch_str.consume();
708  latch_str.consume(";", true);
709  }
710  else if (next_token == "data_in")
711  {
712  latch_str.consume(":", true);
713  latch.data_in = latch_str.consume();
714  latch_str.consume(";", true);
715  }
716  else if (next_token == "clear")
717  {
718  latch_str.consume(":", true);
719  latch.clear = latch_str.consume();
720  latch_str.consume(";", true);
721  }
722  else if (next_token == "preset")
723  {
724  latch_str.consume(":", true);
725  latch.preset = latch_str.consume();
726  latch_str.consume(";", true);
727  }
728  else if (next_token == "clear_preset_var1" || next_token == "clear_preset_var2")
729  {
730  latch_str.consume(":", true);
731  Token<std::string> behav_str = latch_str.consume();
732  latch_str.consume(";", true);
733 
734  if (auto behav = enum_from_string<AsyncSetResetBehavior>(behav_str, AsyncSetResetBehavior::undef); behav != AsyncSetResetBehavior::undef)
735  {
736  if (next_token == "clear_preset_var1")
737  {
738  latch.special_behavior_var1 = behav;
739  }
740  else
741  {
742  latch.special_behavior_var2 = behav;
743  }
744  }
745  else
746  {
747  return ERR("could not parse 'latch' group: invalid clear_preset behavior '" + behav_str.string + "' (line " + std::to_string(behav_str.number) + ")");
748  }
749  }
750  } while (latch_str.remaining() > 0);
751 
752  return OK(latch);
753  }
754 
755  Result<std::monostate> LibertyParser::construct_gate_type(cell_group&& cell)
756  {
757  // get input and from pin groups
758  bool has_inputs = false;
759  u32 num_outputs = 0;
760  std::string output_func;
761  for (const auto& pin : cell.pins)
762  {
763  if (pin.direction == PinDirection::input || pin.direction == PinDirection::inout)
764  {
765  if (!pin.power && !pin.ground)
766  {
767  has_inputs = true;
768  }
769  }
770  else if (pin.direction == PinDirection::output || pin.direction == PinDirection::inout)
771  {
772  num_outputs += pin.pin_names.size();
773  output_func = pin.function;
774  }
775  }
776 
777  std::unique_ptr<GateTypeComponent> parent_component = nullptr;
778  if (!has_inputs && num_outputs == 1)
779  {
780  if (output_func == "0")
781  {
782  cell.properties.insert(GateTypeProperty::combinational);
783  cell.properties.insert(GateTypeProperty::ground);
784  }
785  else if (output_func == "1")
786  {
787  cell.properties.insert(GateTypeProperty::combinational);
788  cell.properties.insert(GateTypeProperty::power);
789  }
790  }
791  else if (cell.ff.has_value())
792  {
793  if (cell.ff->clocked_on.empty() || cell.ff->next_state.empty())
794  {
795  return ERR("could not construct gate type '" + cell.name + "': missing 'clocked_on' or 'next_state' function (or both)");
796  }
797 
798  std::unique_ptr<GateTypeComponent> state_component = GateTypeComponent::create_state_component(nullptr, cell.ff->state1, cell.ff->state2);
799 
800  auto next_state_function = BooleanFunction::from_string(cell.ff->next_state);
801  if (next_state_function.is_error())
802  {
803  return ERR_APPEND(next_state_function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'next_state' function from string");
804  }
805  auto clocked_on_function = BooleanFunction::from_string(cell.ff->clocked_on);
806  if (clocked_on_function.is_error())
807  {
808  return ERR_APPEND(next_state_function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'clocked_on' function from string");
809  }
810  parent_component = GateTypeComponent::create_ff_component(std::move(state_component), next_state_function.get(), clocked_on_function.get());
811 
812  FFComponent* ff_component = parent_component->convert_to<FFComponent>();
813  if (!cell.ff->clear.empty())
814  {
815  auto clear_function = BooleanFunction::from_string(cell.ff->clear);
816  if (clear_function.is_error())
817  {
818  return ERR_APPEND(next_state_function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'clear' function from string");
819  }
820  ff_component->set_async_reset_function(clear_function.get());
821  }
822  if (!cell.ff->preset.empty())
823  {
824  auto preset_function = BooleanFunction::from_string(cell.ff->preset);
825  if (preset_function.is_error())
826  {
827  return ERR_APPEND(next_state_function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'preset' function from string");
828  }
829  ff_component->set_async_set_function(preset_function.get());
830  }
831 
832  ff_component->set_async_set_reset_behavior(cell.ff->special_behavior_var1, cell.ff->special_behavior_var2);
833 
834  for (auto& pin : cell.pins)
835  {
836  if (pin.clock == true)
837  {
838  pin.type = PinType::clock;
839  }
840  else if (pin.function == cell.ff->state1)
841  {
842  pin.type = PinType::state;
843  }
844  else if (pin.function == cell.ff->state2)
845  {
846  pin.type = PinType::neg_state;
847  }
848  }
849  }
850  else if (cell.latch.has_value())
851  {
852  std::unique_ptr<GateTypeComponent> state_component = GateTypeComponent::create_state_component(nullptr, cell.latch->state1, cell.latch->state2);
853 
854  parent_component = GateTypeComponent::create_latch_component(std::move(state_component));
855  LatchComponent* latch_component = parent_component->convert_to<LatchComponent>();
856  assert(latch_component != nullptr);
857 
858  if (!cell.latch->data_in.empty())
859  {
860  auto res = BooleanFunction::from_string(cell.latch->data_in);
861  if (res.is_error())
862  {
863  return ERR_APPEND(res.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'data_in' function from string");
864  }
865  latch_component->set_data_in_function(res.get());
866  }
867  if (!cell.latch->enable.empty())
868  {
869  auto res = BooleanFunction::from_string(cell.latch->enable);
870  if (res.is_error())
871  {
872  return ERR_APPEND(res.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'enable' function from string");
873  }
874  latch_component->set_enable_function(res.get());
875  }
876  if (!cell.latch->clear.empty())
877  {
878  auto res = BooleanFunction::from_string(cell.latch->clear);
879  if (res.is_error())
880  {
881  return ERR_APPEND(res.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'clear' function from string");
882  }
883  latch_component->set_async_reset_function(res.get());
884  }
885  if (!cell.latch->preset.empty())
886  {
887  auto res = BooleanFunction::from_string(cell.latch->preset);
888  if (res.is_error())
889  {
890  return ERR_APPEND(res.get_error(), "could not construct gate type '" + cell.name + "': failed parsing 'preset' function from string");
891  }
892  latch_component->set_async_set_function(res.get());
893  }
894 
895  latch_component->set_async_set_reset_behavior(cell.latch->special_behavior_var1, cell.latch->special_behavior_var2);
896 
897  for (auto& pin : cell.pins)
898  {
899  if (pin.clock == true)
900  {
901  pin.type = PinType::clock;
902  }
903  else if (pin.function == cell.latch->state1)
904  {
905  pin.type = PinType::state;
906  }
907  else if (pin.function == cell.latch->state2)
908  {
909  pin.type = PinType::neg_state;
910  }
911  }
912  }
913 
914  if (cell.properties.empty())
915  {
916  cell.properties.insert(GateTypeProperty::combinational);
917  }
918 
919  GateType* gt = m_gate_lib->create_gate_type(cell.name, cell.properties, std::move(parent_component));
920 
921  // get input and output pins from pin groups
922  for (auto& pin : cell.pins)
923  {
924  if (pin.power == true)
925  {
926  pin.type = PinType::power;
927  }
928 
929  if (pin.ground == true)
930  {
931  pin.type = PinType::ground;
932  }
933 
934  for (const auto& pin_name : pin.pin_names)
935  {
936  if (auto res = gt->create_pin(pin_name, pin.direction, pin.type); res.is_error())
937  {
938  return ERR_APPEND(res.get_error(), "could not construct gate type '" + cell.name + "': failed to create pin '" + pin_name + "'");
939  }
940  }
941  }
942 
943  for (const auto& [bus_name, bus_info] : cell.buses)
944  {
945  std::vector<GatePin*> pins;
946  for (const auto& pin_name : bus_info.pin_names)
947  {
948  if (auto res = gt->get_pin_by_name(pin_name); res == nullptr)
949  {
950  return ERR("could not construct gate type '" + cell.name + "': failed to get pin by name '" + pin_name + "'");
951  }
952  else
953  {
954  pins.push_back(res);
955  }
956  }
957  if (auto res = gt->create_pin_group(bus_name, pins, bus_info.direction, PinType::none, bus_info.ascending, bus_info.start_index); res.is_error())
958  {
959  return ERR_APPEND(res.get_error(), "could not construct gate type '" + cell.name + "': failed to create pin group '" + bus_name + "'");
960  }
961  }
962 
963  if (!cell.buses.empty())
964  {
965  auto functions = construct_bus_functions(cell);
966  if (functions.is_error())
967  {
968  return ERR_APPEND(functions.get_error(), "could not construct gate type '" + cell.name + "': failed to construct bus functions");
969  }
970  gt->add_boolean_functions(functions.get());
971  }
972  else
973  {
974  for (const auto& pin : cell.pins)
975  {
976  if (!pin.function.empty())
977  {
978  for (const auto& name : pin.pin_names)
979  {
980  auto function = BooleanFunction::from_string(pin.function);
981  if (function.is_error())
982  {
983  return ERR_APPEND(function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing output function from string");
984  }
985  gt->add_boolean_function(name, function.get());
986  }
987  }
988 
989  if (!pin.x_function.empty())
990  {
991  for (const auto& name : pin.pin_names)
992  {
993  auto function = BooleanFunction::from_string(pin.x_function);
994  if (function.is_error())
995  {
996  return ERR_APPEND(function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing undefined function from string");
997  }
998  gt->add_boolean_function(name + "_undefined", function.get());
999  }
1000  }
1001 
1002  if (!pin.z_function.empty())
1003  {
1004  for (const auto& name : pin.pin_names)
1005  {
1006  auto function = BooleanFunction::from_string(pin.z_function);
1007  if (function.is_error())
1008  {
1009  return ERR_APPEND(function.get_error(), "could not construct gate type '" + cell.name + "': failed parsing tristate function from string");
1010  }
1011  gt->add_boolean_function(name + "_tristate", function.get());
1012  }
1013  }
1014  }
1015  }
1016 
1017  return OK({});
1018  }
1019 
1020  void LibertyParser::remove_comments(std::string& line, bool& multi_line_comment)
1021  {
1022  bool repeat = true;
1023 
1024  while (repeat)
1025  {
1026  repeat = false;
1027 
1028  // skip empty lines
1029  if (line.empty())
1030  {
1031  break;
1032  }
1033  auto multi_line_comment_begin = line.find("/*");
1034  auto multi_line_comment_end = line.find("*/");
1035 
1036  std::string begin = "";
1037  std::string end = "";
1038 
1039  if (multi_line_comment == true)
1040  {
1041  if (multi_line_comment_end != std::string::npos)
1042  {
1043  // multi-line comment ends in current line
1044  multi_line_comment = false;
1045  line = line.substr(multi_line_comment_end + 2);
1046  repeat = true;
1047  }
1048  else
1049  {
1050  // current line entirely within multi-line comment
1051  line = "";
1052  break;
1053  }
1054  }
1055  else if (multi_line_comment_begin != std::string::npos)
1056  {
1057  if (multi_line_comment_end != std::string::npos)
1058  {
1059  // multi-line comment entirely in current line
1060  line = line.substr(0, multi_line_comment_begin) + line.substr(multi_line_comment_end + 2);
1061  repeat = true;
1062  }
1063  else
1064  {
1065  // multi-line comment starts in current line
1066  multi_line_comment = true;
1067  line = line.substr(0, multi_line_comment_begin);
1068  }
1069  }
1070  }
1071  }
1072 
1073  std::vector<std::string> LibertyParser::tokenize_function(const std::string& function)
1074  {
1075  std::string delimiters = "()[]:!'^+|&* ";
1076  std::string current_token;
1077  std::vector<std::string> res;
1078 
1079  for (char c : function)
1080  {
1081  if (delimiters.find(c) == std::string::npos)
1082  {
1083  current_token += c;
1084  }
1085  else
1086  {
1087  if (!current_token.empty())
1088  {
1089  res.push_back(current_token);
1090  current_token.clear();
1091  }
1092  res.push_back(std::string(1, c));
1093  }
1094  }
1095  if (!current_token.empty())
1096  {
1097  res.push_back(current_token);
1098  current_token.clear();
1099  }
1100 
1101  return res;
1102  }
1103 
1104  std::map<std::string, std::string> LibertyParser::expand_bus_function(const std::map<std::string, bus_group>& buses, const std::vector<std::string>& pin_names, const std::string& function)
1105  {
1106  auto tokenized_funtion = tokenize_function(function);
1107  std::map<std::string, std::string> res;
1108 
1109  for (const auto& name : pin_names)
1110  {
1111  res.emplace(name, "");
1112  }
1113 
1114  std::string tmp = "";
1115 
1116  for (u32 i = 0; i < tokenized_funtion.size(); i++)
1117  {
1118  if (const auto& it = buses.find(tokenized_funtion.at(i)); it != buses.end())
1119  {
1120  if (tokenized_funtion.size() > (i + 3) && tokenized_funtion.at(i + 1) == "[")
1121  {
1122  if (tokenized_funtion.size() > (i + 5) && tokenized_funtion.at(i + 3) == ":" && tokenized_funtion.at(i + 5) == "]")
1123  {
1124  i32 start = std::stoul(tokenized_funtion.at(i + 2));
1125  i32 end = std::stoul(tokenized_funtion.at(i + 4));
1126  i32 direction = (start < end) ? 1 : -1;
1127 
1128  for (const auto& name : pin_names)
1129  {
1130  res[name] += tmp + it->second.index_to_pin.at(start);
1131  start += direction;
1132  }
1133 
1134  i += 5;
1135  }
1136  else if (tokenized_funtion.at(i + 3) == "]")
1137  {
1138  u32 index = std::stoul(tokenized_funtion.at(i + 2));
1139 
1140  for (const auto& name : pin_names)
1141  {
1142  res[name] += tmp + it->second.index_to_pin.at(index);
1143  }
1144 
1145  i += 3;
1146  }
1147  else
1148  {
1149  log_warning("liberty_parser", "could not handle bus '{}' in function '{}' near line {}, ignoring function.", it->first, function, it->second.line_number);
1150  return {};
1151  }
1152  }
1153  else
1154  {
1155  for (u32 j = 0; j < pin_names.size(); j++)
1156  {
1157  res[pin_names.at(j)] += tmp + it->second.pin_names.at(j);
1158  }
1159  }
1160  tmp = "";
1161  }
1162  else
1163  {
1164  tmp += tokenized_funtion.at(i);
1165  }
1166  }
1167 
1168  if (!tmp.empty())
1169  {
1170  for (const auto& name : pin_names)
1171  {
1172  res[name] += tmp;
1173  }
1174  }
1175 
1176  return res;
1177  }
1178 
1179  std::string LibertyParser::prepare_pin_function(const std::map<std::string, bus_group>& buses, const std::string& function)
1180  {
1181  auto tokenized_funtion = tokenize_function(function);
1182  std::string res = "";
1183 
1184  for (u32 i = 0; i < tokenized_funtion.size(); i++)
1185  {
1186  if (const auto& it = buses.find(tokenized_funtion.at(i)); it != buses.end())
1187  {
1188  if (tokenized_funtion.size() > (i + 3) && tokenized_funtion.at(i + 1) == "[" && tokenized_funtion.at(i + 3) == "]")
1189  {
1190  u32 index = std::stoul(tokenized_funtion.at(i + 2));
1191 
1192  res += it->second.index_to_pin.at(index);
1193 
1194  i += 3;
1195  }
1196  else
1197  {
1198  log_warning("liberty_parser", "could not handle bus '{}' in function '{}' near line {}, ignoring function.", it->first, function, it->second.line_number);
1199  return "";
1200  }
1201  }
1202  else
1203  {
1204  res += tokenized_funtion.at(i);
1205  }
1206  }
1207 
1208  return res;
1209  }
1210 
1211  Result<std::unordered_map<std::string, BooleanFunction>> LibertyParser::construct_bus_functions(const cell_group& cell)
1212  {
1213  std::unordered_map<std::string, BooleanFunction> res;
1214 
1215  for (const auto& [bus_name, bus] : cell.buses)
1216  {
1217  UNUSED(bus_name);
1218 
1219  if (bus.direction != PinDirection::output && bus.direction != PinDirection::inout)
1220  {
1221  continue;
1222  }
1223 
1224  for (const auto& pin : bus.pins)
1225  {
1226  if (!pin.function.empty())
1227  {
1228  for (auto [pin_name, function] : expand_bus_function(cell.buses, pin.pin_names, pin.function))
1229  {
1230  auto bf = BooleanFunction::from_string(function);
1231  if (bf.is_error())
1232  {
1233  return ERR_APPEND(bf.get_error(), "could not construct gate type '" + cell.name + "': failed parsing output function from string");
1234  }
1235  res.emplace(pin_name, bf.get());
1236  }
1237  }
1238 
1239  if (!pin.x_function.empty())
1240  {
1241  for (auto [pin_name, function] : expand_bus_function(cell.buses, pin.pin_names, pin.x_function))
1242  {
1243  auto bf = BooleanFunction::from_string(function);
1244  if (bf.is_error())
1245  {
1246  return ERR_APPEND(bf.get_error(), "could not construct gate type '" + cell.name + "': failed parsing undefined function from string");
1247  }
1248  res.emplace(pin_name + "_undefined", bf.get());
1249  }
1250  }
1251 
1252  if (!pin.z_function.empty())
1253  {
1254  for (auto [pin_name, function] : expand_bus_function(cell.buses, pin.pin_names, pin.z_function))
1255  {
1256  auto bf = BooleanFunction::from_string(function);
1257  if (bf.is_error())
1258  {
1259  return ERR_APPEND(bf.get_error(), "could not construct gate type '" + cell.name + "': failed parsing tristate function from string");
1260  }
1261  res.emplace(pin_name + "_tristate", bf.get());
1262  }
1263  }
1264  }
1265  }
1266 
1267  for (const auto& pin : cell.pins)
1268  {
1269  if (!pin.function.empty())
1270  {
1271  if (auto function = prepare_pin_function(cell.buses, pin.function); !function.empty())
1272  {
1273  for (const auto& pin_name : pin.pin_names)
1274  {
1275  auto bf = BooleanFunction::from_string(function);
1276  if (bf.is_error())
1277  {
1278  return ERR_APPEND(bf.get_error(), "could not construct gate type '" + cell.name + "': failed parsing output function from string");
1279  }
1280  res.emplace(pin_name, bf.get());
1281  }
1282  }
1283  }
1284 
1285  if (!pin.x_function.empty())
1286  {
1287  if (auto function = prepare_pin_function(cell.buses, pin.x_function); !function.empty())
1288  {
1289  for (const auto& pin_name : pin.pin_names)
1290  {
1291  auto bf = BooleanFunction::from_string(function);
1292  if (bf.is_error())
1293  {
1294  return ERR_APPEND(bf.get_error(), "could not construct gate type '" + cell.name + "': failed parsing undefined function from string");
1295  }
1296  res.emplace(pin_name + "_undefined", bf.get());
1297  }
1298  }
1299  }
1300 
1301  if (!pin.z_function.empty())
1302  {
1303  if (auto function = prepare_pin_function(cell.buses, pin.z_function); !function.empty())
1304  {
1305  for (const auto& pin_name : pin.pin_names)
1306  {
1307  auto bf = BooleanFunction::from_string(function);
1308  if (bf.is_error())
1309  {
1310  return ERR_APPEND(bf.get_error(), "could not construct gate type '" + cell.name + "': failed parsing tristate function from string");
1311  }
1312  res.emplace(pin_name + "_tristate", bf.get());
1313  }
1314  }
1315  }
1316  }
1317 
1318  return OK(res);
1319  }
1320 } // namespace hal
static Result< BooleanFunction > from_string(const std::string &expression)
static std::unique_ptr< GateTypeComponent > create_state_component(std::unique_ptr< GateTypeComponent > component, const std::string &state_identifier, const std::string &neg_state_identifier)
static std::unique_ptr< GateTypeComponent > create_latch_component(std::unique_ptr< GateTypeComponent > component)
static std::unique_ptr< GateTypeComponent > create_ff_component(std::unique_ptr< GateTypeComponent > component, const BooleanFunction &next_state_bf, const BooleanFunction &clock_bf)
Result< std::unique_ptr< GateLibrary > > parse(const std::filesystem::path &file_path) override
u32 remaining() const
Definition: token_stream.h:494
TokenStream< T > extract_until(const T &expected, u32 end=END_OF_STREAM, bool level_aware=true, bool throw_on_error=false)
Definition: token_stream.h:308
Token< T > consume(u32 num=1)
Definition: token_stream.h:216
uint32_t u32
Definition: defines.h:41
#define UNUSED(expr)
Definition: defines.h:49
int32_t i32
Definition: defines.h:36
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
PinType type
std::vector< PinInformation > pins
PinDirection direction
std::string name