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