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() ) );
227 vertices.insert( (
void *) clk );
234 "unrouted clock net with ID {} ignored",
235 std::to_string( clk->
get_id() ) );
241 const Gate *gate = source_ep->get_gate();
242 queue.push( {
ff, gate, std::vector<const Gate *>{
ff } } );
246 const std::unordered_set<const Gate *> toggle_ffs = get_toggle_ffs( netlist );
248 while( !queue.empty() )
250 const std::tuple<const Gate *, const Gate *, std::vector<const Gate *>> tuple = queue.front();
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 );
257 path.push_back( source );
259 if( is_latch( source ) )
264 else if( is_buffer( source ) || is_inverter( source ) || is_delay( source ) || is_ff( source ) )
266 if( is_ff( source ) && toggle_ffs.find( source ) == toggle_ffs.end() )
272 for(
const Gate *gate : path )
274 vertices.insert( (
void *) gate );
278 for(
u32 idx = 0; idx < path.size() - 1; idx++ )
280 edges.insert( { (
void *) path[idx + 1], (
void *) path[idx] } );
284 path.push_back( source );
286 if( is_ff( source ) )
291 reference = (
Gate *) source;
294 visited.insert( std::make_pair( reference, source ) );
298 if( is_connected_to_control_pin( ep ) )
304 const Net *
net = ep->get_net();
305 if(
net->get_name() ==
"'0'" ||
net->get_name() ==
"'1'" )
311 if(
net->is_global_input_net() )
313 for(
const Gate *gate : path )
315 vertices.insert( (
void *) gate );
319 for(
u32 idx = 0; idx < path.size() - 1; idx++ )
321 edges.insert( { (
void *) path[idx + 1], (
void *) path[idx] } );
324 vertices.insert( (
void *)
net );
328 edges.insert( { (
void *)
net, (
void *) path.back() } );
331 path.push_back( source );
336 if(
net->get_num_of_sources() == 0 )
339 "unrouted clock net with ID {} ignored",
340 std::to_string(
net->get_id() ) );
343 else if(
net->get_num_of_sources() > 1 )
346 "multi-driven clock net with ID {} ignored",
347 std::to_string(
net->get_id() ) );
351 const Gate *new_source =
net->get_sources().front()->get_gate();
352 if( visited.find( { reference, new_source } ) == visited.end() )
354 queue.push( { reference, new_source, path } );
359 std::unique_ptr<ClockTree> clock_tree = std::unique_ptr<ClockTree>(
new ClockTree( netlist ) );
361 igraph_integer_t idx = 0;
362 for(
const void *vertex : vertices )
364 const igraph_integer_t vertex_id = idx++;
366 clock_tree->m_vertices_to_ptrs[vertex_id] = vertex;
367 clock_tree->m_ptrs_to_vertices[vertex] = vertex_id;
370 clock_tree->m_ptrs_to_types = ptrs_to_type;
372 igraph_error_t ierror;
373 igraph_vector_int_t iedges;
374 if( ( ierror = igraph_vector_int_init( &iedges, 2 * edges.size() ) ) != IGRAPH_SUCCESS )
376 return ERR( igraph_strerror( ierror ) );
380 for(
const auto &[src, dst] : edges )
382 VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( src );
383 VECTOR( iedges )[idx++] = clock_tree->m_ptrs_to_vertices.at( dst );
386 if( ( ierror = igraph_create( clock_tree->m_igraph_ptr, &iedges, vertices.size(), IGRAPH_DIRECTED ) )
389 igraph_vector_int_destroy( &iedges );
390 return ERR( igraph_strerror( ierror ) );
393 igraph_vector_int_destroy( &iedges );
395 igraph_vector_int_t indegrees;
396 if( ( ierror = igraph_vector_int_init( &indegrees, 0 ) ) != IGRAPH_SUCCESS )
398 return ERR( igraph_strerror( ierror ) );
401 if( ( ierror = igraph_degree(
402 clock_tree->m_igraph_ptr, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
405 igraph_vector_int_destroy( &indegrees );
406 return ERR( igraph_strerror( ierror ) );
409 for( idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
411 if( VECTOR( indegrees )[idx] != 0 )
415 clock_tree->m_roots.insert( idx );
418 igraph_vector_int_destroy( &indegrees );
420 return OK( std::move( clock_tree ) );
425 std::ofstream dot_fd( pathname );
429 return ERR(
"couldn't export clock tree to '" + pathname +
"'" );
432 dot_fd <<
"digraph { comment=\"created by HAL plugin clock_tree_extractor\"\n";
434 for(
const auto &[ptr, vertex] : m_ptrs_to_vertices )
438 dot_fd <<
" " << ( (
Net *) ptr )->get_name() <<
" [shape=circle];\n";
442 const Gate *gate = (
const Gate *) ptr;
444 std::string coords =
"";
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 )
458 log_error(
"clock_tree_extractor",
"invalid coordinate format: {}", err.what() );
461 std::string shape =
"shape=hexagon";
463 if( is_buffer( gate ) )
465 shape =
"shape=rectangle";
467 else if( is_inverter( gate ) )
469 shape =
"shape=triangle orientation=180";
471 else if( is_ff( gate ) )
475 else if( is_delay( gate ) )
477 shape =
"shape=square";
480 dot_fd <<
" " << gate->
get_id() <<
" [instance=\"" << gate->
get_name() <<
"\" type=\""
485 dot_fd <<
" " << shape;
491 std::queue<std::pair<igraph_integer_t, std::string>> queue;
492 for(
const igraph_integer_t &root : m_roots )
494 queue.push( { root,
"blue" } );
497 igraph_error_t ierror;
498 std::unordered_set<igraph_integer_t> visited;
499 while( !queue.empty() )
501 const std::pair<igraph_integer_t, std::string> pair = queue.front();
504 const igraph_integer_t vertex = pair.first;
505 std::string edge_color = pair.second;
507 if( visited.find( vertex ) != visited.end() )
512 visited.insert( vertex );
514 const void *sptr = m_vertices_to_ptrs.at( vertex );
515 const PtrType stype = m_ptrs_to_types.at( sptr );
519 edge_color = edge_color ==
"red" ?
"blue" :
"red";
522 igraph_vector_int_t neighbors;
523 if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
526 return ERR( igraph_strerror( ierror ) );
529 if( ( ierror = igraph_neighbors(
530 m_igraph_ptr, &neighbors, vertex, IGRAPH_OUT, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
534 igraph_vector_int_destroy( &neighbors );
535 return ERR( igraph_strerror( ierror ) );
538 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
540 const std::string src_id = stype ==
PtrType::GATE ? std::to_string( ( (
Gate *) sptr )->get_id() )
541 : ( (
Net *) sptr )->get_name();
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();
548 dot_fd <<
" " << src_id <<
" -> " << dst_id <<
" [color=" << edge_color <<
"];\n";
549 queue.push( { VECTOR( neighbors )[idx], edge_color } );
552 igraph_vector_int_destroy( &neighbors );
563 auto it = m_ptrs_to_vertices.find( ptr );
564 if( it == m_ptrs_to_vertices.end() )
566 return ERR(
"object is not part of clock tree" );
569 igraph_error_t ierror;
570 igraph_integer_t root = it->second;
573 igraph_vector_int_t parents;
574 if( ( ierror = igraph_vector_int_init( &parents, 0 ) ) != IGRAPH_SUCCESS )
576 return ERR( igraph_strerror( ierror ) );
579 if( ( ierror = igraph_neighbors(
580 m_igraph_ptr, &parents, root, IGRAPH_IN, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
583 igraph_vector_int_destroy( &parents );
584 return ERR( igraph_strerror( ierror ) );
588 if( igraph_vector_int_size( &parents ) == 1 )
590 root = VECTOR( parents )[0];
593 igraph_vector_int_destroy( &parents );
596 igraph_vector_int_t vertices;
597 if( ( ierror = igraph_vector_int_init( &vertices, 0 ) ) != IGRAPH_SUCCESS )
599 return ERR( igraph_strerror( ierror ) );
602 if( ( ierror = igraph_dfs( m_igraph_ptr,
615 igraph_vector_int_destroy( &vertices );
616 return ERR( igraph_strerror( ierror ) );
620 if( ( ierror = igraph_vs_vector( &vs, &vertices ) ) != IGRAPH_SUCCESS )
622 igraph_vector_int_destroy( &vertices );
623 return ERR( igraph_strerror( ierror ) );
626 igraph_vector_int_t map;
627 if( ( ierror = igraph_vector_int_init( &map, igraph_vcount( m_igraph_ptr ) ) ) != IGRAPH_SUCCESS )
629 return ERR( igraph_strerror( ierror ) );
634 igraph_induced_subgraph_map( m_igraph_ptr, &igraph, vs, IGRAPH_SUBGRAPH_AUTO, &map,
nullptr ) )
637 igraph_vs_destroy( &vs );
638 igraph_vector_int_destroy( &map );
639 igraph_vector_int_destroy( &vertices );
640 return ERR( igraph_strerror( ierror ) );
643 igraph_vs_destroy( &vs );
644 igraph_vector_int_destroy( &vertices );
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;
650 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &map ); idx++ )
652 const igraph_integer_t vertex = VECTOR( map )[idx];
658 const void *ptr = m_vertices_to_ptrs.at( idx );
660 vertices_to_ptrs[vertex - 1] = ptr;
661 ptrs_to_types[ptr] = m_ptrs_to_types.at( ptr );
664 igraph_vector_int_destroy( &map );
666 igraph_vector_int_t indegrees;
667 if( ( ierror = igraph_vector_int_init( &indegrees, igraph_vcount( &igraph ) ) ) != IGRAPH_SUCCESS )
669 return ERR( igraph_strerror( ierror ) );
672 if( ( ierror = igraph_degree( &igraph, &indegrees, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS ) )
675 igraph_vector_int_destroy( &indegrees );
676 return ERR( igraph_strerror( ierror ) );
679 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &indegrees ); idx++ )
681 if( VECTOR( indegrees )[idx] != 0 )
688 igraph_vector_int_destroy( &indegrees );
690 return OK( std::make_unique<ClockTree>( m_netlist,
693 std::move( vertices_to_ptrs ),
694 std::move( ptrs_to_types ) ) );
699 auto it = m_ptrs_to_vertices.find( ptr );
700 if( it == m_ptrs_to_vertices.end() )
702 return ERR(
"object is not part of clock tree" );
705 return OK( it->second );
710 auto it = m_vertices_to_ptrs.find( vertex );
711 if( it == m_vertices_to_ptrs.end() )
713 return ERR(
"object is not part of clock tree" );
716 return OK( std::make_pair( it->second, m_ptrs_to_types.at( it->second ) ) );
722 std::vector<igraph_integer_t> result;
724 for(
const void *ptr : ptrs )
729 return ERR( res.get_error().get() );
732 result.push_back( res.get() );
741 std::vector<std::pair<const void *, PtrType>> result;
743 for(
const igraph_integer_t vertex : vertices )
748 return ERR( res.get_error().get() );
751 result.push_back( res.get() );
759 std::vector<const Gate *> result;
761 for(
const auto &[ptr,
type] : m_ptrs_to_types )
765 result.push_back( (
const Gate *) ptr );
774 std::vector<const Net *> result;
776 for(
const auto &[ptr,
type] : m_ptrs_to_types )
780 result.push_back( (
const Net *) ptr );
789 return m_ptrs_to_types;
805 auto it = m_ptrs_to_vertices.find( ptr );
806 if( it == m_ptrs_to_vertices.end() )
808 return ERR(
"object is not part of clock tree" );
811 igraph_error_t ierror;
812 igraph_vector_int_t neighbors;
814 if( ( ierror = igraph_vector_int_init( &neighbors, 0 ) ) != IGRAPH_SUCCESS )
816 return ERR( igraph_strerror( ierror ) );
819 if( ( ierror = igraph_neighbors(
820 m_igraph_ptr, &neighbors, it->second,
direction, IGRAPH_NO_LOOPS, IGRAPH_NO_MULTIPLE ) )
823 igraph_vector_int_destroy( &neighbors );
824 return ERR( igraph_strerror( ierror ) );
827 std::vector<std::pair<const void *, PtrType>> result;
828 for( igraph_integer_t idx = 0; idx < igraph_vector_int_size( &neighbors ); idx++ )
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 ) ) );
834 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,...)