44 #include <igraph/igraph.h>
46 #include <unordered_map>
47 #include <unordered_set>
55 inline bool is_ff(
const Gate *gate )
60 inline bool is_latch(
const Gate *gate )
65 inline bool is_buffer(
const Gate *gate )
70 inline bool is_inverter(
const Gate *gate )
75 inline bool is_delay(
const Gate *gate )
80 inline bool is_control_pin(
const PinType &pin_type )
86 inline bool is_connected_to_control_pin(
const Endpoint *endpoint )
88 return is_control_pin( endpoint->get_pin()->get_type() );
91 const std::unordered_set<const Gate *> get_toggle_ffs(
const Netlist *netlist )
93 const std::vector<Gate *> ffs = netlist->get_gates( is_ff );
95 std::unordered_set<const Gate *> result;
96 for(
const Gate *ff : ffs )
98 const std::vector<Endpoint *> successor_endpoints =
ff->get_successors();
99 const std::size_t successor_endpoints_size = successor_endpoints.size();
101 if( successor_endpoints_size == 0 )
106 std::vector<const Gate *> successors;
107 successors.reserve( successor_endpoints_size );
109 std::transform( successor_endpoints.begin(),
110 successor_endpoints.end(),
111 std::back_inserter( successors ),
112 [](
const Endpoint *ep ) { return ep->get_gate(); } );
114 if( std::find( successors.begin(), successors.end(), ff ) != successors.end() )
124 in_callback(
const igraph_t *graph, igraph_integer_t vid, igraph_integer_t dist,
void *extra )
126 return igraph_vector_int_push_back( (igraph_vector_int_t *) extra, vid );
130 ClockTree::ClockTree(
const Netlist *netlist )
131 : m_netlist( netlist )
132 , m_igraph_ptr( &m_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 ) )
147 m_igraph_ptr = &m_igraph;
149 for(
const auto &[vertex, ptr] : m_vertices_to_ptrs )
151 m_ptrs_to_vertices[ptr] = vertex;
157 igraph_destroy( &m_igraph );
162 if( netlist ==
nullptr )
164 return ERR(
"no netlist provided" );
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;
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;
177 vertices.insert( (
void *)
ff );
180 const std::vector<hal::GatePin *> clock_pins =
ff->get_type()->get_pins( [](
const auto &p ) {
184 if( clock_pins.size() != 1 )
187 "invalid number of input clock pins at gate '" +
ff->get_name() +
"' with ID "
188 + std::to_string(
ff->get_id() ) );
192 const Net *clk =
ff->get_fan_in_net( clock_pins.front() );
196 "no net connected to clock pin at gate '" +
ff->get_name() +
"' with ID "
197 + std::to_string(
ff->get_id() ) );
206 const Gate *gate = source_ep->get_gate();
207 if( !( is_buffer( gate ) || is_inverter( gate ) ) )
220 "invalid number of sources for clock net with ID "
221 + std::to_string( clk->
get_id() ) );
228 vertices.insert( (
void *) clk );
230 edges.insert( { (
void *) clk, (
void *)
ff } );
236 "unrouted clock net with ID {} ignored",
237 std::to_string( clk->
get_id() ) );
243 const Gate *gate = source_ep->get_gate();
244 queue.push( {
ff, gate, std::vector<const Gate *>{
ff } } );
248 const std::unordered_set<const Gate *> toggle_ffs = get_toggle_ffs( netlist );
250 while( !queue.empty() )
252 const std::tuple<const Gate *, const Gate *, std::vector<const Gate *>> tuple = queue.front();
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 );
259 path.push_back( source );
261 if( is_latch( source ) )
266 else if( is_buffer( source ) || is_inverter( source ) || is_delay( source ) || is_ff( source ) )
268 if( is_ff( source ) && toggle_ffs.find( source ) == toggle_ffs.end() )
274 for(
const Gate *gate : path )
276 vertices.insert( (
void *) gate );
280 for(
u32 idx = 0; idx < path.size() - 1; idx++ )
282 edges.insert( { (
void *) path[idx + 1], (
void *) path[idx] } );
286 path.push_back( source );
288 if( is_ff( source ) )
293 reference = (
Gate *) source;
296 visited.insert( std::make_pair( reference, source ) );
300 if( is_connected_to_control_pin( ep ) )
306 const Net *
net = ep->get_net();
307 if(
net->get_name() ==
"'0'" ||
net->get_name() ==
"'1'" )
313 if(
net->is_global_input_net() )
315 for(
const Gate *gate : path )
317 vertices.insert( (
void *) gate );
321 for(
u32 idx = 0; idx < path.size() - 1; idx++ )
323 edges.insert( { (
void *) path[idx + 1], (
void *) path[idx] } );
326 vertices.insert( (
void *)
net );
330 edges.insert( { (
void *)
net, (
void *) path.back() } );
333 path.push_back( source );
338 if(
net->get_num_of_sources() == 0 )
341 "unrouted clock net with ID {} ignored",
342 std::to_string(
net->get_id() ) );
345 else if(
net->get_num_of_sources() > 1 )
348 "multi-driven clock net with ID {} ignored",
349 std::to_string(
net->get_id() ) );
353 const Gate *new_source =
net->get_sources().front()->get_gate();
354 if( visited.find( { reference, new_source } ) == visited.end() )
356 queue.push( { reference, new_source, path } );
361 std::unique_ptr<ClockTree> clock_tree = std::unique_ptr<ClockTree>(
new ClockTree( netlist ) );
363 igraph_integer_t idx = 0;
364 for(
const void *vertex : vertices )
366 const igraph_integer_t vertex_id = idx++;
368 clock_tree->m_vertices_to_ptrs[vertex_id] = vertex;
369 clock_tree->m_ptrs_to_vertices[vertex] = vertex_id;
372 clock_tree->m_ptrs_to_types = ptrs_to_type;
374 igraph_error_t ierror;
375 igraph_vector_int_t iedges;
376 if( ( ierror = igraph_vector_int_init( &iedges, 2 * edges.size() ) ) != IGRAPH_SUCCESS )
378 return ERR( igraph_strerror( ierror ) );
382 for(
const auto &[src, dst] : edges )
384 VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( src );
385 VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( dst );
388 if( ( ierror = igraph_create( clock_tree->m_igraph_ptr, &iedges, vertices.size(), IGRAPH_DIRECTED ) )
391 igraph_vector_int_destroy( &iedges );
392 return ERR( igraph_strerror( ierror ) );
395 igraph_vector_int_destroy( &iedges );
397 igraph_vector_int_t indegrees;
398 if( ( ierror = igraph_vector_int_init( &indegrees, 0 ) ) != IGRAPH_SUCCESS )
400 return ERR( igraph_strerror( ierror ) );
403 if( ( ierror = igraph_degree(
404 clock_tree->m_igraph_ptr, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
407 igraph_vector_int_destroy( &indegrees );
408 return ERR( igraph_strerror( ierror ) );
411 for( idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
413 if( VECTOR( indegrees )[idx] != 0 )
417 clock_tree->m_roots.insert( idx );
420 igraph_vector_int_destroy( &indegrees );
422 return OK( std::move( clock_tree ) );
427 std::ofstream dot_fd( pathname );
431 return ERR(
"couldn't export clock tree to '" + pathname +
"'" );
434 dot_fd <<
"digraph { comment=\"created by HAL plugin clock_tree_extractor\"\n";
436 for(
const auto &[ptr, vertex] : m_ptrs_to_vertices )
440 dot_fd <<
" " << ( (
Net *) ptr )->get_name() <<
" [shape=circle];\n";
444 const Gate *gate = (
const Gate *) ptr;
446 std::string coords =
"";
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 )
460 log_error(
"clock_tree_extractor",
"invalid coordinate format: {}", err.what() );
463 std::string shape =
"shape=hexagon";
465 if( is_buffer( gate ) )
467 shape =
"shape=rectangle";
469 else if( is_inverter( gate ) )
471 shape =
"shape=triangle orientation=180";
473 else if( is_ff( gate ) )
477 else if( is_delay( gate ) )
479 shape =
"shape=square";
482 dot_fd <<
" " << gate->
get_id() <<
" [instance=\"" << gate->
get_name() <<
"\" type=\""
487 dot_fd <<
" " << shape;
493 std::queue<std::pair<igraph_integer_t, std::string>> queue;
494 for(
const igraph_integer_t &root : m_roots )
496 queue.push( { root,
"blue" } );
499 igraph_error_t ierror;
500 std::unordered_set<igraph_integer_t> visited;
501 while( !queue.empty() )
503 const std::pair<igraph_integer_t, std::string> pair = queue.front();
506 const igraph_integer_t vertex = pair.first;
507 std::string edge_color = pair.second;
509 if( visited.find( vertex ) != visited.end() )
514 visited.insert( vertex );
516 const void *sptr = m_vertices_to_ptrs.at( vertex );
517 const PtrType stype = m_ptrs_to_types.at( sptr );
521 edge_color = edge_color ==
"red" ?
"blue" :
"red";
524 igraph_vector_int_t neighbors;
525 if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
528 return ERR( igraph_strerror( ierror ) );
531 if( ( ierror = igraph_neighbors(
532 m_igraph_ptr, &neighbors, vertex, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
536 igraph_vector_int_destroy( &neighbors );
537 return ERR( igraph_strerror( ierror ) );
540 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
542 const std::string src_id = stype ==
PtrType::GATE ? std::to_string( ( (
Gate *) sptr )->get_id() )
543 : ( (
Net *) sptr )->get_name();
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();
550 dot_fd <<
" " << src_id <<
" -> " << dst_id <<
" [color=" << edge_color <<
"];\n";
551 queue.push( { VECTOR( neighbors )[idx], edge_color } );
554 igraph_vector_int_destroy( &neighbors );
565 auto it = m_ptrs_to_vertices.find( ptr );
566 if( it == m_ptrs_to_vertices.end() )
568 return ERR(
"object is not part of clock tree" );
571 igraph_error_t ierror;
572 igraph_integer_t root = it->second;
575 igraph_vector_int_t parents;
576 if( ( ierror = igraph_vector_int_init( &parents, 0 ) ) != IGRAPH_SUCCESS )
578 return ERR( igraph_strerror( ierror ) );
581 if( ( ierror = igraph_neighbors(
582 m_igraph_ptr, &parents, root, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
585 igraph_vector_int_destroy( &parents );
586 return ERR( igraph_strerror( ierror ) );
590 if( igraph_vector_int_size( &parents ) == 1 )
592 root = VECTOR( parents )[0];
595 igraph_vector_int_destroy( &parents );
598 igraph_vector_int_t vertices;
599 if( ( ierror = igraph_vector_int_init( &vertices, 0 ) ) != IGRAPH_SUCCESS )
601 return ERR( igraph_strerror( ierror ) );
604 if( ( ierror = igraph_dfs( m_igraph_ptr,
617 igraph_vector_int_destroy( &vertices );
618 return ERR( igraph_strerror( ierror ) );
622 if( ( ierror = igraph_vs_vector( &vs, &vertices ) ) != IGRAPH_SUCCESS )
624 igraph_vector_int_destroy( &vertices );
625 return ERR( igraph_strerror( ierror ) );
628 igraph_vector_int_t map;
629 if( ( ierror = igraph_vector_int_init( &map, igraph_vcount( m_igraph_ptr ) ) ) != IGRAPH_SUCCESS )
631 return ERR( igraph_strerror( ierror ) );
636 igraph_induced_subgraph_map( m_igraph_ptr, &igraph, vs, IGRAPH_SUBGRAPH_AUTO, &map,
nullptr ) )
639 igraph_vs_destroy( &vs );
640 igraph_vector_int_destroy( &map );
641 igraph_vector_int_destroy( &vertices );
642 return ERR( igraph_strerror( ierror ) );
645 igraph_vs_destroy( &vs );
646 igraph_vector_int_destroy( &vertices );
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;
652 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &map ); idx++ )
654 const igraph_integer_t vertex = VECTOR( map )[idx];
660 const void *ptr = m_vertices_to_ptrs.at( idx );
662 vertices_to_ptrs[vertex - 1] = ptr;
663 ptrs_to_types[ptr] = m_ptrs_to_types.at( ptr );
666 igraph_vector_int_destroy( &map );
668 igraph_vector_int_t indegrees;
669 if( ( ierror = igraph_vector_int_init( &indegrees, igraph_vcount( &igraph ) ) ) != IGRAPH_SUCCESS )
671 return ERR( igraph_strerror( ierror ) );
674 if( ( ierror = igraph_degree( &igraph, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
677 igraph_vector_int_destroy( &indegrees );
678 return ERR( igraph_strerror( ierror ) );
681 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
683 if( VECTOR( indegrees )[idx] != 0 )
690 igraph_vector_int_destroy( &indegrees );
692 return OK( std::make_unique<ClockTree>( m_netlist,
695 std::move( vertices_to_ptrs ),
696 std::move( ptrs_to_types ) ) );
701 auto it = m_ptrs_to_vertices.find( ptr );
702 if( it == m_ptrs_to_vertices.end() )
704 return ERR(
"object is not part of clock tree" );
707 return OK( it->second );
712 auto it = m_vertices_to_ptrs.find( vertex );
713 if( it == m_vertices_to_ptrs.end() )
715 return ERR(
"object is not part of clock tree" );
718 return OK( std::make_pair( it->second, m_ptrs_to_types.at( it->second ) ) );
724 std::vector<igraph_integer_t> result;
726 for(
const void *ptr : ptrs )
731 return ERR( res.get_error().get() );
734 result.push_back( res.get() );
743 std::vector<std::pair<const void *, PtrType>> result;
745 for(
const igraph_integer_t vertex : vertices )
750 return ERR( res.get_error().get() );
753 result.push_back( res.get() );
761 std::vector<const Gate *> result;
763 for(
const auto &[ptr,
type] : m_ptrs_to_types )
767 result.push_back( (
const Gate *) ptr );
776 std::vector<const Net *> result;
778 for(
const auto &[ptr,
type] : m_ptrs_to_types )
782 result.push_back( (
const Net *) ptr );
791 return m_ptrs_to_types;
807 auto it = m_ptrs_to_vertices.find( ptr );
808 if( it == m_ptrs_to_vertices.end() )
810 return ERR(
"object is not part of clock tree" );
813 igraph_error_t ierror;
814 igraph_vector_int_t neighbors;
816 if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
818 return ERR( igraph_strerror( ierror ) );
821 if( ( ierror = igraph_neighbors(
822 m_igraph_ptr, &neighbors, it->second,
direction, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
825 igraph_vector_int_destroy( &neighbors );
826 return ERR( igraph_strerror( ierror ) );
829 std::vector<std::pair<const void *, PtrType>> result;
830 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
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 ) ) );
836 igraph_vector_int_destroy( &neighbors );
std::tuple< std::string, std::string > get_data(const std::string &category, const std::string &key) const
GateType * get_type() const
const std::string & get_name() const
const std::vector< Endpoint * > & get_fan_in_endpoints() const
const std::string & get_name() const
u32 get_num_of_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
bool is_global_input_net() const
std::vector< Endpoint * > get_sources(const std::function< bool(Endpoint *ep)> &filter=nullptr) const
const std::vector< Gate * > & get_gates() const
Result< std::vector< std::pair< const void *, PtrType > > > get_neighbors(const void *ptr, igraph_neimode_t direction) const
Result< igraph_integer_t > get_vertex_from_ptr(const void *ptr) const
const Netlist * get_netlist() const
const igraph_t * get_igraph() const
Result< std::vector< igraph_integer_t > > get_vertices_from_ptrs(const std::vector< const void * > &ptrs) const
const std::vector< const Gate * > get_gates() const
Result< std::pair< const void *, PtrType > > get_ptr_from_vertex(const igraph_integer_t vertex) const
const std::vector< const Net * > get_nets() const
Result< std::monostate > export_dot(const std::string &pathname) const
static Result< std::unique_ptr< ClockTree > > from_netlist(const Netlist *netlist)
Result< std::unique_ptr< ClockTree > > get_subtree(const void *ptr, const bool parent) const
Result< std::vector< std::pair< const void *, PtrType > > > get_ptrs_from_vertices(const std::vector< igraph_integer_t > &vertices) const
const std::unordered_map< const void *, PtrType > get_all() const
#define log_error(channel,...)
#define log_warning(channel,...)