HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
hgl_parser.cpp
Go to the documentation of this file.
2 
12 #include "hal_core/utilities/log.h"
14 #include "hgl_parser/upgrade_hgl.h"
15 #include "rapidjson/filereadstream.h"
16 #include "rapidjson/stringbuffer.h"
17 
18 namespace hal
19 {
20  Result<std::unique_ptr<GateLibrary>> HGLParser::parse(const std::filesystem::path& file_path)
21  {
22  m_path = file_path;
23 
24  FILE* fp = fopen(file_path.string().c_str(), "r");
25  if (fp == NULL)
26  {
27  return ERR("could not parse HGL file '" + m_path.string() + "' : unable to open file");
28  }
29 
30  char buffer[65536];
31  rapidjson::FileReadStream is(fp, buffer, sizeof(buffer));
32  rapidjson::Document document;
33  document.ParseStream<0, rapidjson::UTF8<>, rapidjson::FileReadStream>(is);
34  fclose(fp);
35 
36  if (document.HasParseError())
37  {
38  return ERR("could not parse HGL file '" + m_path.string() + "': failed parsing JSON format");
39  }
40 
41  if (auto res = upgrade_outdated_file(document); res.is_error())
42  {
43  return ERR_APPEND(res.get_error(), "could not parse HGL file '" + m_path.string() + "': failed to upgrade outdated file format");
44  }
45 
46  if (auto res = parse_gate_library(document); res.is_error())
47  {
48  return ERR_APPEND(res.get_error(), "could not parse HGL file '" + m_path.string() + "': failed to parse gate library");
49  }
50 
52 
53  return OK(std::move(m_gate_lib));
54  }
55 
56  Result<std::monostate> HGLParser::upgrade_outdated_file(rapidjson::Document& document)
57  {
58  if (!document.IsObject() || !document.HasMember("version") || !document["version"].IsUint() || document["version"].GetUint() >= HGL_FORMAT_VERSION)
59  {
60  // up to date, or not upgradable at all, which parse_gate_library reports
61  return OK({});
62  }
63 
64  const u32 version = document["version"].GetUint();
65 
66  // the upgrade happens in memory first, so that cells requiring manual work are reported before the file gets replaced
67  auto res = hgl_upgrade::upgrade_document(document);
68  if (res.is_error())
69  {
70  return ERR(res.get_error());
71  }
72  for (const std::string& warning : res.get())
73  {
74  log_warning("gate_library_parser", "'{}' cannot be upgraded to HGL format version {} completely: {}", m_path.string(), HGL_FORMAT_VERSION, warning);
75  }
76 
77  // replacing the file requires the consent of the user
78  if (!is_upgrade_requested())
79  {
81  return ERR("HGL file format version " + std::to_string(version) + " is outdated (requires version " + std::to_string(HGL_FORMAT_VERSION) + "), the file needs to be upgraded");
82  }
83 
84  auto res_replace = hgl_upgrade::replace_file(document, m_path);
85  if (res_replace.is_error())
86  {
87  return ERR(res_replace.get_error());
88  }
89 
90  log_info("gate_library_parser", "upgraded gate library '{}' from HGL format version {} to {}, the original file was kept as '{}'.", m_path.string(), version, HGL_FORMAT_VERSION, res_replace.get().string());
91  return OK({});
92  }
93 
94  Result<std::monostate> HGLParser::parse_gate_library(const rapidjson::Document& document)
95  {
96  if (!document.HasMember("version") || !document["version"].IsUint() || document["version"].GetUint() < HGL_FORMAT_VERSION)
97  {
98  return ERR("could not parse gate library: HGL file format version is outdated (requires version " + std::to_string(HGL_FORMAT_VERSION) + ")");
99  }
100 
101  if (!document.HasMember("library"))
102  {
103  return ERR("could not parse gate library: missing 'library' node");
104  }
105 
106  const std::string gate_lib_name = document["library"].GetString();
107  m_gate_lib = std::make_unique<GateLibrary>(m_path, gate_lib_name);
108 
109  if (document.HasMember("gate_locations") && document["gate_locations"].IsObject())
110  {
111  auto gate_locs = document["gate_locations"].GetObject();
112 
113  if (!gate_locs.HasMember("data_category") || !gate_locs["data_category"].IsString())
114  {
115  return ERR("could not parse gate library '" + gate_lib_name + "': missing 'data_category' entry for gate locations");
116  }
117 
118  if (!gate_locs.HasMember("data_x_identifier") || !gate_locs["data_x_identifier"].IsString())
119  {
120  return ERR("could not parse gate library '" + gate_lib_name + "': missing 'data_x_identifier' entry for gate locations");
121  }
122 
123  if (!gate_locs.HasMember("data_y_identifier") || !gate_locs["data_y_identifier"].IsString())
124  {
125  return ERR("could not parse gate library '" + gate_lib_name + "': missing 'data_y_identifier' entry for gate locations");
126  }
127 
128  m_gate_lib->set_gate_location_data_category(gate_locs["data_category"].GetString());
129  m_gate_lib->set_gate_location_data_identifiers(gate_locs["data_x_identifier"].GetString(), gate_locs["data_y_identifier"].GetString());
130  }
131 
132  if (!document.HasMember("cells"))
133  {
134  return ERR("could not parse gate library '" + gate_lib_name + "': missing 'cells' node");
135  }
136 
137  for (const auto& gate_type : document["cells"].GetArray())
138  {
139  if (auto res = parse_gate_type(gate_type); res.is_error())
140  {
141  return ERR_APPEND(res.get_error(), "could not parse gate library '" + gate_lib_name + "': failed parsing gate type");
142  }
143  }
144 
145  return OK({});
146  }
147 
148  Result<std::monostate> HGLParser::parse_gate_type(const rapidjson::Value& gate_type)
149  {
150  if (!gate_type.HasMember("name") || !gate_type["name"].IsString())
151  {
152  return ERR("could not parse gate type: missing or invalid name");
153  }
154 
155  const std::string name = gate_type["name"].GetString();
156  std::set<GateTypeProperty> properties;
157  if (gate_type.HasMember("types") && gate_type["types"].IsArray())
158  {
159  for (const auto& base_type : gate_type["types"].GetArray())
160  {
161  const std::string property_str = base_type.GetString();
162 
163  try
164  {
165  GateTypeProperty property = enum_from_string<GateTypeProperty>(property_str);
166  properties.insert(property);
167  }
168  catch (const std::runtime_error&)
169  {
170  return ERR("could not parse gate type '" + name + "': invalid property '" + base_type.GetString() + "'");
171  }
172  }
173  }
174  else
175  {
176  properties = {GateTypeProperty::combinational};
177  }
178 
179  std::unique_ptr<GateTypeComponent> parent_component = nullptr;
180  if (gate_type.HasMember("lut_config") && gate_type["lut_config"].IsObject())
181  {
182  const auto& lut_cfg = gate_type["lut_config"];
183  if (auto res = parse_lut_config(lut_cfg); res.is_error())
184  {
185  return ERR_APPEND(res.get_error(), "could not parse gate type '" + name + "': failed parsing LUT configuration");
186  }
187  else
188  {
189  parent_component = res.get();
190  }
191  }
192  else if (gate_type.HasMember("ff_config") && gate_type["ff_config"].IsObject())
193  {
194  if (auto res = parse_ff_config(gate_type["ff_config"]); res.is_error())
195  {
196  return ERR_APPEND(res.get_error(), "could not parse gate type '" + name + "': failed parsing FF configuration");
197  }
198  else
199  {
200  parent_component = res.get();
201  }
202  }
203  else if (gate_type.HasMember("latch_config") && gate_type["latch_config"].IsObject())
204  {
205  if (auto res = parse_latch_config(gate_type["latch_config"]); res.is_error())
206  {
207  return ERR_APPEND(res.get_error(), "could not parse gate type '" + name + "': failed parsing latch configuration");
208  }
209  else
210  {
211  parent_component = res.get();
212  }
213  }
214  else if (gate_type.HasMember("ram_config") && gate_type["ram_config"].IsObject())
215  {
216  if (auto res = parse_ram_config(gate_type["ram_config"]); res.is_error())
217  {
218  return ERR_APPEND(res.get_error(), "could not parse gate type '" + name + "': failed parsing RAM configuration");
219  }
220  else
221  {
222  parent_component = res.get();
223  }
224  }
225 
226  GateType* gt = m_gate_lib->create_gate_type(name, properties, std::move(parent_component));
227  if (gt == nullptr)
228  {
229  return ERR("could not parse gate type '" + name + "': failed to create gate type");
230  }
231 
232  // Parameters are declared at the gate-type level. Their declared sizes feed the BF parser
233  // for any Boolean functions in this cell that reference parameters as variables.
234  std::map<std::string, u16> var_sizes;
235  if (gate_type.HasMember("parameters") && gate_type["parameters"].IsArray())
236  {
237  for (const auto& param_val : gate_type["parameters"].GetArray())
238  {
239  if (!param_val.HasMember("name") || !param_val["name"].IsString())
240  {
241  return ERR("could not parse parameter for gate type '" + name + "': missing or invalid name");
242  }
243  if (!param_val.HasMember("type") || !param_val["type"].IsString())
244  {
245  return ERR("could not parse parameter for gate type '" + name + "': missing or invalid type");
246  }
247  if (!param_val.HasMember("default") || !param_val["default"].IsString())
248  {
249  return ERR("could not parse parameter for gate type '" + name + "': missing or invalid default value");
250  }
251 
252  const std::string pname = param_val["name"].GetString();
253  const std::string pdefault = param_val["default"].GetString();
254  const std::string ptype = param_val["type"].GetString();
255 
256  Parameter param;
257 
258  if (ptype == "boolean")
259  {
260  auto param_res = Parameter::Boolean(pname, pdefault);
261  if (param_res.is_error())
262  {
263  return ERR(param_res.get_error());
264  }
265  param = param_res.get();
266  }
267  else if (ptype == "bit_vector")
268  {
269  if (!param_val.HasMember("size") || !param_val["size"].IsUint())
270  {
271  return ERR("could not parse parameter '" + pname + "' for gate type '" + name + "': bit-vector parameter requires a 'size' field");
272  }
273  const u32 sz = param_val["size"].GetUint();
274 
275  auto param_res = Parameter::BitVector(pname, static_cast<u16>(sz), pdefault);
276  if (param_res.is_error())
277  {
278  return ERR(param_res.get_error());
279  }
280  param = param_res.get();
281  }
282  else if (ptype == "logic_vector")
283  {
284  if (!param_val.HasMember("size") || !param_val["size"].IsUint())
285  {
286  return ERR("could not parse parameter '" + pname + "' for gate type '" + name + "': logic-vector parameter requires a 'size' field");
287  }
288  const u32 sz = param_val["size"].GetUint();
289 
290  auto param_res = Parameter::LogicVector(pname, static_cast<u16>(sz), pdefault);
291  if (param_res.is_error())
292  {
293  return ERR(param_res.get_error());
294  }
295  param = param_res.get();
296  }
297  else if (ptype == "integer")
298  {
299  auto param_res = Parameter::Integer(pname, pdefault);
300  if (param_res.is_error())
301  {
302  return ERR(param_res.get_error());
303  }
304  param = param_res.get();
305  }
306  else if (ptype == "string")
307  {
308  auto param_res = Parameter::String(pname, pdefault);
309  if (param_res.is_error())
310  {
311  return ERR(param_res.get_error());
312  }
313  param = param_res.get();
314  }
315  else if (ptype == "float")
316  {
317  auto param_res = Parameter::Float(pname, pdefault);
318  if (param_res.is_error())
319  {
320  return ERR(param_res.get_error());
321  }
322  param = param_res.get();
323  }
324  else if (ptype == "time")
325  {
326  auto param_res = Parameter::Time(pname, pdefault);
327  if (param_res.is_error())
328  {
329  return ERR(param_res.get_error());
330  }
331  param = param_res.get();
332  }
333  else if (ptype == "enum")
334  {
335  if (!param_val.HasMember("values") || !param_val["values"].IsArray())
336  {
337  return ERR("could not parse parameter '" + pname + "' for gate type '" + name + "': enum parameter requires a 'values' array");
338  }
339  std::vector<std::string> values;
340  for (const auto& v : param_val["values"].GetArray())
341  {
342  if (!v.IsString())
343  {
344  return ERR("could not parse parameter '" + pname + "' for gate type '" + name + "': enum 'values' must be strings");
345  }
346  values.emplace_back(v.GetString());
347  }
348 
349  auto param_res = Parameter::Enum(pname, std::move(values), pdefault);
350  if (param_res.is_error())
351  {
352  return ERR(param_res.get_error());
353  }
354  param = param_res.get();
355  }
356  else
357  {
358  return ERR("could not parse parameter '" + pname + "' for gate type '" + name + "': unknown type '" + ptype + "'");
359  }
360 
361  if (auto res = gt->add_parameter(param); res.is_error())
362  {
363  return ERR_APPEND(res.get_error(), "could not parse parameters for gate type '" + name + "'");
364  }
365 
366  var_sizes[param.get_name()] = param.get_size();
367  }
368  }
369 
370  if (gate_type.HasMember("pin_groups") && gate_type["pin_groups"].IsArray())
371  {
372  for (const auto& pg_val : gate_type["pin_groups"].GetArray())
373  {
374  if (!pg_val.HasMember("name") || !pg_val["name"].IsString())
375  {
376  return ERR("could not parse pin group: missing or invalid name");
377  }
378  std::string pg_name = pg_val["name"].GetString();
379 
380  if (!pg_val.HasMember("direction") || !pg_val["direction"].IsString())
381  {
382  return ERR("could not parse pin group '" + pg_name + "': missing or invalid pin direction");
383  }
384  PinDirection pg_direction;
385  std::string pg_direction_str = pg_val["direction"].GetString();
386  try
387  {
388  pg_direction = enum_from_string<PinDirection>(pg_direction_str);
389  }
390  catch (const std::runtime_error&)
391  {
392  return ERR("could not parse pin '" + pg_name + "': invalid pin direction '" + pg_direction_str + "'");
393  }
394 
395  if (!pg_val.HasMember("type") || !pg_val["type"].IsString())
396  {
397  return ERR("could not parse pin group '" + pg_name + "': missing or invalid pin type");
398  }
399  PinType pg_type;
400  std::string pg_type_str = pg_val["type"].GetString();
401  try
402  {
403  pg_type = enum_from_string<PinType>(pg_type_str);
404  }
405  catch (const std::runtime_error&)
406  {
407  return ERR("could not parse pin group '" + pg_name + "': invalid pin type '" + pg_type_str + "'");
408  }
409 
410  if (!pg_val.HasMember("ascending") || !pg_val["ascending"].IsBool())
411  {
412  return ERR("could not parse pin group '" + pg_name + "': missing or ascending property");
413  }
414  bool ascending = pg_val["ascending"].GetBool();
415 
416  bool ordered = false;
417  if (pg_val.HasMember("ordered") && pg_val["ordered"].IsBool())
418  {
419  ordered = pg_val["ordered"].GetBool();
420  }
421 
422  if (!pg_val.HasMember("start_index") || !pg_val["start_index"].IsUint())
423  {
424  return ERR("could not parse pin group '" + pg_name + "': missing or start index");
425  }
426  u32 start_index = pg_val["start_index"].GetUint();
427 
428  if (pg_val.HasMember("pins") && pg_val["pins"].IsArray())
429  {
430  std::vector<GatePin*> pins;
431 
432  for (const auto& p_val : pg_val["pins"].GetArray())
433  {
434  if (!p_val.HasMember("name") || !p_val["name"].IsString())
435  {
436  return ERR("could not parse pin: missing or invalid name");
437  }
438  std::string p_name = p_val["name"].GetString();
439 
440  if (!p_val.HasMember("direction") || !p_val["direction"].IsString())
441  {
442  return ERR("could not parse pin '" + p_name + "': missing or invalid pin direction");
443  }
444  PinDirection p_direction;
445  std::string p_direction_str = p_val["direction"].GetString();
446  try
447  {
448  p_direction = enum_from_string<PinDirection>(p_direction_str);
449  }
450  catch (const std::runtime_error&)
451  {
452  return ERR("could not parse pin '" + p_name + "': invalid pin direction '" + p_direction_str + "'");
453  }
454 
455  PinType p_type;
456  if (p_val.HasMember("type") && p_val["type"].IsString())
457  {
458  std::string p_type_str = p_val["type"].GetString();
459  try
460  {
461  p_type = enum_from_string<PinType>(p_type_str);
462  }
463  catch (const std::runtime_error&)
464  {
465  return ERR("could not parse pin '" + p_name + "': invalid pin type '" + p_type_str + "'");
466  }
467  }
468  else
469  {
470  p_type = PinType::none;
471  }
472 
473  auto p_res = gt->create_pin(p_name, p_direction, p_type, false);
474  if (p_res.is_error())
475  {
476  return ERR_APPEND(p_res.get_error(), "could not parse gate type '" + name + "' with ID " + std::to_string(gt->get_id()) + ": failed to create pin '" + p_name + "'");
477  }
478  pins.push_back(p_res.get());
479 
480  if (p_val.HasMember("function") && p_val["function"].IsString())
481  {
482  if (auto res = BooleanFunction::from_string(p_val["function"].GetString(), var_sizes); res.is_error())
483  {
484  return ERR_APPEND(res.get_error(),
485  "could not parse gate type '" + name + "' with ID " + std::to_string(gt->get_id()) + ": failed parsing Boolean function with name '" + p_name
486  + "' from string");
487  }
488  else
489  {
490  gt->add_boolean_function(p_name, res.get());
491  }
492  }
493 
494  if (p_val.HasMember("x_function") && p_val["x_function"].IsString())
495  {
496  if (auto res = BooleanFunction::from_string(p_val["x_function"].GetString(), var_sizes); res.is_error())
497  {
498  return ERR_APPEND(res.get_error(),
499  "could not parse gate type '" + name + "' with ID " + std::to_string(gt->get_id()) + ": failed parsing Boolean function with name '" + p_name
500  + "_undefined' from string");
501  }
502  else
503  {
504  gt->add_boolean_function(p_name + "_undefined", res.get());
505  }
506  }
507 
508  if (p_val.HasMember("z_function") && p_val["z_function"].IsString())
509  {
510  if (auto res = BooleanFunction::from_string(p_val["z_function"].GetString(), var_sizes); res.is_error())
511  {
512  return ERR_APPEND(res.get_error(),
513  "could not parse gate type '" + name + "' with ID " + std::to_string(gt->get_id()) + ": failed parsing Boolean function with name '" + p_name
514  + "_tristate' from string");
515  }
516  else
517  {
518  gt->add_boolean_function(p_name + "_tristate", res.get());
519  }
520  }
521  }
522 
523  auto pg_res = gt->create_pin_group(pg_name, pins, pg_direction, pg_type, ascending, start_index, ordered);
524  if (pg_res.is_error())
525  {
526  return ERR_APPEND(pg_res.get_error(), "could not parse gate type '" + name + "' with ID " + std::to_string(gt->get_id()) + ": failed to create pin group '" + pg_name + "'");
527  }
528  }
529  else
530  {
531  return ERR("could not parse gate type '" + name + "' with ID " + std::to_string(gt->get_id()) + ": no pins given for pin group with name '" + pg_name + "'");
532  }
533  }
534  }
535 
536  return OK({});
537  }
538 
539  Result<std::unique_ptr<GateTypeComponent>> HGLParser::parse_lut_config(const rapidjson::Value& lut_config)
540  {
541  // New format: output_pins array with per-pin INIT identifier, bit range, bit order, and input pins.
542  if (lut_config.HasMember("output_pins") && lut_config["output_pins"].IsArray())
543  {
544  struct PinCfg
545  {
546  std::string pin_name;
547  std::string identifier;
548  u32 bit_offset;
549  u32 bit_count;
550  bool is_ascending;
551  std::vector<std::string> input_pins;
552  };
553  std::vector<PinCfg> pin_cfgs;
554 
555  for (const auto& entry : lut_config["output_pins"].GetArray())
556  {
557  if (!entry.HasMember("pin") || !entry["pin"].IsString())
558  {
559  return ERR("could not parse LUT configuration: missing or invalid pin name in output_pins entry");
560  }
561  const std::string pin_name = entry["pin"].GetString();
562 
563  if (!entry.HasMember("data_identifier") || !entry["data_identifier"].IsString())
564  {
565  return ERR("could not parse LUT configuration: missing or invalid data_identifier for pin '" + pin_name + "'");
566  }
567  const std::string identifier = entry["data_identifier"].GetString();
568 
569  if (!entry.HasMember("bit_offset") || !entry["bit_offset"].IsUint())
570  {
571  return ERR("could not parse LUT configuration: missing or invalid bit_offset for pin '" + pin_name + "'");
572  }
573  const u32 bit_offset = entry["bit_offset"].GetUint();
574 
575  if (!entry.HasMember("bit_count") || !entry["bit_count"].IsUint())
576  {
577  return ERR("could not parse LUT configuration: missing or invalid bit_count for pin '" + pin_name + "'");
578  }
579  const u32 bit_count = entry["bit_count"].GetUint();
580 
581  // Per-pin is_ascending (bool) overrides global; falls back to global_ascending.
582  if (!entry.HasMember("is_ascending") || !entry["is_ascending"].IsBool())
583  {
584  return ERR("could not parse LUT configuration: missing or invalid is_ascending for pin '" + pin_name + "'");
585  }
586  bool pin_ascending = entry["is_ascending"].GetBool();
587 
588  if (!entry.HasMember("input_pins") || !entry["input_pins"].IsArray())
589  {
590  return ERR("could not parse LUT configuration: missing or invalid input_pins for pin '" + pin_name + "'");
591  }
592  std::vector<std::string> input_pins;
593  for (const auto& pv : entry["input_pins"].GetArray())
594  {
595  if (!pv.IsString())
596  {
597  return ERR("could not parse LUT configuration: non-string entry in input_pins for pin '" + pin_name + "'");
598  }
599  input_pins.emplace_back(pv.GetString());
600  }
601  if (input_pins.empty())
602  {
603  return ERR("could not parse LUT configuration: input_pins must be non-empty for pin '" + pin_name + "'");
604  }
605 
606  pin_cfgs.push_back({pin_name, identifier, bit_offset, bit_count, pin_ascending, std::move(input_pins)});
607  }
608 
609  std::unordered_map<std::string, LUTComponent::LUTOutputConfig> cfg_map;
610  for (const auto& pc : pin_cfgs)
611  {
612  cfg_map.emplace(pc.pin_name, LUTComponent::LUTOutputConfig(pc.identifier, pc.bit_offset, pc.bit_count, pc.is_ascending, pc.input_pins));
613  }
614 
615  return OK(LUTComponent::create(std::move(cfg_map)));
616  }
617 
618  return OK(LUTComponent::create({}));
619  }
620 
621  Result<std::unique_ptr<GateTypeComponent>> HGLParser::parse_ff_config(const rapidjson::Value& ff_config)
622  {
623  if (!ff_config.HasMember("state") || !ff_config["state"].IsString())
624  {
625  return ERR("could not parse flip-flop configuration: missing or invalid state identifier");
626  }
627  if (!ff_config.HasMember("neg_state") || !ff_config["neg_state"].IsString())
628  {
629  return ERR("could not parse flip-flop configuration: missing or invalid negated state identifier");
630  }
631  if (!ff_config.HasMember("next_state") || !ff_config["next_state"].IsString())
632  {
633  return ERR("could not parse flip-flop configuration: missing or invalid next state function");
634  }
635  if (!ff_config.HasMember("clocked_on") || !ff_config["clocked_on"].IsString())
636  {
637  return ERR("could not parse flip-flop configuration: missing or invalid clock function");
638  }
639 
640  std::unique_ptr<GateTypeComponent> init_component = nullptr;
641  if (ff_config.HasMember("data_category") && ff_config["data_category"].IsString())
642  {
643  std::vector<std::string> init_identifiers;
644  if (ff_config.HasMember("data_identifier") && ff_config["data_identifier"].IsString())
645  { // backward compatability
646  init_identifiers.push_back(ff_config["data_identifier"].GetString());
647  }
648  else
649  {
650  return ERR("could not parse flip-flop configuration: missing or invalid data identifier for flip-flop initialization");
651  }
652  init_component = InitComponent::create(ff_config["data_category"].GetString(), init_identifiers);
653  }
654  else if (ff_config.HasMember("data_identifier") && ff_config["data_identifier"].IsString())
655  {
656  return ERR("could not parse flip-flop configuration: missing or invalid data category for flip-flop initialization");
657  }
658 
659  std::string state_identifier = ff_config["state"].GetString();
660  std::string neg_state_identifier = ff_config["neg_state"].GetString();
661  std::unique_ptr<GateTypeComponent> state_component = StateComponent::create(std::move(init_component), state_identifier, neg_state_identifier);
662  assert(state_component != nullptr);
663 
664  BooleanFunction next_state_function;
665  if (auto res = BooleanFunction::from_string(ff_config["next_state"].GetString()); res.is_error())
666  {
667  return ERR("could not parse flip-flop configuration: failed parsing next state function from string");
668  }
669  else
670  {
671  next_state_function = res.get();
672  }
673  BooleanFunction clocked_on_function;
674  if (auto res = BooleanFunction::from_string(ff_config["clocked_on"].GetString()); res.is_error())
675  {
676  return ERR("could not parse flip-flop configuration: failed parsing clock function from string");
677  }
678  else
679  {
680  clocked_on_function = res.get();
681  }
682 
683  std::unique_ptr<GateTypeComponent> component = FFComponent::create(std::move(state_component), next_state_function, clocked_on_function);
684 
685  FFComponent* ff_component = component->convert_to<FFComponent>();
686  assert(ff_component != nullptr);
687 
688  if (ff_config.HasMember("clear_on") && ff_config["clear_on"].IsString())
689  {
690  if (auto res = BooleanFunction::from_string(ff_config["clear_on"].GetString()); res.is_error())
691  {
692  return ERR("could not parse flip-flop configuration: failed parsing asynchronous reset function from string");
693  }
694  else
695  {
696  ff_component->set_async_reset_function(res.get());
697  }
698  }
699 
700  if (ff_config.HasMember("preset_on") && ff_config["preset_on"].IsString())
701  {
702  if (auto res = BooleanFunction::from_string(ff_config["preset_on"].GetString()); res.is_error())
703  {
704  return ERR("could not parse flip-flop configuration: failed parsing asynchronous set function from string");
705  }
706  else
707  {
708  ff_component->set_async_set_function(res.get());
709  }
710  }
711 
712  bool has_state = ff_config.HasMember("state_clear_preset") && ff_config["state_clear_preset"].IsString();
713  bool has_neg_state = ff_config.HasMember("neg_state_clear_preset") && ff_config["neg_state_clear_preset"].IsString();
714 
715  if (has_state && has_neg_state)
716  {
717  AsyncSetResetBehavior cp1, cp2;
718 
719  if (const auto behav = enum_from_string<AsyncSetResetBehavior>(ff_config["state_clear_preset"].GetString(), AsyncSetResetBehavior::undef); behav != AsyncSetResetBehavior::undef)
720  {
721  cp1 = behav;
722  }
723  else
724  {
725  return ERR("could not parse flip-flop configuration: failed parsing state on concurrent asynchronous set and reset from string");
726  }
727 
728  if (const auto behav = enum_from_string<AsyncSetResetBehavior>(ff_config["neg_state_clear_preset"].GetString(), AsyncSetResetBehavior::undef); behav != AsyncSetResetBehavior::undef)
729  {
730  cp2 = behav;
731  }
732  else
733  {
734  return ERR("could not parse flip-flop configuration: failed parsing negated state on concurrent asynchronous set and reset from string");
735  }
736 
737  ff_component->set_async_set_reset_behavior(cp1, cp2);
738  }
739  else if ((has_state && !has_neg_state) || (!has_state && has_neg_state))
740  {
741  return ERR("could not parse flip-flop configuration: missing state or negated state on concurrent asynchronous set and reset");
742  }
743 
744  return OK(std::move(component));
745  }
746 
747  Result<std::unique_ptr<GateTypeComponent>> HGLParser::parse_latch_config(const rapidjson::Value& latch_config)
748  {
749  if (!latch_config.HasMember("state") || !latch_config["state"].IsString())
750  {
751  return ERR("could not parse latch configuration: missing or invalid state identifier");
752  }
753  if (!latch_config.HasMember("neg_state") || !latch_config["neg_state"].IsString())
754  {
755  return ERR("could not parse latch configuration: missing or invalid negated state identifier");
756  }
757 
758  std::string state_identifier = latch_config["state"].GetString();
759  std::string neg_state_identifier = latch_config["neg_state"].GetString();
760  std::unique_ptr<GateTypeComponent> state_component = StateComponent::create(nullptr, state_identifier, neg_state_identifier);
761  assert(state_component != nullptr);
762 
763  std::unique_ptr<GateTypeComponent> component = LatchComponent::create(std::move(state_component));
764  LatchComponent* latch_component = component->convert_to<LatchComponent>();
765  assert(latch_component != nullptr);
766 
767  if (latch_config.HasMember("data_in") && latch_config["data_in"].IsString() && latch_config.HasMember("enable_on") && latch_config["enable_on"].IsString())
768  {
769  if (auto res = BooleanFunction::from_string(latch_config["data_in"].GetString()); res.is_error())
770  {
771  return ERR("could not parse latch configuration: failed parsing data in function from string");
772  }
773  else
774  {
775  latch_component->set_data_in_function(res.get());
776  }
777 
778  if (auto res = BooleanFunction::from_string(latch_config["enable_on"].GetString()); res.is_error())
779  {
780  return ERR("could not parse latch configuration: failed parsing enable function from string");
781  }
782  else
783  {
784  latch_component->set_enable_function(res.get());
785  }
786  }
787  else if (latch_config.HasMember("data_in") && latch_config["data_in"].IsString())
788  {
789  return ERR("could not parse latch configuration: missing or invalid enable function");
790  }
791  else if (latch_config.HasMember("enable_on") && latch_config["enable_on"].IsString())
792  {
793  return ERR("could not parse latch configuration: missing or invalid data in function");
794  }
795 
796  if (latch_config.HasMember("clear_on") && latch_config["clear_on"].IsString())
797  {
798  if (auto res = BooleanFunction::from_string(latch_config["clear_on"].GetString()); res.is_error())
799  {
800  return ERR("could not parse latch configuration: failed parsing asynchronous reset function from string");
801  }
802  else
803  {
804  latch_component->set_async_reset_function(res.get());
805  }
806  }
807 
808  if (latch_config.HasMember("preset_on") && latch_config["preset_on"].IsString())
809  {
810  if (auto res = BooleanFunction::from_string(latch_config["preset_on"].GetString()); res.is_error())
811  {
812  return ERR("could not parse latch configuration: failed parsing asynchronous set function from string");
813  }
814  else
815  {
816  latch_component->set_async_set_function(res.get());
817  }
818  }
819 
820  bool has_state = latch_config.HasMember("state_clear_preset") && latch_config["state_clear_preset"].IsString();
821  bool has_neg_state = latch_config.HasMember("neg_state_clear_preset") && latch_config["neg_state_clear_preset"].IsString();
822 
823  if (has_state && has_neg_state)
824  {
825  AsyncSetResetBehavior cp1, cp2;
826 
827  if (const auto behav = enum_from_string<AsyncSetResetBehavior>(latch_config["state_clear_preset"].GetString(), AsyncSetResetBehavior::undef); behav != AsyncSetResetBehavior::undef)
828  {
829  cp1 = behav;
830  }
831  else
832  {
833  return ERR("could not parse latch configuration: failed parsing state on concurrent asynchronous set and reset from string");
834  }
835 
836  if (const auto behav = enum_from_string<AsyncSetResetBehavior>(latch_config["neg_state_clear_preset"].GetString(), AsyncSetResetBehavior::undef); behav != AsyncSetResetBehavior::undef)
837  {
838  cp2 = behav;
839  }
840  else
841  {
842  return ERR("could not parse latch configuration: failed parsing negated state on concurrent asynchronous set and reset from string");
843  }
844 
845  latch_component->set_async_set_reset_behavior(cp1, cp2);
846  }
847  else if ((has_state && !has_neg_state) || (!has_state && has_neg_state))
848  {
849  return ERR("could not parse latch configuration: missing state or negated state on concurrent asynchronous set and reset");
850  }
851 
852  return OK(std::move(component));
853  }
854 
855  Result<std::unique_ptr<GateTypeComponent>> HGLParser::parse_ram_config(const rapidjson::Value& ram_config)
856  {
857  if (!ram_config.HasMember("data_identifiers") || !ram_config["data_identifiers"].IsArray())
858  {
859  return ERR("could not parse RAM configuration: missing or invalid data_identifiers");
860  }
861 
862  std::vector<std::string> init_identifiers;
863  for (const auto& identifier : ram_config["data_identifiers"].GetArray())
864  {
865  init_identifiers.push_back(identifier.GetString());
866  }
867 
868  std::unique_ptr<GateTypeComponent> sub_component = nullptr;
869 
870  if (!ram_config.HasMember("bit_size") || !ram_config["bit_size"].IsUint())
871  {
872  return ERR("could not parse RAM configuration: missing or invalid bit size");
873  }
874 
875  if (!ram_config.HasMember("ram_ports") || !ram_config["ram_ports"].IsArray())
876  {
877  return ERR("could not parse RAM configuration: missing or invalid RAM ports");
878  }
879 
880  for (const auto& ram_port : ram_config["ram_ports"].GetArray())
881  {
882  if (!ram_port.HasMember("data_group") || !ram_port["data_group"].IsString())
883  {
884  return ERR("could not parse RAM configuration: missing or invalid data pin groups for RAM port");
885  }
886 
887  if (!ram_port.HasMember("address_group") || !ram_port["address_group"].IsString())
888  {
889  return ERR("could not parse RAM configuration: missing or invalid address pin groups for RAM port");
890  }
891 
892  if (!ram_port.HasMember("clocked_on") || !ram_port["clocked_on"].IsString())
893  {
894  return ERR("could not parse RAM configuration: missing or invalid clock function for RAM port");
895  }
896 
897  if (!ram_port.HasMember("enabled_on") || !ram_port["enabled_on"].IsString())
898  {
899  return ERR("could not parse RAM configuration: missing or invalid enable function for RAM port");
900  }
901 
902  if (!ram_port.HasMember("is_write") || !ram_port["is_write"].IsBool())
903  {
904  return ERR("could not parse RAM configuration: missing or invalid write flag for RAM port");
905  }
906 
907  BooleanFunction clocked_on_function;
908  if (auto res = BooleanFunction::from_string(ram_port["clocked_on"].GetString()); res.is_error())
909  {
910  return ERR("could not parse RAM configuration: failed parsing clock function from string");
911  }
912  else
913  {
914  clocked_on_function = res.get();
915  }
916 
917  BooleanFunction enabled_on_function;
918  if (auto res = BooleanFunction::from_string(ram_port["enabled_on"].GetString()); res.is_error())
919  {
920  return ERR("could not parse RAM configuration: failed parsing clock function from string");
921  }
922  else
923  {
924  enabled_on_function = res.get();
925  }
926 
927  sub_component = RAMPortComponent::create(
928  std::move(sub_component), ram_port["data_group"].GetString(), ram_port["address_group"].GetString(), clocked_on_function, enabled_on_function, ram_port["is_write"].GetBool());
929  }
930 
931  std::unique_ptr<GateTypeComponent> component = RAMComponent::create(std::move(sub_component), ram_config["bit_size"].GetUint(), init_identifiers);
932 
933  return OK(std::move(component));
934  }
935 } // namespace hal
static Result< BooleanFunction > from_string(const std::string &expression)
static std::unique_ptr< FFComponent > create(std::unique_ptr< GateTypeComponent > component, const BooleanFunction &next_state_bf, const BooleanFunction &clock_bf)
static void set_parse_status(ParseStatus status)
@ NoError
The gate library was parsed successfully.
@ NeedsUpgrade
The file format is outdated, it gets upgraded by parsing it again after request_upgrade.
Result< std::unique_ptr< GateLibrary > > parse(const std::filesystem::path &file_path) override
Definition: hgl_parser.cpp:20
static std::unique_ptr< InitComponent > create(const std::string &init_category, const std::vector< std::string > &init_identifiers)
static std::unique_ptr< LUTComponent > create(std::unordered_map< std::string, LUTOutputConfig > configs={})
static std::unique_ptr< LatchComponent > create(std::unique_ptr< GateTypeComponent > component)
static std::unique_ptr< RAMComponent > create(std::unique_ptr< GateTypeComponent > component, const u32 bit_size, const std::vector< std::string > &init_identifiers={})
static std::unique_ptr< RAMPortComponent > create(std::unique_ptr< GateTypeComponent > component, const std::string &data_group, const std::string &addr_group, const BooleanFunction &clock_bf, const BooleanFunction &enable_bf, bool is_write)
static std::unique_ptr< StateComponent > create(std::unique_ptr< GateTypeComponent > component, const std::string &state_identifier, const std::string &neg_state_identifier)
uint16_t u16
Definition: defines.h:40
uint32_t u32
Definition: defines.h:41
#define log_info(channel,...)
Definition: log.h:70
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
Result< std::vector< std::string > > upgrade_document(rapidjson::Document &document)
Result< std::filesystem::path > replace_file(const rapidjson::Document &document, const std::filesystem::path &file_path)
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
PinType
Definition: pin_type.h:36
std::vector< PinInformation > pins
bool ordered
u32 start_index
bool ascending
std::string name
std::string identifier
static Result< Parameter > Boolean(const std::string &name, const std::string &default_value)
Definition: parameter.cpp:319
static Result< Parameter > BitVector(const std::string &name, u16 size, const std::string &default_value)
Definition: parameter.cpp:340
static Result< Parameter > Integer(const std::string &name, const std::string &default_value)
Definition: parameter.cpp:390
static Result< Parameter > String(const std::string &name, const std::string &default_value)
Definition: parameter.cpp:411
static Result< Parameter > LogicVector(const std::string &name, u16 size, const std::string &default_value)
Definition: parameter.cpp:365
static Result< Parameter > Time(const std::string &name, const std::string &default_value)
Definition: parameter.cpp:448
static Result< Parameter > Enum(const std::string &name, const std::vector< std::string > &values, const std::string &default_value)
Definition: parameter.cpp:469
static Result< Parameter > Float(const std::string &name, const std::string &default_value)
Definition: parameter.cpp:427