HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
preprocessing.cpp
Go to the documentation of this file.
3 #include "hal_core/netlist/net.h"
6 
7 namespace hal
8 {
9  namespace xilinx_toolbox
10  {
12  {
13  u32 deleted_gates = 0;
14  u32 new_gates = 0;
15  std::vector<Gate*> to_delete;
16 
17  const auto lut6_type = nl->get_gate_library()->get_gate_type_by_name("LUT6");
18  const auto lut5_type = nl->get_gate_library()->get_gate_type_by_name("LUT5");
19 
20  const auto lut6_2_gates = nl->get_gates([](const Gate* g) { return g->get_type()->get_name() == "LUT6_2"; });
21 
22  for (const auto& g : lut6_2_gates)
23  {
24  auto* o5 = g->get_fan_out_net("O5");
25  auto* o6 = g->get_fan_out_net("O6");
26  const auto* i5 = g->get_fan_in_net("I5");
27 
28  const auto init_get_res = g->get_init_data();
29  if (init_get_res.is_error())
30  {
31  log_warning("xilinx_toolbox", "could not get INIT string of gate '{}' with ID {}, skipping this gate.", g->get_name(), g->get_id());
32  continue;
33  }
34  auto init = init_get_res.get().front();
35  if (init.length() != 16)
36  {
37  log_warning("xilinx_toolbox", "INIT string '{}' has length {}, expected 16.", init, init.length());
38  continue;
39  }
40 
41  if (o5->get_num_of_destinations() > 0)
42  {
43  // create LUT5
44  auto* lut5 = nl->create_gate(lut5_type, g->get_name() + "_split_O5");
45  lut5->set_data("xilinx_preprocessing_information", "original_init", "string", init);
46 
47  auto init_O5 = init.substr(8, 8);
48  if (lut5->set_init_data({init_O5}).is_error())
49  {
50  log_warning("xilinx_toolbox", "could not set INIT string of gate '{}' with ID {}, skipping this gate.", lut5->get_name(), lut5->get_id());
51  }
52 
53  if (auto* mod = g->get_module(); !mod->is_top_module())
54  {
55  mod->assign_gate(lut5);
56  }
57 
58  for (const auto& in_ep : g->get_fan_in_endpoints([](const Endpoint* ep) { return ep->get_pin()->get_name() != "I5"; }))
59  {
60  in_ep->get_net()->add_destination(lut5, in_ep->get_pin()->get_name());
61  }
62 
63  new_gates++;
64  o5->add_source(lut5, "O");
65  }
66 
67  if (o6->get_num_of_destinations() > 0)
68  {
69  // create LUT6
70  auto* lut6 = nl->create_gate(lut6_type, g->get_name() + "_split_O6");
71  lut6->set_data("xilinx_preprocessing_information", "original_init", "string", init);
72 
73  if (lut6->set_init_data({init}).is_error())
74  {
75  log_warning("xilinx_toolbox", "could not set INIT string of gate '{}' with ID {}, skipping this gate.", lut6->get_name(), lut6->get_id());
76  nl->delete_gate(lut6);
77  continue;
78  }
79 
80  if (auto* mod = g->get_module(); !mod->is_top_module())
81  {
82  mod->assign_gate(lut6);
83  }
84 
85  for (const auto& in_ep : g->get_fan_in_endpoints())
86  {
87  in_ep->get_net()->add_destination(lut6, in_ep->get_pin()->get_name());
88  }
89 
90  new_gates++;
91  o6->add_source(lut6, "O");
92  }
93  to_delete.push_back(g);
94  }
95 
96  for (const auto& g : to_delete)
97  {
98  if (!nl->delete_gate(g))
99  {
100  return ERR("Cannot split luts for netlist with ID " + std::to_string(nl->get_id()) + ": Failed to delete gate " + g->get_name() + " with ID " + std::to_string(g->get_id()));
101  }
102  else
103  {
104  deleted_gates++;
105  }
106  }
107 
108  log_info("xilinx_toolbox", "split {} LUT6_2 gates into {} LUT6 and LUT5 gates", deleted_gates, new_gates);
109  return OK(deleted_gates);
110  }
111 
113  {
114  u32 deleted_gates = 0;
115  u32 new_gates = 0;
116  std::vector<Gate*> to_delete;
117 
118  GateType* ff_gt = nl->get_gate_library()->get_gate_type_by_name("FDE");
119  if (ff_gt == nullptr)
120  {
121  return ERR("could not find gate type 'FDE' in gate library");
122  }
123 
124  // iterate over all shift registers of type 'SRL16E' or 'SRLC32E'
125  for (const auto& gate : nl->get_gates([](const auto& g) { return g->get_type()->get_name() == "SRL16E" || g->get_type()->get_name() == "SRLC32E"; }))
126  {
127  auto control_pins = gate->get_type()->get_pins([](const auto& pg) { return (pg->get_direction() == PinDirection::input) && (pg->get_type() == PinType::control); });
128  if (control_pins.size() != 4 && gate->get_type()->get_name() == "SRLC16E" || control_pins.size() != 5 && gate->get_type()->get_name() == "SRLC32E")
129  {
130  return ERR("invalid number of control pins");
131  }
132 
133  if (gate->get_type()->get_name() == "SRL16E")
134  {
135  std::sort(control_pins.begin(), control_pins.end(), [](const auto& p1, const auto& p2) {
136  const u32 idx1 = std::stoull(p1->get_name().substr(1)); // Ai
137  const u32 idx2 = std::stoull(p2->get_name().substr(1)); // Ai
138 
139  return idx1 < idx2;
140  });
141  }
142  else
143  {
144  std::sort(control_pins.begin(), control_pins.end(), [](const auto& p1, const auto& p2) {
145  const u32 idx1 = std::stoull(p1->get_name().substr(2)); // A(i)
146  const u32 idx2 = std::stoull(p2->get_name().substr(2)); // A(i)
147 
148  return idx1 < idx2;
149  });
150  }
151 
152  u32 select_value = 0;
153  for (u32 idx = 0; idx < control_pins.size(); idx++)
154  {
155  const Net* cn = gate->get_fan_in_net(control_pins.at(idx));
156 
157  if (cn == nullptr)
158  {
159  log_warning("xilinx_toolbox", "control net at pin '{}' of gate '{}' with ID {} is 'nullptr'", control_pins.at(idx)->get_name(), gate->get_name(), gate->get_id());
160  continue;
161  }
162 
163  if (!cn->is_gnd_net() && !cn->is_vcc_net())
164  {
165  log_warning("xilinx_toolbox", "control net at pin '{}' of gate '{}' with ID {} is not constant", control_pins.at(idx)->get_name(), gate->get_name(), gate->get_id());
166  continue;
167  }
168 
169  select_value += (cn->is_gnd_net() ? 0 : 1) << idx;
170  }
171 
172  const auto clock_pins = gate->get_type()->get_pins([](const auto& p) { return (p->get_direction() == PinDirection::input) && (p->get_type() == PinType::clock); });
173  if (clock_pins.size() != 1)
174  {
175  return ERR("invalid number of input clock pins at shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
176  }
177 
178  const auto enable_pins = gate->get_type()->get_pins([](const auto& p) { return (p->get_direction() == PinDirection::input) && (p->get_type() == PinType::enable); });
179  if (enable_pins.size() != 1)
180  {
181  return ERR("invalid number of input enable pins at shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
182  }
183 
184  const auto data_pins = gate->get_type()->get_pins([](const auto& p) { return (p->get_direction() == PinDirection::input) && (p->get_type() == PinType::data); });
185  if (data_pins.size() != 1)
186  {
187  return ERR("invalid number of input data pins at shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
188  }
189 
190  Net* clk_in = gate->get_fan_in_net(clock_pins.front());
191  Net* enable_in = gate->get_fan_in_net(enable_pins.front());
192  Net* data_in = gate->get_fan_in_net(data_pins.front());
193  Net* state_out = nullptr;
194  Net* max_state_out = nullptr;
195 
196  if (gate->get_type()->get_name() == "SRLC32E")
197  {
198  state_out = gate->get_fan_out_net("Q");
199  max_state_out = gate->get_fan_out_net("Q31");
200  }
201  else
202  {
203  state_out = gate->get_fan_out_net("Q");
204  }
205 
206  if (clk_in == nullptr)
207  {
208  return ERR("no clock input net connected to shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
209  }
210 
211  if (enable_in == nullptr)
212  {
213  return ERR("no enable input net connected to shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
214  }
215 
216  if (data_in == nullptr)
217  {
218  return ERR("no data input net connected to shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
219  }
220 
221  if (state_out == nullptr && max_state_out == nullptr)
222  {
223  return ERR("no state output net connected to shift register gate '" + gate->get_name() + "' with ID " + std::to_string(gate->get_id()));
224  }
225 
226  u32 register_size = 0;
227  std::vector<Gate*> flip_flops;
228  std::vector<Net*> state_nets;
229 
230  if (max_state_out != nullptr)
231  {
232  register_size = max_state_out->get_num_of_destinations() > 0 ? 31 : select_value;
233  }
234  else
235  {
236  register_size = select_value;
237  }
238 
239  for (u32 ff_idx = 0; ff_idx <= register_size; ff_idx++)
240  {
241  const std::string ff_name = gate->get_name() + "_split_ff_" + std::to_string(ff_idx);
242  Gate* new_gate = nl->create_gate(ff_gt, ff_name);
243  new_gates++;
244 
245  clk_in->add_destination(new_gate, "C");
246  enable_in->add_destination(new_gate, "CE");
247 
248  if (ff_idx == 0)
249  {
250  data_in->add_destination(new_gate, "D");
251  }
252  else
253  {
254  state_nets.back()->add_destination(new_gate, "D");
255  }
256 
257  if (ff_idx == select_value && state_out != nullptr)
258  {
259  state_out->add_source(new_gate, "Q");
260  state_nets.push_back(state_out);
261  }
262  else if (ff_idx == register_size && max_state_out != nullptr)
263  {
264  max_state_out->add_source(new_gate, "Q");
265  state_nets.push_back(max_state_out);
266  }
267  else
268  {
269  Net* new_net = nl->create_net(ff_name + "_out");
270  new_net->add_source(new_gate, "Q");
271  state_nets.push_back(new_net);
272  }
273  }
274 
275  to_delete.push_back(gate);
276  }
277 
278  for (const auto& g : to_delete)
279  {
280  if (!nl->delete_gate(g))
281  {
282  return ERR("Cannot split shift register primitives for netlist with ID " + std::to_string(nl->get_id()) + ": Failed to delete gate " + g->get_name() + " with ID "
283  + std::to_string(g->get_id()));
284  }
285  else
286  {
287  deleted_gates++;
288  }
289  }
290 
291  log_info("xilinx_toolbox", "split {} SRL16E/SRLC32E gates into {} flip-flops", deleted_gates, new_gates);
292 
293  return OK(deleted_gates);
294  }
295  } // namespace xilinx_toolbox
296 } // namespace hal
bool set_data(const std::string &category, const std::string &key, const std::string &data_type, const std::string &value, const bool log_with_info_level=false)
Definition: gate.h:58
Net * get_fan_in_net(const std::string &pin_name) const
Definition: gate.cpp:617
GateType * get_type() const
Definition: gate.cpp:125
Net * get_fan_out_net(const std::string &pin_name) const
Definition: gate.cpp:761
const std::string & get_name() const
Definition: gate.cpp:105
Module * get_module() const
Definition: gate.cpp:174
const std::vector< Endpoint * > & get_fan_in_endpoints() const
Definition: gate.cpp:653
Result< std::vector< std::string > > get_init_data() const
Definition: gate.cpp:1034
u32 get_id() const
Definition: gate.cpp:95
GateType * get_gate_type_by_name(const std::string &name) const
bool is_top_module() const
Definition: module.cpp:314
Definition: net.h:58
Endpoint * add_destination(Gate *gate, const std::string &pin_name)
Definition: net.cpp:300
Endpoint * add_source(Gate *gate, const std::string &pin_name)
Definition: net.cpp:127
u32 get_num_of_destinations(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:432
bool is_vcc_net() const
Definition: net.cpp:479
bool is_gnd_net() const
Definition: net.cpp:474
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:204
Net * create_net(const u32 net_id, const std::string &name)
Definition: netlist.cpp:333
bool delete_gate(Gate *gate)
Definition: netlist.cpp:183
u32 get_id() const
Definition: netlist.cpp:75
Gate * create_gate(const u32 gate_id, GateType *gate_type, const std::string &name="", i32 x=-1, i32 y=-1)
Definition: netlist.cpp:173
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:132
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
Result< u32 > split_luts(Netlist *nl)
Split LUTs with two outputs into two separate LUT gates.
Result< u32 > split_shift_registers(Netlist *nl)
Split shift register primitives and replaces them with equivalent flip-flops chains.
Definition: defines.h:45
This file contains all functions related to the HAL plugin API.