HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
netlist_serializer.cpp
Go to the documentation of this file.
2 
7 #include "hal_core/netlist/net.h"
10 #include "hal_core/utilities/log.h"
11 #include "rapidjson/filereadstream.h"
12 #include "rapidjson/stringbuffer.h"
13 
14 #define PRETTY_JSON_OUTPUT false
15 #if PRETTY_JSON_OUTPUT
16 #include "rapidjson/prettywriter.h"
17 #else
18 #include "rapidjson/writer.h"
19 #endif
20 
21 #include <chrono>
22 #include <fstream>
23 #include <queue>
24 #include <sstream>
25 
26 #ifndef DURATION
27 #define DURATION(begin_time) ((double)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - begin_time).count() / 1000)
28 #endif
29 
30 namespace hal
31 {
32  namespace netlist_serializer
33  {
34  // serializing functions
35  namespace
36  {
37  const int SERIALIZATION_FORMAT_VERSION = 14;
38  int encoded_format_version;
39 
40  // Ver 12 : location of gates
41 #define JSON_STR_HELPER(x) rapidjson::Value{}.SetString(x.c_str(), x.length(), allocator)
42 
43 #define assert_availablility(MEMBER) \
44  if (!root.HasMember(MEMBER)) \
45  { \
46  log_critical("netlist_persistent", "'netlist' node does not include a '{}' node", MEMBER); \
47  return nullptr; \
48  }
49 
50  namespace
51  {
52  struct PinGroupInformation
53  {
54  struct PinInformation
55  {
56  i32 id = -1;
57  Net* net;
58  std::string name;
60  };
61 
62  i32 id = -1;
63  std::string name;
66  std::vector<PinInformation> pins;
67  bool ascending = false;
69  bool ordered = false;
70  };
71 
72  } // namespace
73 
74  // serialize container data
75  rapidjson::Value serialize(const std::map<std::tuple<std::string, std::string>, std::tuple<std::string, std::string>>& data, rapidjson::Document::AllocatorType& allocator)
76  {
77  rapidjson::Value val(rapidjson::kArrayType);
78  for (const auto& it : data)
79  {
80  rapidjson::Value entry(rapidjson::kArrayType);
81  entry.PushBack(JSON_STR_HELPER(std::get<0>(it.first)), allocator);
82  entry.PushBack(JSON_STR_HELPER(std::get<1>(it.first)), allocator);
83  entry.PushBack(JSON_STR_HELPER(std::get<0>(it.second)), allocator);
84  entry.PushBack(JSON_STR_HELPER(std::get<1>(it.second)), allocator);
85  val.PushBack(entry, allocator);
86  }
87  return val;
88  }
89 
90  void deserialize_data(DataContainer* c, const rapidjson::Value& val)
91  {
92  for (const auto& entry : val.GetArray())
93  {
94  c->set_data(entry[0].GetString(), entry[1].GetString(), entry[2].GetString(), entry[3].GetString());
95  }
96  }
97 
98  // serialize endpoint
99  rapidjson::Value serialize(const Endpoint* ep, rapidjson::Document::AllocatorType& allocator)
100  {
101  rapidjson::Value val(rapidjson::kObjectType);
102  val.AddMember("gate_id", ep->get_gate()->get_id(), allocator);
103  val.AddMember("pin_id", ep->get_pin()->get_id(), allocator);
104  return val;
105  }
106 
107  bool deserialize_destination(Netlist* nl, Net* net, const rapidjson::Value& val)
108  {
109  Gate* gate = nl->get_gate_by_id(val["gate_id"].GetUint());
110  GatePin* pin;
111 
112  if (val.HasMember("pin_id"))
113  {
114  const u32 pin_id = val["pin_id"].GetUint();
115  pin = gate->get_type()->get_pin_by_id(pin_id);
116  if (pin == nullptr)
117  {
118  log_error("netlist_persistent",
119  "could not deserialize destination of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to get pin with ID "
120  + std::to_string(pin_id));
121  return false;
122  }
123 
124  if (encoded_format_version <= 12)
125  {
126  // swap pins because of legacy pin group bug
127  if (const auto [group, index] = pin->get_group(); group->size() > 1)
128  {
129  bool ascending = group->is_ascending();
130  u32 len = group->size();
131  i32 start_index = group->get_start_index();
132  i32 end_index = ascending ? (start_index + (i32)len - 1) : (start_index - (i32)len + 1);
133  i32 target_index = ascending ? (end_index - (index - start_index)) : (end_index + (start_index - index));
134 
135  if (const auto pin_res = group->get_pin_at_index(target_index); pin_res.is_error())
136  {
137  log_error("netlist_persistent",
138  "could not deserialize destination of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to swap pin with ID "
139  + std::to_string(pin_id) + ":\n{}",
140  pin_res.get_error().get());
141  return false;
142  }
143  else
144  {
145  pin = pin_res.get();
146  }
147  }
148  }
149  }
150  else
151  {
152  // legacy code for backward compatibility
153  const std::string pin_name = val["pin_type"].GetString();
154  pin = gate->get_type()->get_pin_by_name(pin_name);
155  if (pin == nullptr)
156  {
157  log_error("netlist_persistent",
158  "could not deserialize destination of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to get pin with name '" + pin_name + "'");
159  return false;
160  }
161  }
162 
163  if (!net->add_destination(gate, pin))
164  {
165  log_error("netlist_persistent",
166  "could not deserialize destination of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to add pin '" + pin->get_name()
167  + "' as destination to net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()));
168  return false;
169  }
170  return true;
171  }
172 
173  bool deserialize_source(Netlist* nl, Net* net, const rapidjson::Value& val)
174  {
175  Gate* gate = nl->get_gate_by_id(val["gate_id"].GetUint());
176  GatePin* pin;
177 
178  if (val.HasMember("pin_id"))
179  {
180  const u32 pin_id = val["pin_id"].GetUint();
181  pin = gate->get_type()->get_pin_by_id(pin_id);
182  if (pin == nullptr)
183  {
184  log_error("netlist_persistent",
185  "could not deserialize source of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to get pin with ID " + std::to_string(pin_id));
186  return false;
187  }
188 
189  if (encoded_format_version <= 12)
190  {
191  // swap pins because of legacy pin group bug
192  if (const auto [group, index] = pin->get_group(); group->size() > 1)
193  {
194  bool ascending = group->is_ascending();
195  u32 len = group->size();
196  i32 start_index = group->get_start_index();
197  i32 end_index = ascending ? (start_index + (i32)len - 1) : (start_index - (i32)len + 1);
198  i32 target_index = ascending ? (end_index - (index - start_index)) : (end_index + (start_index - index));
199 
200  if (const auto pin_res = group->get_pin_at_index(target_index); pin_res.is_error())
201  {
202  log_error("netlist_persistent",
203  "could not deserialize source of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to swap pin with ID "
204  + std::to_string(pin_id) + ":\n{}",
205  pin_res.get_error().get());
206  return false;
207  }
208  else
209  {
210  pin = pin_res.get();
211  }
212  }
213  }
214  }
215  else
216  {
217  // legacy code for backward compatibility
218  const std::string pin_name = val["pin_type"].GetString();
219  pin = gate->get_type()->get_pin_by_name(pin_name);
220  if (pin == nullptr)
221  {
222  log_error("netlist_persistent",
223  "could not deserialize source of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to get pin with name '" + pin_name + "'");
224  return false;
225  }
226  }
227 
228  if (net->add_source(gate, pin) == nullptr)
229  {
230  log_error("netlist_persistent",
231  "could not deserialize source of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": failed to add pin '" + pin->get_name()
232  + "' as source to net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()));
233  return false;
234  }
235  return true;
236  }
237 
238  // serialize gate
239  rapidjson::Value serialize(const Gate* gate, rapidjson::Document::AllocatorType& allocator)
240  {
241  rapidjson::Value val(rapidjson::kObjectType);
242  val.AddMember("id", gate->get_id(), allocator);
243  val.AddMember("name", gate->get_name(), allocator);
244  val.AddMember("type", gate->get_type()->get_name(), allocator);
245  if (gate->has_location())
246  {
247  val.AddMember("location_x", gate->get_location_x(), allocator);
248  val.AddMember("location_y", gate->get_location_y(), allocator);
249  }
250  auto data = serialize(gate->get_data_map(), allocator);
251  if (!data.Empty())
252  {
253  val.AddMember("data", data, allocator);
254  }
255  {
256  rapidjson::Value functions(rapidjson::kObjectType);
257  for (const auto& [name, function] : gate->get_boolean_functions(true))
258  {
259  const std::string function_str = function.to_string();
260  functions.AddMember(JSON_STR_HELPER(name), JSON_STR_HELPER(function_str), allocator);
261  }
262  if (functions.MemberCount() > 0)
263  {
264  val.AddMember("custom_functions", functions, allocator);
265  }
266  }
267  return val;
268  }
269 
270  bool deserialize_gate(Netlist* nl, const rapidjson::Value& val, const std::unordered_map<std::string, hal::GateType*>& gate_types)
271  {
272  const u32 gate_id = val["id"].GetUint();
273  const std::string gate_name = val["name"].GetString();
274  const std::string gate_type = val["type"].GetString();
275  i32 lx = -1;
276  i32 ly = -1;
277  if (val.HasMember("location_x") && val.HasMember("location_y"))
278  {
279  lx = val["location_x"].GetInt();
280  ly = val["location_y"].GetInt();
281  }
282  if (auto it = gate_types.find(gate_type); it != gate_types.end())
283  {
284  auto gate = nl->create_gate(gate_id, it->second, gate_name, lx, ly);
285  if (gate == nullptr)
286  {
287  log_error("netlist_persistent", "could not deserialize gate '" + gate_name + "' with ID " + std::to_string(gate_id) + ": failed to create gate");
288  return false;
289  }
290 
291  if (val.HasMember("data"))
292  {
293  deserialize_data(gate, val["data"]);
294  }
295 
296  if (val.HasMember("custom_functions"))
297  {
298  auto functions = val["custom_functions"].GetObject();
299  for (auto f_it = functions.MemberBegin(); f_it != functions.MemberEnd(); ++f_it)
300  {
301  auto func = BooleanFunction::from_string(f_it->value.GetString());
302  if (func.is_error())
303  {
304  log_error("netlist_persistent",
305  "could not deserialize gate '" + gate_name + "' with ID " + std::to_string(gate_id) + ": failed to parse Boolean function from string\n{}",
306  func.get_error().get());
307  return false;
308  }
309  gate->add_boolean_function(f_it->name.GetString(), func.get());
310  }
311  }
312 
313  return true;
314  }
315 
316  log_error("netlist_persistent",
317  "could not deserialize gate '" + gate_name + "' with ID " + std::to_string(gate_id) + ": failed to find gate '" + gate_type + "' in gate library '"
318  + nl->get_gate_library()->get_name() + "'");
319  return false;
320  }
321 
322  // serialize net
323  rapidjson::Value serialize(const Net* net, rapidjson::Document::AllocatorType& allocator)
324  {
325  rapidjson::Value val(rapidjson::kObjectType);
326  val.AddMember("id", net->get_id(), allocator);
327  val.AddMember("name", net->get_name(), allocator);
328 
329  {
330  rapidjson::Value srcs(rapidjson::kArrayType);
331  std::vector<Endpoint*> sorted = net->get_sources();
332  std::sort(sorted.begin(), sorted.end(), [](Endpoint* lhs, Endpoint* rhs) { return lhs->get_gate()->get_id() < rhs->get_gate()->get_id(); });
333  for (const Endpoint* src : sorted)
334  {
335  srcs.PushBack(serialize(src, allocator), allocator);
336  }
337  if (!srcs.Empty())
338  {
339  val.AddMember("srcs", srcs, allocator);
340  }
341  }
342 
343  {
344  rapidjson::Value dsts(rapidjson::kArrayType);
345  std::vector<Endpoint*> sorted = net->get_destinations();
346  std::sort(sorted.begin(), sorted.end(), [](Endpoint* lhs, Endpoint* rhs) { return lhs->get_gate()->get_id() < rhs->get_gate()->get_id(); });
347  for (const Endpoint* dst : sorted)
348  {
349  dsts.PushBack(serialize(dst, allocator), allocator);
350  }
351  if (!dsts.Empty())
352  {
353  val.AddMember("dsts", dsts, allocator);
354  }
355  }
356 
357  auto data = serialize(net->get_data_map(), allocator);
358  if (!data.Empty())
359  {
360  val.AddMember("data", data, allocator);
361  }
362  return val;
363  }
364 
365  bool deserialize_net(Netlist* nl, const rapidjson::Value& val)
366  {
367  const u32 net_id = val["id"].GetUint();
368  const std::string net_name = val["name"].GetString();
369  auto net = nl->create_net(net_id, net_name);
370  if (net == nullptr)
371  {
372  log_error("netlist_persistent", "could not deserialize net '" + net_name + "' with ID " + std::to_string(net_id) + ": failed to create net");
373  return false;
374  }
375 
376  if (val.HasMember("srcs"))
377  {
378  for (const auto& src_node : val["srcs"].GetArray())
379  {
380  if (!deserialize_source(nl, net, src_node))
381  {
382  log_error("netlist_persistent", "could not deserialize net '" + net_name + "' with ID " + std::to_string(net_id) + ": failed to deserialize source");
383  return false;
384  }
385  }
386  }
387 
388  if (val.HasMember("dsts"))
389  {
390  for (const auto& dst_node : val["dsts"].GetArray())
391  {
392  if (!deserialize_destination(nl, net, dst_node))
393  {
394  log_error("netlist_persistent", "could not deserialize net '" + net_name + "' with ID " + std::to_string(net_id) + ": failed to deserialize destination");
395  return false;
396  }
397  }
398  }
399 
400  if (val.HasMember("data"))
401  {
402  deserialize_data(net, val["data"]);
403  }
404 
405  return true;
406  }
407 
408  // serialize module
409  rapidjson::Value serialize(const Module* module, rapidjson::Document::AllocatorType& allocator)
410  {
411  rapidjson::Value val(rapidjson::kObjectType);
412  val.AddMember("id", module->get_id(), allocator);
413  val.AddMember("type", module->get_type(), allocator);
414  val.AddMember("name", module->get_name(), allocator);
415  Module* parent = module->get_parent_module();
416  if (parent == nullptr)
417  {
418  val.AddMember("parent", 0, allocator);
419  }
420  else
421  {
422  val.AddMember("parent", parent->get_id(), allocator);
423  }
424  {
425  rapidjson::Value gates(rapidjson::kArrayType);
426  std::vector<Gate*> sorted = module->get_gates(nullptr, false);
427  std::sort(sorted.begin(), sorted.end(), [](Gate* lhs, Gate* rhs) { return lhs->get_id() < rhs->get_id(); });
428  for (const Gate* g : sorted)
429  {
430  gates.PushBack(g->get_id(), allocator);
431  }
432  if (!gates.Empty())
433  {
434  val.AddMember("gates", gates, allocator);
435  }
436  }
437  {
438  rapidjson::Value json_pin_groups(rapidjson::kArrayType);
439  for (const PinGroup<ModulePin>* pin_group : module->get_pin_groups())
440  {
441  rapidjson::Value json_pin_group(rapidjson::kObjectType);
442  json_pin_group.AddMember("id", pin_group->get_id(), allocator);
443  json_pin_group.AddMember("name", pin_group->get_name(), allocator);
444  json_pin_group.AddMember("direction", enum_to_string(pin_group->get_direction()), allocator);
445  json_pin_group.AddMember("type", enum_to_string(pin_group->get_type()), allocator);
446  json_pin_group.AddMember("ascending", pin_group->is_ascending(), allocator);
447  json_pin_group.AddMember("ordered", pin_group->is_ordered(), allocator);
448  json_pin_group.AddMember("start_index", pin_group->get_start_index(), allocator);
449  rapidjson::Value json_pins(rapidjson::kArrayType);
450  for (const ModulePin* pin : pin_group->get_pins())
451  {
452  rapidjson::Value json_pin(rapidjson::kObjectType);
453  json_pin.AddMember("id", pin->get_id(), allocator);
454  json_pin.AddMember("name", pin->get_name(), allocator);
455  json_pin.AddMember("type", enum_to_string(pin->get_type()), allocator);
456  json_pin.AddMember("net_id", pin->get_net()->get_id(), allocator);
457  json_pins.PushBack(json_pin, allocator);
458  }
459  json_pin_group.AddMember("pins", json_pins, allocator);
460  json_pin_groups.PushBack(json_pin_group, allocator);
461  }
462  if (!json_pin_groups.Empty())
463  {
464  val.AddMember("pin_groups", json_pin_groups, allocator);
465  }
466  }
467 
468  auto data = serialize(module->get_data_map(), allocator);
469  if (!data.Empty())
470  {
471  val.AddMember("data", data, allocator);
472  }
473  return val;
474  }
475 
476  bool deserialize_module(Netlist* nl, const rapidjson::Value& val, std::unordered_map<Module*, std::vector<PinGroupInformation>>& pin_group_cache)
477  {
478  const u32 module_id = val["id"].GetUint();
479  const std::string module_name = val["name"].GetString();
480  const u32 parent_id = val["parent"].GetUint();
481  Module* sm = nl->get_top_module();
482 
483  if (parent_id == 0)
484  {
485  // top_module must not be created but might be renamed
486  const std::string top_module_name = val["name"].GetString();
487  if (top_module_name != sm->get_name())
488  {
489  sm->set_name(top_module_name);
490  }
491  }
492  else
493  {
494  sm = nl->create_module(module_id, module_name, nl->get_module_by_id(parent_id));
495  if (sm == nullptr)
496  {
497  log_error("netlist_persistent", "could not deserialize module '" + module_name + "' with ID " + std::to_string(module_id) + ": failed to create module");
498  return false;
499  }
500  }
501 
502  if (val.HasMember("type"))
503  {
504  sm->set_type(val["type"].GetString());
505  }
506 
507  if (val.HasMember("gates"))
508  {
509  std::vector<Gate*> gates;
510  for (auto& gate_node : val["gates"].GetArray())
511  {
512  if (!sm->is_top_module())
513  {
514  gates.push_back(nl->get_gate_by_id(gate_node.GetUint()));
515  }
516  }
517  sm->assign_gates(gates);
518  }
519 
520  if (val.HasMember("data"))
521  {
522  deserialize_data(sm, val["data"]);
523  }
524 
525  if (val.HasMember("pin_groups"))
526  {
527  // pins need to be cached until all modules have been instantiated
528  for (const auto& json_pin_group : val["pin_groups"].GetArray())
529  {
530  PinGroupInformation pin_group;
531  pin_group.id = json_pin_group["id"].GetUint();
532  pin_group.name = json_pin_group["name"].GetString();
533  if (json_pin_group.HasMember("direction"))
534  {
535  pin_group.direction = enum_from_string<PinDirection>(json_pin_group["direction"].GetString());
536  }
537  else
538  {
539  pin_group.direction = PinDirection::none;
540  }
541  if (json_pin_group.HasMember("type"))
542  {
543  pin_group.type = enum_from_string<PinType>(json_pin_group["type"].GetString());
544  }
545  else
546  {
547  pin_group.type = PinType::none;
548  }
549  if (json_pin_group.HasMember("ordered"))
550  {
551  pin_group.ordered = json_pin_group["ordered"].GetBool();
552  }
553  else
554  {
555  pin_group.type = PinType::none;
556  }
557  pin_group.ascending = json_pin_group["ascending"].GetBool();
558  pin_group.start_index = json_pin_group["start_index"].GetUint();
559 
560  for (const auto& pin_node : json_pin_group["pins"].GetArray())
561  {
562  PinGroupInformation::PinInformation pin;
563  pin.id = pin_node["id"].GetUint();
564  pin.name = pin_node["name"].GetString();
565  pin.net = nl->get_net_by_id(pin_node["net_id"].GetUint());
566  pin.type = enum_from_string<PinType>(pin_node["type"].GetString());
567  pin_group.pins.push_back(pin);
568  }
569  pin_group_cache[sm].push_back(pin_group);
570  }
571  }
572 
573  // legacy code below
574  if (val.HasMember("input_ports"))
575  {
576  for (const auto& json_pin_legacy : val["input_ports"].GetArray())
577  {
578  PinGroupInformation pin_group;
579  pin_group.name = json_pin_legacy["port_name"].GetString();
580  PinGroupInformation::PinInformation pin;
581  pin.name = json_pin_legacy["port_name"].GetString();
582  pin.net = nl->get_net_by_id(json_pin_legacy["net_id"].GetUint());
583  pin_group.pins.push_back(pin);
584  pin_group_cache[sm].push_back(pin_group);
585  }
586  }
587 
588  if (val.HasMember("output_ports"))
589  {
590  for (const auto& json_pin_legacy : val["output_ports"].GetArray())
591  {
592  PinGroupInformation pin_group;
593  pin_group.name = json_pin_legacy["port_name"].GetString();
594  PinGroupInformation::PinInformation pin;
595  pin.name = json_pin_legacy["port_name"].GetString();
596  pin.net = nl->get_net_by_id(json_pin_legacy["net_id"].GetUint());
597  pin_group.pins.push_back(pin);
598  pin_group_cache[sm].push_back(pin_group);
599  }
600  }
601  // legacy code above
602 
603  return true;
604  }
605 
606  bool deserialize_module_pins(const std::unordered_map<Module*, std::vector<PinGroupInformation>>& pin_group_cache)
607  {
608  for (const auto& [sm, pin_groups] : pin_group_cache)
609  {
610  for (const PinGroupInformation& pg : pin_groups)
611  {
612  std::vector<ModulePin*> pins;
613  for (const PinGroupInformation::PinInformation& p : pg.pins)
614  {
615  u32 pid = (p.id > 0) ? (u32)p.id : sm->get_unique_pin_id();
616  if (auto res = sm->create_pin(pid, p.name, p.net, p.type, false); res.is_error())
617  {
618  log_error("netlist_persistent",
619  "could not deserialize pin '" + p.name + "' of module '" + sm->get_name() + "' with ID " + std::to_string(sm->get_id()) + ": failed to create pin\n{}",
620  res.get_error().get());
621  return false;
622  }
623  else
624  {
625  pins.push_back(res.get());
626  }
627  }
628  u32 pgid = (pg.id > 0) ? (u32)pg.id : sm->get_unique_pin_group_id();
629  if (auto res = sm->create_pin_group(pgid, pg.name, pins, pg.direction, pg.type, pg.ascending, pg.start_index, pg.ordered); res.is_error())
630  {
631  log_error("netlist_persistent",
632  "could not deserialize pin group '" + pg.name + "' of module '" + sm->get_name() + "' with ID " + std::to_string(sm->get_id())
633  + ": failed to create pin group\n{}",
634  res.get_error().get());
635  return false;
636  }
637  }
638  }
639  return true;
640  }
641 
642  // serialize netlist
643  void serialize(const Netlist* nl, rapidjson::Document& document)
644  {
645  rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
646  rapidjson::Value root(rapidjson::kObjectType);
647 
648  root.AddMember("gate_library", nl->get_gate_library()->get_path().string(), allocator);
649  root.AddMember("id", nl->get_id(), allocator);
650  root.AddMember("input_file", nl->get_input_filename().string(), allocator);
651  root.AddMember("design_name", nl->get_design_name(), allocator);
652  root.AddMember("device_name", nl->get_device_name(), allocator);
653 
654  {
655  rapidjson::Value gates(rapidjson::kArrayType);
656  rapidjson::Value global_vccs(rapidjson::kArrayType);
657  rapidjson::Value global_gnds(rapidjson::kArrayType);
658  std::vector<Gate*> sorted = nl->get_gates();
659  std::sort(sorted.begin(), sorted.end(), [](Gate* lhs, Gate* rhs) { return lhs->get_id() < rhs->get_id(); });
660  for (const Gate* gate : sorted)
661  {
662  gates.PushBack(serialize(gate, allocator), allocator);
663 
664  if (nl->is_gnd_gate(gate))
665  {
666  global_gnds.PushBack(gate->get_id(), allocator);
667  }
668 
669  if (nl->is_vcc_gate(gate))
670  {
671  global_vccs.PushBack(gate->get_id(), allocator);
672  }
673  }
674  root.AddMember("gates", gates, allocator);
675  root.AddMember("global_vcc", global_vccs, allocator);
676  root.AddMember("global_gnd", global_gnds, allocator);
677  }
678  {
679  rapidjson::Value nets(rapidjson::kArrayType);
680  rapidjson::Value global_in(rapidjson::kArrayType);
681  rapidjson::Value global_out(rapidjson::kArrayType);
682  std::vector<Net*> sorted = nl->get_nets();
683  std::sort(sorted.begin(), sorted.end(), [](Net* lhs, Net* rhs) { return lhs->get_id() < rhs->get_id(); });
684  for (const Net* net : sorted)
685  {
686  nets.PushBack(serialize(net, allocator), allocator);
687 
688  if (nl->is_global_input_net(net))
689  {
690  global_in.PushBack(net->get_id(), allocator);
691  }
692 
693  if (nl->is_global_output_net(net))
694  {
695  global_out.PushBack(net->get_id(), allocator);
696  }
697  }
698  root.AddMember("nets", nets, allocator);
699  root.AddMember("global_in", global_in, allocator);
700  root.AddMember("global_out", global_out, allocator);
701  }
702  {
703  rapidjson::Value modules(rapidjson::kArrayType);
704 
705  // module ids are not sorted to preserve hierarchy
706  std::queue<const Module*> q;
707  q.push(nl->get_top_module());
708  while (!q.empty())
709  {
710  const Module* module = q.front();
711  q.pop();
712 
713  modules.PushBack(serialize(module, allocator), allocator);
714 
715  for (const Module* sm : module->get_submodules())
716  {
717  q.push(sm);
718  }
719  }
720  root.AddMember("modules", modules, allocator);
721  }
722 
723  document.AddMember("netlist", root, document.GetAllocator());
724  }
725 
726  std::unique_ptr<Netlist> deserialize(const rapidjson::Document& document, GateLibrary* gatelib)
727  {
728  if (!document.HasMember("netlist"))
729  {
730  log_error("netlist_persistent", "could not deserialize netlist: file has no 'netlist' node");
731  return nullptr;
732  }
733  auto root = document["netlist"].GetObject();
734 
735  if (!gatelib)
736  {
737  // no preferred gate library explicitly given
738  if (!root.HasMember("gate_library"))
739  {
740  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'gate_library'");
741  return nullptr;
742  }
743 
744  std::filesystem::path glib_path(root["gate_library"].GetString());
745 
746  if (glib_path.is_relative())
747  {
748  ProjectManager* pm = ProjectManager::instance();
749  if (pm)
750  glib_path = pm->get_project_directory() / glib_path;
751  }
752  gatelib = gate_library_manager::get_gate_library(glib_path.string());
753 
754  if (gatelib == nullptr)
755  {
756  // not found : try the other possible gate library extension
757  if (glib_path.extension() == ".hgl")
758  {
759  glib_path.replace_extension(".lib");
760  }
761  else
762  {
763  glib_path.replace_extension(".hgl");
764  }
765 
766  gatelib = gate_library_manager::get_gate_library(glib_path.string());
767  if (gatelib == nullptr)
768  {
769  log_critical("netlist_persistent", "could not deserialize netlist: failed to load gate library '" + std::string(root["gate_library"].GetString()) + "'");
770  return nullptr;
771  }
772  else
773  {
774  log_info("netlist_persistent", "gate library '{}' required but using '{}' instead.", root["gate_library"].GetString(), glib_path.string());
775  }
776  }
777  }
778 
779  auto nl = std::make_unique<Netlist>(gatelib);
780 
781  // disable automatically checking module nets
782  nl->enable_automatic_net_checks(false);
783 
784  if (!root.HasMember("id"))
785  {
786  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'id'");
787  return nullptr;
788  }
789  nl->set_id(root["id"].GetUint());
790 
791  if (!root.HasMember("input_file"))
792  {
793  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'input_file'");
794  return nullptr;
795  }
796  nl->set_input_filename(root["input_file"].GetString());
797 
798  if (!root.HasMember("design_name"))
799  {
800  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'design_name'");
801  return nullptr;
802  }
803  nl->set_design_name(root["design_name"].GetString());
804 
805  if (!root.HasMember("device_name"))
806  {
807  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'device_name'");
808  return nullptr;
809  }
810  nl->set_device_name(root["device_name"].GetString());
811 
812  if (!root.HasMember("gates"))
813  {
814  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'gates'");
815  return nullptr;
816  }
817  auto gate_types = nl->get_gate_library()->get_gate_types();
818  for (auto& gate_node : root["gates"].GetArray())
819  {
820  if (!deserialize_gate(nl.get(), gate_node, gate_types))
821  {
822  log_error("netlist_persistent", "could not deserialize netlist: failed to deserialize gate");
823  return nullptr;
824  }
825  }
826 
827  if (!root.HasMember("global_vcc"))
828  {
829  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'global_vcc'");
830  return nullptr;
831  }
832  for (auto& gate_node : root["global_vcc"].GetArray())
833  {
834  if (!nl->mark_vcc_gate(nl->get_gate_by_id(gate_node.GetUint())))
835  {
836  log_error("netlist_persistent", "could not deserialize netlist: failed to mark VCC gate");
837  return nullptr;
838  }
839  }
840 
841  if (!root.HasMember("global_gnd"))
842  {
843  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'global_gnd'");
844  return nullptr;
845  }
846  for (auto& gate_node : root["global_gnd"].GetArray())
847  {
848  if (!nl->mark_gnd_gate(nl->get_gate_by_id(gate_node.GetUint())))
849  {
850  log_error("netlist_persistent", "could not deserialize netlist: failed to mark GND gate");
851  return nullptr;
852  }
853  }
854 
855  if (!root.HasMember("nets"))
856  {
857  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'nets'");
858  return nullptr;
859  }
860  for (auto& net_node : root["nets"].GetArray())
861  {
862  if (!deserialize_net(nl.get(), net_node))
863  {
864  log_error("netlist_persistent", "could not deserialize netlist: failed to deserialize net");
865  return nullptr;
866  }
867  }
868 
869  if (!root.HasMember("global_in"))
870  {
871  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'global_in'");
872  return nullptr;
873  }
874  for (auto& net_node : root["global_in"].GetArray())
875  {
876  if (!nl->mark_global_input_net(nl->get_net_by_id(net_node.GetUint())))
877  {
878  log_error("netlist_persistent", "could not deserialize netlist: failed to mark global input net");
879  return nullptr;
880  }
881  }
882 
883  if (!root.HasMember("global_out"))
884  {
885  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'global_out'");
886  return nullptr;
887  }
888  for (auto& net_node : root["global_out"].GetArray())
889  {
890  if (!nl->mark_global_output_net(nl->get_net_by_id(net_node.GetUint())))
891  {
892  log_error("netlist_persistent", "could not deserialize netlist: failed to mark global output net");
893  return nullptr;
894  }
895  }
896 
897  if (!root.HasMember("modules"))
898  {
899  log_error("netlist_persistent", "could not deserialize netlist: node 'netlist' has no node 'modules'");
900  return nullptr;
901  }
902  std::unordered_map<Module*, std::vector<PinGroupInformation>> pin_group_cache;
903  for (auto& module_node : root["modules"].GetArray())
904  {
905  if (!deserialize_module(nl.get(), module_node, pin_group_cache))
906  {
907  log_error("netlist_persistent", "could not deserialize netlist: failed to deserialize module");
908  return nullptr;
909  }
910  }
911 
912  // update module nets, internal nets, input nets, and output nets
913  for (Module* mod : nl->get_modules())
914  {
915  mod->update_nets();
916  }
917 
918  // load module pins (nets must have been updated beforehand)
919  if (!deserialize_module_pins(pin_group_cache))
920  {
921  log_error("netlist_persistent", "could not deserialize netlist: failed to deserialize module pins");
922  return nullptr;
923  }
924 
925  // re-enable automatically checking module nets
926  nl->enable_automatic_net_checks(true);
927 
928  return nl;
929  }
930 
931  std::unique_ptr<Netlist> deserialize_document(rapidjson::Document& document, GateLibrary* gatelib, std::string source,
932  std::chrono::time_point<std::chrono::high_resolution_clock>& begin_time)
933  {
934  if (document.HasParseError())
935  {
936  log_error("netlist_persistent", "invalid json string for deserialization");
937  return nullptr;
938  }
939 
940  if (document.HasMember("serialization_format_version"))
941  {
942  encoded_format_version = document["serialization_format_version"].GetUint();
943  if (encoded_format_version < SERIALIZATION_FORMAT_VERSION)
944  {
945  log_warning("netlist_persistent", "the netlist was serialized with an older version of the serializer, deserialization may contain errors.");
946  }
947  else if (encoded_format_version > SERIALIZATION_FORMAT_VERSION)
948  {
949  log_warning("netlist_persistent", "the netlist was serialized with a newer version of the serializer, deserialization may contain errors.");
950  }
951  }
952  else
953  {
954  log_warning("netlist_persistent", "the netlist was serialized with an older version of the serializer, deserialization may contain errors.");
955  }
956 
957  auto netlist = deserialize(document, gatelib);
958 
959  if (netlist)
960  {
961  log_info("netlist_persistent", "deserialized '{}' in {:2.2f} seconds", source, DURATION(begin_time));
962  }
963 
964  // event_controls::enable_all(true);
965  return netlist;
966  }
967 
968  } // namespace
969 
970  bool serialize_to_file(const Netlist* nl, const std::filesystem::path& hal_file)
971  {
972  if (nl == nullptr)
973  {
974  return false;
975  }
976 
977  auto begin_time = std::chrono::high_resolution_clock::now();
978 
979  std::filesystem::path serialize_to_dir = hal_file.parent_path();
980  if (serialize_to_dir.empty())
981  return false;
982 
983  if (serialize_to_dir.is_relative())
984  serialize_to_dir = ProjectManager::instance()->get_project_directory() / serialize_to_dir;
985 
986  // create directory if it got erased in the meantime
987  if (!std::filesystem::exists(serialize_to_dir))
988  {
989  std::error_code err;
990  if (!std::filesystem::create_directories(serialize_to_dir, err))
991  {
992  log_error("netlist_persistent", "Could not create directory '{}', error was '{}'.", serialize_to_dir.string(), err.message());
993  return false;
994  }
995  }
996 
997  std::ofstream hal_file_stream;
998  hal_file_stream.open(hal_file.string());
999  if (hal_file_stream.fail())
1000  {
1001  log_error("netlist_persistent", "could not open or create file {}: please verify that the file and the containing directory is writable", hal_file.string());
1002  return false;
1003  }
1004 
1005  rapidjson::Document document;
1006  document.SetObject();
1007 
1008  document.AddMember("serialization_format_version", SERIALIZATION_FORMAT_VERSION, document.GetAllocator());
1009 
1010  serialize(nl, document);
1011 
1012  rapidjson::StringBuffer strbuf;
1013 #if PRETTY_JSON_OUTPUT == 1
1014  rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
1015 #else
1016  rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
1017 #endif
1018  document.Accept(writer);
1019 
1020  hal_file_stream << strbuf.GetString();
1021 
1022  hal_file_stream.close();
1023 
1024  log_info("netlist_persistent", "serialized netlist in {:2.2f} seconds", DURATION(begin_time));
1025 
1026  return true;
1027  }
1028 
1029  std::unique_ptr<Netlist> deserialize_from_file(const std::filesystem::path& hal_file, GateLibrary* gatelib)
1030  {
1031  auto begin_time = std::chrono::high_resolution_clock::now();
1032 
1033  // event_controls::enable_all(false);
1034 
1035  FILE* pFile = fopen(hal_file.string().c_str(), "rb");
1036  if (pFile == NULL)
1037  {
1038  log_error("netlist_persistent", "unable to open '{}'.", hal_file.string());
1039  return nullptr;
1040  }
1041 
1042  char buffer[65536];
1043  rapidjson::FileReadStream is(pFile, buffer, sizeof(buffer));
1044  rapidjson::Document document;
1045  document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(is);
1046  fclose(pFile);
1047 
1048  return deserialize_document(document, gatelib, hal_file.string(), begin_time);
1049  }
1050 
1051  std::unique_ptr<Netlist> deserialize_from_string(const std::string& hal_string, GateLibrary* gatelib)
1052  {
1053  auto begin_time = std::chrono::high_resolution_clock::now();
1054 
1055  // event_controls::enable_all(false);
1056 
1057  rapidjson::Document document;
1058  document.Parse<0, rapidjson::UTF8<> >(hal_string.c_str());
1059 
1060  return deserialize_document(document, gatelib, "source string", begin_time);
1061  }
1062  } // namespace netlist_serializer
1063 } // namespace hal
1064 
1065 #undef DURATION
static Result< BooleanFunction > from_string(const std::string &expression)
const std::map< std::tuple< std::string, std::string >, std::tuple< std::string, std::string > > & get_data_map() const
Module * get_parent_module() const
Definition: module.cpp:125
const std::vector< Gate * > & get_gates() const
Definition: module.cpp:393
std::string get_name() const
Definition: module.cpp:87
std::vector< PinGroup< ModulePin > * > get_pin_groups(const std::function< bool(PinGroup< ModulePin > *)> &filter=nullptr) const
Definition: module.cpp:964
std::vector< Module * > get_submodules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=false) const
Definition: module.cpp:261
std::string get_type() const
Definition: module.cpp:106
u32 get_id() const
Definition: module.cpp:82
static ProjectManager * instance()
const ProjectDirectory & get_project_directory() const
uint32_t u32
Definition: defines.h:41
int32_t i32
Definition: defines.h:36
#define log_error(channel,...)
Definition: log.h:78
#define log_info(channel,...)
Definition: log.h:70
#define log_critical(channel,...)
Definition: log.h:80
#define log_warning(channel,...)
Definition: log.h:76
const Module * module(const Gate *g, const NodeBoxes &boxes)
GateLibrary * get_gate_library(const std::string &file_path)
std::unique_ptr< Netlist > deserialize_from_string(const std::string &hal_string, GateLibrary *gate_lib=nullptr)
bool serialize_to_file(const Netlist *netlist, const std::filesystem::path &hal_file)
std::unique_ptr< Netlist > deserialize_from_file(const std::filesystem::path &hal_file, GateLibrary *gate_lib=nullptr)
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
std::error_code error_code
Definition: defines.h:46
PinType
Definition: pin_type.h:36
std::string enum_to_string(T e)
Definition: enums.h:53
PinType type
std::vector< PinInformation > pins
#define DURATION(begin_time)
bool ordered
Net * net
u32 start_index
bool ascending
PinDirection direction
std::string name
#define JSON_STR_HELPER(x)
const int SERIALIZATION_FORMAT_VERSION