HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
converter.cpp
Go to the documentation of this file.
9 #include "hal_core/netlist/net.h"
11 #include "hal_core/utilities/log.h"
12 #include "verilator/verilator.h"
13 
14 #include <filesystem>
15 #include <fstream>
16 #include <set>
17 #include <sstream>
18 #include <vector>
19 #include <cctype>
20 
21 namespace hal
22 {
23 
24  namespace verilator
25  {
26  namespace converter
27  {
28 
29  bool convert_gate_library_to_verilog(const Netlist* nl, const std::filesystem::path verilator_sim_path, const std::filesystem::path model_path)
30  {
31  log_info("verilator", "converting {} to verilog for simulation", nl->get_gate_library()->get_name());
32 
33  std::unordered_map<GateType*,std::string> gate_type_names = get_gate_gate_types_from_netlist(nl);
34 
35  // get preset simulation gate models if path given
36  std::filesystem::path gate_definitions_path = verilator_sim_path / "gate_definitions/";
37  std::filesystem::create_directory(gate_definitions_path);
38  std::set<std::string> provided_models;
39  if (!model_path.empty())
40  {
41  provided_models = get_provided_models(model_path, gate_definitions_path);
42  }
43 
44  // create all remaining gate type simulation models
45  for (auto& it : gate_type_names)
46  {
47  // check if model has been given
48  if (provided_models.find(it.first->get_name()) != provided_models.end())
49  {
50  log_debug("verilator", "using provided model for gate: {}", it.first->get_name());
51  continue;
52  }
53 
54  bool replace_name = false;
55  if (it.second == it.first->get_name())
56  log_info("verilator", "creating verilog simulation model for '{}'", it.first->get_name());
57  else
58  {
59  log_info("verilator", "creating verilog simulation model for '{}' which corresponds to gate type '{}'",
60  it.second, it.first->get_name());
61  replace_name = true;
62  }
63  std::stringstream gate_description;
64 
65  // insert prologue
66  gate_description << get_prologue_for_gate_type(it.first) << std::endl;
67 
68  // get function of gate
69  std::string gate_function = get_function_for_gate(it.first);
70  if (gate_function.empty())
71  {
72  log_error("verilator", "unimplemented reached: gate type: '{}', cannot create simulation model...", it.first->get_name());
73  return false;
74  }
75  gate_description << gate_function << std::endl;
76 
77  // insert epilogue
78  gate_description << get_epilogue_for_gate_type() << std::endl;
79 
80  // write file
81  std::ofstream gate_file(gate_definitions_path / (it.second + ".v"));
82  if (replace_name)
83  {
84  std::string buffer = gate_description.str();
85  size_t pos = 0;
86  for (;;)
87  {
88  pos = buffer.find(it.first->get_name());
89  if (pos == std::string::npos) break;
90  buffer.replace(pos, it.first->get_name().size(), it.second);
91  pos += it.second.size();
92  }
93  gate_file << buffer;
94  }
95  else
96  gate_file << gate_description.str();
97  gate_file.close();
98  }
99 
100  return true;
101  }
102 
103  std::set<std::string> get_provided_models(const std::filesystem::path model_path, const std::filesystem::path gate_definition_path)
104  {
105  std::set<std::string> supported_gate_types;
106  if (!std::filesystem::exists(model_path))
107  {
108  log_warning("verilator", "provided_models path '{}' does not exist", model_path.string());
109  return supported_gate_types;
110  }
111  for (const auto& entry : std::filesystem::directory_iterator(model_path))
112  {
113  std::string file = entry.path().filename();
114 
115  if (entry.path().extension() != ".v")
116  {
117  log_info("verilator", "not reading {} from simulation path, since it is not verilog (no .v extension)", file);
118  continue;
119  }
120 
121  file = utils::replace(file, std::string(".v"), std::string(""));
122  supported_gate_types.insert(file);
123 
124  // copy gate lib to verilator folder
125  std::filesystem::copy(entry.path(), gate_definition_path);
126  }
127 
128  if (!supported_gate_types.empty())
129  {
130  log_info("verilator", "using provided gate simulation models for: ");
131  for (const auto& gate : supported_gate_types)
132  {
133  log_info("verilator", "\t{}", gate);
134  }
135  }
136  else
137  {
138  log_info("verilator", "no gate types were provided");
139  }
140 
141  return supported_gate_types;
142  }
143 
144  std::unordered_map<GateType*,std::string> get_gate_gate_types_from_netlist(const Netlist* nl)
145  {
146  std::unordered_map<GateType*,std::string> gate_types;
147 
148  for (const auto& gate : nl->get_gates())
149  {
150  gate_types.emplace(std::make_pair<GateType*,std::string>(gate->get_type(),get_name_for_gate_type(gate->get_type())));
151  }
152 
153  return gate_types;
154  }
155 
156  std::string get_name_for_gate_type(const GateType* gt)
157  {
158  std::stringstream retval;
159  for (char cc : gt->get_name())
160  {
161  if (isalnum(cc))
162  {
163  if (isdigit(cc) && retval.str().empty())
164  retval << 'G';
165  retval << cc;
166  }
167  else if (cc == '_')
168  retval << cc;
169  else
170  {
171  retval << '_' << std::hex << static_cast<unsigned int>(cc) << "_";
172  }
173  }
174  return retval.str();
175  }
176 
177  std::vector<std::string> get_parameters_for_gate(const GateType* gt)
178  {
179  std::vector<std::string> parameters;
180  // insert gate specific function
182  {
183  u32 lut_size = gt->get_input_pins().size();
184  u32 init_len = 1 << lut_size;
185  bool lut_init_descending = false;
186 
187  if (LUTComponent* lut_component = gt->get_component_as<LUTComponent>([](const GateTypeComponent* c) { return LUTComponent::is_class_of(c); }); lut_component != nullptr)
188  {
189  if (!lut_component->is_init_ascending())
190  {
191  lut_init_descending = true;
192  }
193  }
194  else
195  {
196  log_error("verilator", "cannot get LUTComponent, aborting...");
197  return std::vector<std::string>();
198  }
199 
200  std::stringstream parameter;
201 
202  InitComponent* init_component = gt->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); });
203 
204  if (init_component == nullptr)
205  {
206  log_error("verilator", "Could not get init component for gate type {}!", gt->get_name());
207  }
208 
209  if (lut_init_descending)
210  {
211  parameter << "parameter [" << init_len - 1 << ":0]"
212  << " " << init_component->get_init_identifiers().front() << " = " << init_len << "'h" << std::setfill('0') << std::setw(init_len / 4) << 0 << ",";
213  }
214  else
215  {
216  parameter << "parameter [0:" << init_len - 1 << "]"
217  << " " << init_component->get_init_identifiers().front() << " = " << init_len << "'h" << std::setfill('0') << std::setw(init_len / 4) << 0 << ",";
218  }
219 
220  parameters.push_back(parameter.str());
221  }
223  {
224  if (InitComponent* init_component = gt->get_component_as<InitComponent>([](const GateTypeComponent* c) { return InitComponent::is_class_of(c); }); init_component != nullptr)
225  {
226  std::stringstream parameter;
227  parameter << "parameter [0:0]"
228  << " " << init_component->get_init_identifiers().front() << "= 1'b0,";
229  parameters.push_back(parameter.str());
230  }
231  }
232 
233  return parameters;
234  }
235 
236  std::string get_prologue_for_gate_type(const GateType* gt)
237  {
238  std::stringstream prologue;
239 
240  prologue << "`timescale 1 ps/1 ps" << std::endl;
241 
242  prologue << "module " << gt->get_name() << std::endl;
243 
244  // some gates have parameters, which we need to insert
245 
246  std::vector<std::string> parameters = get_parameters_for_gate(gt);
247 
248  // add parameters to all gates
249  if (!parameters.empty())
250  {
251  prologue << "#(" << std::endl;
252  std::string parameter_str;
253  for (const auto& parameter : parameters)
254  {
255  parameter_str += "\t" + parameter + "\n";
256  }
257  parameter_str.erase(parameter_str.find_last_of(","));
258  prologue << parameter_str << std::endl;
259  prologue << ")" << std::endl;
260  }
261 
262  // in and outputs of module
263  prologue << "(" << std::endl;
264 
265  std::unordered_set<GatePin*> visited_pins;
266  for (const auto pin : gt->get_pins())
267  {
268  // check if pin was contained in a group that has already been dealt with
269  if (visited_pins.find(pin) != visited_pins.end())
270  {
271  continue;
272  }
273 
274  PinDirection direction = pin->get_direction();
275  prologue << "\t" << enum_to_string(direction) << " ";
276 
277  if (const auto* pin_group = pin->get_group().first; pin_group != nullptr)
278  {
279  const auto group_pins = pin_group->get_pins();
280  prologue << " [" << std::to_string(pin_group->get_index(group_pins.back()).get()) << ":" << std::to_string(pin_group->get_index(group_pins.front()).get()) << "] "
281  << pin_group->get_name() << "," << std::endl;
282 
283  for (const auto pin : group_pins)
284  {
285  visited_pins.insert(pin);
286  }
287  }
288  else
289  {
290  // append all connected pins
291  prologue << pin->get_name() << "," << std::endl;
292  }
293  }
294 
295  prologue.seekp(-2, prologue.cur); // remove the additional colon and space
296 
297  prologue << std::endl;
298  prologue << ");" << std::endl;
299  prologue << std::endl;
300 
301  return prologue.str();
302  }
303 
304  Result<std::string> verilog_function_printer(const BooleanFunction::Node& node, std::vector<std::string>&& operands)
305  {
306  if (node.get_arity() != operands.size())
307  {
308  return ERR("node arity of " + std::to_string(node.get_arity()) + " does not match number of operands of " + std::to_string(operands.size()));
309  }
310 
311  switch (node.type)
312  {
314  std::string str;
315  for (const auto& value : node.constant)
316  {
317  str = enum_to_string(value) + str;
318  }
319  return OK(std::to_string(node.constant.size()) + "'b" + str);
320  }
322  return OK(std::to_string(node.index));
324  return OK(node.variable);
326  return OK("(" + operands[0] + " & " + operands[1] + ")");
328  return OK("(! " + operands[0] + ")");
330  return OK("(" + operands[0] + " | " + operands[1] + ")");
332  return OK("(" + operands[0] + " ^ " + operands[1] + ")");
333  default:
334  return ERR("unsupported node type '" + std::to_string(node.type) + "'");
335  }
336  }
337 
338  std::string get_function_for_gate(const GateType* gt)
339  {
340  std::stringstream gate_description;
341  // insert gate specific function
343  {
344  gate_description << verilator::converter::get_function_for_lut(gt) << std::endl;
345  }
347  {
348  gate_description << verilator::converter::get_function_for_combinational_gate(gt) << std::endl;
349  }
351  {
352  gate_description << verilator::converter::get_function_for_ff(gt) << std::endl;
353  }
355  {
356  gate_description << verilator::converter::get_function_for_latch(gt) << std::endl;
357  }
359  {
360  gate_description << verilator::converter::get_function_for_combinational_gate(gt) << std::endl;
361  }
362  return gate_description.str();
363  }
364 
366  {
367  std::stringstream epilogue;
368 
369  epilogue << "endmodule" << std::endl;
370 
371  return epilogue.str();
372  }
373  } // namespace converter
374 
375  } // namespace verilator
376 } // namespace hal
std::string get_name() const
const std::string & get_name() const
Definition: gate_type.cpp:64
bool has_property(GateTypeProperty property) const
Definition: gate_type.cpp:101
std::vector< GatePin * > get_input_pins() const
Definition: gate_type.cpp:269
T * get_component_as(const std::function< bool(const GateTypeComponent *)> &filter=nullptr) const
Definition: gate_type.h:89
std::vector< GatePin * > get_pins(const std::function< bool(GatePin *)> &filter=nullptr) const
Definition: gate_type.cpp:210
static bool is_class_of(const GateTypeComponent *component)
const std::vector< std::string > & get_init_identifiers() const
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:204
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:132
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
#define log_debug(channel,...)
Definition: log.h:74
#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
T replace(const T &str, const T &search, const T &replace)
Definition: utils.h:384
bool convert_gate_library_to_verilog(const Netlist *nl, const std::filesystem::path verilator_sim_path, const std::filesystem::path model_path="")
Definition: converter.cpp:29
std::vector< std::string > get_parameters_for_gate(const GateType *gt)
Definition: converter.cpp:177
std::string get_function_for_latch(const GateType *gt)
std::string get_prologue_for_gate_type(const GateType *gt)
Definition: converter.cpp:236
std::string get_function_for_ff(const GateType *gt)
Definition: ff_function.cpp:23
std::string get_function_for_lut(const GateType *gt)
Result< std::string > verilog_function_printer(const BooleanFunction::Node &node, std::vector< std::string > &&operands)
Definition: converter.cpp:304
std::string get_function_for_combinational_gate(const GateType *gt)
std::unordered_map< GateType *, std::string > get_gate_gate_types_from_netlist(const Netlist *nl)
Definition: converter.cpp:144
std::string get_function_for_gate(const GateType *gt)
Definition: converter.cpp:338
std::set< std::string > get_provided_models(const std::filesystem::path model_path, const std::filesystem::path gate_definition_path)
Definition: converter.cpp:103
std::string get_epilogue_for_gate_type()
Definition: converter.cpp:365
std::string get_name_for_gate_type(const GateType *gt)
Definition: converter.cpp:156
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
std::string enum_to_string(T e)
Definition: enums.h:53
PinDirection direction
std::vector< BooleanFunction::Value > constant
The (optional) constant value of the node.
u16 type
The type of the node.
std::string variable
The (optional) variable name of the node.
u16 index
The (optional) index value of the node.