HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
round_candidate.cpp
Go to the documentation of this file.
2 
4 #include "hal_core/netlist/net.h"
7 
8 namespace hal
9 {
10  namespace hawkeye
11  {
12  namespace
13  {
14  void copy_in_eps_of_gate(Netlist* new_nl, const Gate* old_g, Gate* new_g, std::set<Net*>* add_to_set = nullptr)
15  {
16  for (const auto* in_ep : old_g->get_fan_in_endpoints())
17  {
18  Net* old_n = in_ep->get_net();
19  Net* new_n;
20  if (new_n = new_nl->get_net_by_id(old_n->get_id()); new_n == nullptr)
21  {
22  new_n = new_nl->create_net(old_n->get_id(), old_n->get_name());
23  }
24  new_n->add_destination(new_g, in_ep->get_pin());
25 
26  if (add_to_set)
27  {
28  add_to_set->insert(new_n);
29  }
30  }
31  }
32 
33  void copy_out_eps_of_gate(Netlist* new_nl, const Gate* old_g, Gate* new_g, std::set<Net*>* add_to_set = nullptr)
34  {
35  for (const auto* out_ep : old_g->get_fan_out_endpoints())
36  {
37  Net* old_n = out_ep->get_net();
38  Net* new_n;
39  if (new_n = new_nl->get_net_by_id(old_n->get_id()); new_n == nullptr)
40  {
41  new_n = new_nl->create_net(old_n->get_id(), old_n->get_name());
42  }
43  new_n->add_source(new_g, out_ep->get_pin());
44 
45  if (add_to_set)
46  {
47  add_to_set->insert(new_n);
48  }
49  }
50  }
51  } // namespace
52 
54  {
55  std::set<Gate*> state_logic;
56  std::set<Net*> state_inputs, state_outputs, control_inputs, other_inputs;
57 
58  log_info("hawkeye", "start constructing round function candidate from state register candidate...");
59  auto start = std::chrono::system_clock::now();
60 
61  const auto& state_input_reg = candidate->get_input_reg();
62  const auto& state_output_reg = candidate->get_output_reg();
63 
64  // DFS from output reg backwards
65  for (const auto* out_ff : state_output_reg)
66  {
67  auto ff_data_predecessors = out_ff->get_predecessors([](const GatePin* p, const Endpoint* _) { return p->get_type() == PinType::data; });
68 
69  if (ff_data_predecessors.size() != 1)
70  {
71  // FF can only have one predecessor for data input
72  continue;
73  }
74  const auto* pred_ep = ff_data_predecessors.at(0);
75  auto* first_comb_gate = pred_ep->get_gate();
76  if (!first_comb_gate->get_type()->has_property(GateTypeProperty::combinational))
77  {
78  continue;
79  }
80  state_outputs.insert(pred_ep->get_net());
81 
82  std::unordered_set<Gate*> visited;
83  std::vector<Gate*> stack = {first_comb_gate};
84  std::vector<Gate*> previous;
85  while (!stack.empty())
86  {
87  auto* current_gate = stack.back();
88 
89  // pop stack if last gate on stack has been dealt with completely
90  if (!previous.empty() && previous.back() == current_gate)
91  {
92  stack.pop_back();
93  previous.pop_back();
94  continue;
95  }
96 
97  visited.insert(current_gate);
98 
99  // expand towards predecessors
100  bool added = false;
101  for (auto* next_predecessor : current_gate->get_predecessors())
102  {
103  auto* predecessor_gate = next_predecessor->get_gate();
104  if (predecessor_gate->get_type()->has_property(GateTypeProperty::ff))
105  {
106  // if predecessor is part of input state reg, fill set of next state logic
107  if (state_input_reg.find(predecessor_gate) != state_input_reg.end())
108  {
109  state_inputs.insert(next_predecessor->get_net());
110  state_logic.insert(current_gate);
111  state_logic.insert(previous.begin(), previous.end());
112  }
113  }
114  else if (predecessor_gate->get_type()->has_property(GateTypeProperty::combinational))
115  {
116  if (visited.find(predecessor_gate) == visited.end())
117  {
118  // add only combinational predecessors to stack
119  stack.push_back(predecessor_gate);
120  added = true;
121  }
122  else if (state_logic.find(predecessor_gate) != state_logic.end())
123  {
124  state_logic.insert(current_gate);
125  state_logic.insert(previous.begin(), previous.end());
126  }
127  }
128  }
129 
130  if (added)
131  {
132  // push current gate to previous if progress was made
133  previous.push_back(current_gate);
134  }
135  else
136  {
137  // otherwise pop last element from stack as it has been dealt with already
138  stack.pop_back();
139  }
140  }
141  }
142 
143  std::set<Net*> visited;
144  for (auto* gate : state_logic)
145  {
146  // determine control inputs and other inputs to the candidate
147  for (auto* in_net : gate->get_fan_in_nets())
148  {
149  if (visited.find(in_net) != visited.end())
150  {
151  continue;
152  }
153 
154  visited.insert(in_net);
155 
156  if (in_net->get_num_of_sources() != 1)
157  {
158  continue;
159  }
160 
161  if (state_inputs.find(in_net) != state_inputs.end())
162  {
163  continue;
164  }
165 
166  auto* src_gate = in_net->get_sources().at(0)->get_gate();
167  if (state_logic.find(src_gate) != state_logic.end())
168  {
169  continue;
170  }
171 
172  u32 num_state_destinations = in_net->get_num_of_destinations([&state_logic](const Endpoint* ep) { return state_logic.find(ep->get_gate()) != state_logic.end(); });
173  if (num_state_destinations > candidate->get_size() / 2)
174  {
175  control_inputs.insert(in_net);
176  }
177  else
178  {
179  other_inputs.insert(in_net);
180  }
181  }
182  }
183 
184  // copy partial netlist
185  auto round_cand = std::make_unique<RoundCandidate>();
186  round_cand->m_netlist = std::move(netlist_factory::create_netlist(candidate->get_netlist()->get_gate_library()));
187  auto* copied_nl = round_cand->m_netlist.get();
188 
189  round_cand->m_size = candidate->get_size();
190 
191  for (const auto* g : state_input_reg)
192  {
193  auto* new_g = copied_nl->create_gate(g->get_id(), g->get_type(), g->get_name());
194  round_cand->m_in_reg.insert(new_g);
195 
196  copy_out_eps_of_gate(copied_nl, g, new_g); // only fan-out EPs for state input register
197  }
198 
199  for (const auto* g : state_logic)
200  {
201  auto* new_g = copied_nl->create_gate(g->get_id(), g->get_type(), g->get_name());
202  new_g->set_data_map(g->get_data_map()); // take care of LUT INIT strings
203  round_cand->m_state_logic.insert(new_g);
204 
205  copy_in_eps_of_gate(copied_nl, g, new_g);
206  copy_out_eps_of_gate(copied_nl, g, new_g);
207  }
208 
209  if (state_input_reg != state_output_reg)
210  {
211  for (const auto* g : state_output_reg)
212  {
213  auto* new_g = copied_nl->create_gate(g->get_id(), g->get_type(), g->get_name());
214  round_cand->m_out_reg.insert(new_g);
215 
216  copy_in_eps_of_gate(copied_nl, g, new_g); // only fan-in EPs for state output register
217  }
218  }
219  else
220  {
221  // create separate FF instances for state output register so that input and output register are distinct
222  for (const auto* g : state_output_reg)
223  {
224  // only differences: do not enforce ID (already taken by in_reg FF) and append suffix to name
225  auto* new_g = copied_nl->create_gate(g->get_type(), g->get_name() + "_OUT");
226  round_cand->m_out_reg.insert(new_g);
227 
228  copy_in_eps_of_gate(copied_nl, g, new_g); // only fan-in EPs for state output register
229  }
230  }
231 
232  for (const auto* state_in_net : state_inputs)
233  {
234  round_cand->m_state_inputs.insert(copied_nl->get_net_by_id(state_in_net->get_id()));
235  }
236 
237  for (const auto* state_out_net : state_outputs)
238  {
239  round_cand->m_state_outputs.insert(copied_nl->get_net_by_id(state_out_net->get_id()));
240  }
241 
242  for (const auto* control_net : control_inputs)
243  {
244  round_cand->m_control_inputs.insert(copied_nl->get_net_by_id(control_net->get_id()));
245  }
246 
247  for (const auto* other_net : other_inputs)
248  {
249  round_cand->m_other_inputs.insert(copied_nl->get_net_by_id(other_net->get_id()));
250  }
251 
252  auto nl_graph_res = graph_algorithm::NetlistGraph::from_netlist(copied_nl);
253  if (nl_graph_res.is_error())
254  {
255  return ERR(nl_graph_res.get_error());
256  }
257  round_cand->m_graph = std::move(nl_graph_res.get());
258 
259  // DFS from input reg forwards
260  std::map<Gate*, u32> gate_to_longest_distance;
261  for (auto* in_ff : round_cand->m_in_reg)
262  {
263  std::vector<Gate*> stack = {in_ff};
264  std::vector<Gate*> previous;
265  while (!stack.empty())
266  {
267  auto* current_gate = stack.back();
268 
269  // pop stack if last gate on stack has been dealt with completely
270  if (!previous.empty() && previous.back() == current_gate)
271  {
272  stack.pop_back();
273  previous.pop_back();
274  continue;
275  }
276 
277  round_cand->m_input_ffs_of_gate[current_gate].insert(in_ff);
278 
279  // expand towards successors
280  bool added = false;
281  for (auto* next_successor : current_gate->get_successors())
282  {
283  auto* successor_gate = next_successor->get_gate();
284  if (successor_gate->get_type()->has_property(GateTypeProperty::ff))
285  {
286  // if successor is part of output state reg, fill set of gates reached by input FF
287  if (round_cand->m_out_reg.find(successor_gate) != round_cand->m_out_reg.end())
288  {
289  round_cand->m_input_ffs_of_gate[successor_gate].insert(in_ff);
290  }
291  }
292  else if (successor_gate->get_type()->has_property(GateTypeProperty::combinational))
293  {
294  // if successor is part of next state logic, add gate to stack
295  if (round_cand->m_state_logic.find(successor_gate) != round_cand->m_state_logic.end())
296  {
297  stack.push_back(successor_gate);
298  added = true;
299 
300  u32 current_distance = previous.size() + 1;
301  if (const auto dist_it = gate_to_longest_distance.find(successor_gate); dist_it != gate_to_longest_distance.end())
302  {
303  u32 stored_distance = dist_it->second;
304  if (stored_distance < current_distance)
305  {
306  gate_to_longest_distance[successor_gate] = current_distance;
307  }
308  }
309  else
310  {
311  gate_to_longest_distance[successor_gate] = current_distance;
312  }
313  }
314  }
315  }
316 
317  if (added)
318  {
319  // push current gate to previous if progress was made
320  previous.push_back(current_gate);
321  }
322  else
323  {
324  // otherwise pop last element from stack as it has been dealt with already
325  stack.pop_back();
326  }
327  }
328  }
329 
330  // invert gate_to_longest_distance map to fill m_longest_distance_to_gate
331  for (const auto& [gate, distance] : gate_to_longest_distance)
332  {
333  round_cand->m_longest_distance_to_gate[distance].insert(gate);
334  }
335 
336  auto duration_in_seconds = std::chrono::duration<double>(std::chrono::system_clock::now() - start).count();
337  log_info("hawkeye", "successfully constructed round function candidate from state register candidate in {:.2f} seconds", duration_in_seconds);
338 
339  return OK(std::move(round_cand));
340  }
341 
343  {
344  return m_netlist.get();
345  }
346 
348  {
349  return m_graph.get();
350  }
351 
353  {
354  return m_size;
355  }
356 
357  const std::set<Gate*>& RoundCandidate::get_input_reg() const
358  {
359  return m_in_reg;
360  }
361 
362  const std::set<Gate*>& RoundCandidate::get_output_reg() const
363  {
364  return m_out_reg;
365  }
366 
367  const std::set<Gate*>& RoundCandidate::get_state_logic() const
368  {
369  return m_state_logic;
370  }
371 
372  const std::set<Net*>& RoundCandidate::get_state_inputs() const
373  {
374  return m_state_inputs;
375  }
376 
377  const std::set<Net*>& RoundCandidate::get_control_inputs() const
378  {
379  return m_control_inputs;
380  }
381 
382  const std::set<Net*>& RoundCandidate::get_other_inputs() const
383  {
384  return m_other_inputs;
385  }
386 
387  const std::set<Net*>& RoundCandidate::get_state_outputs() const
388  {
389  return m_state_outputs;
390  }
391 
392  const std::map<Gate*, std::set<Gate*>>& RoundCandidate::get_input_ffs_of_gate() const
393  {
394  return m_input_ffs_of_gate;
395  }
396 
397  const std::map<u32, std::set<Gate*>>& RoundCandidate::get_longest_distance_to_gate() const
398  {
399  return m_longest_distance_to_gate;
400  }
401  } // namespace hawkeye
402 } // namespace hal
PinType get_type() const
Definition: base_pin.h:150
Gate * get_gate() const
Definition: endpoint.cpp:23
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:132
A directed graph corresponding to a netlist.
Definition: netlist_graph.h:60
static Result< std::unique_ptr< NetlistGraph > > from_netlist(Netlist *nl, bool create_dummy_vertices=false, const std::function< bool(const Net *)> &filter=nullptr)
Create a directed graph from a netlist.
A register candidate discovered by HAWKEYE.
Netlist * get_netlist() const
Get the netlist associated with the candidate.
u32 get_size() const
Get the size of the candidate, i.e., the width of its registers.
const std::set< Gate * > & get_input_reg() const
Get the candidate's input register.
const std::set< Gate * > & get_output_reg() const
Get the candidate's output register.
const std::set< Gate * > & get_state_logic() const
Get the candidate's combinational logic computing the next state.
const std::set< Net * > & get_other_inputs() const
Get the candidate's other inputs to the logic computing the next state.
const std::set< Net * > & get_control_inputs() const
Get the candidate's control inputs to the logic computing the next state.
u32 get_size() const
Get the size of the candidate, i.e., the width of its registers.
const std::map< Gate *, std::set< Gate * > > & get_input_ffs_of_gate() const
Get a map from each combinational gate of the round function to all the input flip-flops it depends o...
const std::set< Net * > & get_state_outputs() const
Get the candidate's state outputs from the logic computing the next state.
static Result< std::unique_ptr< RoundCandidate > > from_register_candidate(RegisterCandidate *candidate)
Compute a round candidate from a previously identified register candidate.
const std::map< u32, std::set< Gate * > > & get_longest_distance_to_gate() const
Get a map from an integer distance to all gates that are reachable within at most that distance when ...
const std::set< Gate * > & get_output_reg() const
Get the candidate's output register.
Netlist * get_netlist() const
Get the netlist of the round candidate. The netlist is a partial copy of the netlist of the register ...
graph_algorithm::NetlistGraph * get_graph() const
Get the netlist graph of the round candidate.
const std::set< Gate * > & get_input_reg() const
Get the candidate's input register.
const std::set< Net * > & get_state_inputs() const
Get the candidate's state inputs to the logic computing the next state.
uint32_t u32
Definition: defines.h:41
#define log_info(channel,...)
Definition: log.h:70
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
std::unique_ptr< Netlist > create_netlist(const GateLibrary *gate_library)
Create a new empty netlist using the specified gate library.
Definition: defines.h:45
This file contains various functions to create and load netlists.
This file contains the class that holds all information on a round candidate.