@@ -554,6 +554,7 @@ class BlackBoxInst : public Instance {
554
554
std::map<std::string, std::vector<std::string>> output_port_conns, // /<Port connections: Dictionary of <port,nets>
555
555
std::vector<Arc> timing_arcs, // /<Combinational timing arcs
556
556
std::map<std::string, double > ports_tsu, // /<Port setup checks
557
+ std::map<std::string, double > ports_thld, // /<Port hold checks
557
558
std::map<std::string, double > ports_tcq) // /<Port clock-to-q delays
558
559
: type_name_(type_name)
559
560
, inst_name_(inst_name)
@@ -563,6 +564,7 @@ class BlackBoxInst : public Instance {
563
564
, output_port_conns_(output_port_conns)
564
565
, timing_arcs_(timing_arcs)
565
566
, ports_tsu_(ports_tsu)
567
+ , ports_thld_(ports_thld)
566
568
, ports_tcq_(ports_tcq) {}
567
569
568
570
void print_blif (std::ostream& os, size_t & unconn_count, int depth = 0 ) override {
@@ -648,75 +650,80 @@ class BlackBoxInst : public Instance {
648
650
}
649
651
650
652
void print_sdf (std::ostream& os, int depth = 0 ) override {
651
- os << indent (depth) << " (CELL\n " ;
652
- os << indent (depth + 1 ) << " (CELLTYPE \" " << type_name_ << " \" )\n " ;
653
- os << indent (depth + 1 ) << " (INSTANCE " << escape_sdf_identifier (inst_name_) << " )\n " ;
654
- os << indent (depth + 1 ) << " (DELAY\n " ;
655
-
656
- if (!timing_arcs_.empty () || !ports_tcq_.empty ()) {
657
- os << indent (depth + 2 ) << " (ABSOLUTE\n " ;
658
-
659
- // Combinational paths
660
- for (const auto & arc : timing_arcs_) {
661
- double delay_ps = get_delay_ps (arc.delay ());
662
-
663
- std::stringstream delay_triple;
664
- delay_triple << " (" << delay_ps << " :" << delay_ps << " :" << delay_ps << " )" ;
665
653
666
- // Note that we explicitly do not escape the last array indexing so an SDF
667
- // reader will treat the ports as multi-bit
668
- //
669
- // We also only put the last index in if the port has multiple bits
670
- os << indent (depth + 3 ) << " (IOPATH " ;
671
- os << escape_sdf_identifier (arc.source_name ());
672
- if (find_port_size (arc.source_name ()) > 1 ) {
673
- os << " [" << arc.source_ipin () << " ]" ;
674
- }
675
- os << " " ;
676
- os << escape_sdf_identifier (arc.sink_name ());
677
- if (find_port_size (arc.sink_name ()) > 1 ) {
678
- os << " [" << arc.sink_ipin () << " ]" ;
679
- }
680
- os << " " ;
681
- os << delay_triple.str ();
682
- os << " )\n " ;
683
- }
684
-
685
- // Clock-to-Q delays
686
- for (auto kv : ports_tcq_) {
687
- double clock_to_q_ps = get_delay_ps (kv.second );
688
-
689
- std::stringstream delay_triple;
690
- delay_triple << " (" << clock_to_q_ps << " :" << clock_to_q_ps << " :" << clock_to_q_ps << " )" ;
691
-
692
- os << indent (depth + 3 ) << " (IOPATH (posedge clock) " << escape_sdf_identifier (kv.first ) << " " << delay_triple.str () << " " << delay_triple.str () << " )\n " ;
693
- }
694
- os << indent (depth + 2 ) << " )\n " ; // ABSOLUTE
695
- }
696
- os << indent (depth + 1 ) << " )\n " ; // DELAY
697
-
698
- if (!ports_tsu_.empty () || !ports_thld_.empty ()) {
699
- // Setup checks
700
- os << indent (depth + 1 ) << " (TIMINGCHECK\n " ;
701
- for (auto kv : ports_tsu_) {
702
- double setup_ps = get_delay_ps (kv.second );
703
-
704
- std::stringstream delay_triple;
705
- delay_triple << " (" << setup_ps << " :" << setup_ps << " :" << setup_ps << " )" ;
706
-
707
- os << indent (depth + 2 ) << " (SETUP " << escape_sdf_identifier (kv.first ) << " (posedge clock) " << delay_triple.str () << " )\n " ;
708
- }
709
- for (auto kv : ports_thld_) {
710
- double hold_ps = get_delay_ps (kv.second );
711
-
712
- std::stringstream delay_triple;
713
- delay_triple << " (" << hold_ps << " :" << hold_ps << " :" << hold_ps << " )" ;
714
-
715
- os << indent (depth + 2 ) << " (HOLD " << escape_sdf_identifier (kv.first ) << " (posedge clock) " << delay_triple.str () << " )\n " ;
716
- }
717
- os << indent (depth + 1 ) << " )\n " ; // TIMINGCHECK
718
- }
719
- os << indent (depth) << " )\n " ; // CELL
654
+
655
+ if (!timing_arcs_.empty () || !ports_tcq_.empty () || !ports_tsu_.empty () || !ports_thld_.empty ()) {
656
+ os << indent (depth) << " (CELL\n " ;
657
+ os << indent (depth + 1 ) << " (CELLTYPE \" " << type_name_ << " \" )\n " ;
658
+ os << indent (depth + 1 ) << " (INSTANCE " << escape_sdf_identifier (inst_name_) << " )\n " ;
659
+ os << indent (depth + 1 ) << " (DELAY\n " ;
660
+
661
+
662
+ if (!timing_arcs_.empty () || !ports_tcq_.empty ()) {
663
+ os << indent (depth + 2 ) << " (ABSOLUTE\n " ;
664
+
665
+ // Combinational paths
666
+ for (const auto & arc : timing_arcs_) {
667
+ double delay_ps = get_delay_ps (arc.delay ());
668
+
669
+ std::stringstream delay_triple;
670
+ delay_triple << " (" << delay_ps << " :" << delay_ps << " :" << delay_ps << " )" ;
671
+
672
+ // Note that we explicitly do not escape the last array indexing so an SDF
673
+ // reader will treat the ports as multi-bit
674
+ //
675
+ // We also only put the last index in if the port has multiple bits
676
+ os << indent (depth + 3 ) << " (IOPATH " ;
677
+ os << escape_sdf_identifier (arc.source_name ());
678
+ if (find_port_size (arc.source_name ()) > 1 ) {
679
+ os << " [" << arc.source_ipin () << " ]" ;
680
+ }
681
+ os << " " ;
682
+ os << escape_sdf_identifier (arc.sink_name ());
683
+ if (find_port_size (arc.sink_name ()) > 1 ) {
684
+ os << " [" << arc.sink_ipin () << " ]" ;
685
+ }
686
+ os << " " ;
687
+ os << delay_triple.str ();
688
+ os << " )\n " ;
689
+ }
690
+
691
+ // Clock-to-Q delays
692
+ for (auto kv : ports_tcq_) {
693
+ double clock_to_q_ps = get_delay_ps (kv.second );
694
+
695
+ std::stringstream delay_triple;
696
+ delay_triple << " (" << clock_to_q_ps << " :" << clock_to_q_ps << " :" << clock_to_q_ps << " )" ;
697
+
698
+ os << indent (depth + 3 ) << " (IOPATH (posedge clock) " << escape_sdf_identifier (kv.first ) << " " << delay_triple.str () << " " << delay_triple.str () << " )\n " ;
699
+ }
700
+ os << indent (depth + 2 ) << " )\n " ; // ABSOLUTE
701
+ }
702
+ os << indent (depth + 1 ) << " )\n " ; // DELAY
703
+
704
+ if (!ports_tsu_.empty () || !ports_thld_.empty ()) {
705
+ // Setup checks
706
+ os << indent (depth + 1 ) << " (TIMINGCHECK\n " ;
707
+ for (auto kv : ports_tsu_) {
708
+ double setup_ps = get_delay_ps (kv.second );
709
+
710
+ std::stringstream delay_triple;
711
+ delay_triple << " (" << setup_ps << " :" << setup_ps << " :" << setup_ps << " )" ;
712
+
713
+ os << indent (depth + 2 ) << " (SETUP " << escape_sdf_identifier (kv.first ) << " (posedge clock) " << delay_triple.str () << " )\n " ;
714
+ }
715
+ for (auto kv : ports_thld_) {
716
+ double hold_ps = get_delay_ps (kv.second );
717
+
718
+ std::stringstream delay_triple;
719
+ delay_triple << " (" << hold_ps << " :" << hold_ps << " :" << hold_ps << " )" ;
720
+
721
+ os << indent (depth + 2 ) << " (HOLD " << escape_sdf_identifier (kv.first ) << " (posedge clock) " << delay_triple.str () << " )\n " ;
722
+ }
723
+ os << indent (depth + 1 ) << " )\n " ; // TIMINGCHECK
724
+ }
725
+ os << indent (depth) << " )\n " ; // CELL
726
+ }
720
727
}
721
728
722
729
size_t find_port_size (std::string port_name) {
@@ -1278,6 +1285,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1278
1285
std::map<std::string, std::vector<std::string>> output_port_conns;
1279
1286
std::vector<Arc> timing_arcs;
1280
1287
std::map<std::string, double > ports_tsu;
1288
+ std::map<std::string, double > ports_thld;
1281
1289
std::map<std::string, double > ports_tcq;
1282
1290
1283
1291
params[" ADDR_WIDTH" ] = " 0" ;
@@ -1401,7 +1409,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1401
1409
}
1402
1410
}
1403
1411
1404
- return std::make_shared<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1412
+ return std::make_shared<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
1405
1413
}
1406
1414
1407
1415
// /@brief Returns an Instance object representing a Multiplier
@@ -1420,6 +1428,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1420
1428
std::map<std::string, std::vector<std::string>> output_port_conns;
1421
1429
std::vector<Arc> timing_arcs;
1422
1430
std::map<std::string, double > ports_tsu;
1431
+ std::map<std::string, double > ports_thld;
1423
1432
std::map<std::string, double > ports_tcq;
1424
1433
1425
1434
params[" WIDTH" ] = " 0" ;
@@ -1496,7 +1505,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1496
1505
1497
1506
VTR_ASSERT (pb_graph_node->num_clock_ports == 0 ); // No clocks
1498
1507
1499
- return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1508
+ return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
1500
1509
}
1501
1510
1502
1511
// /@brief Returns an Instance object representing an Adder
@@ -1515,6 +1524,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1515
1524
std::map<std::string, std::vector<std::string>> output_port_conns;
1516
1525
std::vector<Arc> timing_arcs;
1517
1526
std::map<std::string, double > ports_tsu;
1527
+ std::map<std::string, double > ports_thld;
1518
1528
std::map<std::string, double > ports_tcq;
1519
1529
1520
1530
params[" WIDTH" ] = " 0" ;
@@ -1595,14 +1605,15 @@ class NetlistWriterVisitor : public NetlistVisitor {
1595
1605
}
1596
1606
}
1597
1607
1598
- return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1608
+ return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
1599
1609
}
1600
1610
1601
1611
std::shared_ptr<Instance> make_blackbox_instance (const t_pb* atom) {
1602
1612
const auto & top_pb_route = find_top_pb_route (atom);
1603
1613
const t_pb_graph_node* pb_graph_node = atom->pb_graph_node ;
1604
1614
const t_pb_type* pb_type = pb_graph_node->pb_type ;
1605
1615
1616
+ auto & timing_ctx = g_vpr_ctx.timing ();
1606
1617
std::string type_name = pb_type->model ->name ;
1607
1618
std::string inst_name = join_identifier (type_name, atom->name );
1608
1619
std::map<std::string, std::string> params;
@@ -1611,6 +1622,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1611
1622
std::map<std::string, std::vector<std::string>> output_port_conns;
1612
1623
std::vector<Arc> timing_arcs;
1613
1624
std::map<std::string, double > ports_tsu;
1625
+ std::map<std::string, double > ports_thld;
1614
1626
std::map<std::string, double > ports_tcq;
1615
1627
1616
1628
// Delay matrix[sink_tnode] -> tuple of source_port_name, pin index, delay
@@ -1627,6 +1639,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1627
1639
std::string net;
1628
1640
if (!top_pb_route.count (cluster_pin_idx)) {
1629
1641
// Disconnected
1642
+ net = " " ;
1630
1643
1631
1644
} else {
1632
1645
// Connected
@@ -1635,13 +1648,27 @@ class NetlistWriterVisitor : public NetlistVisitor {
1635
1648
1636
1649
auto src_tnode = find_tnode (atom, cluster_pin_idx);
1637
1650
net = make_inst_wire (atom_net_id, src_tnode, inst_name, PortType::INPUT, iport, ipin);
1651
+ // Delays
1652
+ //
1653
+ // We record the souce sink tnodes and thier delays here
1654
+ for (tatum::EdgeId edge : timing_ctx.graph ->node_out_edges (src_tnode)) {
1655
+ double delay = delay_calc_->max_edge_delay (*timing_ctx.graph , edge);
1656
+
1657
+ auto sink_tnode = timing_ctx.graph ->edge_sink_node (edge);
1658
+ tnode_delay_matrix[sink_tnode].emplace_back (port->name , ipin, delay);
1659
+ }
1638
1660
}
1639
1661
1640
- input_port_conns[port->name ].push_back (net);
1641
- }
1642
- }
1643
1662
1644
- // Process the output ports
1663
+ input_port_conns[port->name ].push_back (net);
1664
+ if (pin->type == PB_PIN_SEQUENTIAL) {
1665
+ if (!std::isnan (pin->tsu )) ports_tsu[port->name ] = pin->tsu ;
1666
+ if (!std::isnan (pin->thld )) ports_thld[port->name ] = pin->thld ;
1667
+ }
1668
+ }
1669
+ }
1670
+
1671
+ // Process the output ports
1645
1672
for (int iport = 0 ; iport < pb_graph_node->num_output_ports ; ++iport) {
1646
1673
for (int ipin = 0 ; ipin < pb_graph_node->num_output_pins [iport]; ++ipin) {
1647
1674
const t_pb_graph_pin* pin = &pb_graph_node->output_pins [iport][ipin];
@@ -1651,7 +1678,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1651
1678
1652
1679
std::string net;
1653
1680
if (!top_pb_route.count (cluster_pin_idx)) {
1654
- // Disconnected
1681
+ // Disconnected
1655
1682
net = " " ;
1656
1683
} else {
1657
1684
// Connected
@@ -1660,9 +1687,18 @@ class NetlistWriterVisitor : public NetlistVisitor {
1660
1687
1661
1688
auto inode = find_tnode (atom, cluster_pin_idx);
1662
1689
net = make_inst_wire (atom_net_id, inode, inst_name, PortType::OUTPUT, iport, ipin);
1690
+ // Record the timing arcs
1691
+ for (auto & data_tuple : tnode_delay_matrix[inode]) {
1692
+ auto src_name = std::get<0 >(data_tuple);
1693
+ auto src_ipin = std::get<1 >(data_tuple);
1694
+ auto delay = std::get<2 >(data_tuple);
1695
+ timing_arcs.emplace_back (src_name, src_ipin, port->name , ipin, delay);
1696
+ }
1663
1697
}
1664
1698
1699
+
1665
1700
output_port_conns[port->name ].push_back (net);
1701
+ if (pin->type == PB_PIN_SEQUENTIAL && !std::isnan (pin->tco_max )) ports_tcq[port->name ] = pin->tco_max ;
1666
1702
}
1667
1703
}
1668
1704
@@ -1701,7 +1737,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
1701
1737
attrs[attr.first ] = attr.second ;
1702
1738
}
1703
1739
1704
- return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1740
+ return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
1705
1741
}
1706
1742
1707
1743
// /@brief Returns the top level pb_route associated with the given pb
0 commit comments