HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
converter.cpp
Go to the documentation of this file.
7 #include "hal_core/netlist/net.h"
10 #include "verilator/verilator.h"
11 
12 #include <cctype>
13 #include <filesystem>
14 #include <fstream>
15 #include <set>
16 #include <sstream>
17 #include <unordered_set>
18 #include <vector>
19 
20 namespace hal
21 {
22 
23  namespace verilator
24  {
25  namespace converter
26  {
27 
28  bool convert_gate_library_to_verilog(const Netlist* nl, const std::filesystem::path verilator_sim_path, const std::filesystem::path model_path)
29  {
30  log_info("verilator", "converting {} to verilog for simulation", nl->get_gate_library()->get_name());
31 
32  std::unordered_map<GateType*, std::string> gate_type_names = get_gate_gate_types_from_netlist(nl);
33 
34  // get preset simulation gate models if path given
35  std::filesystem::path gate_definitions_path = verilator_sim_path / "gate_definitions/";
36  std::filesystem::create_directory(gate_definitions_path);
37  std::set<std::string> provided_models;
38  if (!model_path.empty())
39  {
40  provided_models = get_provided_models(model_path, gate_definitions_path);
41  }
42 
43  // create all remaining gate type simulation models
44  for (auto& it : gate_type_names)
45  {
46  // check if model has been given
47  if (provided_models.find(it.first->get_name()) != provided_models.end())
48  {
49  log_debug("verilator", "using provided model for gate: {}", it.first->get_name());
50  continue;
51  }
52 
53  bool replace_name = false;
54  if (it.second == it.first->get_name())
55  {
56  log_info("verilator", "creating verilog simulation model for '{}'", it.first->get_name());
57  }
58  else
59  {
60  log_info("verilator", "creating verilog simulation model for '{}' which corresponds to gate type '{}'", 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)
90  {
91  break;
92  }
93  buffer.replace(pos, it.first->get_name().size(), it.second);
94  pos += it.second.size();
95  }
96  gate_file << buffer;
97  }
98  else
99  {
100  gate_file << gate_description.str();
101  }
102  gate_file.close();
103  }
104 
105  return true;
106  }
107 
108  std::set<std::string> get_provided_models(const std::filesystem::path model_path, const std::filesystem::path gate_definition_path)
109  {
110  std::set<std::string> supported_gate_types;
111  if (!std::filesystem::exists(model_path))
112  {
113  log_warning("verilator", "provided_models path '{}' does not exist", model_path.string());
114  return supported_gate_types;
115  }
116  for (const auto& entry : std::filesystem::directory_iterator(model_path))
117  {
118  std::string file = entry.path().filename();
119 
120  if (entry.path().extension() != ".v")
121  {
122  log_info("verilator", "not reading {} from simulation path, since it is not verilog (no .v extension)", file);
123  continue;
124  }
125 
126  file = utils::replace(file, std::string(".v"), std::string(""));
127  supported_gate_types.insert(file);
128 
129  // copy gate lib to verilator folder
130  std::filesystem::copy(entry.path(), gate_definition_path);
131  }
132 
133  if (!supported_gate_types.empty())
134  {
135  log_info("verilator", "using provided gate simulation models for: ");
136  for (const auto& gate : supported_gate_types)
137  {
138  log_info("verilator", "\t{}", gate);
139  }
140  }
141  else
142  {
143  log_info("verilator", "no gate types were provided");
144  }
145 
146  return supported_gate_types;
147  }
148 
149  std::unordered_map<GateType*, std::string> get_gate_gate_types_from_netlist(const Netlist* nl)
150  {
151  std::unordered_map<GateType*, std::string> gate_types;
152 
153  for (const auto& gate : nl->get_gates())
154  {
155  gate_types.emplace(std::make_pair<GateType*, std::string>(gate->get_type(), get_name_for_gate_type(gate->get_type())));
156  }
157 
158  return gate_types;
159  }
160 
161  std::string get_name_for_gate_type(const GateType* gt)
162  {
163  std::stringstream retval;
164  for (char cc : gt->get_name())
165  {
166  if (isalnum(cc))
167  {
168  if (isdigit(cc) && retval.str().empty())
169  {
170  retval << 'G';
171  }
172  retval << cc;
173  }
174  else if (cc == '_')
175  {
176  retval << cc;
177  }
178  else
179  {
180  retval << '_' << std::hex << static_cast<unsigned int>(cc) << "_";
181  }
182  }
183  return retval.str();
184  }
185 
186  std::string get_prologue_for_gate_type(const GateType* gt)
187  {
188  std::stringstream prologue;
189 
190  prologue << "`timescale 1 ps/1 ps" << std::endl;
191  prologue << "module " << gt->get_name() << std::endl;
192 
193  // Emit #(...) parameter block from the gate type's declared parameters
194  const auto& gate_params = gt->get_parameters();
195  if (!gate_params.empty())
196  {
197  prologue << "#(" << std::endl;
198  std::string parameter_str;
199  for (const auto& [name, param] : gate_params)
200  {
201  const u32 size = param.get_size();
202  std::string hex_default = param.get_default_value();
203  if (hex_default.size() >= 2 && hex_default[0] == '0' && (hex_default[1] == 'x' || hex_default[1] == 'X'))
204  hex_default = hex_default.substr(2);
205  if (hex_default.empty())
206  hex_default = std::string(std::max(1u, size / 4), '0');
207  std::stringstream entry;
208  entry << "\tparameter [" << size - 1 << ":0] " << name << " = " << size << "'h"
209  << std::setfill('0') << std::setw(std::max(1u, size / 4)) << hex_default << ",\n";
210  parameter_str += entry.str();
211  }
212  parameter_str.erase(parameter_str.find_last_of(","));
213  prologue << parameter_str << std::endl;
214  prologue << ")" << std::endl;
215  }
216 
217  // in and outputs of module
218  prologue << "(" << std::endl;
219 
220  std::unordered_set<GatePin*> visited_pins;
221  for (const auto pin : gt->get_pins())
222  {
223  // check if pin was contained in a group that has already been dealt with
224  if (visited_pins.find(pin) != visited_pins.end())
225  {
226  continue;
227  }
228 
229  PinDirection direction = pin->get_direction();
230  prologue << "\t" << enum_to_string(direction) << " ";
231 
232  if (const auto* pin_group = pin->get_group().first; pin_group != nullptr)
233  {
234  const auto group_pins = pin_group->get_pins();
235  prologue << " [" << std::to_string(pin_group->get_index(group_pins.back()).get()) << ":" << std::to_string(pin_group->get_index(group_pins.front()).get()) << "] "
236  << pin_group->get_name() << "," << std::endl;
237 
238  for (const auto pin : group_pins)
239  {
240  visited_pins.insert(pin);
241  }
242  }
243  else
244  {
245  // append all connected pins
246  prologue << pin->get_name() << "," << std::endl;
247  }
248  }
249 
250  prologue.seekp(-2, prologue.cur); // remove the additional colon and space
251 
252  prologue << std::endl;
253  prologue << ");" << std::endl;
254  prologue << std::endl;
255 
256  return prologue.str();
257  }
258 
259  Result<std::string> verilog_function_printer(const BooleanFunction::Node& node, std::vector<std::string>&& operands)
260  {
261  if (node.get_arity() != operands.size())
262  {
263  return ERR("node arity of " + std::to_string(node.get_arity()) + " does not match number of operands of " + std::to_string(operands.size()));
264  }
265 
266  switch (node.type)
267  {
269  std::string str;
270  for (const auto& value : node.constant)
271  {
272  str = enum_to_string(value) + str;
273  }
274  return OK(std::to_string(node.constant.size()) + "'b" + str);
275  }
277  return OK(std::to_string(node.index));
279  return OK(node.variable);
281  return OK("(" + operands[0] + " & " + operands[1] + ")");
283  return OK("(! " + operands[0] + ")");
285  return OK("(" + operands[0] + " | " + operands[1] + ")");
287  return OK("(" + operands[0] + " ^ " + operands[1] + ")");
288  default:
289  return ERR("unsupported node type '" + std::to_string(node.type) + "'");
290  }
291  }
292 
293  std::string get_function_for_gate(const GateType* gt)
294  {
295  std::stringstream gate_description;
296  // insert gate specific function
298  {
299  gate_description << verilator::converter::get_function_for_lut(gt) << std::endl;
300  }
302  {
303  gate_description << verilator::converter::get_function_for_combinational_gate(gt) << std::endl;
304  }
306  {
307  gate_description << verilator::converter::get_function_for_ff(gt) << std::endl;
308  }
310  {
311  gate_description << verilator::converter::get_function_for_latch(gt) << std::endl;
312  }
314  {
315  gate_description << verilator::converter::get_function_for_combinational_gate(gt) << std::endl;
316  }
317  return gate_description.str();
318  }
319 
321  {
322  std::stringstream epilogue;
323 
324  epilogue << "endmodule" << std::endl;
325 
326  return epilogue.str();
327  }
328  } // namespace converter
329 
330  } // namespace verilator
331 } // namespace hal
u32 size
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
const std::unordered_map< std::string, Parameter > & get_parameters() const
Definition: gate_type.cpp:762
std::vector< GatePin * > get_pins(const std::function< bool(GatePin *)> &filter=nullptr) const
Definition: gate_type.cpp:210
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:134
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:428
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:28
std::string get_function_for_latch(const GateType *gt)
std::string get_prologue_for_gate_type(const GateType *gt)
Definition: converter.cpp:186
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:259
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:149
std::string get_function_for_gate(const GateType *gt)
Definition: converter.cpp:293
std::set< std::string > get_provided_models(const std::filesystem::path model_path, const std::filesystem::path gate_definition_path)
Definition: converter.cpp:108
std::string get_epilogue_for_gate_type()
Definition: converter.cpp:320
std::string get_name_for_gate_type(const GateType *gt)
Definition: converter.cpp:161
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
std::string enum_to_string(T e)
Definition: enums.h:53
PinDirection direction
std::string name
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.