Skip to content

Commit fc03207

Browse files
committed
vpr: Refactor timing graph construction code into more sub-functions
This splits out node/edge construction for netlist primitives into smaller easier to read sub-functions (previously one too large function).
1 parent ee32d7e commit fc03207

File tree

2 files changed

+88
-65
lines changed

2 files changed

+88
-65
lines changed

vpr/src/timing/timing_graph_builder.cpp

Lines changed: 83 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ void TimingGraphBuilder::build(bool allow_dangling_combinational_nodes) {
302302
//Break any combinational loops (i.e. if the graph is not a DAG)
303303
fix_comb_loops();
304304

305-
//Levelize the graph (i.e. determine its topological ordering and record
305+
//Levelize the graph (i.e. determine its topological ordering and record
306306
//the level of each node) for the timing analyzer
307307
tg_->levelize();
308308
}
@@ -388,6 +388,16 @@ void TimingGraphBuilder::add_block_to_timing_graph(const AtomBlockId blk) {
388388
* bad practise, but it happens). We detect such cases and also create a
389389
* SOURCE (and leave any combinational inputs to that node disconnected).
390390
*/
391+
392+
auto clock_generator_tnodes = create_block_timing_nodes(blk);
393+
create_block_internal_data_timing_edges(blk, clock_generator_tnodes);
394+
create_block_internal_clock_timing_edges(blk, clock_generator_tnodes);
395+
}
396+
397+
//Constructs the timing graph nodes for the specified block
398+
//
399+
//Returns the set of created tnodese which are clock generators
400+
std::set<tatum::NodeId> TimingGraphBuilder::create_block_timing_nodes(const AtomBlockId blk) {
391401
std::set<std::string> output_ports_used_as_combinational_sinks;
392402

393403
//Create the tnodes corresponding to input pins
@@ -501,6 +511,10 @@ void TimingGraphBuilder::add_block_to_timing_graph(const AtomBlockId blk) {
501511
netlist_lookup_.set_atom_pin_tnode(output_pin, tnode, BlockTnode::EXTERNAL);
502512
}
503513

514+
return clock_generator_tnodes;
515+
}
516+
517+
void TimingGraphBuilder::create_block_internal_clock_timing_edges(const AtomBlockId blk, const std::set<tatum::NodeId>& clock_generator_tnodes) {
504518
//Connect the clock pins to the sources and sinks
505519
for (AtomPinId pin : netlist_.block_pins(blk)) {
506520
for (auto blk_tnode_type : {BlockTnode::EXTERNAL, BlockTnode::INTERNAL}) {
@@ -511,46 +525,78 @@ void TimingGraphBuilder::add_block_to_timing_graph(const AtomBlockId blk) {
511525

512526
auto node_type = tg_->node_type(tnode);
513527

514-
if (node_type == NodeType::SOURCE || node_type == NodeType::SINK) {
515-
//Look-up the clock name on the port model
516-
AtomPortId port = netlist_.pin_port(pin);
517-
const t_model_ports* model_port = netlist_.port_model(port);
518-
519-
VTR_ASSERT_MSG(!model_port->clock.empty(), "Sequential pins must have a clock");
520-
521-
//Find the clock pin in the netlist
522-
AtomPortId clk_port = netlist_.find_port(blk, model_port->clock);
523-
VTR_ASSERT(clk_port);
524-
VTR_ASSERT_MSG(netlist_.port_width(clk_port) == 1, "Primitive clock ports can only contain one pin");
525-
526-
AtomPinId clk_pin = netlist_.port_pin(clk_port, 0);
527-
VTR_ASSERT(clk_pin);
528-
529-
//Convert the pin to it's tnode
530-
NodeId clk_tnode = netlist_lookup_.atom_pin_tnode(clk_pin);
531-
VTR_ASSERT(clk_tnode);
532-
533-
//Determine the type of edge to create
534-
//This corresponds to how the clock (clk_tnode) relates
535-
//to the data (tnode). So a SOURCE data tnode should be
536-
//a PRIMTIVE_CLOCK_LAUNCH (clock launches data), while
537-
//a SINK data tnode should be a PRIMITIVE_CLOCK_CAPTURE
538-
//(clock captures data).
539-
tatum::EdgeType type;
540-
if (node_type == NodeType::SOURCE) {
541-
type = tatum::EdgeType::PRIMITIVE_CLOCK_LAUNCH;
542-
} else {
543-
VTR_ASSERT(node_type == NodeType::SINK);
544-
type = tatum::EdgeType::PRIMITIVE_CLOCK_CAPTURE;
545-
}
528+
if (node_type != NodeType::SOURCE && node_type != NodeType::SINK) continue;
529+
530+
VTR_ASSERT_SAFE(node_type == NodeType::SOURCE || node_type == NodeType::SINK);
531+
532+
//Look-up the clock name on the port model
533+
AtomPortId port = netlist_.pin_port(pin);
534+
const t_model_ports* model_port = netlist_.port_model(port);
535+
536+
VTR_ASSERT_MSG(!model_port->clock.empty(), "Sequential pins must have a clock");
537+
538+
//Find the clock pin in the netlist
539+
AtomPortId clk_port = netlist_.find_port(blk, model_port->clock);
540+
VTR_ASSERT(clk_port);
541+
VTR_ASSERT_MSG(netlist_.port_width(clk_port) == 1, "Primitive clock ports can only contain one pin");
542+
543+
AtomPinId clk_pin = netlist_.port_pin(clk_port, 0);
544+
VTR_ASSERT(clk_pin);
545+
546+
//Convert the pin to it's tnode
547+
NodeId clk_tnode = netlist_lookup_.atom_pin_tnode(clk_pin);
548+
VTR_ASSERT(clk_tnode);
549+
550+
//Determine the type of edge to create
551+
//This corresponds to how the clock (clk_tnode) relates
552+
//to the data (tnode). So a SOURCE data tnode should be
553+
//a PRIMTIVE_CLOCK_LAUNCH (clock launches data), while
554+
//a SINK data tnode should be a PRIMITIVE_CLOCK_CAPTURE
555+
//(clock captures data).
556+
tatum::EdgeType type;
557+
if (node_type == NodeType::SOURCE) {
558+
type = tatum::EdgeType::PRIMITIVE_CLOCK_LAUNCH;
559+
} else {
560+
VTR_ASSERT(node_type == NodeType::SINK);
561+
type = tatum::EdgeType::PRIMITIVE_CLOCK_CAPTURE;
562+
}
563+
564+
//Add the edge from the clock to the source/sink
565+
tg_->add_edge(type, clk_tnode, tnode);
566+
}
567+
}
568+
569+
//Connect the combinational edges from clock input pins
570+
//
571+
//These are typically used to represent clock buffers
572+
for (AtomPinId src_clock_pin : netlist_.block_clock_pins(blk)) {
573+
NodeId src_tnode = netlist_lookup_.atom_pin_tnode(src_clock_pin, BlockTnode::EXTERNAL);
574+
575+
if (!src_tnode) continue;
576+
577+
//Look-up the combinationally connected sink ports name on the port model
578+
AtomPortId src_port = netlist_.pin_port(src_clock_pin);
579+
const t_model_ports* model_port = netlist_.port_model(src_port);
580+
581+
for (const std::string& sink_port_name : model_port->combinational_sink_ports) {
582+
AtomPortId sink_port = netlist_.find_port(blk, sink_port_name);
583+
if (!sink_port) continue; //Port may not be connected
584+
585+
//We now need to create edges between the source pin, and all the pins in the
586+
//output port
587+
for (AtomPinId sink_pin : netlist_.port_pins(sink_port)) {
588+
//Get the tnode of the sink
589+
NodeId sink_tnode = netlist_lookup_.atom_pin_tnode(sink_pin, BlockTnode::EXTERNAL);
546590

547-
//Add the edge from the clock to the source/sink
548-
tg_->add_edge(type, clk_tnode, tnode);
591+
tg_->add_edge(tatum::EdgeType::PRIMITIVE_COMBINATIONAL, src_tnode, sink_tnode);
592+
VTR_LOG("Adding edge from '%s' (tnode: %zu) -> '%s' (tnode: %zu) to allow clocks to propagate\n", netlist_.pin_name(src_clock_pin).c_str(), size_t(src_tnode), netlist_.pin_name(sink_pin).c_str(), size_t(sink_tnode));
549593
}
550594
}
551595
}
596+
}
552597

553-
//Connect the combinational edges from input pins
598+
void TimingGraphBuilder::create_block_internal_data_timing_edges(const AtomBlockId blk, const std::set<tatum::NodeId>& clock_generator_tnodes) {
599+
//Connect the combinational edges from data input pins
554600
//
555601
//These edges may represent an intermediate (combinational) sub-path of a
556602
//timing path (i.e. between IPINs and OPINs), the start of a timing path (i.e. SOURCE
@@ -560,7 +606,7 @@ void TimingGraphBuilder::add_block_to_timing_graph(const AtomBlockId blk) {
560606
//Note that the creation of these edges is driven by the 'combinationl_sink_ports' specified
561607
//in the architecture primitive model
562608
for (AtomPinId src_pin : netlist_.block_input_pins(blk)) {
563-
//Note that we have already created all the relevant nodes, and appropriately labelled them as
609+
//Note that we have already created all the relevant nodes, and appropriately labelled them as
564610
//internal/external. As a result, we only need to consider the 'internal' tnodes when creating
565611
//the edges within the current block.
566612
NodeId src_tnode = netlist_lookup_.atom_pin_tnode(src_pin, BlockTnode::INTERNAL);
@@ -617,34 +663,6 @@ void TimingGraphBuilder::add_block_to_timing_graph(const AtomBlockId blk) {
617663
}
618664
}
619665
}
620-
621-
//Connect the combinational edges from clock pins
622-
//
623-
//These are typically used to represent clock buffers
624-
for (AtomPinId src_clock_pin : netlist_.block_clock_pins(blk)) {
625-
NodeId src_tnode = netlist_lookup_.atom_pin_tnode(src_clock_pin, BlockTnode::EXTERNAL);
626-
627-
if (!src_tnode) continue;
628-
629-
//Look-up the combinationally connected sink ports name on the port model
630-
AtomPortId src_port = netlist_.pin_port(src_clock_pin);
631-
const t_model_ports* model_port = netlist_.port_model(src_port);
632-
633-
for (const std::string& sink_port_name : model_port->combinational_sink_ports) {
634-
AtomPortId sink_port = netlist_.find_port(blk, sink_port_name);
635-
if (!sink_port) continue; //Port may not be connected
636-
637-
//We now need to create edges between the source pin, and all the pins in the
638-
//output port
639-
for (AtomPinId sink_pin : netlist_.port_pins(sink_port)) {
640-
//Get the tnode of the sink
641-
NodeId sink_tnode = netlist_lookup_.atom_pin_tnode(sink_pin, BlockTnode::EXTERNAL);
642-
643-
tg_->add_edge(tatum::EdgeType::PRIMITIVE_COMBINATIONAL, src_tnode, sink_tnode);
644-
VTR_LOG("Adding edge from '%s' (tnode: %zu) -> '%s' (tnode: %zu) to allow clocks to propagate\n", netlist_.pin_name(src_clock_pin).c_str(), size_t(src_tnode), netlist_.pin_name(sink_pin).c_str(), size_t(sink_tnode));
645-
}
646-
}
647-
}
648666
}
649667

650668
void TimingGraphBuilder::add_net_to_timing_graph(const AtomNetId net) {

vpr/src/timing/timing_graph_builder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ class TimingGraphBuilder {
3131
void add_block_to_timing_graph(const AtomBlockId blk);
3232
void add_net_to_timing_graph(const AtomNetId net);
3333

34+
//Helper functions for add_block_to_timing_graph()
35+
std::set<tatum::NodeId> create_block_timing_nodes(const AtomBlockId blk);
36+
void create_block_internal_data_timing_edges(const AtomBlockId blk, const std::set<tatum::NodeId>& clock_generator_tnodes);
37+
void create_block_internal_clock_timing_edges(const AtomBlockId blk, const std::set<tatum::NodeId>& clock_generator_tnodes);
38+
3439
void fix_comb_loops();
3540
tatum::EdgeId find_scc_edge_to_break(std::vector<tatum::NodeId> scc);
3641

0 commit comments

Comments
 (0)