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