HAL  v4.5.0-133-g64838ea8d
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
clock_tree.cpp
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved.
4 // Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved.
5 // Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved.
6 // Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved.
7 // Copyright (c) 2025-2026 Sascha Tommasone. All rights reserved.
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in all
17 // copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 // SOFTWARE.
26 
28 
31 #include "hal_core/netlist/gate.h"
36 #include "hal_core/netlist/net.h"
38 #include "hal_core/utilities/log.h"
40 
41 #include <algorithm>
42 #include <cstddef>
43 #include <fstream>
44 #include <igraph/igraph.h>
45 #include <queue>
46 #include <unordered_map>
47 #include <unordered_set>
48 
49 namespace hal
50 {
51  namespace cte
52  {
53  namespace
54  {
55  inline bool is_ff( const Gate *gate )
56  {
57  return gate->get_type()->has_property( GateTypeProperty::ff );
58  }
59 
60  inline bool is_latch( const Gate *gate )
61  {
62  return gate->get_type()->has_property( GateTypeProperty::latch );
63  }
64 
65  inline bool is_buffer( const Gate *gate )
66  {
67  return gate->get_type()->has_property( GateTypeProperty::c_buffer );
68  }
69 
70  inline bool is_inverter( const Gate *gate )
71  {
72  return gate->get_type()->has_property( GateTypeProperty::c_inverter );
73  }
74 
75  inline bool is_delay( const Gate *gate )
76  {
77  return gate->get_type()->has_property( GateTypeProperty::delay );
78  }
79 
80  inline bool is_control_pin( const PinType &pin_type )
81  {
82  return pin_type == PinType::clock || pin_type == PinType::enable || pin_type == PinType::select
83  || pin_type == PinType::set || pin_type == PinType::reset;
84  }
85 
86  inline bool is_connected_to_control_pin( const Endpoint *endpoint )
87  {
88  return is_control_pin( endpoint->get_pin()->get_type() );
89  }
90 
91  const std::unordered_set<const Gate *> get_toggle_ffs( const Netlist *netlist )
92  {
93  const std::vector<Gate *> ffs = netlist->get_gates( is_ff );
94 
95  std::unordered_set<const Gate *> result;
96  for( const Gate *ff : ffs )
97  {
98  const std::vector<Endpoint *> successor_endpoints = ff->get_successors();
99  const std::size_t successor_endpoints_size = successor_endpoints.size();
100 
101  if( successor_endpoints_size == 0 )
102  {
103  continue;
104  }
105 
106  std::vector<const Gate *> successors;
107  successors.reserve( successor_endpoints_size );
108 
109  std::transform( successor_endpoints.begin(),
110  successor_endpoints.end(),
111  std::back_inserter( successors ),
112  []( const Endpoint *ep ) { return ep->get_gate(); } );
113 
114  if( std::find( successors.begin(), successors.end(), ff ) != successors.end() )
115  {
116  result.insert( ff );
117  }
118  }
119 
120  return result;
121  }
122 
123  igraph_error_t
124  in_callback( const igraph_t *graph, igraph_integer_t vid, igraph_integer_t dist, void *extra )
125  {
126  return igraph_vector_int_push_back( (igraph_vector_int_t *) extra, vid );
127  }
128  } // namespace
129 
130  ClockTree::ClockTree( const Netlist *netlist )
131  : m_netlist( netlist )
132  , m_igraph_ptr( &m_igraph )
133  {
134  }
135 
136  ClockTree::ClockTree( const Netlist *netlist,
137  igraph_t &&igraph,
138  std::unordered_set<igraph_integer_t> &&roots,
139  std::unordered_map<igraph_integer_t, const void *> &&vertices_to_ptrs,
140  std::unordered_map<const void *, PtrType> &&ptrs_to_types )
141  : m_netlist( netlist )
142  , m_igraph( std::move( igraph ) )
143  , m_roots( std::move( roots ) )
144  , m_vertices_to_ptrs( std::move( vertices_to_ptrs ) )
145  , m_ptrs_to_types( std::move( ptrs_to_types ) )
146  {
147  m_igraph_ptr = &m_igraph;
148 
149  for( const auto &[vertex, ptr] : m_vertices_to_ptrs )
150  {
151  m_ptrs_to_vertices[ptr] = vertex;
152  }
153  }
154 
156  {
157  igraph_destroy( &m_igraph );
158  }
159 
161  {
162  if( netlist == nullptr )
163  {
164  return ERR( "no netlist provided" );
165  }
166 
167  std::unordered_set<void *> vertices;
168  std::unordered_set<std::pair<void *, void *>, VoidPtrHash> edges;
169  std::unordered_map<const void *, PtrType> ptrs_to_type;
170 
171  std::queue<std::tuple<const Gate *, const Gate *, std::vector<const Gate *>>> queue;
173  std::unordered_set<std::pair<const Gate *, const Gate *>, VoidPtrHash> visited;
174 
175  for( const Gate *ff : netlist->get_gates( is_ff ) )
176  {
177  vertices.insert( (void *) ff );
178  ptrs_to_type[(void *) ff] = PtrType::GATE;
179 
180  const std::vector<hal::GatePin *> clock_pins = ff->get_type()->get_pins( []( const auto &p ) {
181  return ( p->get_direction() == PinDirection::input ) && ( p->get_type() == PinType::clock );
182  } );
183 
184  if( clock_pins.size() != 1 )
185  {
186  log_error( "clock_tree_extractor",
187  "invalid number of input clock pins at gate '" + ff->get_name() + "' with ID "
188  + std::to_string( ff->get_id() ) );
189  continue;
190  }
191 
192  const Net *clk = ff->get_fan_in_net( clock_pins.front() );
193  if( clk == nullptr )
194  {
195  log_error( "clock_tree_extractor",
196  "no net connected to clock pin at gate '" + ff->get_name() + "' with ID "
197  + std::to_string( ff->get_id() ) );
198  continue;
199  }
200 
201  if( clk->get_num_of_sources() > 1 )
202  {
203  bool valid = true;
204  for( const Endpoint *source_ep : clk->get_sources() )
205  {
206  const Gate *gate = source_ep->get_gate();
207  if( !( is_buffer( gate ) || is_inverter( gate ) ) )
208  {
209  // In theory, it should be either all buffers or all inverters. But depending on
210  // extraction results, e.g., it could happen that a buffer is split into two inverters.
211  // So I just assume it is fine if all the sources are either a buffer or an inverter
212  // without enforcing strict buffer only or inverter only.
213  valid = false;
214  break;
215  }
216  }
217  if( !valid )
218  {
219  log_error( "clock_tree_extractor",
220  "invalid number of sources for clock net with ID "
221  + std::to_string( clk->get_id() ) );
222  continue;
223  }
224  }
225  else if( clk->is_global_input_net() )
226  {
227  // the flip-flop is clocked straight from the outside: the net is the root and the flip-flop its only child
228  vertices.insert( (void *) clk );
229  ptrs_to_type[(void *) clk] = PtrType::NET;
230  edges.insert( { (void *) clk, (void *) ff } );
231  continue;
232  }
233  else if( clk->get_num_of_sources() == 0 )
234  {
235  log_warning( "clock_tree_extractor",
236  "unrouted clock net with ID {} ignored",
237  std::to_string( clk->get_id() ) );
238  continue;
239  }
240 
241  for( const Endpoint *source_ep : clk->get_sources() )
242  {
243  const Gate *gate = source_ep->get_gate();
244  queue.push( { ff, gate, std::vector<const Gate *>{ ff } } );
245  }
246  }
247 
248  const std::unordered_set<const Gate *> toggle_ffs = get_toggle_ffs( netlist );
249 
250  while( !queue.empty() )
251  {
252  const std::tuple<const Gate *, const Gate *, std::vector<const Gate *>> tuple = queue.front();
253  queue.pop();
254 
255  Gate *source = (Gate *) std::get<1>( tuple );
256  Gate *reference = (Gate *) std::get<0>( tuple );
257  std::vector<const Gate *> path = std::get<2>( tuple );
258 
259  path.push_back( source );
260 
261  if( is_latch( source ) )
262  {
263  // Ignore latches
264  continue;
265  }
266  else if( is_buffer( source ) || is_inverter( source ) || is_delay( source ) || is_ff( source ) )
267  {
268  if( is_ff( source ) && toggle_ffs.find( source ) == toggle_ffs.end() )
269  {
270  // Include only toggle flip-flops for now
271  continue;
272  }
273 
274  for( const Gate *gate : path )
275  {
276  vertices.insert( (void *) gate );
277  ptrs_to_type[(void *) gate] = PtrType::GATE;
278  }
279 
280  for( u32 idx = 0; idx < path.size() - 1; idx++ )
281  {
282  edges.insert( { (void *) path[idx + 1], (void *) path[idx] } );
283  }
284 
285  path.clear();
286  path.push_back( source );
287 
288  if( is_ff( source ) )
289  {
290  continue;
291  }
292 
293  reference = (Gate *) source;
294  }
295 
296  visited.insert( std::make_pair( reference, source ) );
297 
298  for( const Endpoint *ep : source->get_fan_in_endpoints() )
299  {
300  if( is_connected_to_control_pin( ep ) )
301  {
302  // Don't traverse control signals of clock gates
303  continue;
304  }
305 
306  const Net *net = ep->get_net();
307  if( net->get_name() == "'0'" || net->get_name() == "'1'" )
308  {
309  // Don't traverse power/ground signals
310  continue;
311  }
312 
313  if( net->is_global_input_net() )
314  {
315  for( const Gate *gate : path )
316  {
317  vertices.insert( (void *) gate );
318  ptrs_to_type[(void *) gate] = PtrType::GATE;
319  }
320 
321  for( u32 idx = 0; idx < path.size() - 1; idx++ )
322  {
323  edges.insert( { (void *) path[idx + 1], (void *) path[idx] } );
324  }
325 
326  vertices.insert( (void *) net );
327 
328  ptrs_to_type[(void *) net] = PtrType::NET;
329 
330  edges.insert( { (void *) net, (void *) path.back() } );
331 
332  path.clear();
333  path.push_back( source );
334 
335  continue;
336  }
337 
338  if( net->get_num_of_sources() == 0 )
339  {
340  log_warning( "clock_tree_extractor",
341  "unrouted clock net with ID {} ignored",
342  std::to_string( net->get_id() ) );
343  continue;
344  }
345  else if( net->get_num_of_sources() > 1 )
346  {
347  log_warning( "clock_tree_extractor",
348  "multi-driven clock net with ID {} ignored",
349  std::to_string( net->get_id() ) );
350  continue;
351  }
352 
353  const Gate *new_source = net->get_sources().front()->get_gate();
354  if( visited.find( { reference, new_source } ) == visited.end() )
355  {
356  queue.push( { reference, new_source, path } );
357  }
358  }
359  }
360 
361  std::unique_ptr<ClockTree> clock_tree = std::unique_ptr<ClockTree>( new ClockTree( netlist ) );
362 
363  igraph_integer_t idx = 0;
364  for( const void *vertex : vertices )
365  {
366  const igraph_integer_t vertex_id = idx++;
367 
368  clock_tree->m_vertices_to_ptrs[vertex_id] = vertex;
369  clock_tree->m_ptrs_to_vertices[vertex] = vertex_id;
370  }
371 
372  clock_tree->m_ptrs_to_types = ptrs_to_type;
373 
374  igraph_error_t ierror;
375  igraph_vector_int_t iedges;
376  if( ( ierror = igraph_vector_int_init( &iedges, 2 * edges.size() ) ) != IGRAPH_SUCCESS )
377  {
378  return ERR( igraph_strerror( ierror ) );
379  }
380 
381  idx = 0;
382  for( const auto &[src, dst] : edges )
383  {
384  VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( src );
385  VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( dst );
386  }
387 
388  if( ( ierror = igraph_create( clock_tree->m_igraph_ptr, &iedges, vertices.size(), IGRAPH_DIRECTED ) )
389  != IGRAPH_SUCCESS )
390  {
391  igraph_vector_int_destroy( &iedges );
392  return ERR( igraph_strerror( ierror ) );
393  }
394 
395  igraph_vector_int_destroy( &iedges );
396 
397  igraph_vector_int_t indegrees;
398  if( ( ierror = igraph_vector_int_init( &indegrees, 0 ) ) != IGRAPH_SUCCESS )
399  {
400  return ERR( igraph_strerror( ierror ) );
401  }
402 
403  if( ( ierror = igraph_degree(
404  clock_tree->m_igraph_ptr, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
405  != IGRAPH_SUCCESS )
406  {
407  igraph_vector_int_destroy( &indegrees );
408  return ERR( igraph_strerror( ierror ) );
409  }
410 
411  for( idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
412  {
413  if( VECTOR( indegrees )[idx] != 0 )
414  {
415  continue;
416  }
417  clock_tree->m_roots.insert( idx );
418  }
419 
420  igraph_vector_int_destroy( &indegrees );
421 
422  return OK( std::move( clock_tree ) );
423  }
424 
425  Result<std::monostate> ClockTree::export_dot( const std::string &pathname ) const
426  {
427  std::ofstream dot_fd( pathname );
428 
429  if( !dot_fd )
430  {
431  return ERR( "couldn't export clock tree to '" + pathname + "'" );
432  }
433 
434  dot_fd << "digraph { comment=\"created by HAL plugin clock_tree_extractor\"\n";
435 
436  for( const auto &[ptr, vertex] : m_ptrs_to_vertices )
437  {
438  if( m_ptrs_to_types.at( ptr ) == PtrType::NET )
439  {
440  dot_fd << " " << ( (Net *) ptr )->get_name() << " [shape=circle];\n";
441  continue;
442  }
443 
444  const Gate *gate = (const Gate *) ptr;
445 
446  std::string coords = "";
447 
448  // Workaround for negative coordinates
449 
450  // const i32 x = gate->get_location_x();
451  // const i32 y = gate->get_location_y();
452 
453  try
454  {
455  const i32 x = std::stoi( std::get<1>( gate->get_data( "generic", "X" ) ) );
456  const i32 y = std::stoi( std::get<1>( gate->get_data( "generic", "Y" ) ) );
457  coords = " x=" + std::to_string( x ) + " y=" + std::to_string( y );
458  } catch( const std::invalid_argument &err )
459  {
460  log_error( "clock_tree_extractor", "invalid coordinate format: {}", err.what() );
461  }
462 
463  std::string shape = "shape=hexagon"; // default (clock gates)
464 
465  if( is_buffer( gate ) )
466  {
467  shape = "shape=rectangle";
468  }
469  else if( is_inverter( gate ) )
470  {
471  shape = "shape=triangle orientation=180";
472  }
473  else if( is_ff( gate ) )
474  {
475  shape = ""; // no shape
476  }
477  else if( is_delay( gate ) )
478  {
479  shape = "shape=square";
480  }
481 
482  dot_fd << " " << gate->get_id() << " [instance=\"" << gate->get_name() << "\" type=\""
483  << gate->get_type()->get_name() << "\"" << coords;
484 
485  if( !shape.empty() )
486  {
487  dot_fd << " " << shape;
488  }
489 
490  dot_fd << "];\n";
491  }
492 
493  std::queue<std::pair<igraph_integer_t, std::string>> queue;
494  for( const igraph_integer_t &root : m_roots )
495  {
496  queue.push( { root, "blue" } );
497  }
498 
499  igraph_error_t ierror;
500  std::unordered_set<igraph_integer_t> visited;
501  while( !queue.empty() )
502  {
503  const std::pair<igraph_integer_t, std::string> pair = queue.front();
504  queue.pop();
505 
506  const igraph_integer_t vertex = pair.first;
507  std::string edge_color = pair.second;
508 
509  if( visited.find( vertex ) != visited.end() )
510  {
511  continue;
512  }
513 
514  visited.insert( vertex );
515 
516  const void *sptr = m_vertices_to_ptrs.at( vertex );
517  const PtrType stype = m_ptrs_to_types.at( sptr );
518 
519  if( stype == PtrType::GATE && is_inverter( (Gate *) sptr ) )
520  {
521  edge_color = edge_color == "red" ? "blue" : "red";
522  }
523 
524  igraph_vector_int_t neighbors;
525  if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
526  {
527  dot_fd.close();
528  return ERR( igraph_strerror( ierror ) );
529  }
530 
531  if( ( ierror = igraph_neighbors(
532  m_igraph_ptr, &neighbors, vertex, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
533  != IGRAPH_SUCCESS )
534  {
535  dot_fd.close();
536  igraph_vector_int_destroy( &neighbors );
537  return ERR( igraph_strerror( ierror ) );
538  }
539 
540  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
541  {
542  const std::string src_id = stype == PtrType::GATE ? std::to_string( ( (Gate *) sptr )->get_id() )
543  : ( (Net *) sptr )->get_name();
544 
545  const void *dptr = m_vertices_to_ptrs.at( VECTOR( neighbors )[idx] );
546  const PtrType dtype = m_ptrs_to_types.at( dptr );
547  const std::string dst_id = dtype == PtrType::GATE ? std::to_string( ( (Gate *) dptr )->get_id() )
548  : ( (Net *) dptr )->get_name();
549 
550  dot_fd << " " << src_id << " -> " << dst_id << " [color=" << edge_color << "];\n";
551  queue.push( { VECTOR( neighbors )[idx], edge_color } );
552  }
553 
554  igraph_vector_int_destroy( &neighbors );
555  }
556 
557  dot_fd << "}\n";
558  dot_fd.close();
559 
560  return OK( {} );
561  }
562 
563  Result<std::unique_ptr<ClockTree>> ClockTree::get_subtree( const void *ptr, const bool parent ) const
564  {
565  auto it = m_ptrs_to_vertices.find( ptr );
566  if( it == m_ptrs_to_vertices.end() )
567  {
568  return ERR( "object is not part of clock tree" );
569  }
570 
571  igraph_error_t ierror;
572  igraph_integer_t root = it->second;
573  if( parent )
574  {
575  igraph_vector_int_t parents;
576  if( ( ierror = igraph_vector_int_init( &parents, 0 ) ) != IGRAPH_SUCCESS )
577  {
578  return ERR( igraph_strerror( ierror ) );
579  }
580 
581  if( ( ierror = igraph_neighbors(
582  m_igraph_ptr, &parents, root, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
583  != IGRAPH_SUCCESS )
584  {
585  igraph_vector_int_destroy( &parents );
586  return ERR( igraph_strerror( ierror ) );
587  }
588 
589  // Only accept, if there is only one parent vertex for now.
590  if( igraph_vector_int_size( &parents ) == 1 )
591  {
592  root = VECTOR( parents )[0];
593  }
594 
595  igraph_vector_int_destroy( &parents );
596  }
597 
598  igraph_vector_int_t vertices;
599  if( ( ierror = igraph_vector_int_init( &vertices, 0 ) ) != IGRAPH_SUCCESS )
600  {
601  return ERR( igraph_strerror( ierror ) );
602  }
603 
604  if( ( ierror = igraph_dfs( m_igraph_ptr,
605  root,
606  IGRAPH_OUT,
607  false,
608  nullptr,
609  nullptr,
610  nullptr,
611  nullptr,
612  in_callback,
613  nullptr,
614  &vertices ) )
615  != IGRAPH_SUCCESS )
616  {
617  igraph_vector_int_destroy( &vertices );
618  return ERR( igraph_strerror( ierror ) );
619  }
620 
621  igraph_vs_t vs;
622  if( ( ierror = igraph_vs_vector( &vs, &vertices ) ) != IGRAPH_SUCCESS )
623  {
624  igraph_vector_int_destroy( &vertices );
625  return ERR( igraph_strerror( ierror ) );
626  }
627 
628  igraph_vector_int_t map;
629  if( ( ierror = igraph_vector_int_init( &map, igraph_vcount( m_igraph_ptr ) ) ) != IGRAPH_SUCCESS )
630  {
631  return ERR( igraph_strerror( ierror ) );
632  }
633 
634  igraph_t igraph;
635  if( ( ierror =
636  igraph_induced_subgraph_map( m_igraph_ptr, &igraph, vs, IGRAPH_SUBGRAPH_AUTO, &map, nullptr ) )
637  != IGRAPH_SUCCESS )
638  {
639  igraph_vs_destroy( &vs );
640  igraph_vector_int_destroy( &map );
641  igraph_vector_int_destroy( &vertices );
642  return ERR( igraph_strerror( ierror ) );
643  }
644 
645  igraph_vs_destroy( &vs );
646  igraph_vector_int_destroy( &vertices );
647 
648  std::unordered_set<igraph_integer_t> roots;
649  std::unordered_map<const void *, PtrType> ptrs_to_types;
650  std::unordered_map<igraph_integer_t, const void *> vertices_to_ptrs;
651 
652  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &map ); idx++ )
653  {
654  const igraph_integer_t vertex = VECTOR( map )[idx];
655  if( vertex == 0 )
656  {
657  continue;
658  }
659 
660  const void *ptr = m_vertices_to_ptrs.at( idx );
661 
662  vertices_to_ptrs[vertex - 1] = ptr;
663  ptrs_to_types[ptr] = m_ptrs_to_types.at( ptr );
664  }
665 
666  igraph_vector_int_destroy( &map );
667 
668  igraph_vector_int_t indegrees;
669  if( ( ierror = igraph_vector_int_init( &indegrees, igraph_vcount( &igraph ) ) ) != IGRAPH_SUCCESS )
670  {
671  return ERR( igraph_strerror( ierror ) );
672  }
673 
674  if( ( ierror = igraph_degree( &igraph, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
675  != IGRAPH_SUCCESS )
676  {
677  igraph_vector_int_destroy( &indegrees );
678  return ERR( igraph_strerror( ierror ) );
679  }
680 
681  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
682  {
683  if( VECTOR( indegrees )[idx] != 0 )
684  {
685  continue;
686  }
687  roots.insert( idx );
688  }
689 
690  igraph_vector_int_destroy( &indegrees );
691 
692  return OK( std::make_unique<ClockTree>( m_netlist,
693  std::move( igraph ),
694  std::move( roots ),
695  std::move( vertices_to_ptrs ),
696  std::move( ptrs_to_types ) ) );
697  }
698 
700  {
701  auto it = m_ptrs_to_vertices.find( ptr );
702  if( it == m_ptrs_to_vertices.end() )
703  {
704  return ERR( "object is not part of clock tree" );
705  }
706 
707  return OK( it->second );
708  }
709 
711  {
712  auto it = m_vertices_to_ptrs.find( vertex );
713  if( it == m_vertices_to_ptrs.end() )
714  {
715  return ERR( "object is not part of clock tree" );
716  }
717 
718  return OK( std::make_pair( it->second, m_ptrs_to_types.at( it->second ) ) );
719  }
720 
722  ClockTree::get_vertices_from_ptrs( const std::vector<const void *> &ptrs ) const
723  {
724  std::vector<igraph_integer_t> result;
725 
726  for( const void *ptr : ptrs )
727  {
728  auto res = get_vertex_from_ptr( ptr );
729  if( res.is_error() )
730  {
731  return ERR( res.get_error().get() );
732  }
733 
734  result.push_back( res.get() );
735  }
736 
737  return OK( result );
738  }
739 
741  ClockTree::get_ptrs_from_vertices( const std::vector<igraph_integer_t> &vertices ) const
742  {
743  std::vector<std::pair<const void *, PtrType>> result;
744 
745  for( const igraph_integer_t vertex : vertices )
746  {
747  auto res = get_ptr_from_vertex( vertex );
748  if( res.is_error() )
749  {
750  return ERR( res.get_error().get() );
751  }
752 
753  result.push_back( res.get() );
754  }
755 
756  return OK( result );
757  }
758 
759  const std::vector<const Gate *> ClockTree::get_gates() const
760  {
761  std::vector<const Gate *> result;
762 
763  for( const auto &[ptr, type] : m_ptrs_to_types )
764  {
765  if( type == PtrType::GATE )
766  {
767  result.push_back( (const Gate *) ptr );
768  }
769  }
770 
771  return result;
772  }
773 
774  const std::vector<const Net *> ClockTree::get_nets() const
775  {
776  std::vector<const Net *> result;
777 
778  for( const auto &[ptr, type] : m_ptrs_to_types )
779  {
780  if( type == PtrType::NET )
781  {
782  result.push_back( (const Net *) ptr );
783  }
784  }
785 
786  return result;
787  }
788 
789  const std::unordered_map<const void *, PtrType> ClockTree::get_all() const
790  {
791  return m_ptrs_to_types;
792  }
793 
795  {
796  return m_netlist;
797  }
798 
799  const igraph_t *ClockTree::get_igraph() const
800  {
801  return m_igraph_ptr;
802  }
803 
805  ClockTree::get_neighbors( const void *ptr, igraph_neimode_t direction ) const
806  {
807  auto it = m_ptrs_to_vertices.find( ptr );
808  if( it == m_ptrs_to_vertices.end() )
809  {
810  return ERR( "object is not part of clock tree" );
811  }
812 
813  igraph_error_t ierror;
814  igraph_vector_int_t neighbors;
815 
816  if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
817  {
818  return ERR( igraph_strerror( ierror ) );
819  }
820 
821  if( ( ierror = igraph_neighbors(
822  m_igraph_ptr, &neighbors, it->second, direction, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
823  != IGRAPH_SUCCESS )
824  {
825  igraph_vector_int_destroy( &neighbors );
826  return ERR( igraph_strerror( ierror ) );
827  }
828 
829  std::vector<std::pair<const void *, PtrType>> result;
830  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
831  {
832  const void *n_ptr = m_vertices_to_ptrs.at( VECTOR( neighbors )[idx] );
833  result.push_back( std::make_pair( n_ptr, m_ptrs_to_types.at( n_ptr ) ) );
834  }
835 
836  igraph_vector_int_destroy( &neighbors );
837 
838  return OK( result );
839  }
840  } // namespace cte
841 } // namespace hal
std::tuple< std::string, std::string > get_data(const std::string &category, const std::string &key) const
Definition: gate.h:58
GateType * get_type() const
Definition: gate.cpp:125
const std::string & get_name() const
Definition: gate.cpp:105
const std::vector< Endpoint * > & get_fan_in_endpoints() const
Definition: gate.cpp:653
u32 get_id() const
Definition: gate.cpp:95
const std::string & get_name() const
Definition: gate_type.cpp:64
Definition: net.h:58
u32 get_num_of_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:258
u32 get_id() const
Definition: net.cpp:88
bool is_global_input_net() const
Definition: net.cpp:504
std::vector< Endpoint * > get_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
Definition: net.cpp:276
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
Result< std::vector< std::pair< const void *, PtrType > > > get_neighbors(const void *ptr, igraph_neimode_t direction) const
Definition: clock_tree.cpp:805
Result< igraph_integer_t > get_vertex_from_ptr(const void *ptr) const
Definition: clock_tree.cpp:699
const Netlist * get_netlist() const
Definition: clock_tree.cpp:794
const igraph_t * get_igraph() const
Definition: clock_tree.cpp:799
Result< std::vector< igraph_integer_t > > get_vertices_from_ptrs(const std::vector< const void * > &ptrs) const
Definition: clock_tree.cpp:722
const std::vector< const Gate * > get_gates() const
Definition: clock_tree.cpp:759
Result< std::pair< const void *, PtrType > > get_ptr_from_vertex(const igraph_integer_t vertex) const
Definition: clock_tree.cpp:710
const std::vector< const Net * > get_nets() const
Definition: clock_tree.cpp:774
Result< std::monostate > export_dot(const std::string &pathname) const
Definition: clock_tree.cpp:425
static Result< std::unique_ptr< ClockTree > > from_netlist(const Netlist *netlist)
Definition: clock_tree.cpp:160
Result< std::unique_ptr< ClockTree > > get_subtree(const void *ptr, const bool parent) const
Definition: clock_tree.cpp:563
Result< std::vector< std::pair< const void *, PtrType > > > get_ptrs_from_vertices(const std::vector< igraph_integer_t > &vertices) const
Definition: clock_tree.cpp:741
const std::unordered_map< const void *, PtrType > get_all() const
Definition: clock_tree.cpp:789
uint32_t u32
Definition: defines.h:41
int32_t i32
Definition: defines.h:36
#define log_error(channel,...)
Definition: log.h:78
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
Definition: defines.h:45
PinType
Definition: pin_type.h:36
PinType type
Net * net
PinDirection direction