HAL
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 {
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
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation source
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:391
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:962
std::vector< Module * > get_submodules(const std::function< bool(Module *)> &filter=nullptr, bool recursive=false) const
Definition: module.cpp:259
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
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)
bool serialize_to_file(const Netlist *nl, const std::filesystem::path &hal_file)
std::unique_ptr< Netlist > deserialize_from_string(const std::string &hal_string, GateLibrary *gatelib)
std::unique_ptr< Netlist > deserialize_from_file(const std::filesystem::path &hal_file, GateLibrary *gatelib)
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:52
quint32 u32
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