HAL  v4.5.0-257-ge24279b4e
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
hgl_writer.cpp
Go to the documentation of this file.
2 
11 #include "hal_core/utilities/log.h"
12 #include "rapidjson/filewritestream.h"
13 #include "rapidjson/prettywriter.h"
14 
15 #include <algorithm>
16 #include <iostream>
17 #include <string>
18 
19 namespace hal
20 {
21  bool HGLWriter::write(const GateLibrary* gate_lib, const std::filesystem::path& file_path)
22  {
23  if (gate_lib == nullptr)
24  {
25  log_error("hgl_writer", "received a nullptr as gate library.", file_path.string());
26  return false;
27  }
28 
29  FILE* fp = fopen(file_path.string().c_str(), "w");
30  if (fp == NULL)
31  {
32  log_error("hgl_writer", "unable to open '{}' for writing.", file_path.string());
33  return false;
34  }
35 
36  rapidjson::Document document;
37  document.SetObject();
38 
39  if (!write_gate_library(document, gate_lib))
40  {
41  fclose(fp);
42  return false;
43  }
44 
45  char writeBuffer[65536];
46  rapidjson::FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
47 
48  rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(os);
49  document.Accept(writer);
50 
51  fclose(fp);
52 
53  return true;
54  }
55 
56  bool HGLWriter::write_gate_library(rapidjson::Document& document, const GateLibrary* gate_lib)
57  {
58  rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
59 
60  // file format version
61  document.AddMember("version", HGL_FORMAT_VERSION, allocator);
62 
63  // library name
64  document.AddMember("library", gate_lib->get_name(), allocator);
65 
66  // gate location data specification
67  rapidjson::Value gate_locs(rapidjson::kObjectType);
68  gate_locs.AddMember("data_category", gate_lib->get_gate_location_data_category(), allocator);
69  const std::pair<std::string, std::string>& location_identifiers = gate_lib->get_gate_location_data_identifiers();
70  gate_locs.AddMember("data_x_identifier", location_identifiers.first, allocator);
71  gate_locs.AddMember("data_y_identifier", location_identifiers.second, allocator);
72  document.AddMember("gate_locations", gate_locs, allocator);
73 
74  // gate types
75  std::vector<GateType*> gate_types;
76 
77  for (const auto& gt : gate_lib->get_gate_types())
78  {
79  if ((gt.first != "HAL_GND") && (gt.first != "HAL_VDD"))
80  {
81  gate_types.push_back(gt.second);
82  }
83  }
84 
85  std::sort(gate_types.begin(), gate_types.end(), [](GateType* l, GateType* r) { return l->get_id() < r->get_id(); });
86 
87  rapidjson::Value cells(rapidjson::kArrayType);
88  for (const auto gt : gate_types)
89  {
90  rapidjson::Value cell(rapidjson::kObjectType);
91 
92  // name
93  cell.AddMember("name", gt->get_name(), allocator);
94 
95  // base type
96  std::set<GateTypeProperty> properties = gt->get_properties();
97 
98  rapidjson::Value bts(rapidjson::kArrayType);
99 
100  for (const auto& property : properties)
101  {
102  std::string bt_str = enum_to_string<GateTypeProperty>(property);
103  bts.PushBack(rapidjson::Value{}.SetString(bt_str.c_str(), bt_str.length(), allocator), allocator);
104  }
105 
106  cell.AddMember("types", bts, allocator);
107 
108  // parameters: declared at the gate-type level. Variables in Boolean functions whose
109  // names match a parameter are sized according to the declaration when re-parsed.
110  const auto& parameters = gt->get_parameters();
111  if (!parameters.empty())
112  {
113  rapidjson::Value params_array(rapidjson::kArrayType);
114  for (const auto& [pname, p] : parameters)
115  {
116  rapidjson::Value entry(rapidjson::kObjectType);
117  entry.AddMember("name", rapidjson::Value{}.SetString(pname.c_str(), pname.length(), allocator), allocator);
118  switch (p.get_type())
119  {
121  entry.AddMember("type", "boolean", allocator);
122  break;
124  entry.AddMember("type", "bit_vector", allocator);
125  entry.AddMember("size", static_cast<u32>(p.get_size()), allocator);
126  break;
128  entry.AddMember("type", "logic_vector", allocator);
129  entry.AddMember("size", static_cast<u32>(p.get_size()), allocator);
130  break;
132  entry.AddMember("type", "integer", allocator);
133  break;
135  entry.AddMember("type", "string", allocator);
136  break;
138  entry.AddMember("type", "float", allocator);
139  break;
141  entry.AddMember("type", "time", allocator);
142  break;
143  case Parameter::Type::Enum: {
144  entry.AddMember("type", "enum", allocator);
145  rapidjson::Value values_array(rapidjson::kArrayType);
146  for (const auto& v : p.get_enum_values())
147  {
148  values_array.PushBack(rapidjson::Value{}.SetString(v.c_str(), v.length(), allocator), allocator);
149  }
150  entry.AddMember("values", values_array, allocator);
151  break;
152  }
153  }
154  entry.AddMember("default", rapidjson::Value{}.SetString(p.get_default_value().c_str(), p.get_default_value().length(), allocator), allocator);
155  params_array.PushBack(entry, allocator);
156  }
157  cell.AddMember("parameters", params_array, allocator);
158  }
159 
160  std::unordered_map<std::string, BooleanFunction> functions = gt->get_boolean_functions();
161 
162  // lut_config, ff_config, latch_config, ram_config
163  if (LUTComponent* lut_component = gt->get_component_as<LUTComponent>([](const GateTypeComponent* c) { return LUTComponent::is_class_of(c); }); lut_component != nullptr)
164  {
165  rapidjson::Value lut_config(rapidjson::kObjectType);
166 
167  rapidjson::Value output_pins(rapidjson::kArrayType);
168  const auto& pin_configs = lut_component->get_output_pin_configs();
169  for (const GatePin* pin : gt->get_pins([](const GatePin* p) { return p->get_type() == PinType::lut; }))
170  {
171  const std::string& pin_name = pin->get_name();
172  rapidjson::Value entry(rapidjson::kObjectType);
173  entry.AddMember("pin", rapidjson::Value{}.SetString(pin_name.c_str(), pin_name.length(), allocator), allocator);
174  const auto it = pin_configs.find(pin_name);
175  if (it == pin_configs.end())
176  {
177  log_error("hgl_writer", "LUT gate type '{}': output pin '{}' has no INIT config — skipping.", gt->get_name(), pin_name);
178  continue;
179  }
180  const auto& cfg = it->second;
181  entry.AddMember("data_identifier", rapidjson::Value{}.SetString(cfg.init_identifier.c_str(), cfg.init_identifier.length(), allocator), allocator);
182  entry.AddMember("bit_offset", cfg.bit_offset, allocator);
183  entry.AddMember("bit_count", cfg.bit_count, allocator);
184  entry.AddMember("is_ascending", cfg.is_ascending, allocator);
185  rapidjson::Value input_pins_arr(rapidjson::kArrayType);
186  for (const auto& ip : cfg.input_pins)
187  {
188  input_pins_arr.PushBack(rapidjson::Value{}.SetString(ip.c_str(), ip.length(), allocator), allocator);
189  }
190  entry.AddMember("input_pins", input_pins_arr, allocator);
191  output_pins.PushBack(entry, allocator);
192  }
193  lut_config.AddMember("output_pins", output_pins, allocator);
194  cell.AddMember("lut_config", lut_config, allocator);
195  }
196  else if (FFComponent* ff_component = gt->get_component_as<FFComponent>([](const GateTypeComponent* c) { return FFComponent::is_class_of(c); }); ff_component != nullptr)
197  {
198  rapidjson::Value ff_config(rapidjson::kObjectType);
199 
200  StateComponent* state_component = ff_component->get_component_as<StateComponent>([](const GateTypeComponent* c) { return StateComponent::is_class_of(c); });
201  if (state_component == nullptr)
202  {
203  log_error("hgl_writer", "missing StateComponent for FF state identifiers of gate type '{}'.", gt->get_name());
204  return false;
205  }
206 
207  ff_config.AddMember("state", state_component->get_state_identifier(), allocator);
208  ff_config.AddMember("neg_state", state_component->get_neg_state_identifier(), allocator);
209 
210  InitComponent* init_component = state_component->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
211  if (init_component != nullptr)
212  {
213  // data_category, data_identifier
214  ff_config.AddMember("data_category", init_component->get_init_category(), allocator);
215  ff_config.AddMember("data_identifier", init_component->get_init_identifiers().front(), allocator);
216  }
217 
218  // next_state, clocked_on, clear_on, preset_on
219  ff_config.AddMember("next_state", ff_component->get_next_state_function().to_string(), allocator);
220  ff_config.AddMember("clocked_on", ff_component->get_clock_function().to_string(), allocator);
221  if (BooleanFunction bf = ff_component->get_async_reset_function(); !bf.is_empty())
222  {
223  ff_config.AddMember("clear_on", bf.to_string(), allocator);
224  }
225  if (BooleanFunction bf = ff_component->get_async_set_function(); !bf.is_empty())
226  {
227  ff_config.AddMember("preset_on", bf.to_string(), allocator);
228  }
229 
230  std::pair<AsyncSetResetBehavior, AsyncSetResetBehavior> cp_behav = ff_component->get_async_set_reset_behavior();
231  if (cp_behav.first != AsyncSetResetBehavior::undef)
232  {
233  ff_config.AddMember("state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.first), allocator);
234  }
235  if (cp_behav.second != AsyncSetResetBehavior::undef)
236  {
237  ff_config.AddMember("neg_state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.second), allocator);
238  }
239 
240  cell.AddMember("ff_config", ff_config, allocator);
241  }
242  else if (LatchComponent* latch_component = gt->get_component_as<LatchComponent>([](const GateTypeComponent* c) { return LatchComponent::is_class_of(c); }); latch_component != nullptr)
243  {
244  rapidjson::Value latch_config(rapidjson::kObjectType);
245 
246  StateComponent* state_component = latch_component->get_component_as<StateComponent>([](const GateTypeComponent* c) { return StateComponent::is_class_of(c); });
247  if (state_component == nullptr)
248  {
249  log_error("hgl_writer", "missing StateComponent for latch state identifiers of gate type '{}'.", gt->get_name());
250  return false;
251  }
252 
253  latch_config.AddMember("state", state_component->get_state_identifier(), allocator);
254  latch_config.AddMember("neg_state", state_component->get_neg_state_identifier(), allocator);
255 
256  // next_state, clocked_on, clear_on, preset_on
257  if (BooleanFunction bf = latch_component->get_data_in_function(); !bf.is_empty())
258  {
259  latch_config.AddMember("data_in", bf.to_string(), allocator);
260  }
261  if (BooleanFunction bf = latch_component->get_enable_function(); !bf.is_empty())
262  {
263  latch_config.AddMember("enable_on", bf.to_string(), allocator);
264  }
265  if (BooleanFunction bf = latch_component->get_async_reset_function(); !bf.is_empty())
266  {
267  latch_config.AddMember("clear_on", bf.to_string(), allocator);
268  }
269  if (BooleanFunction bf = latch_component->get_async_set_function(); !bf.is_empty())
270  {
271  latch_config.AddMember("preset_on", bf.to_string(), allocator);
272  }
273 
274  std::pair<AsyncSetResetBehavior, AsyncSetResetBehavior> cp_behav = latch_component->get_async_set_reset_behavior();
275  if (cp_behav.first != AsyncSetResetBehavior::undef)
276  {
277  latch_config.AddMember("state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.first), allocator);
278  }
279  if (cp_behav.second != AsyncSetResetBehavior::undef)
280  {
281  latch_config.AddMember("neg_state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.second), allocator);
282  }
283 
284  cell.AddMember("latch_config", latch_config, allocator);
285  }
286  else if (RAMComponent* ram_component = gt->get_component_as<RAMComponent>([](const GateTypeComponent* c) { return RAMComponent::is_class_of(c); }); ram_component != nullptr)
287  {
288  rapidjson::Value ram_config(rapidjson::kObjectType);
289 
290  rapidjson::Value identifiers(rapidjson::kArrayType);
291  for (const std::string& identifier : ram_component->get_init_identifiers())
292  {
293  identifiers.PushBack(rapidjson::Value{}.SetString(identifier.c_str(), identifier.length(), allocator), allocator);
294  }
295  ram_config.AddMember("data_identifiers", identifiers, allocator);
296  ram_config.AddMember("bit_size", ram_component->get_bit_size(), allocator);
297 
298  rapidjson::Value ram_ports(rapidjson::kArrayType);
299  for (const GateTypeComponent* component : ram_component->get_components([](const GateTypeComponent* c) { return RAMPortComponent::is_class_of(c); }))
300  {
301  const RAMPortComponent* port_component = component->convert_to<RAMPortComponent>();
302  if (port_component == nullptr)
303  {
304  return false;
305  }
306 
307  rapidjson::Value port(rapidjson::kObjectType);
308  port.AddMember("data_group", port_component->get_data_group(), allocator);
309  port.AddMember("address_group", port_component->get_address_group(), allocator);
310  port.AddMember("clocked_on", port_component->get_clock_function().to_string(), allocator);
311  port.AddMember("enabled_on", port_component->get_enable_function().to_string(), allocator);
312  port.AddMember("is_write", port_component->is_write_port(), allocator);
313  ram_ports.PushBack(port, allocator);
314  }
315  ram_config.AddMember("ram_ports", ram_ports, allocator);
316  cell.AddMember("ram_config", ram_config, allocator);
317  }
318 
319  // pins
320  const auto pin_groups = gt->get_pin_groups();
321  rapidjson::Value pg_array(rapidjson::kArrayType);
322  for (const auto* group : pin_groups)
323  {
324  rapidjson::Value pg_val(rapidjson::kObjectType);
325  pg_val.AddMember("name", group->get_name(), allocator);
326  pg_val.AddMember("direction", enum_to_string(group->get_direction()), allocator);
327  pg_val.AddMember("type", enum_to_string(group->get_type()), allocator);
328  pg_val.AddMember("ascending", group->is_ascending(), allocator);
329  pg_val.AddMember("start_index", group->get_start_index(), allocator);
330  pg_val.AddMember("ordered", group->is_ordered(), allocator);
331 
332  // pins of group
333  rapidjson::Value p_array(rapidjson::kArrayType);
334  for (const auto* pin : group->get_pins())
335  {
336  rapidjson::Value p_val(rapidjson::kObjectType);
337  p_val.AddMember("name", pin->get_name(), allocator);
338  p_val.AddMember("direction", enum_to_string(pin->get_direction()), allocator);
339  p_val.AddMember("type", enum_to_string(pin->get_type()), allocator);
340 
341  // check pin function
342  if (pin->get_direction() == PinDirection::output || pin->get_direction() == PinDirection::inout)
343  {
344  if (const auto it = functions.find(pin->get_name()); it != functions.end())
345  {
346  p_val.AddMember("function", it->second.to_string(), allocator);
347  }
348 
349  if (const auto it = functions.find(pin->get_name() + "_undefined"); it != functions.end())
350  {
351  p_val.AddMember("x_function", it->second.to_string(), allocator);
352  }
353 
354  if (const auto it = functions.find(pin->get_name() + "_tristate"); it != functions.end())
355  {
356  p_val.AddMember("z_function", it->second.to_string(), allocator);
357  }
358  }
359 
360  p_array.PushBack(p_val, allocator);
361  }
362 
363  pg_val.AddMember("pins", p_array, allocator);
364  pg_array.PushBack(pg_val, allocator);
365  }
366 
367  cell.AddMember("pin_groups", pg_array, allocator);
368  cells.PushBack(cell, allocator);
369  }
370 
371  document.AddMember("cells", cells, allocator);
372 
373  return true;
374  }
375 
376  std::vector<HGLWriter::PinCtx> HGLWriter::get_pins(GateType* gt, const std::unordered_map<std::string, BooleanFunction>& functions)
377  {
378  std::vector<PinCtx> res;
379  for (const auto* pin : gt->get_pins())
380  {
381  PinCtx res_pin;
382  res_pin.name = pin->get_name();
383  res_pin.direction = enum_to_string(pin->get_direction());
384  res_pin.type = enum_to_string(pin->get_type());
385 
386  if (pin->get_direction() == PinDirection::output || pin->get_direction() == PinDirection::inout)
387  {
388  if (const auto it = functions.find(pin->get_name()); it != functions.end())
389  {
390  res_pin.function = it->second.to_string();
391  }
392 
393  if (const auto it = functions.find(pin->get_name() + "_undefined"); it != functions.end())
394  {
395  res_pin.x_function = it->second.to_string();
396  }
397 
398  if (const auto it = functions.find(pin->get_name() + "_tristate"); it != functions.end())
399  {
400  res_pin.z_function = it->second.to_string();
401  }
402  }
403 
404  res.push_back(res_pin);
405  }
406 
407  return res;
408  }
409 } // namespace hal
const std::pair< std::string, std::string > & get_gate_location_data_identifiers() const
std::unordered_map< std::string, GateType * > get_gate_types(const std::function< bool(const GateType *)> &filter=nullptr) const
std::string get_name() const
const std::string & get_gate_location_data_category() const
bool write(const GateLibrary *gate_lib, const std::filesystem::path &file_path) override
Definition: hgl_writer.cpp:21
static bool is_class_of(const GateTypeComponent *component)
static bool is_class_of(const GateTypeComponent *component)
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
Definition: defines.h:45
std::string enum_to_string(T e)
Definition: enums.h:53
std::string identifier