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