HAL
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 <iostream>
16 #include <string>
17 
18 namespace hal
19 {
20  bool HGLWriter::write(const GateLibrary* gate_lib, const std::filesystem::path& file_path)
21  {
22  if (gate_lib == nullptr)
23  {
24  log_error("hgl_writer", "received a nullptr as gate library.", file_path.string());
25  return false;
26  }
27 
28  FILE* fp = fopen(file_path.string().c_str(), "w");
29  if (fp == NULL)
30  {
31  log_error("hgl_writer", "unable to open '{}' for writing.", file_path.string());
32  return false;
33  }
34 
35  rapidjson::Document document;
36  document.SetObject();
37 
38  if (!write_gate_library(document, gate_lib))
39  {
40  fclose(fp);
41  return false;
42  }
43 
44  char writeBuffer[65536];
45  rapidjson::FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
46 
47  rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(os);
48  document.Accept(writer);
49 
50  fclose(fp);
51 
52  return true;
53  }
54 
55  bool HGLWriter::write_gate_library(rapidjson::Document& document, const GateLibrary* gate_lib)
56  {
57  rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
58 
59  // file format version
60  document.AddMember("version", HGL_FORMAT_VERSION, allocator);
61 
62  // library name
63  document.AddMember("library", gate_lib->get_name(), allocator);
64 
65  // gate location data specification
66  rapidjson::Value gate_locs(rapidjson::kObjectType);
67  gate_locs.AddMember("data_category", gate_lib->get_gate_location_data_category(), allocator);
68  const std::pair<std::string, std::string>& location_identifiers = gate_lib->get_gate_location_data_identifiers();
69  gate_locs.AddMember("data_x_identifier", location_identifiers.first, allocator);
70  gate_locs.AddMember("data_y_identifier", location_identifiers.second, allocator);
71  document.AddMember("gate_locations", gate_locs, allocator);
72 
73  // gate types
74  std::vector<GateType*> gate_types;
75 
76  for (const auto& gt : gate_lib->get_gate_types())
77  {
78  if ((gt.first != "HAL_GND") && (gt.first != "HAL_VDD"))
79  {
80  gate_types.push_back(gt.second);
81  }
82  }
83 
84  std::sort(gate_types.begin(), gate_types.end(), [](GateType* l, GateType* r) { return l->get_id() < r->get_id(); });
85 
86  rapidjson::Value cells(rapidjson::kArrayType);
87  for (const auto gt : gate_types)
88  {
89  rapidjson::Value cell(rapidjson::kObjectType);
90 
91  // name
92  cell.AddMember("name", gt->get_name(), allocator);
93 
94  // base type
95  std::set<GateTypeProperty> properties = gt->get_properties();
96 
97  rapidjson::Value bts(rapidjson::kArrayType);
98 
99  for (const auto& property : properties)
100  {
101  std::string bt_str = enum_to_string<GateTypeProperty>(property);
102  bts.PushBack(rapidjson::Value{}.SetString(bt_str.c_str(), bt_str.length(), allocator), allocator);
103  }
104 
105  cell.AddMember("types", bts, allocator);
106 
107  std::unordered_map<std::string, BooleanFunction> functions = gt->get_boolean_functions();
108 
109  // lut_config, ff_config, latch_config, ram_config
110  if (LUTComponent* lut_component = gt->get_component_as<LUTComponent>([](const GateTypeComponent* c) { return LUTComponent::is_class_of(c); }); lut_component != nullptr)
111  {
112  rapidjson::Value lut_config(rapidjson::kObjectType);
113 
114  InitComponent* init_component = lut_component->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
115  if (init_component == nullptr)
116  {
117  log_error("hgl_writer", "missing InitComponent for LUT initialization data of gate type '{}'.", gt->get_name());
118  return false;
119  }
120 
121  // bit_order
122  if (lut_component->is_init_ascending())
123  {
124  lut_config.AddMember("bit_order", "ascending", allocator);
125  }
126  else
127  {
128  lut_config.AddMember("bit_order", "descending", allocator);
129  }
130 
131  // data_category and data_identifier
132  lut_config.AddMember("data_category", init_component->get_init_category(), allocator);
133  lut_config.AddMember("data_identifier", init_component->get_init_identifiers().front(), allocator);
134 
135  cell.AddMember("lut_config", lut_config, allocator);
136  }
137  else if (FFComponent* ff_component = gt->get_component_as<FFComponent>([](const GateTypeComponent* c) { return FFComponent::is_class_of(c); }); ff_component != nullptr)
138  {
139  rapidjson::Value ff_config(rapidjson::kObjectType);
140 
141  StateComponent* state_component = ff_component->get_component_as<StateComponent>([](const GateTypeComponent* c) { return StateComponent::is_class_of(c); });
142  if (state_component == nullptr)
143  {
144  log_error("hgl_writer", "missing StateComponent for FF state identifiers of gate type '{}'.", gt->get_name());
145  return false;
146  }
147 
148  ff_config.AddMember("state", state_component->get_state_identifier(), allocator);
149  ff_config.AddMember("neg_state", state_component->get_neg_state_identifier(), allocator);
150 
151  InitComponent* init_component = state_component->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
152  if (init_component != nullptr)
153  {
154  // data_category, data_identifier
155  ff_config.AddMember("data_category", init_component->get_init_category(), allocator);
156  ff_config.AddMember("data_identifier", init_component->get_init_identifiers().front(), allocator);
157  }
158 
159  // next_state, clocked_on, clear_on, preset_on
160  ff_config.AddMember("next_state", ff_component->get_next_state_function().to_string(), allocator);
161  ff_config.AddMember("clocked_on", ff_component->get_clock_function().to_string(), allocator);
162  if (BooleanFunction bf = ff_component->get_async_reset_function(); !bf.is_empty())
163  {
164  ff_config.AddMember("clear_on", bf.to_string(), allocator);
165  }
166  if (BooleanFunction bf = ff_component->get_async_set_function(); !bf.is_empty())
167  {
168  ff_config.AddMember("preset_on", bf.to_string(), allocator);
169  }
170 
171  std::pair<AsyncSetResetBehavior, AsyncSetResetBehavior> cp_behav = ff_component->get_async_set_reset_behavior();
172  if (cp_behav.first != AsyncSetResetBehavior::undef)
173  {
174  ff_config.AddMember("state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.first), allocator);
175  }
176  if (cp_behav.second != AsyncSetResetBehavior::undef)
177  {
178  ff_config.AddMember("neg_state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.second), allocator);
179  }
180 
181  cell.AddMember("ff_config", ff_config, allocator);
182  }
183  else if (LatchComponent* latch_component = gt->get_component_as<LatchComponent>([](const GateTypeComponent* c) { return LatchComponent::is_class_of(c); }); latch_component != nullptr)
184  {
185  rapidjson::Value latch_config(rapidjson::kObjectType);
186 
187  StateComponent* state_component = latch_component->get_component_as<StateComponent>([](const GateTypeComponent* c) { return StateComponent::is_class_of(c); });
188  if (state_component == nullptr)
189  {
190  log_error("hgl_writer", "missing StateComponent for latch state identifiers of gate type '{}'.", gt->get_name());
191  return false;
192  }
193 
194  latch_config.AddMember("state", state_component->get_state_identifier(), allocator);
195  latch_config.AddMember("neg_state", state_component->get_neg_state_identifier(), allocator);
196 
197  // next_state, clocked_on, clear_on, preset_on
198  if (BooleanFunction bf = latch_component->get_data_in_function(); !bf.is_empty())
199  {
200  latch_config.AddMember("data_in", bf.to_string(), allocator);
201  }
202  if (BooleanFunction bf = latch_component->get_enable_function(); !bf.is_empty())
203  {
204  latch_config.AddMember("enable_on", bf.to_string(), allocator);
205  }
206  if (BooleanFunction bf = latch_component->get_async_reset_function(); !bf.is_empty())
207  {
208  latch_config.AddMember("clear_on", bf.to_string(), allocator);
209  }
210  if (BooleanFunction bf = latch_component->get_async_set_function(); !bf.is_empty())
211  {
212  latch_config.AddMember("preset_on", bf.to_string(), allocator);
213  }
214 
215  std::pair<AsyncSetResetBehavior, AsyncSetResetBehavior> cp_behav = latch_component->get_async_set_reset_behavior();
216  if (cp_behav.first != AsyncSetResetBehavior::undef)
217  {
218  latch_config.AddMember("state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.first), allocator);
219  }
220  if (cp_behav.second != AsyncSetResetBehavior::undef)
221  {
222  latch_config.AddMember("neg_state_clear_preset", enum_to_string<AsyncSetResetBehavior>(cp_behav.second), allocator);
223  }
224 
225  cell.AddMember("latch_config", latch_config, allocator);
226  }
227  else if (RAMComponent* ram_component = gt->get_component_as<RAMComponent>([](const GateTypeComponent* c) { return RAMComponent::is_class_of(c); }); ram_component != nullptr)
228  {
229  rapidjson::Value ram_config(rapidjson::kObjectType);
230 
231  InitComponent* init_component = ram_component->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
232  if (init_component == nullptr)
233  {
234  return false;
235  }
236 
237  // data_category, data_identifier
238  ram_config.AddMember("data_category", init_component->get_init_category(), allocator);
239 
240  rapidjson::Value identifiers(rapidjson::kArrayType);
241  for (const std::string& identifier : init_component->get_init_identifiers())
242  {
243  identifiers.PushBack(rapidjson::Value{}.SetString(identifier.c_str(), identifier.length(), allocator), allocator);
244  }
245  ram_config.AddMember("data_identifiers", identifiers, allocator);
246  ram_config.AddMember("bit_size", ram_component->get_bit_size(), allocator);
247 
248  rapidjson::Value ram_ports(rapidjson::kArrayType);
249  for (const GateTypeComponent* component : ram_component->get_components([](const GateTypeComponent* c) { return RAMPortComponent::is_class_of(c); }))
250  {
251  const RAMPortComponent* port_component = component->convert_to<RAMPortComponent>();
252  if (port_component == nullptr)
253  {
254  return false;
255  }
256 
257  rapidjson::Value port(rapidjson::kObjectType);
258  port.AddMember("data_group", port_component->get_data_group(), allocator);
259  port.AddMember("address_group", port_component->get_address_group(), allocator);
260  port.AddMember("clocked_on", port_component->get_clock_function().to_string(), allocator);
261  port.AddMember("enabled_on", port_component->get_enable_function().to_string(), allocator);
262  port.AddMember("is_write", port_component->is_write_port(), allocator);
263  ram_ports.PushBack(port, allocator);
264  }
265  ram_config.AddMember("ram_ports", ram_ports, allocator);
266  cell.AddMember("ram_config", ram_config, allocator);
267  }
268 
269  // pins
270  const auto pin_groups = gt->get_pin_groups();
271  rapidjson::Value pg_array(rapidjson::kArrayType);
272  for (const auto* group : pin_groups)
273  {
274  rapidjson::Value pg_val(rapidjson::kObjectType);
275  pg_val.AddMember("name", group->get_name(), allocator);
276  pg_val.AddMember("direction", enum_to_string(group->get_direction()), allocator);
277  pg_val.AddMember("type", enum_to_string(group->get_type()), allocator);
278  pg_val.AddMember("ascending", group->is_ascending(), allocator);
279  pg_val.AddMember("start_index", group->get_start_index(), allocator);
280  pg_val.AddMember("ordered", group->is_ordered(), allocator);
281 
282  // pins of group
283  rapidjson::Value p_array(rapidjson::kArrayType);
284  for (const auto* pin : group->get_pins())
285  {
286  rapidjson::Value p_val(rapidjson::kObjectType);
287  p_val.AddMember("name", pin->get_name(), allocator);
288  p_val.AddMember("direction", enum_to_string(pin->get_direction()), allocator);
289  p_val.AddMember("type", enum_to_string(pin->get_type()), allocator);
290 
291  // check pin function
292  if (pin->get_direction() == PinDirection::output || pin->get_direction() == PinDirection::inout)
293  {
294  if (const auto it = functions.find(pin->get_name()); it != functions.end())
295  {
296  p_val.AddMember("function", it->second.to_string(), allocator);
297  }
298 
299  if (const auto it = functions.find(pin->get_name() + "_undefined"); it != functions.end())
300  {
301  p_val.AddMember("x_function", it->second.to_string(), allocator);
302  }
303 
304  if (const auto it = functions.find(pin->get_name() + "_tristate"); it != functions.end())
305  {
306  p_val.AddMember("z_function", it->second.to_string(), allocator);
307  }
308  }
309 
310  p_array.PushBack(p_val, allocator);
311  }
312 
313  pg_val.AddMember("pins", p_array, allocator);
314  pg_array.PushBack(pg_val, allocator);
315  }
316 
317  cell.AddMember("pin_groups", pg_array, allocator);
318  cells.PushBack(cell, allocator);
319  }
320 
321  document.AddMember("cells", cells, allocator);
322 
323  return true;
324  }
325 
326  std::vector<HGLWriter::PinCtx> HGLWriter::get_pins(GateType* gt, const std::unordered_map<std::string, BooleanFunction>& functions)
327  {
328  std::vector<PinCtx> res;
329  for (const auto* pin : gt->get_pins())
330  {
331  PinCtx res_pin;
332  res_pin.name = pin->get_name();
333  res_pin.direction = enum_to_string(pin->get_direction());
334  res_pin.type = enum_to_string(pin->get_type());
335 
336  if (pin->get_direction() == PinDirection::output || pin->get_direction() == PinDirection::inout)
337  {
338  if (const auto it = functions.find(pin->get_name()); it != functions.end())
339  {
340  res_pin.function = it->second.to_string();
341  }
342 
343  if (const auto it = functions.find(pin->get_name() + "_undefined"); it != functions.end())
344  {
345  res_pin.x_function = it->second.to_string();
346  }
347 
348  if (const auto it = functions.find(pin->get_name() + "_tristate"); it != functions.end())
349  {
350  res_pin.z_function = it->second.to_string();
351  }
352  }
353 
354  res.push_back(res_pin);
355  }
356 
357  return res;
358  }
359 } // 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:20
static bool is_class_of(const GateTypeComponent *component)
static bool is_class_of(const GateTypeComponent *component)
#define log_error(channel,...)
Definition: log.h:78
std::string enum_to_string(T e)
Definition: enums.h:52