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