HAL  v4.5.0-124-g47ab54673
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  vertices.insert( (void *) clk );
228  ptrs_to_type[(void *) clk] = PtrType::NET;
229  continue;
230  }
231  else if( clk->get_num_of_sources() == 0 )
232  {
233  log_warning( "clock_tree_extractor",
234  "unrouted clock net with ID {} ignored",
235  std::to_string( clk->get_id() ) );
236  continue;
237  }
238 
239  for( const Endpoint *source_ep : clk->get_sources() )
240  {
241  const Gate *gate = source_ep->get_gate();
242  queue.push( { ff, gate, std::vector<const Gate *>{ ff } } );
243  }
244  }
245 
246  const std::unordered_set<const Gate *> toggle_ffs = get_toggle_ffs( netlist );
247 
248  while( !queue.empty() )
249  {
250  const std::tuple<const Gate *, const Gate *, std::vector<const Gate *>> tuple = queue.front();
251  queue.pop();
252 
253  Gate *source = (Gate *) std::get<1>( tuple );
254  Gate *reference = (Gate *) std::get<0>( tuple );
255  std::vector<const Gate *> path = std::get<2>( tuple );
256 
257  path.push_back( source );
258 
259  if( is_latch( source ) )
260  {
261  // Ignore latches
262  continue;
263  }
264  else if( is_buffer( source ) || is_inverter( source ) || is_delay( source ) || is_ff( source ) )
265  {
266  if( is_ff( source ) && toggle_ffs.find( source ) == toggle_ffs.end() )
267  {
268  // Include only toggle flip-flops for now
269  continue;
270  }
271 
272  for( const Gate *gate : path )
273  {
274  vertices.insert( (void *) gate );
275  ptrs_to_type[(void *) gate] = PtrType::GATE;
276  }
277 
278  for( u32 idx = 0; idx < path.size() - 1; idx++ )
279  {
280  edges.insert( { (void *) path[idx + 1], (void *) path[idx] } );
281  }
282 
283  path.clear();
284  path.push_back( source );
285 
286  if( is_ff( source ) )
287  {
288  continue;
289  }
290 
291  reference = (Gate *) source;
292  }
293 
294  visited.insert( std::make_pair( reference, source ) );
295 
296  for( const Endpoint *ep : source->get_fan_in_endpoints() )
297  {
298  if( is_connected_to_control_pin( ep ) )
299  {
300  // Don't traverse control signals of clock gates
301  continue;
302  }
303 
304  const Net *net = ep->get_net();
305  if( net->get_name() == "'0'" || net->get_name() == "'1'" )
306  {
307  // Don't traverse power/ground signals
308  continue;
309  }
310 
311  if( net->is_global_input_net() )
312  {
313  for( const Gate *gate : path )
314  {
315  vertices.insert( (void *) gate );
316  ptrs_to_type[(void *) gate] = PtrType::GATE;
317  }
318 
319  for( u32 idx = 0; idx < path.size() - 1; idx++ )
320  {
321  edges.insert( { (void *) path[idx + 1], (void *) path[idx] } );
322  }
323 
324  vertices.insert( (void *) net );
325 
326  ptrs_to_type[(void *) net] = PtrType::NET;
327 
328  edges.insert( { (void *) net, (void *) path.back() } );
329 
330  path.clear();
331  path.push_back( source );
332 
333  continue;
334  }
335 
336  if( net->get_num_of_sources() == 0 )
337  {
338  log_warning( "clock_tree_extractor",
339  "unrouted clock net with ID {} ignored",
340  std::to_string( net->get_id() ) );
341  continue;
342  }
343  else if( net->get_num_of_sources() > 1 )
344  {
345  log_warning( "clock_tree_extractor",
346  "multi-driven clock net with ID {} ignored",
347  std::to_string( net->get_id() ) );
348  continue;
349  }
350 
351  const Gate *new_source = net->get_sources().front()->get_gate();
352  if( visited.find( { reference, new_source } ) == visited.end() )
353  {
354  queue.push( { reference, new_source, path } );
355  }
356  }
357  }
358 
359  std::unique_ptr<ClockTree> clock_tree = std::unique_ptr<ClockTree>( new ClockTree( netlist ) );
360 
361  igraph_integer_t idx = 0;
362  for( const void *vertex : vertices )
363  {
364  const igraph_integer_t vertex_id = idx++;
365 
366  clock_tree->m_vertices_to_ptrs[vertex_id] = vertex;
367  clock_tree->m_ptrs_to_vertices[vertex] = vertex_id;
368  }
369 
370  clock_tree->m_ptrs_to_types = ptrs_to_type;
371 
372  igraph_error_t ierror;
373  igraph_vector_int_t iedges;
374  if( ( ierror = igraph_vector_int_init( &iedges, 2 * edges.size() ) ) != IGRAPH_SUCCESS )
375  {
376  return ERR( igraph_strerror( ierror ) );
377  }
378 
379  idx = 0;
380  for( const auto &[src, dst] : edges )
381  {
382  VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( src );
383  VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( dst );
384  }
385 
386  if( ( ierror = igraph_create( clock_tree->m_igraph_ptr, &iedges, vertices.size(), IGRAPH_DIRECTED ) )
387  != IGRAPH_SUCCESS )
388  {
389  igraph_vector_int_destroy( &iedges );
390  return ERR( igraph_strerror( ierror ) );
391  }
392 
393  igraph_vector_int_destroy( &iedges );
394 
395  igraph_vector_int_t indegrees;
396  if( ( ierror = igraph_vector_int_init( &indegrees, 0 ) ) != IGRAPH_SUCCESS )
397  {
398  return ERR( igraph_strerror( ierror ) );
399  }
400 
401  if( ( ierror = igraph_degree(
402  clock_tree->m_igraph_ptr, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
403  != IGRAPH_SUCCESS )
404  {
405  igraph_vector_int_destroy( &indegrees );
406  return ERR( igraph_strerror( ierror ) );
407  }
408 
409  for( idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
410  {
411  if( VECTOR( indegrees )[idx] != 0 )
412  {
413  continue;
414  }
415  clock_tree->m_roots.insert( idx );
416  }
417 
418  igraph_vector_int_destroy( &indegrees );
419 
420  return OK( std::move( clock_tree ) );
421  }
422 
423  Result<std::monostate> ClockTree::export_dot( const std::string &pathname ) const
424  {
425  std::ofstream dot_fd( pathname );
426 
427  if( !dot_fd )
428  {
429  return ERR( "couldn't export clock tree to '" + pathname + "'" );
430  }
431 
432  dot_fd << "digraph { comment=\"created by HAL plugin clock_tree_extractor\"\n";
433 
434  for( const auto &[ptr, vertex] : m_ptrs_to_vertices )
435  {
436  if( m_ptrs_to_types.at( ptr ) == PtrType::NET )
437  {
438  dot_fd << " " << ( (Net *) ptr )->get_name() << " [shape=circle];\n";
439  continue;
440  }
441 
442  const Gate *gate = (const Gate *) ptr;
443 
444  std::string coords = "";
445 
446  // Workaround for negative coordinates
447 
448  // const i32 x = gate->get_location_x();
449  // const i32 y = gate->get_location_y();
450 
451  try
452  {
453  const i32 x = std::stoi( std::get<1>( gate->get_data( "generic", "X" ) ) );
454  const i32 y = std::stoi( std::get<1>( gate->get_data( "generic", "Y" ) ) );
455  coords = " x=" + std::to_string( x ) + " y=" + std::to_string( y );
456  } catch( const std::invalid_argument &err )
457  {
458  log_error( "clock_tree_extractor", "invalid coordinate format: {}", err.what() );
459  }
460 
461  std::string shape = "shape=hexagon"; // default (clock gates)
462 
463  if( is_buffer( gate ) )
464  {
465  shape = "shape=rectangle";
466  }
467  else if( is_inverter( gate ) )
468  {
469  shape = "shape=triangle orientation=180";
470  }
471  else if( is_ff( gate ) )
472  {
473  shape = ""; // no shape
474  }
475  else if( is_delay( gate ) )
476  {
477  shape = "shape=square";
478  }
479 
480  dot_fd << " " << gate->get_id() << " [instance=\"" << gate->get_name() << "\" type=\""
481  << gate->get_type()->get_name() << "\"" << coords;
482 
483  if( !shape.empty() )
484  {
485  dot_fd << " " << shape;
486  }
487 
488  dot_fd << "];\n";
489  }
490 
491  std::queue<std::pair<igraph_integer_t, std::string>> queue;
492  for( const igraph_integer_t &root : m_roots )
493  {
494  queue.push( { root, "blue" } );
495  }
496 
497  igraph_error_t ierror;
498  std::unordered_set<igraph_integer_t> visited;
499  while( !queue.empty() )
500  {
501  const std::pair<igraph_integer_t, std::string> pair = queue.front();
502  queue.pop();
503 
504  const igraph_integer_t vertex = pair.first;
505  std::string edge_color = pair.second;
506 
507  if( visited.find( vertex ) != visited.end() )
508  {
509  continue;
510  }
511 
512  visited.insert( vertex );
513 
514  const void *sptr = m_vertices_to_ptrs.at( vertex );
515  const PtrType stype = m_ptrs_to_types.at( sptr );
516 
517  if( stype == PtrType::GATE && is_inverter( (Gate *) sptr ) )
518  {
519  edge_color = edge_color == "red" ? "blue" : "red";
520  }
521 
522  igraph_vector_int_t neighbors;
523  if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
524  {
525  dot_fd.close();
526  return ERR( igraph_strerror( ierror ) );
527  }
528 
529  if( ( ierror = igraph_neighbors(
530  m_igraph_ptr, &neighbors, vertex, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
531  != IGRAPH_SUCCESS )
532  {
533  dot_fd.close();
534  igraph_vector_int_destroy( &neighbors );
535  return ERR( igraph_strerror( ierror ) );
536  }
537 
538  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
539  {
540  const std::string src_id = stype == PtrType::GATE ? std::to_string( ( (Gate *) sptr )->get_id() )
541  : ( (Net *) sptr )->get_name();
542 
543  const void *dptr = m_vertices_to_ptrs.at( VECTOR( neighbors )[idx] );
544  const PtrType dtype = m_ptrs_to_types.at( dptr );
545  const std::string dst_id = dtype == PtrType::GATE ? std::to_string( ( (Gate *) dptr )->get_id() )
546  : ( (Net *) dptr )->get_name();
547 
548  dot_fd << " " << src_id << " -> " << dst_id << " [color=" << edge_color << "];\n";
549  queue.push( { VECTOR( neighbors )[idx], edge_color } );
550  }
551 
552  igraph_vector_int_destroy( &neighbors );
553  }
554 
555  dot_fd << "}\n";
556  dot_fd.close();
557 
558  return OK( {} );
559  }
560 
561  Result<std::unique_ptr<ClockTree>> ClockTree::get_subtree( const void *ptr, const bool parent ) const
562  {
563  auto it = m_ptrs_to_vertices.find( ptr );
564  if( it == m_ptrs_to_vertices.end() )
565  {
566  return ERR( "object is not part of clock tree" );
567  }
568 
569  igraph_error_t ierror;
570  igraph_integer_t root = it->second;
571  if( parent )
572  {
573  igraph_vector_int_t parents;
574  if( ( ierror = igraph_vector_int_init( &parents, 0 ) ) != IGRAPH_SUCCESS )
575  {
576  return ERR( igraph_strerror( ierror ) );
577  }
578 
579  if( ( ierror = igraph_neighbors(
580  m_igraph_ptr, &parents, root, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
581  != IGRAPH_SUCCESS )
582  {
583  igraph_vector_int_destroy( &parents );
584  return ERR( igraph_strerror( ierror ) );
585  }
586 
587  // Only accept, if there is only one parent vertex for now.
588  if( igraph_vector_int_size( &parents ) == 1 )
589  {
590  root = VECTOR( parents )[0];
591  }
592 
593  igraph_vector_int_destroy( &parents );
594  }
595 
596  igraph_vector_int_t vertices;
597  if( ( ierror = igraph_vector_int_init( &vertices, 0 ) ) != IGRAPH_SUCCESS )
598  {
599  return ERR( igraph_strerror( ierror ) );
600  }
601 
602  if( ( ierror = igraph_dfs( m_igraph_ptr,
603  root,
604  IGRAPH_OUT,
605  false,
606  nullptr,
607  nullptr,
608  nullptr,
609  nullptr,
610  in_callback,
611  nullptr,
612  &vertices ) )
613  != IGRAPH_SUCCESS )
614  {
615  igraph_vector_int_destroy( &vertices );
616  return ERR( igraph_strerror( ierror ) );
617  }
618 
619  igraph_vs_t vs;
620  if( ( ierror = igraph_vs_vector( &vs, &vertices ) ) != IGRAPH_SUCCESS )
621  {
622  igraph_vector_int_destroy( &vertices );
623  return ERR( igraph_strerror( ierror ) );
624  }
625 
626  igraph_vector_int_t map;
627  if( ( ierror = igraph_vector_int_init( &map, igraph_vcount( m_igraph_ptr ) ) ) != IGRAPH_SUCCESS )
628  {
629  return ERR( igraph_strerror( ierror ) );
630  }
631 
632  igraph_t igraph;
633  if( ( ierror =
634  igraph_induced_subgraph_map( m_igraph_ptr, &igraph, vs, IGRAPH_SUBGRAPH_AUTO, &map, nullptr ) )
635  != IGRAPH_SUCCESS )
636  {
637  igraph_vs_destroy( &vs );
638  igraph_vector_int_destroy( &map );
639  igraph_vector_int_destroy( &vertices );
640  return ERR( igraph_strerror( ierror ) );
641  }
642 
643  igraph_vs_destroy( &vs );
644  igraph_vector_int_destroy( &vertices );
645 
646  std::unordered_set<igraph_integer_t> roots;
647  std::unordered_map<const void *, PtrType> ptrs_to_types;
648  std::unordered_map<igraph_integer_t, const void *> vertices_to_ptrs;
649 
650  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &map ); idx++ )
651  {
652  const igraph_integer_t vertex = VECTOR( map )[idx];
653  if( vertex == 0 )
654  {
655  continue;
656  }
657 
658  const void *ptr = m_vertices_to_ptrs.at( idx );
659 
660  vertices_to_ptrs[vertex - 1] = ptr;
661  ptrs_to_types[ptr] = m_ptrs_to_types.at( ptr );
662  }
663 
664  igraph_vector_int_destroy( &map );
665 
666  igraph_vector_int_t indegrees;
667  if( ( ierror = igraph_vector_int_init( &indegrees, igraph_vcount( &igraph ) ) ) != IGRAPH_SUCCESS )
668  {
669  return ERR( igraph_strerror( ierror ) );
670  }
671 
672  if( ( ierror = igraph_degree( &igraph, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
673  != IGRAPH_SUCCESS )
674  {
675  igraph_vector_int_destroy( &indegrees );
676  return ERR( igraph_strerror( ierror ) );
677  }
678 
679  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
680  {
681  if( VECTOR( indegrees )[idx] != 0 )
682  {
683  continue;
684  }
685  roots.insert( idx );
686  }
687 
688  igraph_vector_int_destroy( &indegrees );
689 
690  return OK( std::make_unique<ClockTree>( m_netlist,
691  std::move( igraph ),
692  std::move( roots ),
693  std::move( vertices_to_ptrs ),
694  std::move( ptrs_to_types ) ) );
695  }
696 
698  {
699  auto it = m_ptrs_to_vertices.find( ptr );
700  if( it == m_ptrs_to_vertices.end() )
701  {
702  return ERR( "object is not part of clock tree" );
703  }
704 
705  return OK( it->second );
706  }
707 
709  {
710  auto it = m_vertices_to_ptrs.find( vertex );
711  if( it == m_vertices_to_ptrs.end() )
712  {
713  return ERR( "object is not part of clock tree" );
714  }
715 
716  return OK( std::make_pair( it->second, m_ptrs_to_types.at( it->second ) ) );
717  }
718 
720  ClockTree::get_vertices_from_ptrs( const std::vector<const void *> &ptrs ) const
721  {
722  std::vector<igraph_integer_t> result;
723 
724  for( const void *ptr : ptrs )
725  {
726  auto res = get_vertex_from_ptr( ptr );
727  if( res.is_error() )
728  {
729  return ERR( res.get_error().get() );
730  }
731 
732  result.push_back( res.get() );
733  }
734 
735  return OK( result );
736  }
737 
739  ClockTree::get_ptrs_from_vertices( const std::vector<igraph_integer_t> &vertices ) const
740  {
741  std::vector<std::pair<const void *, PtrType>> result;
742 
743  for( const igraph_integer_t vertex : vertices )
744  {
745  auto res = get_ptr_from_vertex( vertex );
746  if( res.is_error() )
747  {
748  return ERR( res.get_error().get() );
749  }
750 
751  result.push_back( res.get() );
752  }
753 
754  return OK( result );
755  }
756 
757  const std::vector<const Gate *> ClockTree::get_gates() const
758  {
759  std::vector<const Gate *> result;
760 
761  for( const auto &[ptr, type] : m_ptrs_to_types )
762  {
763  if( type == PtrType::GATE )
764  {
765  result.push_back( (const Gate *) ptr );
766  }
767  }
768 
769  return result;
770  }
771 
772  const std::vector<const Net *> ClockTree::get_nets() const
773  {
774  std::vector<const Net *> result;
775 
776  for( const auto &[ptr, type] : m_ptrs_to_types )
777  {
778  if( type == PtrType::NET )
779  {
780  result.push_back( (const Net *) ptr );
781  }
782  }
783 
784  return result;
785  }
786 
787  const std::unordered_map<const void *, PtrType> ClockTree::get_all() const
788  {
789  return m_ptrs_to_types;
790  }
791 
793  {
794  return m_netlist;
795  }
796 
797  const igraph_t *ClockTree::get_igraph() const
798  {
799  return m_igraph_ptr;
800  }
801 
803  ClockTree::get_neighbors( const void *ptr, igraph_neimode_t direction ) const
804  {
805  auto it = m_ptrs_to_vertices.find( ptr );
806  if( it == m_ptrs_to_vertices.end() )
807  {
808  return ERR( "object is not part of clock tree" );
809  }
810 
811  igraph_error_t ierror;
812  igraph_vector_int_t neighbors;
813 
814  if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
815  {
816  return ERR( igraph_strerror( ierror ) );
817  }
818 
819  if( ( ierror = igraph_neighbors(
820  m_igraph_ptr, &neighbors, it->second, direction, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
821  != IGRAPH_SUCCESS )
822  {
823  igraph_vector_int_destroy( &neighbors );
824  return ERR( igraph_strerror( ierror ) );
825  }
826 
827  std::vector<std::pair<const void *, PtrType>> result;
828  for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
829  {
830  const void *n_ptr = m_vertices_to_ptrs.at( VECTOR( neighbors )[idx] );
831  result.push_back( std::make_pair( n_ptr, m_ptrs_to_types.at( n_ptr ) ) );
832  }
833 
834  igraph_vector_int_destroy( &neighbors );
835 
836  return OK( result );
837  }
838  } // namespace cte
839 } // 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:803
Result< igraph_integer_t > get_vertex_from_ptr(const void *ptr) const
Definition: clock_tree.cpp:697
const Netlist * get_netlist() const
Definition: clock_tree.cpp:792
const igraph_t * get_igraph() const
Definition: clock_tree.cpp:797
Result< std::vector< igraph_integer_t > > get_vertices_from_ptrs(const std::vector< const void * > &ptrs) const
Definition: clock_tree.cpp:720
const std::vector< const Gate * > get_gates() const
Definition: clock_tree.cpp:757
Result< std::pair< const void *, PtrType > > get_ptr_from_vertex(const igraph_integer_t vertex) const
Definition: clock_tree.cpp:708
const std::vector< const Net * > get_nets() const
Definition: clock_tree.cpp:772
Result< std::monostate > export_dot(const std::string &pathname) const
Definition: clock_tree.cpp:423
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:561
Result< std::vector< std::pair< const void *, PtrType > > > get_ptrs_from_vertices(const std::vector< igraph_integer_t > &vertices) const
Definition: clock_tree.cpp:739
const std::unordered_map< const void *, PtrType > get_all() const
Definition: clock_tree.cpp:787
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