HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
vhdl_parser.cpp
Go to the documentation of this file.
2 
10 
11 #include <fstream>
12 #include <iomanip>
13 #include <queue>
14 
15 namespace hal
16 {
17  namespace
18  {
19 
20  } // namespace
21 
22  Result<std::monostate> VHDLParser::parse(const std::filesystem::path& file_path)
23  {
24  m_path = file_path;
25  m_entities.clear();
26  m_attribute_buffer.clear();
27  m_attribute_types.clear();
28 
29  {
30  std::ifstream ifs;
31  ifs.open(file_path.string(), std::ifstream::in);
32  if (!ifs.is_open())
33  {
34  return ERR("unable to open VHDL file '" + file_path.string() + "'");
35  }
36  m_fs << ifs.rdbuf();
37  ifs.close();
38  }
39 
40  // tokenize file
41  tokenize();
42 
43  // parse tokens into intermediate format
44  try
45  {
46  if (const auto res = parse_tokens(); res.is_error())
47  {
48  return ERR_APPEND(res.get_error(), "could not parse VHDL file '" + m_path.string() + "'");
49  }
50  }
52  {
53  if (e.line_number != (u32)-1)
54  {
55  return ERR("could not parse VHDL file '" + m_path.string() + "': " + core_strings::to<std::string>(e.message) + " near line " + std::to_string(e.line_number));
56  }
57  else
58  {
59  return ERR("could not parse VHDL file '" + m_path.string() + "': " + core_strings::to<std::string>(e.message));
60  }
61  }
62 
63  if (m_entities.empty())
64  {
65  return ERR("could not parse VHDL file '" + m_path.string() + "': it does not contain any entities");
66  }
67 
68  // expand module port identifiers, signals, and assignments
69  for (auto& [entity_name, vhdl_entity] : m_entities_by_name)
70  {
71  // expand port identifiers
72  for (const auto& port : vhdl_entity->m_ports)
73  {
74  if (!port->m_ranges.empty())
75  {
76  port->m_expanded_identifiers = expand_ranges(port->m_identifier, port->m_ranges);
77  vhdl_entity->m_expanded_port_identifiers.insert(port->m_expanded_identifiers.begin(), port->m_expanded_identifiers.end());
78  }
79  else
80  {
81  port->m_expanded_identifiers = {port->m_identifier};
82  vhdl_entity->m_expanded_port_identifiers.insert(port->m_identifier);
83  }
84  }
85 
86  // expand signals
87  for (auto& signal : vhdl_entity->m_signals)
88  {
89  if (!signal->m_ranges.empty())
90  {
91  signal->m_expanded_names = expand_ranges(signal->m_name, signal->m_ranges);
92  }
93  else
94  {
95  signal->m_expanded_names = std::vector<ci_string>({signal->m_name});
96  }
97  }
98 
99  // expand assignments
100  for (auto& assignment : vhdl_entity->m_assignments)
101  {
102  auto left_res = expand_assignment_expression(vhdl_entity, assignment.m_variable);
103  if (left_res.is_error())
104  {
105  return ERR_APPEND(left_res.get_error(), "could not parse VHDL file '" + m_path.string() + "': unable to expand signal assignment");
106  }
107  const std::vector<ci_string> left_signals = left_res.get();
108 
109  auto right_res = expand_assignment_expression(vhdl_entity, assignment.m_assignment);
110  if (right_res.is_error())
111  {
112  return ERR_APPEND(right_res.get_error(), "could not parse VHDL file '" + m_path.string() + "': unable to expand signal assignment");
113  }
114  const std::vector<ci_string> right_signals = right_res.get();
115 
116  u32 left_size = left_signals.size();
117  u32 right_size = right_signals.size();
118  if (left_signals.empty() || right_signals.empty())
119  {
120  return ERR("could not parse VHDL file '" + m_path.string() + "': failed to expand assignments within entity '" + core_strings::to<std::string>(entity_name) + "'");
121  }
122  else if (left_size != right_size)
123  {
124  return ERR("could not parse VHDL file '" + m_path.string() + "': assignment width mismatch within entity '" + core_strings::to<std::string>(entity_name) + "'");
125  }
126  else
127  {
128  for (u32 i = 0; i < right_size; i++)
129  {
130  vhdl_entity->m_expanded_assignments.push_back(std::make_pair(left_signals.at(i), right_signals.at(i)));
131  }
132  }
133  }
134  }
135 
136  // expand entity port assignments
137  for (auto& [entity_name, vhdl_entity] : m_entities_by_name)
138  {
139  for (auto& instance : vhdl_entity->m_instances)
140  {
141  if (auto entity_it = m_entities_by_name.find(instance->m_type); entity_it != m_entities_by_name.end())
142  {
143  instance->m_is_entity = true;
144 
145  if (!instance->m_port_assignments.empty())
146  {
147  // all port assignments by name
148  if (instance->m_port_assignments.front().m_port.has_value())
149  {
150  for (const auto& port_assignment : instance->m_port_assignments)
151  {
152  auto right_res = expand_assignment_expression(vhdl_entity, port_assignment.m_assignment);
153  if (right_res.is_error())
154  {
155  return ERR_APPEND(right_res.get_error(), "could not parse VHDL file '" + m_path.string() + "': unable to expand entity port assignment");
156  }
157  const std::vector<ci_string> right_port = right_res.get();
158  if (!right_port.empty())
159  {
160  std::vector<ci_string> left_port;
161  if (const identifier_t* identifier = std::get_if<identifier_t>(&(port_assignment.m_port.value())); identifier != nullptr)
162  {
163  if (const auto it = entity_it->second->m_ports_by_identifier.find(*identifier); it != entity_it->second->m_ports_by_identifier.end())
164  {
165  left_port = it->second->m_expanded_identifiers;
166  }
167  else
168  {
169  return ERR("could not parse VHDL file '" + m_path.string() + "': unable to assign signal to port '" + core_strings::to<std::string>(*identifier)
170  + "' as it is not a port of entity '" + core_strings::to<std::string>(entity_it->first) + "'");
171  }
172  }
173  else if (const ranged_identifier_t* ranged_identifier = std::get_if<ranged_identifier_t>(&(port_assignment.m_port.value())); ranged_identifier != nullptr)
174  {
175  left_port = expand_ranges(ranged_identifier->first, ranged_identifier->second);
176  }
177  else
178  {
179  return ERR("could not parse VHDL file '" + m_path.string() + "': unable to expand entity port assignment");
180  }
181 
182  if (left_port.empty())
183  {
184  return ERR("could not parse VHDL file '" + m_path.string() + "': unable to expand entity port assignment");
185  }
186 
187  u32 max_size = right_port.size() <= left_port.size() ? right_port.size() : left_port.size();
188 
189  for (u32 i = 0; i < max_size; i++)
190  {
191  instance->m_expanded_port_assignments.push_back(std::make_pair(left_port.at(i), right_port.at(i)));
192  }
193  }
194  }
195  }
196  // all port assignments by order
197  else
198  {
199  std::vector<ci_string> ports;
200  for (const auto& port : m_entities_by_name.at(instance->m_type)->m_ports)
201  {
202  ports.insert(ports.end(), port->m_expanded_identifiers.begin(), port->m_expanded_identifiers.end());
203  }
204 
205  auto port_it = ports.begin();
206 
207  for (const auto& port_assignment : instance->m_port_assignments)
208  {
209  auto right_res = expand_assignment_expression(vhdl_entity, port_assignment.m_assignment);
210  if (right_res.is_error())
211  {
212  return ERR_APPEND(right_res.get_error(), "could not parse VHDL file '" + m_path.string() + "': unable to expand entity port assignment");
213  }
214  const std::vector<ci_string> right_port = right_res.get();
215  if (!right_port.empty())
216  {
217  std::vector<ci_string> left_port;
218 
219  for (u32 i = 0; i < right_port.size() && port_it != ports.end(); i++)
220  {
221  left_port.push_back(*port_it++);
222  }
223 
224  u32 max_size = right_port.size() <= left_port.size() ? right_port.size() : left_port.size();
225 
226  for (u32 i = 0; i < max_size; i++)
227  {
228  instance->m_expanded_port_assignments.push_back(std::make_pair(left_port.at(i), right_port.at(i)));
229  }
230  }
231  }
232  }
233  }
234  }
235  }
236  }
237 
238  return OK({});
239  }
240 
242  {
243  // create empty netlist
244  std::unique_ptr<Netlist> result = netlist_factory::create_netlist(gate_library);
245  m_netlist = result.get();
246  if (m_netlist == nullptr)
247  {
248  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': failed to create empty netlist");
249  }
250 
251  m_gate_types.clear();
252  m_gnd_gate_types.clear();
253  m_vcc_gate_types.clear();
254  m_instance_name_occurrences.clear();
255  m_signal_name_occurrences.clear();
256  m_net_by_name.clear();
257  m_nets_to_merge.clear();
258  m_module_ports.clear();
259  m_module_port_by_net.clear();
260  for (const auto& vhdl_entity : m_entities)
261  {
262  for (const auto& instance : vhdl_entity->m_instances)
263  {
264  if (!instance->m_is_entity)
265  {
266  instance->m_expanded_port_assignments.clear();
267  }
268  }
269  }
270 
271  // buffer gate types
272  for (const auto& [gt_name, gt] : gate_library->get_gate_types())
273  {
274  m_gate_types[core_strings::to<ci_string>(gt_name)] = gt;
275  }
276  for (const auto& [gt_name, gt] : gate_library->get_gnd_gate_types())
277  {
278  m_gnd_gate_types[core_strings::to<ci_string>(gt_name)] = gt;
279  }
280  for (const auto& [gt_name, gt] : gate_library->get_vcc_gate_types())
281  {
282  m_vcc_gate_types[core_strings::to<ci_string>(gt_name)] = gt;
283  }
284 
285  // create const 0 and const 1 net, will be removed if unused
286  m_zero_net = m_netlist->create_net("'0'");
287  if (m_zero_net == nullptr)
288  {
289  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': failed to create zero net");
290  }
291  m_net_by_name[core_strings::to<ci_string>(m_zero_net->get_name())] = m_zero_net;
292 
293  m_one_net = m_netlist->create_net("'1'");
294  if (m_one_net == nullptr)
295  {
296  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': failed to create one net");
297  }
298  m_net_by_name[core_strings::to<ci_string>(m_one_net->get_name())] = m_one_net;
299 
300  // construct the netlist with the last module being considered the top module
301  std::map<ci_string, u32> entity_name_to_refereneces;
302  for (const auto& [_name, vhdl_entity] : m_entities_by_name)
303  {
304  for (const auto& instance : vhdl_entity->m_instances)
305  {
306  if (const auto it = m_entities_by_name.find(instance->m_type); it != m_entities_by_name.end())
307  {
308  entity_name_to_refereneces[it->first]++;
309  }
310  }
311  }
312 
313  std::vector<ci_string> top_module_candidates;
314  for (const auto& [name, _entity] : m_entities_by_name)
315  {
316  if (entity_name_to_refereneces.find(name) == entity_name_to_refereneces.end())
317  {
318  top_module_candidates.push_back(name);
319  }
320  }
321 
322  if (top_module_candidates.empty())
323  {
324  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': unable to find any top module candidates");
325  }
326 
327  if (top_module_candidates.size() > 1)
328  {
329  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': found multiple entities as candidates for the top module");
330  }
331 
332  // construct the netlist with the the top module
333  VhdlEntity* top_entity = m_entities_by_name.at(top_module_candidates.front());
334 
335  if (const auto res = construct_netlist(top_entity); res.is_error())
336  {
337  return ERR_APPEND(res.get_error(), "could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "'");
338  }
339 
340  // add global GND gate if required by any instance
341  if (m_netlist->get_gnd_gates().empty())
342  {
343  if (m_zero_net->get_num_of_destinations() > 0)
344  {
345  GateType* gnd_type = m_gnd_gate_types.begin()->second;
346  GatePin* output_pin = gnd_type->get_output_pins().front();
347  Gate* gnd = m_netlist->create_gate(m_netlist->get_unique_gate_id(), gnd_type, "global_gnd");
348 
349  if (!m_netlist->mark_gnd_gate(gnd))
350  {
351  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': failed to mark GND gate");
352  }
353 
354  if (!m_zero_net->add_source(gnd, output_pin))
355  {
356  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': could not add source to GND gate");
357  }
358  }
359  else
360  {
361  m_netlist->delete_net(m_zero_net);
362  }
363  }
364 
365  // add global VCC gate if required by any instance
366  if (m_netlist->get_vcc_gates().empty())
367  {
368  if (m_one_net->get_num_of_destinations() > 0)
369  {
370  GateType* vcc_type = m_vcc_gate_types.begin()->second;
371  GatePin* output_pin = vcc_type->get_output_pins().front();
372  Gate* vcc = m_netlist->create_gate(m_netlist->get_unique_gate_id(), vcc_type, "global_vcc");
373 
374  if (!m_netlist->mark_vcc_gate(vcc))
375  {
376  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': failed to mark VCC gate");
377  }
378 
379  if (!m_one_net->add_source(vcc, output_pin))
380  {
381  return ERR("could not instantiate VHDL netlist '" + m_path.string() + "' with gate library '" + gate_library->get_name() + "': could not add source to VCC gate");
382  }
383  }
384  else
385  {
386  m_netlist->delete_net(m_one_net);
387  }
388  }
389 
390  // delete unused nets
391  std::queue<Net*> nets_to_be_deleted;
392 
393  for (auto net : m_netlist->get_nets())
394  {
395  const u32 num_of_sources = net->get_num_of_sources();
396  const u32 num_of_destinations = net->get_num_of_destinations();
397  const bool no_source = num_of_sources == 0 && !(net->is_global_input_net() && num_of_destinations != 0);
398  const bool no_destination = num_of_destinations == 0 && !(net->is_global_output_net() && num_of_sources != 0);
399  if (no_source && no_destination)
400  {
401  m_netlist->delete_net(net);
402  }
403  }
404 
405  while (!nets_to_be_deleted.empty())
406  {
407  Net* net = nets_to_be_deleted.front();
408  nets_to_be_deleted.pop();
409  m_netlist->delete_net(net);
410  }
411 
412  m_netlist->load_gate_locations_from_data();
413 
414  return OK(std::move(result));
415  }
416 
417  // ###########################################################################
418  // ########### Parse HDL into Intermediate Format ##########
419  // ###########################################################################
420 
421  void VHDLParser::tokenize()
422  {
423  std::vector<Token<core_strings::CaseInsensitiveString>> parsed_tokens;
424  const std::string delimiters = ",(): ;=><&";
426  u32 line_number = 0;
427 
428  std::string line;
429  bool in_string = false;
430  bool escaped = false;
431 
432  while (std::getline(m_fs, line))
433  {
434  line_number++;
435  if (line.find("--") != std::string::npos)
436  {
437  line = line.substr(0, line.find("--"));
438  }
439  for (char c : utils::trim(line))
440  {
441  if (in_string == false && c == '\\')
442  {
443  escaped = !escaped;
444  continue;
445  }
446  else if (escaped && std::isspace(c))
447  {
448  escaped = false;
449  continue;
450  }
451  else if (!escaped && c == '"')
452  {
453  in_string = !in_string;
454  }
455 
456  if (delimiters.find(c) == std::string::npos || escaped || in_string)
457  {
458  current_token += c;
459  }
460  else
461  {
462  if (!current_token.empty())
463  {
464  if (parsed_tokens.size() > 1 && utils::is_digits(parsed_tokens.at(parsed_tokens.size() - 2).string) && parsed_tokens.at(parsed_tokens.size() - 1) == "."
465  && utils::is_digits(current_token))
466  {
467  parsed_tokens.pop_back();
468  parsed_tokens.back() += "." + current_token;
469  }
470  else
471  {
472  parsed_tokens.emplace_back(line_number, current_token);
473  }
474  current_token.clear();
475  }
476 
477  if (!parsed_tokens.empty())
478  {
479  if (c == '=' && parsed_tokens.back() == "<")
480  {
481  parsed_tokens.back() = "<=";
482  continue;
483  }
484  else if (c == '=' && parsed_tokens.back() == ":")
485  {
486  parsed_tokens.back() = ":=";
487  continue;
488  }
489  else if (c == '>' && parsed_tokens.back() == "=")
490  {
491  parsed_tokens.back() = "=>";
492  continue;
493  }
494  }
495 
496  if (!std::isspace(c))
497  {
498  parsed_tokens.emplace_back(line_number, core_strings::CaseInsensitiveString(1, c));
499  }
500  }
501  }
502  if (!current_token.empty())
503  {
504  parsed_tokens.emplace_back(line_number, current_token);
505  current_token.clear();
506  }
507  }
508  m_token_stream = TokenStream(parsed_tokens, {"("}, {")"});
509  }
510 
511  Result<std::monostate> VHDLParser::parse_tokens()
512  {
513  while (m_token_stream.remaining() > 0)
514  {
515  if (m_token_stream.peek() == "library" || m_token_stream.peek() == "use")
516  {
517  parse_library();
518  }
519  else if (m_token_stream.peek() == "entity")
520  {
521  if (const auto res = parse_entity(); res.is_error())
522  {
523  return ERR_APPEND(res.get_error(), "could not parse tokens");
524  }
525  }
526  else if (m_token_stream.peek() == "architecture")
527  {
528  if (const auto res = parse_architecture(); res.is_error())
529  {
530  return ERR_APPEND(res.get_error(), "could not parse tokens");
531  }
532  }
533  else
534  {
535  return ERR("could not parse tokens: unexpected token '" + core_strings::to<std::string>(m_token_stream.peek().string) + "' in global scope (line "
536  + std::to_string(m_token_stream.peek().number) + ")");
537  }
538  }
539 
540  return OK({});
541  }
542 
543  void VHDLParser::parse_library()
544  {
545  if (m_token_stream.peek() == "use")
546  {
547  m_token_stream.consume("use", true);
548  auto lib = m_token_stream.consume().string;
549  m_token_stream.consume(";", true);
550 
551  // remove specific import like ".all" but keep the "."
552  lib = utils::trim(lib.substr(0, lib.rfind(".") + 1));
553  m_libraries.insert(lib);
554  }
555  else
556  {
557  m_token_stream.consume_until(";");
558  m_token_stream.consume(";", true);
559  }
560  }
561 
562  Result<std::monostate> VHDLParser::parse_entity()
563  {
564  m_token_stream.consume("entity", true);
565  const u32 line_number = m_token_stream.peek().number;
566  const ci_string entity_name = m_token_stream.consume().string;
567 
568  // verify entity name
569  if (const auto it = m_entities_by_name.find(entity_name); it != m_entities_by_name.end())
570  {
571  return ERR("could not parse entity '" + core_strings::to<std::string>(entity_name) + "' (line " + std::to_string(line_number) + "): an entity with name '"
572  + core_strings::to<std::string>(entity_name) + "' does already exist (line " + std::to_string(it->second->m_line_number) + ")");
573  }
574 
575  m_token_stream.consume("is", true);
576  auto vhdl_entity = std::make_unique<VhdlEntity>();
577  VhdlEntity* vhdl_entity_raw = vhdl_entity.get();
578  vhdl_entity_raw->m_line_number = line_number;
579  vhdl_entity_raw->m_name = entity_name;
580 
581  m_attribute_buffer.clear();
582 
583  Token<ci_string> next_token = m_token_stream.peek();
584  while (next_token != "end")
585  {
586  if (next_token == "generic")
587  {
588  m_token_stream.consume_until(";");
589  m_token_stream.consume(";", true);
590  }
591  else if (next_token == "port")
592  {
593  if (const auto res = parse_port_definitons(vhdl_entity_raw); res.is_error())
594  {
595  return ERR_APPEND(res.get_error(),
596  "could not parse entity '" + core_strings::to<std::string>(entity_name) + "': failed to parse port definition (line " + std::to_string(next_token.number) + ")");
597  }
598  }
599  else if (next_token == "attribute")
600  {
601  if (const auto res = parse_attribute(); res.is_error())
602  {
603  return ERR_APPEND(res.get_error(),
604  "could not parse entity '" + core_strings::to<std::string>(entity_name) + "': failed to parse attribute (line " + std::to_string(next_token.number) + ")");
605  }
606  }
607  else
608  {
609  return ERR("could not parse entity '" + core_strings::to<std::string>(entity_name) + "': unexpected token '" + core_strings::to<std::string>(next_token.string)
610  + "' in entity definition (line " + std::to_string(next_token.number) + ")");
611  }
612 
613  next_token = m_token_stream.peek();
614  }
615 
616  m_token_stream.consume("end", true);
617  m_token_stream.consume();
618  m_token_stream.consume(";", true);
619 
620  // add to collection of entities
621  m_entities.push_back(std::move(vhdl_entity));
622  m_entities_by_name[entity_name] = vhdl_entity_raw;
623  m_last_entity = entity_name;
624 
625  return OK({});
626  }
627 
628  Result<std::monostate> VHDLParser::parse_port_definitons(VhdlEntity* vhdl_entity)
629  {
630  // default port assignments are not supported
631  m_token_stream.consume("port", true);
632  m_token_stream.consume("(", true);
633  auto port_def_stream = m_token_stream.extract_until(")");
634 
635  while (port_def_stream.remaining() > 0)
636  {
637  std::vector<core_strings::CaseInsensitiveString> port_names;
638  // std::set<signal> signals;
639 
640  const auto line_number = port_def_stream.peek().number;
641 
642  // extract names
643  do
644  {
645  port_names.push_back(port_def_stream.consume().string);
646  } while (port_def_stream.consume(",", false));
647 
648  port_def_stream.consume(":", true);
649 
650  // extract direction
652  const ci_string direction_str = port_def_stream.consume().string;
653  if (direction_str == "in")
654  {
656  }
657  else if (direction_str == "out")
658  {
660  }
661  else if (direction_str == "inout")
662  {
664  }
665  else
666  {
667  return ERR("could not parse port definitions: invalid direction '" + core_strings::to<std::string>(direction_str) + "' for port declaration (line " + std::to_string(line_number)
668  + ")");
669  }
670 
671  // extract ranges
672  TokenStream<ci_string> port_stream = port_def_stream.extract_until(";");
673  std::vector<std::vector<u32>> ranges;
674  if (auto res = parse_signal_ranges(port_stream); res.is_error())
675  {
676  return ERR_APPEND(res.get_error(), "could not parse port definitions: unable to parse signal ranges (line " + std::to_string(line_number) + ")");
677  }
678  else
679  {
680  ranges = res.get();
681  }
682 
683  port_def_stream.consume(";", port_def_stream.remaining() > 0); // last entry has no semicolon, so no throw in that case
684 
685  for (const ci_string& port_name : port_names)
686  {
687  auto port = std::make_unique<VhdlPort>();
688  port->m_identifier = port_name;
689  port->m_direction = direction;
690  port->m_ranges = ranges;
691  vhdl_entity->m_ports_by_identifier[port->m_identifier] = port.get();
692  vhdl_entity->m_ports.push_back(std::move(port));
693 
694  if (vhdl_entity->m_signals_by_name.find(port_name) == vhdl_entity->m_signals_by_name.end())
695  {
696  auto signal = std::make_unique<VhdlSignal>();
697  signal->m_name = port_name;
698  if (!ranges.empty())
699  {
700  signal->m_ranges = ranges;
701  }
702  vhdl_entity->m_signals_by_name[port_name] = signal.get();
703  vhdl_entity->m_signals.push_back(std::move(signal));
704  }
705  }
706  }
707 
708  m_token_stream.consume(")", true);
709  m_token_stream.consume(";", true);
710 
711  return OK({});
712  }
713 
714  Result<std::monostate> VHDLParser::parse_attribute()
715  {
716  const u32 line_number = m_token_stream.peek().number;
717 
718  m_token_stream.consume("attribute", true);
719  const ci_string attribute_name = m_token_stream.consume().string;
720 
721  if (m_token_stream.peek() == ":")
722  {
723  m_token_stream.consume(":", true);
724  m_attribute_types[attribute_name] = m_token_stream.join_until(";", " ");
725  m_token_stream.consume(";", true);
726  }
727  else if (m_token_stream.peek() == "of" && m_token_stream.peek(2) == ":")
728  {
729  AttributeTarget target_class;
730  m_token_stream.consume("of", true);
731  const ci_string attribute_target = m_token_stream.consume().string;
732  m_token_stream.consume(":", true);
733  const ci_string attribute_class = m_token_stream.consume().string;
734  m_token_stream.consume("is", true);
735  ci_string attribute_value = m_token_stream.join_until(";", " ").string;
736  m_token_stream.consume(";", true);
737  ci_string attribute_type;
738 
739  if (attribute_value[0] == '\"' && attribute_value.back() == '\"')
740  {
741  attribute_value = attribute_value.substr(1, attribute_value.size() - 2);
742  }
743 
744  if (const auto type_it = m_attribute_types.find(attribute_name); type_it == m_attribute_types.end())
745  {
746  log_warning("vhdl_parser", "attribute {} has unknown base type in line {}.", attribute_name, line_number);
747  attribute_type = "unknown";
748  }
749  else
750  {
751  attribute_type = type_it->second;
752  }
753 
754  if (attribute_class == "entity")
755  {
756  target_class = AttributeTarget::ENTITY;
757  }
758  else if (attribute_class == "label")
759  {
760  target_class = AttributeTarget::INSTANCE;
761  }
762  else if (attribute_class == "signal")
763  {
764  target_class = AttributeTarget::SIGNAL;
765  }
766  else
767  {
768  log_warning("vhdl_parser", "unsupported attribute class '{}' in line {}, ignoring attribute.", attribute_class, line_number);
769  return OK({});
770  }
771 
772  VhdlDataEntry attribute;
773  attribute.m_name = core_strings::to<std::string>(attribute_name);
774  attribute.m_type = core_strings::to<std::string>(attribute_type);
775  attribute.m_value = core_strings::to<std::string>(attribute_value);
776  m_attribute_buffer[target_class].emplace(attribute_target, attribute);
777  }
778  else
779  {
780  return ERR("could not parse attribute: malformed attribute definition (line " + std::to_string(line_number) + ")");
781  }
782 
783  return OK({});
784  }
785 
786  Result<std::monostate> VHDLParser::parse_architecture()
787  {
788  m_token_stream.consume("architecture", true);
789  m_token_stream.consume();
790  m_token_stream.consume("of", true);
791 
792  u32 line_number = m_token_stream.peek().number;
793  const auto entity_name_token = m_token_stream.consume();
794 
795  if (const auto it = m_entities_by_name.find(entity_name_token.string); it == m_entities_by_name.end())
796  {
797  return ERR("could not parse architecture: architecture refers to non-existent entity '" + core_strings::to<std::string>(entity_name_token.string) + "' (line "
798  + std::to_string(entity_name_token.number) + ")");
799  }
800  else
801  {
802  VhdlEntity* vhdl_entity = it->second;
803 
804  m_token_stream.consume("is", true);
805 
806  if (const auto res = parse_architecture_header(vhdl_entity); res.is_error())
807  {
808  return ERR_APPEND(res.get_error(), "could not parse architecture: unable to parse architecture header (line " + std::to_string(line_number) + ")");
809  }
810  if (const auto res = parse_architecture_body(vhdl_entity); res.is_error())
811  {
812  return ERR_APPEND(res.get_error(), "could not parse architecture: unable to parse architecture body (line " + std::to_string(line_number) + ")");
813  }
814  if (const auto res = assign_attributes(vhdl_entity); res.is_error())
815  {
816  return ERR_APPEND(res.get_error(), "could not parse architecture: unable to assign attributes (line " + std::to_string(line_number) + ")");
817  }
818 
819  return OK({});
820  }
821  }
822 
823  Result<std::monostate> VHDLParser::parse_architecture_header(VhdlEntity* vhdl_entity)
824  {
825  auto next_token = m_token_stream.peek();
826  while (next_token != "begin")
827  {
828  if (next_token == "signal")
829  {
830  if (const auto res = parse_signal_definition(vhdl_entity); res.is_error())
831  {
832  return ERR_APPEND(res.get_error(), "could not parse architecture header: unable to parse signal definition (line " + std::to_string(next_token.number) + ")");
833  }
834  }
835  else if (next_token == "component")
836  {
837  // components are ignored
838  m_token_stream.consume("component", true);
839  const ci_string component_name = m_token_stream.consume().string;
840  m_token_stream.consume_until("end");
841  m_token_stream.consume("end", true);
842  m_token_stream.consume("component", true);
843  if (m_token_stream.peek() != ";")
844  {
845  m_token_stream.consume(component_name, true); // optional repetition of component name
846  }
847  m_token_stream.consume(";", true);
848  }
849  else if (next_token == "attribute")
850  {
851  if (const auto res = parse_attribute(); res.is_error())
852  {
853  return ERR_APPEND(res.get_error(), "could not parse architecture header: unable to parse attribute (line " + std::to_string(next_token.number) + ")");
854  }
855  }
856  else
857  {
858  return ERR("could not parse architecture header: unexpected token '" + core_strings::to<std::string>(next_token.string) + "' (line " + std::to_string(next_token.number) + ")");
859  }
860 
861  next_token = m_token_stream.peek();
862  }
863 
864  return OK({});
865  }
866 
867  Result<std::monostate> VHDLParser::parse_signal_definition(VhdlEntity* vhdl_entity)
868  {
869  m_token_stream.consume("signal", true);
870  u32 line_number = m_token_stream.peek().number;
871 
872  // extract names
873  std::vector<ci_string> signal_names;
874  do
875  {
876  signal_names.push_back(m_token_stream.consume().string);
877  } while (m_token_stream.consume(",", false));
878 
879  m_token_stream.consume(":", true);
880 
881  // extract bounds
882  TokenStream<ci_string> signal_stream = m_token_stream.extract_until(";");
883  std::vector<std::vector<u32>> ranges;
884  if (auto res = parse_signal_ranges(signal_stream); res.is_error())
885  {
886  return ERR_APPEND(res.get_error(), "could not parse signal definition: unable to parse signal ranges (line " + std::to_string(line_number) + ")");
887  }
888  else
889  {
890  ranges = res.get();
891  }
892 
893  m_token_stream.consume(";", true);
894 
895  for (const auto& signal_name : signal_names)
896  {
897  if (vhdl_entity->m_signals_by_name.find(signal_name) == vhdl_entity->m_signals_by_name.end())
898  {
899  auto signal = std::make_unique<VhdlSignal>();
900  signal->m_name = signal_name;
901  signal->m_ranges = ranges;
902  vhdl_entity->m_signals_by_name[signal_name] = signal.get();
903  vhdl_entity->m_signals.push_back(std::move(signal));
904  }
905  }
906 
907  return OK({});
908  }
909 
910  Result<std::monostate> VHDLParser::parse_architecture_body(VhdlEntity* vhdl_entity)
911  {
912  m_token_stream.consume("begin", true);
913  auto next_token = m_token_stream.peek();
914 
915  while (next_token != "end")
916  {
917  // new instance found
918  if (m_token_stream.peek(1) == ":")
919  {
920  if (const auto res = parse_instance(vhdl_entity); res.is_error())
921  {
922  return ERR_APPEND(res.get_error(),
923  "could not parse architecture body of entity '" + core_strings::to<std::string>(vhdl_entity->m_name) + "': unable to parse instance (line "
924  + std::to_string(next_token.number) + ")");
925  }
926  }
927  // not in instance -> has to be a direct assignment
928  else if (m_token_stream.find_next("<=") < m_token_stream.find_next(";"))
929  {
930  if (const auto res = parse_assignment(vhdl_entity); res.is_error())
931  {
932  return ERR_APPEND(res.get_error(),
933  "could not parse architecture body of entity '" + core_strings::to<std::string>(vhdl_entity->m_name) + "': unable to parse assignment (line "
934  + std::to_string(next_token.number) + ")");
935  }
936  }
937  else
938  {
939  return ERR("could not parse architecture body of entity '" + core_strings::to<std::string>(vhdl_entity->m_name) + "': unexpected token '"
940  + core_strings::to<std::string>(m_token_stream.peek().string) + "' (line " + std::to_string(next_token.number) + ")");
941  }
942 
943  next_token = m_token_stream.peek();
944  }
945 
946  m_token_stream.consume("end", true);
947  m_token_stream.consume();
948  m_token_stream.consume(";", true);
949 
950  return OK({});
951  }
952 
953  Result<std::monostate> VHDLParser::parse_assignment(VhdlEntity* vhdl_entity)
954  {
955  u32 line_number = m_token_stream.peek().number;
956  VhdlAssignment assignment;
957 
958  if (auto res = parse_assignment_expression(m_token_stream.extract_until("<=")); res.is_error())
959  {
960  return ERR_APPEND(res.get_error(), "could not parse assignment: unable to parse assignment expression (line " + std::to_string(line_number) + ")");
961  }
962  else
963  {
964  assignment.m_variable = res.get();
965  }
966  m_token_stream.consume("<=", true);
967  if (auto res = parse_assignment_expression(m_token_stream.extract_until(";")); res.is_error())
968  {
969  return ERR_APPEND(res.get_error(), "could not parse assignment: unable to parse assignment expression (line " + std::to_string(line_number) + ")");
970  }
971  else
972  {
973  assignment.m_assignment = res.get();
974  }
975  m_token_stream.consume(";", true);
976 
977  vhdl_entity->m_assignments.push_back(std::move(assignment));
978  return OK({});
979  }
980 
981  Result<std::monostate> VHDLParser::parse_instance(VhdlEntity* vhdl_entity)
982  {
983  auto instance = std::make_unique<VhdlInstance>();
984  u32 line_number = m_token_stream.peek().number;
985  instance->m_name = m_token_stream.consume();
986  m_token_stream.consume(":", true);
987 
988  // remove prefix from type
989  if (m_token_stream.peek() == "entity")
990  {
991  m_token_stream.consume("entity", true);
992  instance->m_type = m_token_stream.consume();
993  if (const size_t pos = instance->m_type.find('.'); pos != std::string::npos)
994  {
995  instance->m_type = instance->m_type.substr(pos + 1);
996  }
997  if (m_entities_by_name.find(instance->m_type) == m_entities_by_name.end())
998  {
999  return ERR("could not parse instance '" + core_strings::to<std::string>(instance->m_name) + "' of type '" + core_strings::to<std::string>(instance->m_type) + "': entity with name '"
1000  + core_strings::to<std::string>(instance->m_type) + "' does not exist (line " + std::to_string(line_number) + ")");
1001  }
1002  }
1003  else if (m_token_stream.peek() == "component")
1004  {
1005  m_token_stream.consume("component", true);
1006  instance->m_type = m_token_stream.consume();
1007  }
1008  else
1009  {
1010  instance->m_type = m_token_stream.consume();
1011  ci_string prefix;
1012 
1013  // find longest matching library prefix
1014  for (const auto& lib : m_libraries)
1015  {
1016  if (lib.size() > prefix.size() && utils::starts_with(instance->m_type, lib))
1017  {
1018  prefix = lib;
1019  }
1020  }
1021 
1022  // remove prefix
1023  if (!prefix.empty())
1024  {
1025  instance->m_type = instance->m_type.substr(prefix.size());
1026  }
1027  }
1028 
1029  if (m_token_stream.consume("generic"))
1030  {
1031  line_number = m_token_stream.peek().number;
1032  if (const auto res = parse_generic_assign(instance.get()); res.is_error())
1033  {
1034  return ERR_APPEND(res.get_error(),
1035  "could not parse instance '" + core_strings::to<std::string>(instance->m_name) + "' of type '" + core_strings::to<std::string>(instance->m_type)
1036  + "': unable to parse generic assignment (line " + std::to_string(line_number) + ")");
1037  }
1038  }
1039 
1040  if (m_token_stream.peek() == "port")
1041  {
1042  if (const auto res = parse_port_assign(instance.get()); res.is_error())
1043  {
1044  return ERR_APPEND(res.get_error(),
1045  "could not parse instance '" + core_strings::to<std::string>(instance->m_name) + "' of type '" + core_strings::to<std::string>(instance->m_type)
1046  + "': unable to parse port assignment (line " + std::to_string(line_number) + ")");
1047  }
1048  }
1049 
1050  vhdl_entity->m_instances_by_name[instance->m_name] = instance.get();
1051  vhdl_entity->m_instances.push_back(std::move(instance));
1052 
1053  m_token_stream.consume(";", true);
1054 
1055  return OK({});
1056  }
1057 
1058  Result<std::monostate> VHDLParser::parse_port_assign(VhdlInstance* instance)
1059  {
1060  u32 line_number = m_token_stream.peek().number;
1061  m_token_stream.consume("port", true);
1062  m_token_stream.consume("map", true);
1063  m_token_stream.consume("(", true);
1064  TokenStream<ci_string> port_stream = m_token_stream.extract_until(")");
1065  m_token_stream.consume(")", true);
1066 
1067  if (port_stream.find_next("=>") != TokenStream<ci_string>::END_OF_STREAM)
1068  {
1069  while (port_stream.remaining() > 0)
1070  {
1071  TokenStream<ci_string> left_stream = port_stream.extract_until("=>");
1072  port_stream.consume("=>", true);
1073  TokenStream<ci_string> right_stream = port_stream.extract_until(",");
1074  port_stream.consume(",", port_stream.remaining() > 0); // last entry has no comma
1075 
1076  if (!right_stream.consume("open"))
1077  {
1078  VhdlPortAssignment port_assignment;
1079 
1080  if (auto res = parse_assignment_expression(std::move(left_stream)); res.is_error())
1081  {
1082  return ERR_APPEND(res.get_error(), "could not parse port assignment: unable to parse port (line " + std::to_string(line_number) + ")");
1083  }
1084  else
1085  {
1086  // vector can only have a single entry for left side of port assignment
1087  port_assignment.m_port = res.get().front();
1088  }
1089 
1090  if (auto res = parse_assignment_expression(std::move(right_stream)); res.is_error())
1091  {
1092  return ERR_APPEND(res.get_error(), "could not parse port assignment: unable to parse assignment (line " + std::to_string(line_number) + ")");
1093  }
1094  else
1095  {
1096  port_assignment.m_assignment = res.get();
1097  }
1098 
1099  instance->m_port_assignments.push_back(std::move(port_assignment));
1100  }
1101  }
1102  }
1103  else
1104  {
1105  while (port_stream.remaining() > 0)
1106  {
1107  TokenStream<ci_string> right_stream = port_stream.extract_until(",");
1108  port_stream.consume(",", port_stream.remaining() > 0); // last entry has no comma
1109 
1110  if (!right_stream.consume("open"))
1111  {
1112  VhdlPortAssignment port_assignment;
1113 
1114  if (auto res = parse_assignment_expression(std::move(right_stream)); res.is_error())
1115  {
1116  return ERR_APPEND(res.get_error(), "could not parse port assignment: unable to parse assignment (line " + std::to_string(line_number) + ")");
1117  }
1118  else
1119  {
1120  port_assignment.m_assignment = res.get();
1121  }
1122 
1123  instance->m_port_assignments.push_back(std::move(port_assignment));
1124  }
1125  else
1126  {
1127  VhdlPortAssignment port_assignment;
1128  port_assignment.m_assignment.push_back("");
1129  instance->m_port_assignments.push_back(std::move(port_assignment));
1130  }
1131  }
1132  }
1133 
1134  return OK({});
1135  }
1136 
1137  Result<std::monostate> VHDLParser::parse_generic_assign(VhdlInstance* instance)
1138  {
1139  m_token_stream.consume("map", true);
1140  m_token_stream.consume("(", true);
1141  TokenStream<ci_string> generic_stream = m_token_stream.extract_until(")");
1142  m_token_stream.consume(")", true);
1143 
1144  while (generic_stream.remaining() > 0)
1145  {
1146  VhdlDataEntry generic;
1147 
1148  generic.m_line_number = generic_stream.peek().number;
1149  generic.m_name = core_strings::to<std::string>(generic_stream.join_until("=>", "").string);
1150  generic_stream.consume("=>", true);
1151  const auto rhs = generic_stream.join_until(",", "");
1152  generic_stream.consume(",", generic_stream.remaining() > 0); // last entry has no comma
1153 
1154  // determine data type
1155  if ((rhs == "true") || (rhs == "false"))
1156  {
1157  generic.m_value = core_strings::to<std::string>(rhs.string);
1158  generic.m_type = "boolean";
1159  }
1160  else if (utils::is_integer(rhs.string))
1161  {
1162  generic.m_value = core_strings::to<std::string>(rhs.string);
1163  generic.m_type = "integer";
1164  }
1165  else if (utils::is_floating_point(rhs.string))
1166  {
1167  generic.m_value = core_strings::to<std::string>(rhs.string);
1168  generic.m_type = "floating_point";
1169  }
1170  else if (utils::ends_with(rhs.string, ci_string("s")) || utils::ends_with(rhs.string, ci_string("sec")) || utils::ends_with(rhs.string, ci_string("min"))
1171  || utils::ends_with(rhs.string, ci_string("hr")))
1172  {
1173  generic.m_value = core_strings::to<std::string>(rhs.string);
1174  generic.m_type = "time";
1175  }
1176  else if (rhs.string.at(0) == '\"' && rhs.string.back() == '\"')
1177  {
1178  generic.m_value = core_strings::to<std::string>(rhs.string.substr(1, rhs.string.size() - 2));
1179  generic.m_type = "string";
1180  }
1181  else if (rhs.string.at(0) == '\'' && rhs.string.at(2) == '\'')
1182  {
1183  generic.m_value = core_strings::to<std::string>(rhs.string.substr(1, 1));
1184  generic.m_type = "bit_value";
1185  }
1186  else if (rhs.string.at(1) == '\"' && rhs.string.back() == '\"')
1187  {
1188  if (auto res = get_hex_from_literal(rhs); res.is_error())
1189  {
1190  return ERR_APPEND(res.get_error(), "could not parse generic assignment: unable to translate token to hexadecimal string");
1191  }
1192  else
1193  {
1194  generic.m_value = core_strings::to<std::string>(res.get());
1195  generic.m_type = "bit_vector";
1196  }
1197  }
1198  else
1199  {
1200  return ERR("could not parse generic assignment: unable to identify data type of generic map value '" + core_strings::to<std::string>(rhs.string) + "' in instance '"
1201  + core_strings::to<std::string>(instance->m_name) + "' (line " + std::to_string(generic.m_line_number) + ")");
1202  }
1203 
1204  instance->m_generics.push_back(generic);
1205  }
1206 
1207  return OK({});
1208  }
1209 
1210  Result<std::monostate> VHDLParser::assign_attributes(VhdlEntity* vhdl_entity)
1211  {
1212  for (const auto& [target_class, attributes] : m_attribute_buffer)
1213  {
1214  // entity attributes
1215  if (target_class == AttributeTarget::ENTITY)
1216  {
1217  for (const auto& [target, attribute] : attributes)
1218  {
1219  if (vhdl_entity->m_name != target)
1220  {
1221  return ERR("could not assign attributes: invalid attribute target '" + core_strings::to<std::string>(target) + "' within entity '"
1222  + core_strings::to<std::string>(vhdl_entity->m_name) + "' (line " + std::to_string(attribute.m_line_number) + ")");
1223  }
1224  else
1225  {
1226  vhdl_entity->m_attributes.push_back(attribute);
1227  }
1228  }
1229  }
1230  // instance attributes
1231  else if (target_class == AttributeTarget::INSTANCE)
1232  {
1233  for (const auto& [target, attribute] : attributes)
1234  {
1235  if (const auto instance_it = vhdl_entity->m_instances_by_name.find(target); instance_it == vhdl_entity->m_instances_by_name.end())
1236  {
1237  return ERR("could not assign attributes: invalid attribute target '" + core_strings::to<std::string>(target) + "' within entity '"
1238  + core_strings::to<std::string>(vhdl_entity->m_name) + "' (line " + std::to_string(attribute.m_line_number) + ")");
1239  }
1240  else
1241  {
1242  instance_it->second->m_attributes.push_back(attribute);
1243  }
1244  }
1245  }
1246  // signal attributes
1247  else if (target_class == AttributeTarget::SIGNAL)
1248  {
1249  for (const auto& [target, attribute] : attributes)
1250  {
1251  if (const auto signal_it = vhdl_entity->m_signals_by_name.find(target); signal_it != vhdl_entity->m_signals_by_name.end())
1252  {
1253  signal_it->second->m_attributes.push_back(attribute);
1254  }
1255  else
1256  {
1257  return ERR("could not assign attributes: invalid attribute target '" + core_strings::to<std::string>(target) + "' within entity '"
1258  + core_strings::to<std::string>(vhdl_entity->m_name) + "' (line " + std::to_string(attribute.m_line_number) + ")");
1259  }
1260  }
1261  }
1262  }
1263 
1264  return OK({});
1265  }
1266 
1267  // ###########################################################################
1268  // ########### Assemble Netlist from Intermediate Format ##########
1269  // ###########################################################################
1270 
1271  Result<std::monostate> VHDLParser::construct_netlist(VhdlEntity* top_entity)
1272  {
1273  m_netlist->set_design_name(core_strings::to<std::string>(top_entity->m_name));
1274  m_netlist->enable_automatic_net_checks(false);
1275 
1276  std::unordered_map<ci_string, u32> instantiation_count;
1277 
1278  // preparations for alias: count the occurences of all names
1279  std::queue<VhdlEntity*> q;
1280  q.push(top_entity);
1281 
1282  while (!q.empty())
1283  {
1284  VhdlEntity* entity = q.front();
1285  q.pop();
1286 
1287  instantiation_count[entity->m_name]++;
1288 
1289  // collect and count all net names in the netlist
1290  for (const auto& s : entity->m_signals)
1291  {
1292  std::vector<ci_string> expanded_names;
1293  expand_ranges_recursively(expanded_names, s->m_name, s->m_ranges, 0);
1294  for (const auto& net_name : expanded_names)
1295  {
1296  m_signal_name_occurrences[net_name]++;
1297  }
1298  }
1299 
1300  for (const auto& instance : entity->m_instances)
1301  {
1302  m_instance_name_occurrences[instance->m_name]++;
1303 
1304  // add type of instance to q if it is a module
1305  if (const auto it = m_entities_by_name.find(instance->m_type); it != m_entities_by_name.end())
1306  {
1307  q.push(it->second);
1308  }
1309  }
1310  }
1311 
1312  for (auto& [entity_name, vhdl_entity] : m_entities_by_name)
1313  {
1314  // detect unused entities
1315  if (instantiation_count[entity_name] == 0)
1316  {
1317  log_warning("vhdl_parser", "entity '{}' has been defined in the netlist but is not instantiated.", entity_name);
1318  continue;
1319  }
1320 
1321  // expand gate pin assignments
1322  for (const auto& instance : vhdl_entity->m_instances)
1323  {
1324  if (const auto gate_type_it = m_gate_types.find(instance->m_type); gate_type_it != m_gate_types.end())
1325  {
1326  if (!instance->m_port_assignments.empty())
1327  {
1328  // all port assignments by name
1329  if (instance->m_port_assignments.front().m_port.has_value())
1330  {
1331  // cache pin groups
1332  std::unordered_map<ci_string, std::vector<ci_string>> pin_groups;
1333  for (const auto pin_group : gate_type_it->second->get_pin_groups())
1334  {
1335  const auto pins = pin_group->get_pins();
1336  for (auto it = pins.rbegin(); it != pins.rend(); it++)
1337  {
1338  const auto* pin = *it;
1339  pin_groups[core_strings::to<ci_string>(pin_group->get_name())].push_back(core_strings::to<ci_string>(pin->get_name()));
1340  }
1341  }
1342 
1343  for (const auto& port_assignment : instance->m_port_assignments)
1344  {
1345  auto right_res = expand_assignment_expression(vhdl_entity, port_assignment.m_assignment);
1346  if (right_res.is_error())
1347  {
1348  return ERR_APPEND(right_res.get_error(), "could not construct netlist: unable to expand gate port assignment");
1349  }
1350  auto right_port = right_res.get();
1351 
1352  if (!right_port.empty())
1353  {
1354  std::vector<ci_string> left_port;
1355 
1356  if (const identifier_t* identifier = std::get_if<identifier_t>(&(port_assignment.m_port.value())); identifier != nullptr)
1357  {
1358  if (const auto group_it = pin_groups.find(*identifier); group_it != pin_groups.end())
1359  {
1360  left_port = group_it->second;
1361  }
1362  else
1363  {
1364  left_port.push_back(*identifier);
1365  }
1366  }
1367  else if (const ranged_identifier_t* ranged_identifier = std::get_if<ranged_identifier_t>(&(port_assignment.m_port.value())); ranged_identifier != nullptr)
1368  {
1369  left_port = expand_ranges(ranged_identifier->first, ranged_identifier->second);
1370  }
1371  else
1372  {
1373  return ERR("could not construct netlist: unable to expand gate port assignment");
1374  }
1375 
1376  if (right_port.size() != left_port.size())
1377  {
1378  return ERR("could not construct netlist: pin assignment width mismatch at instance '" + core_strings::to<std::string>(instance->m_name) + "' of gate type '"
1379  + core_strings::to<std::string>(instance->m_type) + "' within entity '" + core_strings::to<std::string>(entity_name) + "'");
1380  }
1381 
1382  for (u32 i = 0; i < left_port.size(); i++)
1383  {
1384  instance->m_expanded_port_assignments.push_back(std::make_pair(left_port.at(i), right_port.at(i)));
1385  }
1386  }
1387  }
1388  }
1389  // all port assignments by order
1390  else
1391  {
1392  // cache pins
1393  std::vector<ci_string> pins;
1394  for (const auto pin : gate_type_it->second->get_pins())
1395  {
1396  pins.push_back(core_strings::to<ci_string>(pin->get_name()));
1397  }
1398  auto pin_it = pins.begin();
1399 
1400  for (const auto& port_assignment : instance->m_port_assignments)
1401  {
1402  auto right_res = expand_assignment_expression(vhdl_entity, port_assignment.m_assignment);
1403  if (right_res.is_error())
1404  {
1405  return ERR_APPEND(right_res.get_error(), "could not construct netlist: unable to expand gate port assignment");
1406  }
1407  auto right_port = right_res.get();
1408 
1409  if (!right_port.empty())
1410  {
1411  std::vector<ci_string> left_port;
1412 
1413  for (u32 i = 0; i < right_port.size() && pin_it != pins.end(); i++)
1414  {
1415  left_port.push_back(*pin_it++);
1416  }
1417 
1418  u32 max_size = right_port.size() <= left_port.size() ? right_port.size() : left_port.size();
1419 
1420  for (u32 i = 0; i < max_size; i++)
1421  {
1422  instance->m_expanded_port_assignments.push_back(std::make_pair(left_port.at(i), right_port.at(i)));
1423  }
1424  }
1425  }
1426  }
1427  }
1428  }
1429  }
1430  }
1431 
1432  // for the top module, generate global i/o signals for all ports
1433  std::unordered_map<ci_string, ci_string> top_assignments;
1434  for (const auto& port : top_entity->m_ports)
1435  {
1436  for (const auto& expanded_port_identifier : port->m_expanded_identifiers)
1437  {
1438  const auto signal_name = get_unique_alias("", expanded_port_identifier + "__GLOBAL_IO__", m_signal_name_occurrences);
1439 
1440  Net* global_port_net = m_netlist->create_net(core_strings::to<std::string>(signal_name));
1441  if (global_port_net == nullptr)
1442  {
1443  return ERR("could not construct netlist: failed to create global I/O net '" + core_strings::to<std::string>(signal_name) + "'");
1444  }
1445 
1446  m_net_by_name[signal_name] = global_port_net;
1447 
1448  // assign global port nets to ports of top module
1449  top_assignments[expanded_port_identifier] = signal_name;
1450 
1451  if (port->m_direction == PinDirection::input || port->m_direction == PinDirection::inout)
1452  {
1453  if (!global_port_net->mark_global_input_net())
1454  {
1455  return ERR("could not construct netlist: failed to mark global I/O net '" + core_strings::to<std::string>(signal_name) + "' as global input");
1456  }
1457  }
1458 
1459  if (port->m_direction == PinDirection::output || port->m_direction == PinDirection::inout)
1460  {
1461  if (!global_port_net->mark_global_output_net())
1462  {
1463  return ERR("could not construct netlist: failed to mark global I/O net '" + core_strings::to<std::string>(signal_name) + "' as global output");
1464  }
1465  }
1466  }
1467  }
1468 
1469  if (const auto res = instantiate_entity("top_module", top_entity, nullptr, top_assignments); res.is_error())
1470  {
1471  return ERR_APPEND(res.get_error(), "could not construct netlist: unable to instantiate top module");
1472  }
1473 
1474  // merge nets without gates in between them
1475  std::unordered_map<ci_string, ci_string> merged_nets;
1476  std::unordered_map<ci_string, std::vector<ci_string>> master_to_slaves;
1477 
1478  for (auto& [master, slave] : m_nets_to_merge)
1479  {
1480  // check if master net has already been merged into other net
1481  while (true)
1482  {
1483  if (const auto master_it = merged_nets.find(master); master_it != merged_nets.end())
1484  {
1485  master = master_it->second;
1486  }
1487  else
1488  {
1489  break;
1490  }
1491  }
1492 
1493  // check if slave net has already been merged into other net
1494  while (true)
1495  {
1496  if (const auto slave_it = merged_nets.find(slave); slave_it != merged_nets.end())
1497  {
1498  slave = slave_it->second;
1499  }
1500  else
1501  {
1502  break;
1503  }
1504  }
1505 
1506  auto master_net = m_net_by_name.at(master);
1507  auto slave_net = m_net_by_name.at(slave);
1508 
1509  if (master_net == slave_net)
1510  {
1511  continue;
1512  }
1513  else if (slave_net == m_zero_net || slave_net == m_one_net)
1514  {
1515  auto* tmp_net = master_net;
1516  master_net = slave_net;
1517  slave_net = tmp_net;
1518 
1519  auto tmp_name = master;
1520  master = slave;
1521  slave = tmp_name;
1522  }
1523 
1524  // merge sources
1525  if (slave_net->is_global_input_net())
1526  {
1527  master_net->mark_global_input_net();
1528  }
1529 
1530  for (auto src : slave_net->get_sources())
1531  {
1532  Gate* src_gate = src->get_gate();
1533  GatePin* src_pin = src->get_pin();
1534 
1535  if (!slave_net->remove_source(src))
1536  {
1537  return ERR("could not construct netlist: failed to remove source from net '" + slave_net->get_name() + "' with ID " + std::to_string(slave_net->get_id()));
1538  }
1539 
1540  if (!master_net->is_a_source(src_gate, src_pin))
1541  {
1542  if (!master_net->add_source(src_gate, src_pin))
1543  {
1544  return ERR("could not construct netlist: failed to add source to net '" + master_net->get_name() + "' with ID " + std::to_string(master_net->get_id()));
1545  }
1546  }
1547  }
1548 
1549  // merge destinations
1550  if (slave_net->is_global_output_net())
1551  {
1552  master_net->mark_global_output_net();
1553  }
1554 
1555  for (auto dst : slave_net->get_destinations())
1556  {
1557  Gate* dst_gate = dst->get_gate();
1558  GatePin* dst_pin = dst->get_pin();
1559 
1560  if (!slave_net->remove_destination(dst))
1561  {
1562  return ERR("could not construct netlist: failed to remove destination from net '" + slave_net->get_name() + "' with ID " + std::to_string(slave_net->get_id()));
1563  }
1564 
1565  if (!master_net->is_a_destination(dst_gate, dst_pin))
1566  {
1567  if (!master_net->add_destination(dst_gate, dst_pin))
1568  {
1569  return ERR("could not construct netlist: failed to add destination to net '" + master_net->get_name() + "' with ID " + std::to_string(master_net->get_id()));
1570  }
1571  }
1572  }
1573 
1574  // merge generics and attributes
1575  for (const auto& [identifier, content] : slave_net->get_data_map())
1576  {
1577  if (!master_net->set_data(std::get<0>(identifier), std::get<1>(identifier), std::get<0>(content), std::get<1>(content)))
1578  {
1579  log_warning("vhdl_parser",
1580  "unable to transfer data from slave net '{}' with ID {} to master net '{}' with ID {}.",
1581  slave_net->get_name(),
1582  slave_net->get_id(),
1583  master_net->get_name(),
1584  master_net->get_id());
1585  }
1586  }
1587 
1588  // update module ports
1589  if (const auto it = m_module_port_by_net.find(slave_net); it != m_module_port_by_net.end())
1590  {
1591  for (auto [module, index] : it->second)
1592  {
1593  std::get<1>(m_module_ports.at(module).at(index)) = master_net;
1594  }
1595  m_module_port_by_net[master_net].insert(m_module_port_by_net[master_net].end(), it->second.begin(), it->second.end());
1596  m_module_port_by_net.erase(it);
1597  }
1598 
1599  m_netlist->delete_net(slave_net);
1600  m_net_by_name.erase(slave);
1601  merged_nets[slave] = master;
1602  master_to_slaves[master].push_back(slave);
1603  }
1604 
1605  // annotate all surviving master nets with the net names that where merged into them
1606  for (auto& master_net : m_netlist->get_nets())
1607  {
1608  const auto master_name = master_net->get_name();
1609 
1610  if (const auto m2s_it = master_to_slaves.find(core_strings::to<ci_string>(master_name)); m2s_it != master_to_slaves.end())
1611  {
1612  std::vector<std::vector<ci_string>> merged_slaves;
1613  auto current_slaves = m2s_it->second;
1614 
1615  while (!current_slaves.empty())
1616  {
1617  std::vector<ci_string> next_slaves;
1618  for (const auto& s : current_slaves)
1619  {
1620  if (const auto m2s_inner_it = master_to_slaves.find(s); m2s_inner_it != master_to_slaves.end())
1621  {
1622  next_slaves.insert(next_slaves.end(), m2s_inner_it->second.begin(), m2s_inner_it->second.end());
1623  }
1624  }
1625 
1626  merged_slaves.push_back(current_slaves);
1627  current_slaves = next_slaves;
1628  next_slaves.clear();
1629  }
1630 
1631  // annotate all merged slave wire names as a JSON formatted list of list of strings
1632  // each net can span a tree of "consumed" slave wire names where the nth list represents all wire names that where merged at depth n
1633  ci_string merged_str = "";
1634  bool has_merged_nets = false;
1635  for (const auto& vec : merged_slaves)
1636  {
1637  if (!vec.empty())
1638  {
1639  has_merged_nets = true;
1640  }
1641  // const auto s = utils::join(", ", vec, [](const auto e) { return '"' + e + '"'; });
1642  ci_string s = vec.empty() ? "" : vec.front();
1643  for (u32 idx = 1; idx < vec.size(); idx++)
1644  {
1645  s += ci_string(", ") + vec.at(idx);
1646  }
1647 
1648  merged_str += "[" + s + "], ";
1649  }
1650  merged_str = merged_str.substr(0, merged_str.size() - 2);
1651 
1652  if (has_merged_nets)
1653  {
1654  master_net->set_data("parser_annotation", "merged_nets", "string", "[" + core_strings::to<std::string>(merged_str) + "]");
1655  }
1656  }
1657  }
1658 
1659  // update module nets, internal nets, input nets, and output nets
1660  for (Module* module : m_netlist->get_modules())
1661  {
1662  module->update_nets();
1663  }
1664 
1665  // assign module pins
1666  for (const auto& [module, ports] : m_module_ports)
1667  {
1668  for (const auto& [port_name, port_net] : ports)
1669  {
1670  // check if net is actually a port net
1671  if (!module->is_input_net(port_net) && !module->is_output_net(port_net))
1672  {
1673  continue;
1674  }
1675 
1676  if (auto res = module->create_pin(port_name, port_net); res.is_error())
1677  {
1678  return ERR_APPEND(res.get_error(),
1679  "could not construct netlist: failed to create pin '" + port_name + "' at net '" + port_net->get_name() + "' with ID " + std::to_string(port_net->get_id())
1680  + " within module '" + module->get_name() + "' with ID " + std::to_string(module->get_id()));
1681  }
1682  }
1683  }
1684 
1685  for (Module* module : m_netlist->get_modules())
1686  {
1687  std::unordered_set<Net*> input_nets = module->get_input_nets();
1688  std::unordered_set<Net*> output_nets = module->get_input_nets();
1689 
1690  if ((module->get_pin_by_net(m_one_net) == nullptr) && (input_nets.find(m_one_net) != input_nets.end() || output_nets.find(m_one_net) != input_nets.end()))
1691  {
1692  if (auto res = module->create_pin("'1'", m_one_net); res.is_error())
1693  {
1694  return ERR_APPEND(res.get_error(),
1695  "could not construct netlist: failed to create pin '1' at net '" + m_one_net->get_name() + "' with ID " + std::to_string(m_one_net->get_id()) + "within module '"
1696  + module->get_name() + "' with ID " + std::to_string(module->get_id()));
1697  }
1698  }
1699 
1700  if ((module->get_pin_by_net(m_zero_net) == nullptr) && (input_nets.find(m_zero_net) != input_nets.end() || output_nets.find(m_zero_net) != input_nets.end()))
1701  {
1702  if (auto res = module->create_pin("'0'", m_zero_net); res.is_error())
1703  {
1704  return ERR_APPEND(res.get_error(),
1705  "could not construct netlist: failed to create pin '0' at net '" + m_zero_net->get_name() + "' with ID " + std::to_string(m_zero_net->get_id())
1706  + "within module '" + module->get_name() + "' with ID " + std::to_string(module->get_id()));
1707  }
1708  }
1709  }
1710 
1711  m_netlist->enable_automatic_net_checks(true);
1712  return OK({});
1713  }
1714 
1715  Result<Module*>
1716  VHDLParser::instantiate_entity(const ci_string& instance_identifier, VhdlEntity* vhdl_entity, Module* parent, const std::unordered_map<ci_string, ci_string>& parent_module_assignments)
1717  {
1718  std::unordered_map<ci_string, ci_string> signal_alias;
1719  std::unordered_map<ci_string, ci_string> instance_alias;
1720 
1721  // TODO check parent module assignments for port aliases
1722 
1723  const std::string parent_name = parent == (nullptr) ? "" : parent->get_name();
1724  instance_alias[instance_identifier] = get_unique_alias(core_strings::to<ci_string>(parent_name), instance_identifier, m_instance_name_occurrences);
1725 
1726  // create netlist module
1727  Module* module;
1728  if (parent == nullptr)
1729  {
1730  module = m_netlist->get_top_module();
1731  module->set_name(core_strings::to<std::string>(instance_alias.at(instance_identifier)));
1732  }
1733  else
1734  {
1735  module = m_netlist->create_module(core_strings::to<std::string>(instance_alias.at(instance_identifier)), parent);
1736  }
1737 
1738  ci_string instance_type = vhdl_entity->m_name;
1739  if (module == nullptr)
1740  {
1741  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1742  + "': failed to create module");
1743  }
1744  module->set_type(core_strings::to<std::string>(instance_type));
1745 
1746  // assign entity-level attributes
1747  for (const VhdlDataEntry& attribute : vhdl_entity->m_attributes)
1748  {
1749  if (!module->set_data("attribute", attribute.m_name, attribute.m_type, attribute.m_value))
1750  {
1751  log_warning("vhdl_parser",
1752  "could not set attribute '{} = {}' of type '{}' for instance '{}' type '{}'.",
1753  attribute.m_name,
1754  attribute.m_value,
1755  attribute.m_type,
1756  instance_identifier,
1757  instance_type);
1758  }
1759  }
1760 
1761  // assign module port names
1762  for (const auto& port : vhdl_entity->m_ports)
1763  {
1764  for (const auto& expanded_port_identifier : port->m_expanded_identifiers)
1765  {
1766  if (const auto it = parent_module_assignments.find(expanded_port_identifier); it != parent_module_assignments.end())
1767  {
1768  Net* port_net = m_net_by_name.at(it->second);
1769  m_module_ports[module].push_back(std::make_pair(core_strings::to<std::string>(expanded_port_identifier), port_net));
1770  m_module_port_by_net[port_net].push_back(std::make_pair(module, m_module_ports[module].size() - 1));
1771  }
1772  }
1773  }
1774 
1775  // create internal signals
1776  for (const auto& signal : vhdl_entity->m_signals)
1777  {
1778  for (const auto& expanded_name : signal->m_expanded_names)
1779  {
1780  signal_alias[expanded_name] = get_unique_alias(instance_alias[instance_identifier], expanded_name, m_signal_name_occurrences);
1781 
1782  // create new net for the signal
1783  Net* signal_net = m_netlist->create_net(core_strings::to<std::string>(signal_alias.at(expanded_name)));
1784  if (signal_net == nullptr)
1785  {
1786  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1787  + "': failed to create net '" + core_strings::to<std::string>(expanded_name) + "'");
1788  }
1789 
1790  m_net_by_name[signal_alias.at(expanded_name)] = signal_net;
1791 
1792  // assign signal attributes
1793  for (const VhdlDataEntry& attribute : signal->m_attributes)
1794  {
1795  if (!signal_net->set_data("attribute", attribute.m_name, attribute.m_type, attribute.m_value))
1796  {
1797  log_warning("vhdl_parser",
1798  "could not set attribute ({} = {}) for net '{}' of instance '{}' of type '{}'.",
1799  attribute.m_name,
1800  attribute.m_value,
1801  expanded_name,
1802  instance_identifier,
1803  instance_type);
1804  }
1805  }
1806  }
1807  }
1808 
1809  // schedule assigned nets for merging
1810  for (const auto& [left_expanded_signal, right_expanded_signal] : vhdl_entity->m_expanded_assignments)
1811  {
1812  ci_string a = left_expanded_signal;
1813  ci_string b = right_expanded_signal;
1814 
1815  if (const auto alias_it = signal_alias.find(a); alias_it != signal_alias.end())
1816  {
1817  a = alias_it->second;
1818  }
1819  else
1820  {
1821  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1822  + "': failed to find alias for net '" + core_strings::to<std::string>(a) + "'");
1823  }
1824 
1825  if (const auto alias_it = signal_alias.find(b); alias_it != signal_alias.end())
1826  {
1827  b = alias_it->second;
1828  }
1829  else if (b == "'Z'" || b == "'X'")
1830  {
1831  continue;
1832  }
1833  else if (b != "'0'" && b != "'1'")
1834  {
1835  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1836  + "': failed to find alias for net '" + core_strings::to<std::string>(b) + "'");
1837  }
1838 
1839  m_nets_to_merge.push_back(std::make_pair(a, b));
1840  }
1841 
1842  // schedule assigned port nets for merging
1843  for (const auto& [port_expression, net_name] : parent_module_assignments)
1844  {
1845  if (const auto alias_it = signal_alias.find(port_expression); alias_it != signal_alias.end())
1846  {
1847  const bool swap = net_name.find("__GLOBAL_IO__") == std::string::npos;
1848  m_nets_to_merge.push_back(swap ? std::make_pair(net_name, alias_it->second) : std::make_pair(alias_it->second, net_name));
1849  }
1850  else
1851  {
1852  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1853  + "': failed to find alias for net '" + core_strings::to<std::string>(port_expression) + "'");
1854  }
1855  }
1856 
1857  // process instances i.e. gates or other entities
1858  for (const auto& instance : vhdl_entity->m_instances)
1859  {
1860  // will later hold either module or gate, so attributes can be assigned properly
1861  DataContainer* container = nullptr;
1862 
1863  // assign actual signal names to ports
1864  std::unordered_map<ci_string, ci_string> instance_assignments;
1865 
1866  // if the instance is another entity, recursively instantiate it
1867  if (auto entity_it = m_entities_by_name.find(instance->m_type); entity_it != m_entities_by_name.end())
1868  {
1869  // expand port assignments
1870  for (const auto& [port, assignment] : instance->m_expanded_port_assignments)
1871  {
1872  if (const auto alias_it = signal_alias.find(assignment); alias_it != signal_alias.end())
1873  {
1874  instance_assignments[port] = alias_it->second;
1875  }
1876  else if (assignment == "'0'" || assignment == "'1'")
1877  {
1878  instance_assignments[port] = assignment;
1879  }
1880  else if (assignment == "'Z'" || assignment == "'X'" || assignment == "")
1881  {
1882  continue;
1883  }
1884  else
1885  {
1886  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1887  + "': port assignment '" + core_strings::to<std::string>(port) + " = " + core_strings::to<std::string>(assignment) + "' is invalid");
1888  }
1889  }
1890 
1891  if (auto res = instantiate_entity(instance->m_name, entity_it->second, module, instance_assignments); res.is_error())
1892  {
1893  return ERR_APPEND(res.get_error(),
1894  "could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1895  + "': unable to create instance '" + core_strings::to<std::string>(instance->m_name) + "' of type '"
1896  + core_strings::to<std::string>(entity_it->second->m_name) + "'");
1897  }
1898  else
1899  {
1900  container = res.get();
1901  }
1902  }
1903  // otherwise it has to be an element from the gate library
1904  else if (const auto gate_type_it = m_gate_types.find(instance->m_type); gate_type_it != m_gate_types.end())
1905  {
1906  // create the new gate
1907  instance_alias[instance->m_name] = get_unique_alias(instance_alias[instance_identifier], instance->m_name, m_instance_name_occurrences);
1908 
1909  Gate* new_gate = m_netlist->create_gate(gate_type_it->second, core_strings::to<std::string>(instance_alias.at(instance->m_name)));
1910  if (new_gate == nullptr)
1911  {
1912  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1913  + "': failed to create gate '" + core_strings::to<std::string>(instance->m_name) + "'");
1914  }
1915 
1916  if (!module->is_top_module())
1917  {
1918  module->assign_gate(new_gate);
1919  }
1920 
1921  container = new_gate;
1922 
1923  // if gate is of a GND or VCC gate type, mark it as such
1924  if (m_vcc_gate_types.find(instance->m_type) != m_vcc_gate_types.end() && !new_gate->mark_vcc_gate())
1925  {
1926  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type) + "': failed to mark '"
1927  + core_strings::to<std::string>(instance->m_name) + "' of type '" + core_strings::to<std::string>(instance->m_type) + "' as GND gate");
1928  }
1929  if (m_gnd_gate_types.find(instance->m_type) != m_gnd_gate_types.end() && !new_gate->mark_gnd_gate())
1930  {
1931  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type) + "': failed to mark '"
1932  + core_strings::to<std::string>(instance->m_name) + "' of type '" + core_strings::to<std::string>(instance->m_type) + "' as VCC gate");
1933  }
1934 
1935  // cache pin names
1936  std::unordered_map<ci_string, GatePin*> pin_names_map;
1937  for (auto* pin : gate_type_it->second->get_pins())
1938  {
1939  pin_names_map[core_strings::to<ci_string>(pin->get_name())] = pin;
1940  }
1941 
1942  // expand pin assignments
1943  for (const auto& [pin, assignment] : instance->m_expanded_port_assignments)
1944  {
1945  ci_string signal;
1946 
1947  if (const auto alias_it = signal_alias.find(assignment); alias_it != signal_alias.end())
1948  {
1949  signal = alias_it->second;
1950  }
1951  else if (assignment == "'0'" || assignment == "'1'")
1952  {
1953  signal = assignment;
1954  }
1955  else if (assignment == "'Z'" || assignment == "'X'" || assignment == "")
1956  {
1957  continue;
1958  }
1959  else
1960  {
1961  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1962  + "': failed to assign '" + core_strings::to<std::string>(assignment) + "' to pin '" + core_strings::to<std::string>(pin) + "' of gate '"
1963  + core_strings::to<std::string>(instance->m_name) + "' of type '" + core_strings::to<std::string>(instance->m_type) + "' as the assignment is invalid");
1964  }
1965 
1966  // get the respective net for the assignment
1967  if (const auto net_it = m_net_by_name.find(signal); net_it == m_net_by_name.end())
1968  {
1969  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1970  + "': failed to assign signal'" + core_strings::to<std::string>(signal) + "' to pin '" + core_strings::to<std::string>(pin)
1971  + "' as the signal has not been declared");
1972  }
1973  else
1974  {
1975  Net* current_net = net_it->second;
1976 
1977  // add net src/dst by pin types
1978  bool is_input = false;
1979  bool is_output = false;
1980 
1981  if (const auto it = pin_names_map.find(pin); it != pin_names_map.end())
1982  {
1983  PinDirection direction = it->second->get_direction();
1985  {
1986  is_input = true;
1987  }
1988 
1990  {
1991  is_output = true;
1992  }
1993  }
1994 
1995  if (!is_input && !is_output)
1996  {
1997  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
1998  + "': failed to assign net '" + core_strings::to<std::string>(signal) + "' to pin '" + core_strings::to<std::string>(pin) + "' as it is not a pin of gate '"
1999  + new_gate->get_name() + "' of type '" + new_gate->get_type()->get_name() + "'");
2000  }
2001 
2002  if (is_output && !current_net->add_source(new_gate, core_strings::to<std::string>(pin)))
2003  {
2004  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
2005  + "': failed to add net '" + core_strings::to<std::string>(signal) + "' as a source to gate '" + new_gate->get_name() + "' via pin '"
2006  + core_strings::to<std::string>(pin) + "'");
2007  }
2008 
2009  if (is_input && !current_net->add_destination(new_gate, core_strings::to<std::string>(pin)))
2010  {
2011  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
2012  + "': failed to add net '" + core_strings::to<std::string>(signal) + "' as a destination to gate '" + new_gate->get_name() + "' via pin '"
2013  + core_strings::to<std::string>(pin) + "'");
2014  }
2015  }
2016  }
2017  }
2018  else
2019  {
2020  return ERR("could not create instance '" + core_strings::to<std::string>(instance_identifier) + "' of type '" + core_strings::to<std::string>(instance_type)
2021  + "': failed to find gate type '" + core_strings::to<std::string>(instance->m_type) + "' in gate library '" + m_netlist->get_gate_library()->get_name() + "'");
2022  }
2023 
2024  // assign instance attributes
2025  for (const auto& attribute : instance->m_attributes)
2026  {
2027  if (!container->set_data("attribute", attribute.m_name, attribute.m_type, attribute.m_value))
2028  {
2029  log_warning("vhdl_parser",
2030  "could not set attribute '{} = {}' of type '{}' for instance '{}' of type '{}' within instance '{}' of type '{}'.",
2031  attribute.m_name,
2032  attribute.m_value,
2033  attribute.m_type,
2034  instance->m_name,
2035  instance->m_type,
2036  instance_identifier,
2037  instance_type);
2038  }
2039  }
2040 
2041  // process generics
2042  for (const auto& generic : instance->m_generics)
2043  {
2044  if (!container->set_data("generic", generic.m_name, generic.m_type, generic.m_value))
2045  {
2046  log_warning("vhdl_parser",
2047  "could not set generic '{} = {}' of type '{}' for instance '{}' of type '{}' within instance '{}' of type '{}'.",
2048  generic.m_name,
2049  generic.m_value,
2050  generic.m_type,
2051  instance->m_name,
2052  instance->m_type,
2053  instance_identifier,
2054  instance_type);
2055  }
2056  }
2057  }
2058 
2059  return OK(module);
2060  }
2061 
2062  // ###########################################################################
2063  // ################### Helper Functions ####################
2064  // ###########################################################################
2065 
2066  namespace
2067  {
2068  const static std::map<core_strings::CaseInsensitiveString, size_t> id_to_dim = {{"std_logic_vector", 1}, {"std_logic_vector2", 2}, {"std_logic_vector3", 3}};
2069 
2070  static const std::map<char, BooleanFunction::Value> bin_map = {{'0', BooleanFunction::Value::ZERO},
2071  {'1', BooleanFunction::Value::ONE},
2072  {'X', BooleanFunction::Value::X},
2073  {'Z', BooleanFunction::Value::Z}};
2074 
2075  static const std::map<char, std::vector<BooleanFunction::Value>> oct_map = {{'0', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO}},
2076  {'1', {BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO}},
2077  {'2', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO}},
2078  {'3', {BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO}},
2079  {'4', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE}},
2080  {'5', {BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE}},
2081  {'6', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE}},
2082  {'7', {BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE}},
2083  {'X', {BooleanFunction::Value::X, BooleanFunction::Value::X, BooleanFunction::Value::X}},
2084  {'Z', {BooleanFunction::Value::Z, BooleanFunction::Value::Z, BooleanFunction::Value::Z}}};
2085 
2086  static const std::map<char, std::vector<BooleanFunction::Value>> hex_map = {
2087  {'0', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO}},
2088  {'1', {BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO}},
2089  {'2', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO}},
2090  {'3', {BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO}},
2091  {'4', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO}},
2092  {'5', {BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO}},
2093  {'6', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO}},
2094  {'7', {BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO}},
2095  {'8', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE}},
2096  {'9', {BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE}},
2097  {'A', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE}},
2098  {'B', {BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE}},
2099  {'C', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE}},
2100  {'D', {BooleanFunction::Value::ONE, BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE}},
2101  {'E', {BooleanFunction::Value::ZERO, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE}},
2102  {'F', {BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE, BooleanFunction::Value::ONE}},
2103  {'X', {BooleanFunction::Value::X, BooleanFunction::Value::X, BooleanFunction::Value::X, BooleanFunction::Value::X}},
2104  {'Z', {BooleanFunction::Value::Z, BooleanFunction::Value::Z, BooleanFunction::Value::Z, BooleanFunction::Value::Z}}};
2105  } // namespace
2106 
2107  // generate a unique name for a gate/module instance
2108  VHDLParser::ci_string VHDLParser::get_unique_alias(const ci_string& parent_name, const ci_string& name, const std::unordered_map<ci_string, u32>& name_occurences) const
2109  {
2110  ci_string unique_alias = name;
2111 
2112  if (!parent_name.empty())
2113  {
2114  // if there is no other instance with that name, we omit the name prefix
2115  if (const auto instance_name_it = name_occurences.find(name); instance_name_it != name_occurences.end() && instance_name_it->second > 1)
2116  {
2117  unique_alias = parent_name + ci_string("/") + unique_alias;
2118  }
2119  }
2120 
2121  return unique_alias;
2122  }
2123 
2124  std::vector<u32> VHDLParser::parse_range(TokenStream<ci_string>& range_stream) const
2125  {
2126  if (range_stream.remaining() == 1)
2127  {
2128  return {(u32)std::stoi(core_strings::to<std::string>(range_stream.consume().string))};
2129  }
2130 
2131  int direction = 1;
2132  const int end = std::stoi(core_strings::to<std::string>(range_stream.consume().string));
2133 
2134  if (range_stream.peek() == "downto")
2135  {
2136  range_stream.consume("downto");
2137  }
2138  else
2139  {
2140  range_stream.consume("to", true);
2141  direction = -1;
2142  }
2143 
2144  const int start = std::stoi(core_strings::to<std::string>(range_stream.consume().string));
2145 
2146  std::vector<u32> res;
2147  for (int i = start; i != end + direction; i += direction)
2148  {
2149  res.push_back((u32)i);
2150  }
2151  return res;
2152  }
2153 
2154  Result<std::vector<std::vector<u32>>> VHDLParser::parse_signal_ranges(TokenStream<ci_string>& signal_stream) const
2155  {
2156  std::vector<std::vector<u32>> ranges;
2157  const u32 line_number = signal_stream.peek().number;
2158 
2159  const Token<ci_string> type_name = signal_stream.consume();
2160  if (type_name == "std_logic")
2161  {
2162  return OK(ranges);
2163  }
2164 
2165  signal_stream.consume("(", true);
2166  TokenStream<ci_string> signal_bounds_stream = signal_stream.extract_until(")");
2167 
2168  // process ranges
2169  do
2170  {
2171  TokenStream<ci_string> bound_stream = signal_bounds_stream.extract_until(",");
2172  ranges.emplace_back(parse_range(bound_stream));
2173  } while (signal_bounds_stream.consume(","));
2174 
2175  signal_stream.consume(")", true);
2176 
2177  if (id_to_dim.find(type_name) != id_to_dim.end())
2178  {
2179  const size_t dimension = id_to_dim.at(type_name);
2180 
2181  if (ranges.size() != dimension)
2182  {
2183  return ERR("could not parse signal ranges: mismatch of dimensions (line " + std::to_string(line_number) + ")");
2184  }
2185  }
2186  else
2187  {
2188  return ERR("could not parse signal ranges: type name '" + core_strings::to<std::string>(type_name.string) + "' is invalid (line " + std::to_string(line_number) + ")");
2189  }
2190 
2191  return OK(ranges);
2192  }
2193 
2194  void VHDLParser::expand_ranges_recursively(std::vector<ci_string>& expanded_names, const ci_string& current_name, const std::vector<std::vector<u32>>& ranges, u32 dimension) const
2195  {
2196  // expand signal recursively
2197  if (ranges.size() > dimension)
2198  {
2199  for (const u32 index : ranges[dimension])
2200  {
2201  expand_ranges_recursively(expanded_names, current_name + "(" + core_strings::to<ci_string>(std::to_string(index)) + ")", ranges, dimension + 1);
2202  }
2203  }
2204  else
2205  {
2206  // last dimension
2207  expanded_names.push_back(current_name);
2208  }
2209  }
2210 
2211  std::vector<VHDLParser::ci_string> VHDLParser::expand_ranges(const ci_string& name, const std::vector<std::vector<u32>>& ranges) const
2212  {
2213  std::vector<ci_string> res;
2214 
2215  expand_ranges_recursively(res, name, ranges, 0);
2216 
2217  return res;
2218  }
2219 
2220  Result<std::vector<BooleanFunction::Value>> VHDLParser::get_binary_vector(std::string value) const
2221  {
2222  value = utils::to_upper(utils::replace(value, std::string("_"), std::string("")));
2223 
2224  std::string prefix;
2225  std::string number;
2226  std::vector<BooleanFunction::Value> result;
2227 
2228  // base specified?
2229  if (value.at(0) != '\"')
2230  {
2231  prefix = value.at(0);
2232  number = value.substr(2, value.rfind('\"') - 2);
2233  }
2234  else
2235  {
2236  prefix = "B";
2237  number = value.substr(1, value.rfind('\"') - 1);
2238  }
2239 
2240  // select base
2241  switch (prefix.at(0))
2242  {
2243  case 'B': {
2244  for (auto it = number.rbegin(); it != number.rend(); it++)
2245  {
2246  const char c = *it;
2247  if (c == '0' || c == '1' || c == 'Z' || c == 'X')
2248  {
2249  result.push_back(bin_map.at(c));
2250  }
2251  else
2252  {
2253  return ERR("could not convert string to binary vector: invalid character within binary number literal '" + value + "'");
2254  }
2255  }
2256  break;
2257  }
2258 
2259  case 'O':
2260  for (auto it = number.rbegin(); it != number.rend(); it++)
2261  {
2262  const char c = *it;
2263  if ((c >= '0' && c <= '7') || c == 'X' || c == 'Z')
2264  {
2265  const auto& bits = oct_map.at(c);
2266  result.insert(result.end(), bits.begin(), bits.end());
2267  }
2268  else
2269  {
2270  return ERR("could not convert string to binary vector: invalid character within octal number literal '" + value + "'");
2271  }
2272  }
2273  break;
2274 
2275  case 'D': {
2276  u64 tmp_val = 0;
2277 
2278  for (const char c : number)
2279  {
2280  if ((c >= '0' && c <= '9'))
2281  {
2282  tmp_val = (tmp_val * 10) + (c - '0');
2283  }
2284  else
2285  {
2286  return ERR("could not convert string to binary vector: invalid character within decimal number literal '" + value + "'");
2287  }
2288  }
2289 
2290  do
2291  {
2292  result.push_back(((tmp_val & 1) == 1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
2293  tmp_val >>= 1;
2294  } while (tmp_val != 0);
2295  break;
2296  }
2297 
2298  case 'H': {
2299  for (auto it = number.rbegin(); it != number.rend(); it++)
2300  {
2301  const char c = *it;
2302  if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || c == 'X' || c == 'Z')
2303  {
2304  const auto& bits = hex_map.at(c);
2305  result.insert(result.end(), bits.begin(), bits.end());
2306  }
2307  else
2308  {
2309  return ERR("could not convert string to binary vector: invalid character within hexadecimal number literal '" + value + "'");
2310  }
2311  }
2312  break;
2313  }
2314 
2315  default: {
2316  return ERR("could not convert string to binary vector: invalid base '" + prefix + "' within number literal '" + value + "'");
2317  }
2318  }
2319 
2320  return OK(result);
2321  }
2322 
2323  Result<std::string> VHDLParser::get_hex_from_literal(const Token<ci_string>& value_token) const
2324  {
2325  const u32 line_number = value_token.number;
2326  const ci_string value = utils::to_upper(utils::replace(value_token.string, ci_string("_"), ci_string("")));
2327 
2328  ci_string prefix;
2329  ci_string number;
2330  u32 base;
2331 
2332  // base specified?
2333  if (value.at(0) != '\"')
2334  {
2335  prefix = value.at(0);
2336  number = value.substr(2, value.rfind('\"') - 2);
2337  }
2338  else
2339  {
2340  prefix = "B";
2341  number = value.substr(1, value.rfind('\"') - 1);
2342  }
2343 
2344  // select base
2345  switch (prefix.at(0))
2346  {
2347  case 'B': {
2348  if (!std::all_of(number.begin(), number.end(), [](const char& c) { return (c >= '0' && c <= '1'); }))
2349  {
2350  return ERR("could not convert token to hexadecimal string: invalid character within binary number literal '" + core_strings::to<std::string>(value) + "' (line "
2351  + std::to_string(line_number) + ")");
2352  }
2353 
2354  base = 2;
2355  break;
2356  }
2357 
2358  case 'O': {
2359  if (!std::all_of(number.begin(), number.end(), [](const char& c) { return (c >= '0' && c <= '7'); }))
2360  {
2361  return ERR("could not convert token to hexadecimal string: invalid character within ocatl number literal '" + core_strings::to<std::string>(value) + "' (line "
2362  + std::to_string(line_number) + ")");
2363  }
2364 
2365  base = 8;
2366  break;
2367  }
2368 
2369  case 'D': {
2370  if (!std::all_of(number.begin(), number.end(), [](const char& c) { return (c >= '0' && c <= '9'); }))
2371  {
2372  return ERR("could not convert token to hexadecimal string: invalid character within decimal number literal '" + core_strings::to<std::string>(value) + "' (line "
2373  + std::to_string(line_number) + ")");
2374  }
2375 
2376  base = 10;
2377  break;
2378  }
2379 
2380  case 'X': {
2381  std::string res;
2382 
2383  for (const char c : number)
2384  {
2385  if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
2386  {
2387  res += c;
2388  }
2389  else
2390  {
2391  return ERR("could not convert token to hexadecimal string: invalid character within hexadecimal number literal '" + core_strings::to<std::string>(value) + "' (line "
2392  + std::to_string(line_number) + ")");
2393  }
2394  }
2395 
2396  return OK(res);
2397  }
2398 
2399  default: {
2400  return ERR("could not convert token to hexadecimal string: invalid base '" + core_strings::to<std::string>(prefix) + "' within number literal '" + core_strings::to<std::string>(value)
2401  + "' (line " + std::to_string(line_number) + ")");
2402  }
2403  }
2404 
2405  std::stringstream ss;
2406  ss << std::uppercase << std::hex << stoull(core_strings::to<std::string>(number), 0, base);
2407  return OK(ss.str());
2408  }
2409 
2410  Result<std::vector<VHDLParser::assignment_t>> VHDLParser::parse_assignment_expression(TokenStream<ci_string>&& stream) const
2411  {
2412  // PARSE ASSIGNMENT
2413  // assignment can currently be one of the following:
2414  // (1) NAME
2415  // (2) NUMBER
2416  // (3) NAME(INDEX1, INDEX2, ...)
2417  // (4) NAME(BEGIN_INDEX1 to/downto END_INDEX1, BEGIN_INDEX2 to/downto END_INDEX2, ...)
2418  // (5) ((1 - 4), (1 - 4), ...)
2419 
2420  std::vector<TokenStream<ci_string>> parts;
2421 
2422  if (stream.size() == 0)
2423  {
2424  return OK({});
2425  }
2426 
2427  // (5) ((1 - 4), (1 - 4), ...)
2428  if (stream.consume("("))
2429  {
2430  do
2431  {
2432  parts.push_back(stream.extract_until(","));
2433  } while (stream.consume(",", false));
2434 
2435  stream.consume(")", true);
2436  }
2437  else
2438  {
2439  parts.push_back(stream);
2440  }
2441 
2442  std::vector<assignment_t> result;
2443  result.reserve(parts.size());
2444 
2445  for (auto it = parts.rbegin(); it != parts.rend(); it++)
2446  {
2447  TokenStream<ci_string>& part_stream = *it;
2448 
2449  const Token<ci_string> signal_name_token = part_stream.consume();
2450  ci_string signal_name = signal_name_token.string;
2451 
2452  // (2) NUMBER
2455  {
2456  if (auto res = get_binary_vector(core_strings::to<std::string>(signal_name_token.string)); res.is_error())
2457  {
2458  return ERR_APPEND(res.get_error(), "could not expand assignment signal: unable to convert literal to binary string (line " + std::to_string(signal_name_token.number) + ")");
2459  }
2460  else
2461  {
2462  result.push_back(std::move(res.get()));
2463  }
2464  }
2465  else if (signal_name == "'0'")
2466  {
2467  result.push_back(numeral_t({BooleanFunction::Value::ZERO}));
2468  }
2469  else if (signal_name == "'1'")
2470  {
2471  result.push_back(numeral_t({BooleanFunction::Value::ONE}));
2472  }
2473  else if (signal_name == "'X'")
2474  {
2475  result.push_back(numeral_t({BooleanFunction::Value::X}));
2476  }
2477  else if (signal_name == "'Z'")
2478  {
2479  result.push_back(numeral_t({BooleanFunction::Value::Z}));
2480  }
2481  else
2482  {
2483  // (3) NAME(INDEX1, INDEX2, ...)
2484  // (4) NAME(BEGIN_INDEX1 to/downto END_INDEX1, BEGIN_INDEX2 to/downto END_INDEX2, ...)
2485  if (part_stream.consume("("))
2486  {
2487  std::vector<std::vector<u32>> ranges;
2488  u32 closing_pos = part_stream.find_next(")");
2489  do
2490  {
2491  TokenStream<ci_string> range_stream = part_stream.extract_until(",", closing_pos);
2492  ranges.emplace_back(parse_range(range_stream));
2493 
2494  } while (part_stream.consume(",", false));
2495  part_stream.consume(")", true);
2496  result.push_back(ranged_identifier_t({std::move(signal_name), std::move(ranges)}));
2497  }
2498  else
2499  {
2500  // (1) NAME
2501  result.push_back(std::move(signal_name));
2502  }
2503  }
2504  }
2505 
2506  return OK(result);
2507  }
2508 
2509  Result<std::vector<VHDLParser::ci_string>> VHDLParser::expand_assignment_expression(VhdlEntity* vhdl_entity, const std::vector<assignment_t>& vars) const
2510  {
2511  std::vector<ci_string> result;
2512  for (const auto& var : vars)
2513  {
2514  if (const identifier_t* identifier = std::get_if<identifier_t>(&var); identifier != nullptr)
2515  {
2516  if (identifier->empty())
2517  {
2518  result.push_back(*identifier);
2519  continue;
2520  }
2521  std::vector<std::vector<u32>> ranges;
2522 
2523  if (const auto signal_it = vhdl_entity->m_signals_by_name.find(*identifier); signal_it != vhdl_entity->m_signals_by_name.end())
2524  {
2525  ranges = signal_it->second->m_ranges;
2526  }
2527  else if (const auto port_it = vhdl_entity->m_ports_by_identifier.find(*identifier); port_it != vhdl_entity->m_ports_by_identifier.end())
2528  {
2529  ranges = port_it->second->m_ranges;
2530  }
2531  else
2532  {
2533  return ERR("could not expand assignment expression': '" + core_strings::to<std::string>(*identifier) + "' is neither a signal nor a port of entity '"
2534  + core_strings::to<std::string>(vhdl_entity->m_name) + "'");
2535  }
2536 
2537  std::vector<ci_string> expanded = expand_ranges(*identifier, ranges);
2538  result.insert(result.end(), expanded.begin(), expanded.end());
2539  }
2540  else if (const ranged_identifier_t* ranged_identifier = std::get_if<ranged_identifier_t>(&var); ranged_identifier != nullptr)
2541  {
2542  std::vector<ci_string> expanded = expand_ranges(ranged_identifier->first, ranged_identifier->second);
2543  result.insert(result.end(), expanded.begin(), expanded.end());
2544  }
2545  else if (const numeral_t* numeral = std::get_if<numeral_t>(&var); numeral != nullptr)
2546  {
2547  for (auto value : *numeral)
2548  {
2549  result.push_back(core_strings::to<ci_string>("'" + BooleanFunction::to_string(value) + "'"));
2550  }
2551  }
2552  }
2553 
2554  return OK(result);
2555  }
2556 } // namespace hal
u32 size
static std::string to_string(Value value)
bool set_data(const std::string &category, const std::string &key, const std::string &data_type, const std::string &value, const bool log_with_info_level=false)
Definition: gate.h:58
std::unordered_map< std::string, GateType * > get_gate_types(const std::function< bool(const GateType *)> &filter=nullptr) const
std::unordered_map< std::string, GateType * > get_vcc_gate_types() const
std::unordered_map< std::string, GateType * > get_gnd_gate_types() const
std::string get_name() const
std::vector< GatePin * > get_output_pins() const
Definition: gate_type.cpp:285
bool is_input_net(Net *net) const
Definition: module.cpp:557
void set_name(const std::string &name)
Definition: module.cpp:92
void update_nets()
Definition: module.cpp:436
bool is_top_module() const
Definition: module.cpp:314
bool assign_gate(Gate *gate)
Definition: module.cpp:324
bool is_output_net(Net *net) const
Definition: module.cpp:567
std::string get_name() const
Definition: module.cpp:87
const std::unordered_set< Net * > & get_input_nets() const
Definition: module.cpp:542
void set_type(const std::string &type)
Definition: module.cpp:111
ModulePin * get_pin_by_net(Net *net) const
Definition: module.cpp:1019
Result< ModulePin * > create_pin(const u32 id, const std::string &name, Net *net, PinType type=PinType::none, bool create_group=true, bool force_name=false)
Definition: module.cpp:789
u32 get_id() const
Definition: module.cpp:82
Definition: net.h:58
u32 get_id() const
Definition: net.cpp:88
Endpoint * add_source(Gate *gate, const std::string &pin_name)
Definition: net.cpp:127
const std::string & get_name() const
Definition: net.cpp:98
u32 get_num_of_destinations(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:432
Module * get_top_module() const
Definition: netlist.cpp:608
u32 get_unique_gate_id()
Definition: netlist.cpp:160
bool mark_vcc_gate(Gate *gate)
Definition: netlist.cpp:228
bool mark_gnd_gate(Gate *gate)
Definition: netlist.cpp:244
bool load_gate_locations_from_data(const std::string &data_category="", const std::pair< std::string, std::string > &data_identifiers=std::pair< std::string, std::string >())
Definition: netlist.cpp:862
bool delete_net(Net *net)
Definition: netlist.cpp:343
Net * create_net(const u32 net_id, const std::string &name)
Definition: netlist.cpp:333
const std::vector< Gate * > & get_gnd_gates() const
Definition: netlist.cpp:309
void set_design_name(const std::string &name)
Definition: netlist.cpp:109
void enable_automatic_net_checks(bool enable_checks=true)
Definition: netlist.cpp:563
const std::vector< Gate * > & get_vcc_gates() const
Definition: netlist.cpp:304
const std::vector< Module * > & get_modules() const
Definition: netlist.cpp:624
Gate * create_gate(const u32 gate_id, GateType *gate_type, const std::string &name="", i32 x=-1, i32 y=-1)
Definition: netlist.cpp:173
const std::vector< Net * > & get_nets() const
Definition: netlist.cpp:364
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:132
Module * create_module(const u32 module_id, const std::string &name, Module *parent, const std::vector< Gate * > &gates={})
Definition: netlist.cpp:587
u32 remaining() const
Definition: token_stream.h:494
static const u32 END_OF_STREAM
Definition: token_stream.h:147
Token< T > consume_until(const T &expected, u32 end=END_OF_STREAM, bool level_aware=true, bool throw_on_error=false)
Definition: token_stream.h:266
Token< T > & peek(i32 offset=0)
Definition: token_stream.h:392
u32 find_next(const T &match, u32 end=END_OF_STREAM, bool level_aware=true) const
Definition: token_stream.h:446
Token< T > join_until(const T &match, const T &joiner, u32 end=END_OF_STREAM, bool level_aware=true, bool throw_on_error=false)
Definition: token_stream.h:338
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
Result< std::monostate > parse(const std::filesystem::path &file_path) override
Definition: vhdl_parser.cpp:22
Result< std::unique_ptr< Netlist > > instantiate(const GateLibrary *gate_library) override
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
#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
const Module * module(const Gate *g, const NodeBoxes &boxes)
std::basic_string< char, CaseInsensitiveCharTraits > CaseInsensitiveString
std::unique_ptr< Netlist > create_netlist(const GateLibrary *gate_library)
Create a new empty netlist using the specified gate library.
T replace(const T &str, const T &search, const T &replace)
Definition: utils.h:384
bool is_digits(const T &s)
Definition: utils.h:188
bool starts_with(const T &s, const T &start)
Definition: utils.h:169
bool is_floating_point(const T &s)
Definition: utils.h:220
bool ends_with(const T &s, const T &end)
Definition: utils.h:149
T to_upper(const T &s)
Definition: utils.h:465
bool is_integer(const T &s)
Definition: utils.h:200
T trim(const T &s, const char *to_remove=" \t\r\n")
Definition: utils.h:360
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
std::vector< PinInformation > pins
Net * net
PinDirection direction
std::string name
This file contains various functions to create and load netlists.
std::string identifier