HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
gate.cpp
Go to the documentation of this file.
2 
10 #include "hal_core/netlist/net.h"
15 #include "hal_core/utilities/log.h"
16 
17 #include <algorithm>
18 #include <assert.h>
19 #include <cctype>
20 #include <iomanip>
21 #include <sstream>
22 
23 namespace
24 {
25  template<typename T, T m, int k>
26  inline T swapbits(T p)
27  {
28  T q = ((p >> k) ^ p) & m;
29  return p ^ q ^ (q << k);
30  }
31 
32  std::string lut_init_read(const hal::DataContainer* dc, const std::string& key)
33  {
34  if (!dc->has_parameter(key))
35  {
36  return "";
37  }
38  const std::string pv = dc->get_parameter_value(key).get();
39  return (pv.size() >= 2 && pv[0] == '0' && pv[1] == 'x') ? pv.substr(2) : pv;
40  }
41 
42  void lut_init_write(hal::DataContainer* dc, const std::string& key, const std::string& plain_hex)
43  {
44  if (plain_hex.empty())
45  {
46  return;
47  }
48  const std::string value = "0x" + plain_hex;
49  const size_t nbits = plain_hex.size() * 4;
50  if (nbits == 0 || nbits > 64)
51  {
52  return;
53  }
54 
55  auto param_res = hal::Parameter::BitVector(key, static_cast<u16>(nbits), "");
56  if (param_res.is_error())
57  {
58  return;
59  }
60 
61  dc->set_parameter(param_res.get(), value);
62  }
63 
64  u64 bitreverse(u64 n)
65  {
66  static const u64 m0 = 0x5555555555555555LLU;
67  static const u64 m1 = 0x0300c0303030c303LLU;
68  static const u64 m2 = 0x00c0300c03f0003fLLU;
69  static const u64 m3 = 0x00000ffc00003fffLLU;
70  n = ((n >> 1) & m0) | (n & m0) << 1;
71  n = swapbits<u64, m1, 4>(n);
72  n = swapbits<u64, m2, 8>(n);
73  n = swapbits<u64, m3, 20>(n);
74  n = (n >> 34) | (n << 30);
75  return n;
76  }
77 } // namespace
78 
79 namespace hal
80 {
81  Gate::Gate(NetlistInternalManager* mgr, EventHandler* event_handler, const u32 id, GateType* gt, const std::string& name, i32 x, i32 y)
82  : m_internal_manager(mgr), m_id(id), m_name(name), m_type(gt), m_x(x), m_y(y), m_event_handler(event_handler)
83  {
84  ;
85  }
86 
87  bool Gate::operator==(const Gate& other) const
88  {
89  if (m_id != other.get_id() || m_name != other.get_name() || m_type != other.get_type())
90  {
91  log_debug("gate", "the gates with IDs {} and {} are not equal due to an unequal ID, name, or type.", m_id, other.get_id());
92  return false;
93  }
94 
95  if (m_x != other.get_location_x() || m_y != other.get_location_y())
96  {
97  log_debug("gate", "the gates with IDs {} and {} are not equal due to unequal location data.", m_id, other.get_id());
98  return false;
99  }
100 
101  if (is_gnd_gate() != other.is_gnd_gate() || is_vcc_gate() != other.is_vcc_gate())
102  {
103  log_debug("gate", "the gates with IDs {} and {} are not equal as one is a GND or VCC gate and the other is not.", m_id, other.get_id());
104  return false;
105  }
106 
107  if (m_functions != other.get_boolean_functions(true))
108  {
109  log_debug("gate", "the gates with IDs {} and {} are not equal due to an unequal Boolean functions.", m_id, other.get_id());
110  return false;
111  }
112 
113  if (!DataContainer::operator==(other))
114  {
115  log_debug("gate", "the gates with IDs {} and {} are not equal due to unequal data.", m_id, other.get_id());
116  return false;
117  }
118 
119  return true;
120  }
121 
122  bool Gate::operator!=(const Gate& other) const
123  {
124  return !operator==(other);
125  }
126 
127  ssize_t Gate::get_hash() const
128  {
129  return (uintptr_t)this;
130  }
131 
132  u32 Gate::get_id() const
133  {
134  return m_id;
135  }
136 
137  Netlist* Gate::get_netlist() const
138  {
139  return m_internal_manager->m_netlist;
140  }
141 
142  const std::string& Gate::get_name() const
143  {
144  return m_name;
145  }
146 
147  void Gate::set_name(const std::string& name)
148  {
149  if (utils::trim(name).empty())
150  {
151  log_error("gate", "gate name cannot be empty.");
152  return;
153  }
154 
155  if (name != m_name)
156  {
157  m_name = name;
158  m_event_handler->notify(GateEvent::event::name_changed, this);
159  }
160  }
161 
162  GateType* Gate::get_type() const
163  {
164  return m_type;
165  }
166 
167  i32 Gate::get_location_x() const
168  {
169  return m_x;
170  }
171 
172  i32 Gate::get_location_y() const
173  {
174  return m_y;
175  }
176 
177  std::pair<i32, i32> Gate::get_location() const
178  {
179  return {m_x, m_y};
180  }
181 
182  bool Gate::has_location() const
183  {
184  return m_x >= 0 && m_y >= 0;
185  }
186 
187  void Gate::set_location_x(i32 x)
188  {
189  if (x != m_x)
190  {
191  m_x = x;
192  m_event_handler->notify(GateEvent::event::location_changed, this);
193  }
194  }
195 
196  void Gate::set_location_y(i32 y)
197  {
198  if (y != m_y)
199  {
200  m_y = y;
201  m_event_handler->notify(GateEvent::event::location_changed, this);
202  }
203  }
204 
205  void Gate::set_location(const std::pair<i32, i32>& location)
206  {
207  set_location_x(location.first);
208  set_location_y(location.second);
209  }
210 
211  Module* Gate::get_module() const
212  {
213  return m_module;
214  }
215 
216  std::vector<Module*> Gate::get_modules(const std::function<bool(Module*)>& filter, bool recursive) const
217  {
218  std::vector<Module*> res;
219 
220  if (!filter)
221  {
222  res.push_back(m_module);
223  }
224  else
225  {
226  if (filter(m_module))
227  {
228  res.push_back(m_module);
229  }
230  }
231 
232  if (recursive)
233  {
234  std::vector<Module*> more = m_module->get_parent_modules(filter, true);
235  res.reserve(res.size() + more.size());
236  res.insert(res.end(), more.begin(), more.end());
237  }
238  return res;
239  }
240 
241  Grouping* Gate::get_grouping() const
242  {
243  return m_grouping;
244  }
245 
246  BooleanFunction Gate::get_boolean_function(const std::string& name) const
247  {
248  std::string internal_name = name;
249  if (internal_name.empty())
250  {
251  const auto output_pins = m_type->get_output_pins();
252  if (output_pins.empty())
253  {
254  log_warning("gate", "could not get Boolean function of gate '{}' with ID {}: gate type has no output pins", m_name, m_id);
255  return BooleanFunction();
256  }
257  internal_name = output_pins.front()->get_name();
258  }
259  auto res = get_boolean_function(internal_name, false, false);
260  if (res.is_error())
261  {
262  log_warning("gate", "{}", res.get_error().get());
263  return BooleanFunction();
264  }
265  return res.get();
266  }
267 
268  Result<BooleanFunction> Gate::get_boolean_function(const std::string& name, bool inlined, bool substitute_nets) const
269  {
270  if (name.empty())
271  {
272  return ERR("could not get Boolean function of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": name must not be empty");
273  }
274  const std::string& internal_name = name;
275 
276  if (substitute_nets && !inlined)
277  {
278  return ERR("could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": substitute_nets requires inlined=true");
279  }
280 
281  // Raw lookup (no inlining): LUT → m_functions → gate type BFs
282  if (!inlined)
283  {
284  if (m_type->has_component_of_type(GateTypeComponent::ComponentType::lut))
285  {
286  auto lut_pins = m_type->get_pins([&internal_name](const GatePin* p) { return p->get_type() == PinType::lut && p->get_name() == internal_name; });
287  if (!lut_pins.empty())
288  {
289  return OK(get_lut_function(lut_pins.front()));
290  }
291  }
292  if (auto it = m_functions.find(internal_name); it != m_functions.end())
293  {
294  return OK(it->second);
295  }
296  const auto type_bfs = m_type->get_boolean_functions();
297  if (auto it = type_bfs.find(internal_name); it != type_bfs.end())
298  {
299  return OK(it->second);
300  }
301  return ERR("could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": no function with that name exists");
302  }
303 
304  // Inlined path: substitute internal/output pin variables and gate parameters.
305  // Seed on_stack with the starting name so immediate self-references are caught
306  // in the first variable scan rather than requiring an extra recursion level.
307  BooleanFunction bf;
308  const GatePin* pin = m_type->get_pin_by_name(internal_name);
309  if (pin != nullptr)
310  {
311  std::unordered_set<std::string> on_stack = {internal_name};
312  auto res = get_inlined_boolean_function(get_boolean_function(pin), on_stack);
313  if (res.is_error())
314  {
315  return ERR_APPEND(res.get_error(), "could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id));
316  }
317  bf = res.get();
318  }
319  else
320  {
321  // Not a pin (custom-named function): raw lookup then inline
322  if (auto it = m_functions.find(internal_name); it != m_functions.end())
323  {
324  bf = it->second;
325  }
326  else
327  {
328  const auto type_bfs = m_type->get_boolean_functions();
329  if (auto it = type_bfs.find(internal_name); it != type_bfs.end())
330  {
331  bf = it->second;
332  }
333  else
334  {
335  return ERR("could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": no function with that name exists");
336  }
337  }
338  std::unordered_set<std::string> on_stack;
339  auto res = get_inlined_boolean_function(bf, on_stack);
340  if (res.is_error())
341  {
342  return ERR_APPEND(res.get_error(), "could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id));
343  }
344  bf = res.get();
345  }
346 
347  if (substitute_nets)
348  {
349  const auto& type_params = m_type->get_parameters();
350  std::map<std::string, BooleanFunction> net_subs;
351  for (const auto& var : bf.get_variable_names())
352  {
353  if (type_params.count(var))
354  {
355  continue; // parameter variable, not a net
356  }
357  const GatePin* var_pin = m_type->get_pin_by_name(var);
358  if (var_pin == nullptr || var_pin->get_direction() != PinDirection::input)
359  {
360  return ERR("could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": variable '" + var
361  + "' is not a recognized input pin");
362  }
363  const Net* const input_net = get_fan_in_net(var);
364  if (input_net == nullptr)
365  {
366  return ERR("could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": no fan-in net at pin '" + var + "'");
367  }
368  net_subs[var] = BooleanFunctionNetDecorator(*input_net).get_boolean_variable();
369  }
370  if (!net_subs.empty())
371  {
372  auto sub_res = bf.substitute(net_subs);
373  if (sub_res.is_error())
374  {
375  return ERR_APPEND(sub_res.get_error(),
376  "could not get Boolean function '" + internal_name + "' of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": net substitution failed");
377  }
378  bf = sub_res.get();
379  }
380  }
381 
382  return OK(bf);
383  }
384 
385  BooleanFunction Gate::get_boolean_function(const GatePin* pin) const
386  {
387  if (pin == nullptr)
388  {
389  auto output_pins = m_type->get_output_pins();
390  if (output_pins.empty())
391  {
392  log_warning("gate", "could not get Boolean function of gate '{}' with ID {}: gate type '{}' with ID {} has no output pins", m_name, m_id, m_type->get_name(), m_type->get_id());
393  return BooleanFunction();
394  }
395  pin = output_pins.front();
396  }
397  return get_boolean_function(pin->get_name());
398  }
399 
400  Result<BooleanFunction> Gate::get_boolean_function(const GatePin* pin, bool inlined, bool substitute_nets) const
401  {
402  if (pin == nullptr)
403  {
404  return ERR("could not get Boolean function of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": given pin is a nullptr");
405  }
406  return get_boolean_function(pin->get_name(), inlined, substitute_nets);
407  }
408 
409  bool Gate::has_boolean_function(const std::string& name) const
410  {
411  // follows the lookup of get_boolean_function
412  std::string internal_name = name;
413  if (internal_name.empty())
414  {
415  auto output_pins = m_type->get_output_pins();
416  if (output_pins.empty())
417  {
418  return false;
419  }
420  internal_name = output_pins.front()->get_name();
421  }
422 
423  if (m_type->has_component_of_type(GateTypeComponent::ComponentType::lut))
424  {
425  if (const GatePin* pin = m_type->get_pin_by_name(internal_name); pin != nullptr && pin->get_type() == PinType::lut)
426  {
427  return true;
428  }
429  }
430 
431  if (m_functions.find(internal_name) != m_functions.end())
432  {
433  return true;
434  }
435 
436  const auto& map = m_type->get_boolean_functions();
437  return map.find(internal_name) != map.end();
438  }
439 
440  bool Gate::has_boolean_function(const GatePin* pin) const
441  {
442  if (pin == nullptr)
443  {
444  // checks the first output pin, as get_boolean_function does
445  return has_boolean_function(std::string());
446  }
447 
448  return has_boolean_function(pin->get_name());
449  }
450 
451  std::unordered_map<std::string, BooleanFunction> Gate::get_boolean_functions(bool only_custom_functions) const
452  {
453  std::unordered_map<std::string, BooleanFunction> result;
454  if (!only_custom_functions)
455  {
456  for (const auto& [fn, _] : m_type->get_boolean_functions())
457  {
458  result[fn] = get_boolean_function(fn);
459  }
460  if (m_type->has_component_of_type(GateTypeComponent::ComponentType::lut))
461  {
462  for (const auto* p : m_type->get_pins([](const GatePin* p) { return p->get_type() == PinType::lut; }))
463  {
464  result[p->get_name()] = get_boolean_function(p->get_name());
465  }
466  }
467  }
468  for (const auto& [fn, _] : m_functions)
469  {
470  result[fn] = get_boolean_function(fn);
471  }
472  return result;
473  }
474 
475  Result<std::unordered_map<std::string, BooleanFunction>> Gate::get_boolean_functions(bool only_custom_functions, bool inlined, bool substitute_nets) const
476  {
477  std::vector<std::string> names;
478  if (!only_custom_functions)
479  {
480  for (const auto& [fn, _] : m_type->get_boolean_functions())
481  {
482  names.push_back(fn);
483  }
484  if (m_type->has_component_of_type(GateTypeComponent::ComponentType::lut))
485  {
486  for (const auto* p : m_type->get_pins([](const GatePin* p) { return p->get_type() == PinType::lut; }))
487  {
488  names.push_back(p->get_name());
489  }
490  }
491  }
492  for (const auto& [fn, _] : m_functions)
493  {
494  names.push_back(fn);
495  }
496 
497  std::unordered_map<std::string, BooleanFunction> result;
498  for (const auto& fn : names)
499  {
500  auto res = get_boolean_function(fn, inlined, substitute_nets);
501  if (res.is_error())
502  {
503  return ERR_APPEND(res.get_error(), "could not get Boolean functions of gate '" + m_name + "' with ID " + std::to_string(m_id));
504  }
505  result[fn] = res.get();
506  }
507  return OK(result);
508  }
509 
510  Result<BooleanFunction> Gate::get_inlined_boolean_function(BooleanFunction bf, std::unordered_set<std::string>& on_stack) const
511  {
512  const auto& type_params = m_type->get_parameters();
513  std::map<std::string, BooleanFunction> subs;
514  bool has_param_subs = false;
515 
516  for (const auto& var : bf.get_variable_names())
517  {
518  const GatePin* var_pin = m_type->get_pin_by_name(var);
519  if (var_pin == nullptr)
520  {
521  // May be a parameter — substitute with its instance value if set
522  if (type_params.count(var))
523  {
524  if (const auto it = m_parameters.find(var); it != m_parameters.end())
525  {
526  const auto& [decl, value] = it->second;
527  if (auto enc = decl.encode_as_int(value); enc.is_ok())
528  {
529  subs[var] = BooleanFunction::Const(enc.get(), decl.get_size());
530  has_param_subs = true;
531  }
532  }
533  }
534  // Unknown variable or un-valued parameter: leave as-is
535  continue;
536  }
537  const PinDirection dir = var_pin->get_direction();
538  if (dir == PinDirection::internal || dir == PinDirection::output)
539  {
540  if (on_stack.count(var))
541  {
542  return ERR("could not inline Boolean function of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": circular dependency at variable '" + var + "'");
543  }
544  on_stack.insert(var);
545  auto res = get_inlined_boolean_function(get_boolean_function(var_pin), on_stack);
546  on_stack.erase(var);
547  if (res.is_error())
548  {
549  return ERR_APPEND(res.get_error(), "could not inline Boolean function of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": failed at variable '" + var + "'");
550  }
551  subs[var] = res.get();
552  }
553  // input pins: leave as-is
554  }
555 
556  if (!subs.empty())
557  {
558  auto sub_res = bf.substitute(subs);
559  if (sub_res.is_error())
560  {
561  return ERR_APPEND(sub_res.get_error(), "could not inline Boolean function of gate '" + m_name + "' with ID " + std::to_string(m_id) + ": substitution failed");
562  }
563  bf = has_param_subs ? sub_res.get().simplify() : sub_res.get();
564  }
565 
566  return OK(bf);
567  }
568 
569  BooleanFunction Gate::get_lut_function(const GatePin* pin) const
570  {
571  if (pin == nullptr)
572  {
573  log_error("gate", "could not get LUT function of gate '{}' with ID {}: pin is nullptr.", m_name, m_id);
574  return BooleanFunction();
575  }
576 
577  const LUTComponent* lut_component = m_type->get_component_as<LUTComponent>([](const GateTypeComponent* c) { return c->get_type() == GateTypeComponent::ComponentType::lut; });
578  if (lut_component == nullptr)
579  {
580  return BooleanFunction();
581  }
582 
583  const LUTComponent::LUTOutputConfig* cfg = lut_component->get_output_pin_config(pin->get_name());
584  if (cfg == nullptr)
585  {
586  return BooleanFunction();
587  }
588 
589  const u32 bit_count = cfg->bit_count;
590  const u32 bit_offset = cfg->bit_offset;
591 
592  if (bit_count > 64)
593  {
594  log_error("gate", "LUT gate '{}' with ID {} in netlist with ID {} has an INIT string longer than 64 bits, which is not supported.", m_name, m_id, m_internal_manager->m_netlist->get_id());
595  return BooleanFunction();
596  }
597 
598  std::string config_str = lut_init_read(this, cfg->init_identifier);
599  if (config_str.empty())
600  {
601  return BooleanFunction::Const(BooleanFunction::Value::ZERO);
602  }
603 
604  if (cfg->input_pins.empty())
605  {
606  log_error("gate", "LUT gate '{}' with ID {}: output pin '{}' has no input_pins configured.", m_name, m_id, pin->get_name());
607  return BooleanFunction();
608  }
609  std::vector<GatePin*> inputs;
610  for (const auto& pname : cfg->input_pins)
611  {
612  if (GatePin* p = m_type->get_pin_by_name(pname); p != nullptr)
613  {
614  inputs.push_back(p);
615  }
616  }
617 
618  {
619  auto res = LUTComponent::extract_init_slice(config_str, bit_offset, bit_count);
620  if (res.is_error())
621  {
622  log_error("gate", "LUT gate '{}' with ID {} in netlist with ID {}: {}", m_name, m_id, m_internal_manager->m_netlist->get_id(), res.get_error().get());
623  return BooleanFunction();
624  }
625  config_str = res.get();
626  }
627 
628  u64 config = 0;
629  try
630  {
631  config = std::stoull(config_str, nullptr, 16);
632  }
633  catch (const std::invalid_argument&)
634  {
635  log_error("gate",
636  "LUT gate '{}' with ID {} in netlist with ID {} has invalid configuration string of '{}', which is not a hex value.",
637  m_name,
638  m_id,
639  m_internal_manager->m_netlist->get_id(),
640  config_str);
641  return BooleanFunction();
642  }
643  catch (const std::out_of_range&)
644  {
645  log_error("gate",
646  "LUT gate '{}' with ID {} in netlist with ID {} has invalid configuration string of '{}', which has too many hex digits.",
647  m_name,
648  m_id,
649  m_internal_manager->m_netlist->get_id(),
650  config_str);
651  return BooleanFunction();
652  }
653 
654  const u32 max_config_size = bit_count;
655 
656  if (cfg->is_ascending)
657  {
658  config = bitreverse(config) >> (64 - max_config_size);
659  }
660 
661  auto& cache = m_internal_manager->m_lut_function_cache;
662  const auto cache_key = std::make_pair(inputs, config);
663  if (const auto it = cache.find(cache_key); it != cache.end())
664  {
665  return it->second;
666  }
667 
668  const u32 config_size = (config == 0) ? 0 : (64u - static_cast<u32>(__builtin_clzll(config)));
669  if (config_size > max_config_size)
670  {
671  log_error("gate",
672  "LUT gate '{}' with ID {} in netlist with ID {} supports up to {} config bits, but '{}' encodes {} bits.",
673  m_name,
674  m_id,
675  m_internal_manager->m_netlist->get_id(),
676  max_config_size,
677  config_str,
678  config_str.size() * 4);
679  return BooleanFunction();
680  }
681 
682  auto result = BooleanFunction::Const(BooleanFunction::Value::ZERO);
683  for (u32 i = 0; config != 0 && i < max_config_size; i++)
684  {
685  if (config & 1)
686  {
687  auto conjunction = BooleanFunction::Const(1, 1);
688  auto input_values = i;
689  for (auto input : inputs)
690  {
691  conjunction &= ((input_values & 1) == 1) ? BooleanFunction::Var(input->get_name()) : ~BooleanFunction::Var(input->get_name());
692  input_values >>= 1;
693  }
694  result |= conjunction;
695  }
696  config >>= 1;
697  }
698 
699  auto f = result.simplify();
700  cache[cache_key] = f;
701  return f;
702  }
703 
704  bool Gate::add_boolean_function(const std::string& name, const BooleanFunction& func)
705  {
706  LUTComponent* lut_component = m_type->get_component_as<LUTComponent>([](const GateTypeComponent* component) { return component->get_type() == GateTypeComponent::ComponentType::lut; });
707  if (lut_component != nullptr)
708  {
709  auto lut_pins = m_type->get_pins([&name](const GatePin* p) { return p->get_type() == PinType::lut && p->get_name() == name; });
710  const LUTComponent::LUTOutputConfig* output_cfg = lut_component->get_output_pin_config(name);
711  if (!lut_pins.empty() && output_cfg != nullptr)
712  {
713  const std::string& key = output_cfg->init_identifier;
714  const u32 bit_offset = output_cfg->bit_offset;
715  const u32 bit_count = output_cfg->bit_count;
716 
717  {
718  std::vector<std::string> input_pin_names;
719  if (!output_cfg->input_pins.empty())
720  {
721  input_pin_names = output_cfg->input_pins;
722  }
723  else
724  {
725  input_pin_names = m_type->get_input_pin_names();
726  const u32 effective_count = __builtin_ctz(bit_count);
727  if (effective_count < input_pin_names.size())
728  {
729  input_pin_names.resize(effective_count);
730  }
731  }
732 
733  auto tt = func.compute_truth_table(input_pin_names);
734  if (tt.is_error())
735  {
736  log_error("netlist", "Boolean function '{} = {}' cannot be added to LUT gate '{}' with ID {}.", name, func.to_string(), m_name, m_id);
737  return false;
738  }
739  auto truth_table = tt.get();
740  if (truth_table.size() > 1)
741  {
742  log_error("netlist", "Boolean function '{} = {}' cannot be added to LUT gate '{}' with ID {} (= function is > 1-bit in output size).", name, func.to_string(), m_name, m_id);
743  return false;
744  }
745 
746  if (!output_cfg->is_ascending)
747  {
748  std::reverse(truth_table[0].begin(), truth_table[0].end());
749  }
750 
751  u64 new_bits = 0;
752  for (auto v : truth_table[0])
753  {
754  if (v == BooleanFunction::X)
755  {
756  log_error("netlist",
757  "Boolean function '{} = {}' cannot be added to LUT gate '{}' with ID {} in netlist with ID {} as its truth table contains undefined values.",
758  name,
759  func.to_string(),
760  m_name,
761  m_id,
762  m_internal_manager->m_netlist->get_id());
763  return false;
764  }
765  new_bits <<= 1;
766  new_bits |= v;
767  }
768 
769  // Ensure the base string has the full expected width before splicing.
770  const u32 total_inputs = m_type->get_input_pins().size();
771  std::string existing_str = lut_init_read(this, key);
772  if (existing_str.empty())
773  {
774  existing_str = std::string(static_cast<size_t>(1u << (total_inputs - 2)), '0');
775  }
776 
777  std::stringstream slice_ss;
778  slice_ss << std::hex << std::setfill('0') << std::setw(static_cast<int>((bit_count + 3) / 4)) << new_bits;
779 
780  auto res = LUTComponent::splice_init_slice(existing_str, slice_ss.str(), bit_offset, bit_count);
781  if (res.is_error())
782  {
783  log_error("netlist", "cannot add Boolean function '{}' to LUT gate '{}' with ID {}: {}.", name, m_name, m_id, res.get_error().get());
784  return false;
785  }
786  lut_init_write(this, key, res.get());
787  }
788  }
789  }
790 
791  m_functions[name] = func;
792  m_event_handler->notify(GateEvent::event::boolean_function_changed, this);
793  return true;
794  }
795 
796  bool Gate::mark_vcc_gate()
797  {
798  return m_internal_manager->m_netlist->mark_vcc_gate(this);
799  }
800 
801  bool Gate::mark_gnd_gate()
802  {
803  return m_internal_manager->m_netlist->mark_gnd_gate(this);
804  }
805 
806  bool Gate::unmark_vcc_gate()
807  {
808  return m_internal_manager->m_netlist->unmark_vcc_gate(this);
809  }
810 
811  bool Gate::unmark_gnd_gate()
812  {
813  return m_internal_manager->m_netlist->unmark_gnd_gate(this);
814  }
815 
816  bool Gate::is_vcc_gate() const
817  {
818  return m_internal_manager->m_netlist->is_vcc_gate(this);
819  }
820 
821  bool Gate::is_gnd_gate() const
822  {
823  return m_internal_manager->m_netlist->is_gnd_gate(this);
824  }
825 
826  const std::vector<Net*>& Gate::get_fan_in_nets() const
827  {
828  return m_in_nets;
829  }
830 
831  std::vector<Net*> Gate::get_fan_in_nets(const std::function<bool(Net*)>& filter) const
832  {
833  std::vector<Net*> res;
834  if (!filter)
835  {
836  res = m_in_nets;
837  }
838  else
839  {
840  for (auto n : m_in_nets)
841  {
842  if (!filter(n))
843  {
844  continue;
845  }
846  res.push_back(n);
847  }
848  }
849  return res;
850  }
851 
852  Net* Gate::get_fan_in_net(const std::string& pin_name) const
853  {
854  auto ep = get_fan_in_endpoint(pin_name);
855  if (ep == nullptr)
856  {
857  return nullptr;
858  }
859  return ep->get_net();
860  }
861 
862  Net* Gate::get_fan_in_net(const GatePin* pin) const
863  {
864  auto ep = get_fan_in_endpoint(pin);
865  if (ep == nullptr)
866  {
867  return nullptr;
868  }
869  return ep->get_net();
870  }
871 
872  bool Gate::is_fan_in_net(const Net* net) const
873  {
874  if (net == nullptr)
875  {
876  log_warning("gate", "could not check whether net is a fan-in of gate '{}' with ID {}: 'nullptr' given as net", m_name, m_id);
877  return false;
878  }
879 
880  if (const auto it = std::find_if(m_in_endpoints.begin(), m_in_endpoints.end(), [net](const Endpoint* ep) { return ep->get_net() == net; }); it != m_in_endpoints.end())
881  {
882  return true;
883  }
884 
885  return false;
886  }
887 
888  const std::vector<Endpoint*>& Gate::get_fan_in_endpoints() const
889  {
890  return m_in_endpoints;
891  }
892 
893  std::vector<Endpoint*> Gate::get_fan_in_endpoints(const std::function<bool(Endpoint*)>& filter) const
894  {
895  std::vector<Endpoint*> res;
896  if (!filter)
897  {
898  res = m_in_endpoints;
899  }
900  else
901  {
902  for (auto ep : m_in_endpoints)
903  {
904  if (!filter(ep))
905  {
906  continue;
907  }
908  res.push_back(ep);
909  }
910  }
911  return res;
912  }
913 
914  Endpoint* Gate::get_fan_in_endpoint(const std::string& pin_name) const
915  {
916  const GatePin* pin = m_type->get_pin_by_name(pin_name);
917  if (pin == nullptr)
918  {
919  log_warning("gate",
920  "could not get fan-in endpoint of pin '{}' at gate '{}' with ID {}: no pin with that name exists for gate type '{}'",
921  pin_name,
922  m_name,
923  std::to_string(m_id),
924  m_type->get_name());
925  return nullptr;
926  }
927  return get_fan_in_endpoint(pin);
928  }
929 
930  Endpoint* Gate::get_fan_in_endpoint(const GatePin* pin) const
931  {
932  if (pin == nullptr)
933  {
934  log_warning("gate", "could not get fan-in endpoint of gate '{}' with ID {}: 'nullptr' given as pin", m_name, m_id);
935  return nullptr;
936  }
937  if (PinDirection direction = pin->get_direction(); direction != PinDirection::input && direction != PinDirection::inout)
938  {
939  log_warning("gate", "could not get fan-in endpoint of pin '{}' at gate '{}' with ID {}: pin is not an input pin", pin->get_name(), m_name, m_id);
940  return nullptr;
941  }
942  auto it = std::find_if(m_in_endpoints.begin(), m_in_endpoints.end(), [pin](const auto* ep) { return ep->get_pin() == pin; });
943  if (it == m_in_endpoints.end())
944  {
945  log_debug("gate", "could not get fan-in endpoint of pin '{}' at gate '{}' with ID {}: no net is connected to pin", pin->get_name(), m_name, m_id);
946  return nullptr;
947  }
948 
949  return *it;
950  }
951 
952  Endpoint* Gate::get_fan_in_endpoint(const Net* net) const
953  {
954  if (net == nullptr)
955  {
956  log_warning("gate", "could not get fan-in endpoint of gate '{}' with ID {}: 'nullptr' given as net", m_name, m_id);
957  return nullptr;
958  }
959 
960  const auto it = std::find_if(m_in_endpoints.begin(), m_in_endpoints.end(), [net](const Endpoint* ep) { return ep->get_net() == net; });
961  if (it == m_in_endpoints.end())
962  {
963  log_warning("gate", "could not get fan-in endpoint of net '{}' with ID {} at gate '{}' with ID {}: net is not an input net", net->get_name(), net->get_id(), m_name, m_id);
964  return nullptr;
965  }
966 
967  return *it;
968  }
969 
970  const std::vector<Net*>& Gate::get_fan_out_nets() const
971  {
972  return m_out_nets;
973  }
974 
975  std::vector<Net*> Gate::get_fan_out_nets(const std::function<bool(Net*)>& filter) const
976  {
977  std::vector<Net*> res;
978  if (!filter)
979  {
980  res = m_out_nets;
981  }
982  else
983  {
984  for (auto n : m_out_nets)
985  {
986  if (!filter(n))
987  {
988  continue;
989  }
990  res.push_back(n);
991  }
992  }
993  return res;
994  }
995 
996  Net* Gate::get_fan_out_net(const std::string& pin_name) const
997  {
998  auto ep = get_fan_out_endpoint(pin_name);
999  if (ep == nullptr)
1000  {
1001  return nullptr;
1002  }
1003  return ep->get_net();
1004  }
1005 
1006  Net* Gate::get_fan_out_net(const GatePin* pin) const
1007  {
1008  auto ep = get_fan_out_endpoint(pin);
1009  if (ep == nullptr)
1010  {
1011  return nullptr;
1012  }
1013  return ep->get_net();
1014  }
1015 
1016  bool Gate::is_fan_out_net(const Net* net) const
1017  {
1018  if (net == nullptr)
1019  {
1020  log_warning("gate", "could not check whether net is a fan-out of gate '{}' with ID {}: 'nullptr' given as net", m_name, m_id);
1021  return false;
1022  }
1023 
1024  if (const auto it = std::find_if(m_out_endpoints.begin(), m_out_endpoints.end(), [net](const Endpoint* ep) { return ep->get_net() == net; }); it != m_out_endpoints.end())
1025  {
1026  return true;
1027  }
1028 
1029  return false;
1030  }
1031 
1032  const std::vector<Endpoint*>& Gate::get_fan_out_endpoints() const
1033  {
1034  return m_out_endpoints;
1035  }
1036 
1037  std::vector<Endpoint*> Gate::get_fan_out_endpoints(const std::function<bool(Endpoint*)>& filter) const
1038  {
1039  std::vector<Endpoint*> res;
1040  if (!filter)
1041  {
1042  res = m_out_endpoints;
1043  }
1044  else
1045  {
1046  for (auto ep : m_out_endpoints)
1047  {
1048  if (!filter(ep))
1049  {
1050  continue;
1051  }
1052  res.push_back(ep);
1053  }
1054  }
1055  return res;
1056  }
1057 
1058  Endpoint* Gate::get_fan_out_endpoint(const std::string& pin_name) const
1059  {
1060  const GatePin* pin = m_type->get_pin_by_name(pin_name);
1061  if (pin == nullptr)
1062  {
1063  log_warning("gate", "could not get fan-out endpoint of pin '{}' at gate '{}' with ID {}: no pin with that name exists for gate type '{}'", pin_name, m_name, m_id, m_type->get_name());
1064  return nullptr;
1065  }
1066  return get_fan_out_endpoint(pin);
1067  }
1068 
1069  Endpoint* Gate::get_fan_out_endpoint(const GatePin* pin) const
1070  {
1071  if (pin == nullptr)
1072  {
1073  log_warning("gate", "could not get fan-out endpoint of gate '{}' with ID {}: 'nullptr' given as pin", m_name, m_id);
1074  return nullptr;
1075  }
1076  if (PinDirection direction = pin->get_direction(); direction != PinDirection::output && direction != PinDirection::inout)
1077  {
1078  log_warning("gate", "could not get fan-out endpoint of pin '{}' at gate '{}' with ID {}: pin is not an output pin", pin->get_name(), m_name, m_id);
1079  return nullptr;
1080  }
1081  auto it = std::find_if(m_out_endpoints.begin(), m_out_endpoints.end(), [pin](const auto* ep) { return ep->get_pin() == pin; });
1082  if (it == m_out_endpoints.end())
1083  {
1084  log_debug("gate", "could not get fan-out endpoint of pin '{}' at gate '{}' with ID {}: no net is connected to pin", pin->get_name(), m_name, m_id);
1085  return nullptr;
1086  }
1087 
1088  return *it;
1089  }
1090 
1091  Endpoint* Gate::get_fan_out_endpoint(const Net* net) const
1092  {
1093  if (net == nullptr)
1094  {
1095  log_warning("gate", "could not get fan-out endpoint of gate '{}' with ID {}: 'nullptr' given as net", m_name, m_id);
1096  return nullptr;
1097  }
1098 
1099  const auto it = std::find_if(m_out_endpoints.begin(), m_out_endpoints.end(), [net](const Endpoint* ep) { return ep->get_net() == net; });
1100  if (it == m_out_endpoints.end())
1101  {
1102  log_warning("gate", "could not get fan-out endpoint of net '{}' with ID {} at gate '{}' with ID {}: net is not an output net", net->get_name(), net->get_id(), m_name, m_id);
1103  return nullptr;
1104  }
1105 
1106  return *it;
1107  }
1108 
1109  std::vector<Gate*> Gate::get_unique_predecessors(const std::function<bool(const GatePin* pin, Endpoint*)>& filter) const
1110  {
1111  std::unordered_set<Gate*> res;
1112  auto endpoints = get_predecessors(filter);
1113  res.reserve(endpoints.size());
1114  for (auto ep : endpoints)
1115  {
1116  res.insert(ep->get_gate());
1117  }
1118  return std::vector<Gate*>(res.begin(), res.end());
1119  }
1120 
1121  std::vector<Endpoint*> Gate::get_predecessors(const std::function<bool(const GatePin* pin, Endpoint*)>& filter) const
1122  {
1123  std::vector<Endpoint*> result;
1124  for (auto ep : m_in_endpoints)
1125  {
1126  auto pred_pin = ep->get_pin();
1127  auto predecessors = ep->get_net()->get_sources();
1128  if (!filter)
1129  {
1130  result.insert(result.end(), predecessors.begin(), predecessors.end());
1131  }
1132  else
1133  {
1134  for (auto pre : predecessors)
1135  {
1136  if (!filter(pred_pin, pre))
1137  {
1138  continue;
1139  }
1140  result.push_back(pre);
1141  }
1142  }
1143  }
1144  return result;
1145  }
1146 
1147  Endpoint* Gate::get_predecessor(const GatePin* pin) const
1148  {
1149  if (pin == nullptr)
1150  {
1151  log_warning("gate", "could not get predecessor endpoint of gate '{}' with ID {}: 'nullptr' given as pin", m_name, std::to_string(m_id));
1152  return nullptr;
1153  }
1154  if (auto direction = pin->get_direction(); direction != PinDirection::input && direction != PinDirection::inout)
1155  {
1156  log_warning("gate", "could not get predecessor endpoint of pin '{}' at gate '{}' with ID {}: pin is not an input pin", pin->get_name(), m_name, std::to_string(m_id));
1157  return nullptr;
1158  }
1159  auto predecessors = get_predecessors([pin](const auto p, auto) -> bool { return *p == *pin; });
1160  if (predecessors.size() == 0)
1161  {
1162  return nullptr;
1163  }
1164  if (predecessors.size() > 1)
1165  {
1166  log_warning("gate", "gate '{}' with ID {} has multiple predecessors at input pin '{}' in netlist with ID {}.", m_name, m_id, pin->get_name(), m_internal_manager->m_netlist->get_id());
1167  return nullptr;
1168  }
1169 
1170  return predecessors[0];
1171  }
1172 
1173  Endpoint* Gate::get_predecessor(const std::string& pin_name) const
1174  {
1175  const GatePin* pin = m_type->get_pin_by_name(pin_name);
1176  if (pin == nullptr)
1177  {
1178  log_warning("gate",
1179  "could not get predecessor endpoint of pin '{}' at gate '{}' with ID {}: no pin with that name exists for gate type '{}'",
1180  pin_name,
1181  m_name,
1182  std::to_string(m_id),
1183  m_type->get_name());
1184  return nullptr;
1185  }
1186  return get_predecessor(pin);
1187  }
1188 
1189  std::vector<Gate*> Gate::get_unique_successors(const std::function<bool(const GatePin* pin, Endpoint*)>& filter) const
1190  {
1191  std::unordered_set<Gate*> res;
1192  auto endpoints = get_successors(filter);
1193  res.reserve(endpoints.size());
1194  for (auto ep : endpoints)
1195  {
1196  res.insert(ep->get_gate());
1197  }
1198  return std::vector<Gate*>(res.begin(), res.end());
1199  }
1200 
1201  std::vector<Endpoint*> Gate::get_successors(const std::function<bool(const GatePin* pin, Endpoint*)>& filter) const
1202  {
1203  std::vector<Endpoint*> result;
1204  for (auto ep : m_out_endpoints)
1205  {
1206  auto suc_pin = ep->get_pin();
1207  auto successors = ep->get_net()->get_destinations();
1208  if (!filter)
1209  {
1210  result.insert(result.end(), successors.begin(), successors.end());
1211  }
1212  else
1213  {
1214  for (auto suc : successors)
1215  {
1216  if (!filter(suc_pin, suc))
1217  {
1218  continue;
1219  }
1220  result.push_back(suc);
1221  }
1222  }
1223  }
1224  return result;
1225  }
1226 
1227  Endpoint* Gate::get_successor(const GatePin* pin) const
1228  {
1229  if (pin == nullptr)
1230  {
1231  log_warning("gate", "could not get successor endpoint of gate '{}' with ID {}: 'nullptr' given as pin", m_name, std::to_string(m_id));
1232  return nullptr;
1233  }
1234  if (auto direction = pin->get_direction(); direction != PinDirection::output && direction != PinDirection::inout)
1235  {
1236  log_warning("gate", "could not get successor endpoint of pin '{}' at gate '{}' with ID {}: pin is not an output pin", pin->get_name(), m_name, std::to_string(m_id));
1237  return nullptr;
1238  }
1239  auto successors = get_successors([pin](const auto p, auto) -> bool { return *p == *pin; });
1240  if (successors.size() == 0)
1241  {
1242  return nullptr;
1243  }
1244  if (successors.size() > 1)
1245  {
1246  log_warning("gate", "gate '{}' with ID {} has multiple successor at output pin '{}' in netlist with ID {}.", m_name, m_id, pin->get_name(), m_internal_manager->m_netlist->get_id());
1247  return nullptr;
1248  }
1249 
1250  return successors[0];
1251  }
1252 
1253  Endpoint* Gate::get_successor(const std::string& pin_name) const
1254  {
1255  const GatePin* pin = m_type->get_pin_by_name(pin_name);
1256  if (pin == nullptr)
1257  {
1258  log_warning("gate",
1259  "could not get successor endpoint of pin '{}' at gate '{}' with ID {}: no pin with that name exists for gate type '{}'",
1260  pin_name,
1261  m_name,
1262  std::to_string(m_id),
1263  m_type->get_name());
1264  return nullptr;
1265  }
1266  return get_successor(pin);
1267  }
1268 
1269 } // namespace hal
const std::string & get_name() const
Definition: base_pin.h:110
PinType get_type() const
Definition: base_pin.h:150
PinDirection get_direction() const
Definition: base_pin.h:130
std::set< std::string > get_variable_names() const
Result< std::vector< std::vector< Value > > > compute_truth_table(const std::vector< std::string > &ordered_variables={}, bool remove_unknown_variables=false) const
BooleanFunction simplify() const
static std::string to_string(Value value)
std::vector< BooleanFunction > get_parameters() const
BooleanFunction substitute(const std::string &old_variable_name, const std::string &new_variable_name) const
Result< std::string > get_parameter_value(const std::string &name) const
bool has_parameter(const Parameter &param) const
Result< std::monostate > set_parameter(const Parameter &param, const std::string &value)
Definition: gate.h:59
i32 get_location_x() const
Definition: gate.cpp:167
i32 get_location_y() const
Definition: gate.cpp:172
GateType * get_type() const
Definition: gate.cpp:162
const std::string & get_name() const
Definition: gate.cpp:142
bool is_vcc_gate() const
Definition: gate.cpp:816
bool is_gnd_gate() const
Definition: gate.cpp:821
std::unordered_map< std::string, BooleanFunction > get_boolean_functions(bool only_custom_functions=false) const
Definition: gate.cpp:451
u32 get_id() const
Definition: gate.cpp:132
T * get_component_as(const std::function< bool(const GateTypeComponent *)> &filter=nullptr)
const LUTOutputConfig * get_output_pin_config(const std::string &pin_name) const
std::vector< Module * > get_parent_modules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=true) const
Definition: module.cpp:131
Definition: net.h:58
uint64_t u64
Definition: defines.h:42
uint16_t u16
Definition: defines.h:40
uint32_t u32
Definition: defines.h:41
int32_t i32
Definition: defines.h:36
#define log_error(channel,...)
Definition: log.h:78
#define log_debug(channel,...)
Definition: log.h:74
#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
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
Net * net
PinDirection direction
std::string name
i32 id
std::vector< std::string > input_pins
Definition: lut_component.h:76
static Result< Parameter > BitVector(const std::string &name, u16 size, const std::string &default_value)
Definition: parameter.cpp:340