HAL  v4.5.0-258-gf372a0264
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
lut_component.cpp
Go to the documentation of this file.
2 
5 
6 #include <algorithm>
7 #include <cctype>
8 #include <iomanip>
9 #include <limits>
10 #include <sstream>
11 
12 namespace hal
13 {
14  LUTComponent::LUTComponent(std::unordered_map<std::string, LUTOutputConfig> configs) : m_output_pin_configs(std::move(configs))
15  {
16  }
17 
18  std::unique_ptr<LUTComponent> LUTComponent::create(std::unordered_map<std::string, LUTOutputConfig> configs)
19  {
20  for (auto it = configs.begin(); it != configs.end();)
21  {
22  const u32 bc = it->second.bit_count;
23  if (bc == 0 || (bc & (bc - 1)) != 0)
24  {
25  log_error("lut_component", "cannot add output pin config for pin '{}': bit_count {} must be a non-zero power of two — skipping.", it->first, bc);
26  it = configs.erase(it);
27  }
28  else if (it->second.input_pins.empty())
29  {
30  log_error("lut_component", "cannot add output pin config for pin '{}': input_pins must be non-empty — skipping.", it->first);
31  it = configs.erase(it);
32  }
33  else
34  {
35  ++it;
36  }
37  }
38  return std::unique_ptr<LUTComponent>(new LUTComponent(std::move(configs)));
39  }
40 
41  LUTComponent::ComponentType LUTComponent::get_type() const
42  {
43  return m_type;
44  }
45 
46  bool LUTComponent::is_class_of(const GateTypeComponent* component)
47  {
48  return component->get_type() == m_type;
49  }
50 
51  std::vector<GateTypeComponent*> LUTComponent::get_components(const std::function<bool(const GateTypeComponent*)>& filter) const
52  {
53  return {};
54  }
55 
56  const LUTComponent::LUTOutputConfig* LUTComponent::get_output_pin_config(const std::string& pin_name) const
57  {
58  if (auto it = m_output_pin_configs.find(pin_name); it != m_output_pin_configs.end())
59  {
60  return &it->second;
61  }
62  return nullptr;
63  }
64 
65  const std::unordered_map<std::string, LUTComponent::LUTOutputConfig>& LUTComponent::get_output_pin_configs() const
66  {
67  return m_output_pin_configs;
68  }
69 
70  Result<std::string> LUTComponent::extract_init_slice(const std::string& full_hex, u32 bit_offset, u32 bit_count)
71  {
72  if (bit_count == 0)
73  {
74  return ERR("bit_count must be non-zero");
75  }
76 
77  if (full_hex.empty())
78  {
79  return ERR("INIT string is empty");
80  }
81 
82  const size_t min_chars = (static_cast<size_t>(bit_offset) + bit_count + 3) / 4;
83  if (full_hex.size() < min_chars)
84  {
85  return ERR("INIT string '" + full_hex + "' is too short: need at least " + std::to_string(min_chars) + " hex char(s) to cover slice [" + std::to_string(bit_offset) + ", "
86  + std::to_string(bit_offset + bit_count) + "), got " + std::to_string(full_hex.size()));
87  }
88 
89  u64 full_val = 0;
90  try
91  {
92  full_val = std::stoull(full_hex, nullptr, 16);
93  }
94  catch (const std::invalid_argument&)
95  {
96  return ERR("INIT string '" + full_hex + "' is not a valid hex value");
97  }
98  catch (const std::out_of_range&)
99  {
100  return ERR("INIT string '" + full_hex + "' is out of range for u64");
101  }
102 
103  const u64 mask = (bit_count >= 64) ? std::numeric_limits<u64>::max() : ((1ULL << bit_count) - 1);
104  const u64 sliced = (full_val >> bit_offset) & mask;
105 
106  std::stringstream ss;
107  ss << std::hex << std::uppercase << std::setfill('0') << std::setw(static_cast<int>((bit_count + 3) / 4)) << sliced;
108  return OK(ss.str());
109  }
110 
111  Result<std::string> LUTComponent::splice_init_slice(const std::string& full_hex, const std::string& slice_hex, u32 bit_offset, u32 bit_count)
112  {
113  if (bit_count == 0)
114  {
115  return ERR("bit_count must be non-zero");
116  }
117 
118  u64 existing = 0;
119  if (!full_hex.empty())
120  {
121  try
122  {
123  existing = std::stoull(full_hex, nullptr, 16);
124  }
125  catch (const std::invalid_argument&)
126  {
127  return ERR("full INIT string '" + full_hex + "' is not a valid hex value");
128  }
129  catch (const std::out_of_range&)
130  {
131  return ERR("full INIT string '" + full_hex + "' is out of range for u64");
132  }
133  }
134 
135  u64 new_slice = 0;
136  try
137  {
138  new_slice = std::stoull(slice_hex, nullptr, 16);
139  }
140  catch (const std::invalid_argument&)
141  {
142  return ERR("slice value '" + slice_hex + "' is not a valid hex value");
143  }
144  catch (const std::out_of_range&)
145  {
146  return ERR("slice value '" + slice_hex + "' is out of range for u64");
147  }
148 
149  const u64 mask = (bit_count >= 64) ? std::numeric_limits<u64>::max() : ((1ULL << bit_count) - 1);
150  const u64 spliced = (existing & ~(mask << bit_offset)) | ((new_slice & mask) << bit_offset);
151 
152  const int width = full_hex.empty() ? static_cast<int>((bit_offset + bit_count + 3) / 4) : static_cast<int>(full_hex.size());
153 
154  std::stringstream ss;
155  ss << std::hex << std::uppercase << std::setfill('0') << std::setw(width) << spliced;
156  return OK(ss.str());
157  }
158 
159  namespace
160  {
161  std::string lut_param_read(const Gate* gate, const std::string& key)
162  {
163  if (!gate->has_parameter(key))
164  {
165  return "";
166  }
167  const std::string pv = gate->get_parameter_value(key).get();
168  return (pv.size() >= 2 && pv[0] == '0' && pv[1] == 'x') ? pv.substr(2) : pv;
169  }
170  } // namespace
171 
172  Result<std::string> LUTComponent::get_init_string(const Gate* gate, const std::string& pin_name) const
173  {
174  if (gate == nullptr)
175  {
176  return ERR("gate is nullptr");
177  }
178  const GatePin* pin = gate->get_type()->get_pin_by_name(pin_name);
179  if (pin == nullptr)
180  {
181  return ERR("pin '" + pin_name + "' does not exist on gate type '" + gate->get_type()->get_name() + "'");
182  }
183  return get_init_string(gate, pin);
184  }
185 
186  Result<std::string> LUTComponent::get_init_string(const Gate* gate, const GatePin* pin) const
187  {
188  if (gate == nullptr)
189  {
190  return ERR("gate is nullptr");
191  }
192  if (pin == nullptr)
193  {
194  return ERR("pin is nullptr");
195  }
196  if (pin->get_type() != PinType::lut)
197  {
198  return ERR("pin '" + pin->get_name() + "' is not of type PinType::lut");
199  }
200  const PinDirection dir = pin->get_direction();
201  if (dir != PinDirection::output && dir != PinDirection::internal)
202  {
203  return ERR("pin '" + pin->get_name() + "' must have direction output or internal");
204  }
205  const LUTOutputConfig* cfg = get_output_pin_config(pin->get_name());
206  if (cfg == nullptr)
207  {
208  return ERR("pin '" + pin->get_name() + "' has no INIT config");
209  }
210  const std::string full_str = lut_param_read(gate, cfg->init_identifier);
211  auto res = extract_init_slice(full_str, cfg->bit_offset, cfg->bit_count);
212  if (res.is_error())
213  {
214  return ERR("could not get INIT string for gate '" + gate->get_name() + "': " + res.get_error().get());
215  }
216  return OK(res.get());
217  }
218 
219  Result<std::monostate> LUTComponent::set_init_string(Gate* gate, const std::string& pin_name, const std::string& hex) const
220  {
221  if (gate == nullptr)
222  {
223  return ERR("gate is nullptr");
224  }
225  const GatePin* pin = gate->get_type()->get_pin_by_name(pin_name);
226  if (pin == nullptr)
227  {
228  return ERR("pin '" + pin_name + "' does not exist on gate type '" + gate->get_type()->get_name() + "'");
229  }
230  return set_init_string(gate, pin, hex);
231  }
232 
233  Result<std::monostate> LUTComponent::set_init_string(Gate* gate, const GatePin* pin, const std::string& hex) const
234  {
235  if (gate == nullptr)
236  {
237  return ERR("gate is nullptr");
238  }
239  if (pin == nullptr)
240  {
241  return ERR("pin is nullptr");
242  }
243  if (pin->get_type() != PinType::lut)
244  {
245  return ERR("pin '" + pin->get_name() + "' is not of type PinType::lut");
246  }
247  const PinDirection dir = pin->get_direction();
248  if (dir != PinDirection::output && dir != PinDirection::internal)
249  {
250  return ERR("pin '" + pin->get_name() + "' must have direction output or internal");
251  }
252  const LUTOutputConfig* cfg = get_output_pin_config(pin->get_name());
253  if (cfg == nullptr)
254  {
255  return ERR("pin '" + pin->get_name() + "' has no INIT config");
256  }
257  if (hex.empty() || !std::all_of(hex.begin(), hex.end(), [](unsigned char c) { return std::isxdigit(c); }))
258  {
259  return ERR("'" + hex + "' is not a valid hex string");
260  }
261  const size_t expected_chars = (static_cast<size_t>(cfg->bit_count) + 3) / 4;
262  if (hex.size() != expected_chars)
263  {
264  return ERR("hex string '" + hex + "' has wrong length: expected " + std::to_string(expected_chars) + " characters for " + std::to_string(cfg->bit_count) + " bits");
265  }
266 
267  const std::string existing_str = lut_param_read(gate, cfg->init_identifier);
268  auto res = splice_init_slice(existing_str, hex, cfg->bit_offset, cfg->bit_count);
269  if (res.is_error())
270  {
271  return ERR("could not set INIT string for gate '" + gate->get_name() + "': " + res.get_error().get());
272  }
273 
274  const std::string spliced_str = res.get();
275  const std::string value = "0x" + spliced_str;
276  const size_t nbits = spliced_str.size() * 4;
277  auto param_res = Parameter::BitVector(cfg->init_identifier, static_cast<u16>(nbits), "");
278  if (param_res.is_error())
279  {
280  return ERR("could not create parameter: " + param_res.get_error().get());
281  }
282  gate->set_parameter(param_res.get(), value);
283  return OK({});
284  }
285 } // 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
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
GateType * get_type() const
Definition: gate.cpp:162
const std::string & get_name() const
Definition: gate.cpp:142
virtual ComponentType get_type() const =0
const std::string & get_name() const
Definition: gate_type.cpp:64
GatePin * get_pin_by_name(const std::string &name) const
Definition: gate_type.cpp:318
uint64_t u64
Definition: defines.h:42
uint16_t u16
Definition: defines.h:40
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36