Skip to content

Commit 9098cd1

Browse files
authored
Merge pull request verilog-to-routing#1566 from antmicro/blackbox_timing_to_upstream
Blackbox SDF timing fixes
2 parents ec78e3e + 5dc8e83 commit 9098cd1

File tree

1 file changed

+120
-74
lines changed

1 file changed

+120
-74
lines changed

vpr/src/base/netlist_writer.cpp

Lines changed: 120 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@
9292
//File local type declarations
9393
//
9494

95+
// This pair cointains the following values:
96+
// - double: hold, setup or clock-to-q delays of the port
97+
// - string: port name of the associated source clock pin of the sequential port
98+
typedef std::pair<double, std::string> sequential_port_delay_pair;
99+
95100
/*enum class PortType {
96101
* IN,
97102
* OUT,
@@ -553,8 +558,9 @@ class BlackBoxInst : public Instance {
553558
std::map<std::string, std::vector<std::string>> input_port_conns, ///<Port connections: Dictionary of <port,nets>
554559
std::map<std::string, std::vector<std::string>> output_port_conns, ///<Port connections: Dictionary of <port,nets>
555560
std::vector<Arc> timing_arcs, ///<Combinational timing arcs
556-
std::map<std::string, double> ports_tsu, ///<Port setup checks
557-
std::map<std::string, double> ports_tcq) ///<Port clock-to-q delays
561+
std::map<std::string, sequential_port_delay_pair> ports_tsu, ///<Port setup checks
562+
std::map<std::string, sequential_port_delay_pair> ports_thld, ///<Port hold checks
563+
std::map<std::string, sequential_port_delay_pair> ports_tcq) ///<Port clock-to-q delays
558564
: type_name_(type_name)
559565
, inst_name_(inst_name)
560566
, params_(params)
@@ -563,6 +569,7 @@ class BlackBoxInst : public Instance {
563569
, output_port_conns_(output_port_conns)
564570
, timing_arcs_(timing_arcs)
565571
, ports_tsu_(ports_tsu)
572+
, ports_thld_(ports_thld)
566573
, ports_tcq_(ports_tcq) {}
567574

568575
void print_blif(std::ostream& os, size_t& unconn_count, int depth = 0) override {
@@ -648,75 +655,77 @@ class BlackBoxInst : public Instance {
648655
}
649656

650657
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";
658+
if (!timing_arcs_.empty() || !ports_tcq_.empty() || !ports_tsu_.empty() || !ports_thld_.empty()) {
659+
os << indent(depth) << "(CELL\n";
660+
os << indent(depth + 1) << "(CELLTYPE \"" << type_name_ << "\")\n";
661+
os << indent(depth + 1) << "(INSTANCE " << escape_sdf_identifier(inst_name_) << ")\n";
662+
os << indent(depth + 1) << "(DELAY\n";
655663

656-
if (!timing_arcs_.empty() || !ports_tcq_.empty()) {
657-
os << indent(depth + 2) << "(ABSOLUTE\n";
664+
if (!timing_arcs_.empty() || !ports_tcq_.empty()) {
665+
os << indent(depth + 2) << "(ABSOLUTE\n";
658666

659-
//Combinational paths
660-
for (const auto& arc : timing_arcs_) {
661-
double delay_ps = get_delay_ps(arc.delay());
667+
//Combinational paths
668+
for (const auto& arc : timing_arcs_) {
669+
double delay_ps = get_delay_ps(arc.delay());
662670

663-
std::stringstream delay_triple;
664-
delay_triple << "(" << delay_ps << ":" << delay_ps << ":" << delay_ps << ")";
671+
std::stringstream delay_triple;
672+
delay_triple << "(" << delay_ps << ":" << delay_ps << ":" << delay_ps << ")";
665673

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() << "]";
674+
//Note that we explicitly do not escape the last array indexing so an SDF
675+
//reader will treat the ports as multi-bit
676+
//
677+
//We also only put the last index in if the port has multiple bits
678+
os << indent(depth + 3) << "(IOPATH ";
679+
os << escape_sdf_identifier(arc.source_name());
680+
if (find_port_size(arc.source_name()) > 1) {
681+
os << "[" << arc.source_ipin() << "]";
682+
}
683+
os << " ";
684+
os << escape_sdf_identifier(arc.sink_name());
685+
if (find_port_size(arc.sink_name()) > 1) {
686+
os << "[" << arc.sink_ipin() << "]";
687+
}
688+
os << " ";
689+
os << delay_triple.str();
690+
os << ")\n";
679691
}
680-
os << " ";
681-
os << delay_triple.str();
682-
os << ")\n";
683-
}
684692

685-
//Clock-to-Q delays
686-
for (auto kv : ports_tcq_) {
687-
double clock_to_q_ps = get_delay_ps(kv.second);
693+
//Clock-to-Q delays
694+
for (auto kv : ports_tcq_) {
695+
double clock_to_q_ps = get_delay_ps(kv.second.first);
688696

689-
std::stringstream delay_triple;
690-
delay_triple << "(" << clock_to_q_ps << ":" << clock_to_q_ps << ":" << clock_to_q_ps << ")";
697+
std::stringstream delay_triple;
698+
delay_triple << "(" << clock_to_q_ps << ":" << clock_to_q_ps << ":" << clock_to_q_ps << ")";
691699

692-
os << indent(depth + 3) << "(IOPATH (posedge clock) " << escape_sdf_identifier(kv.first) << " " << delay_triple.str() << " " << delay_triple.str() << ")\n";
700+
os << indent(depth + 3) << "(IOPATH (posedge " << escape_sdf_identifier(kv.second.second) << ") " << escape_sdf_identifier(kv.first) << " " << delay_triple.str() << " " << delay_triple.str() << ")\n";
701+
}
702+
os << indent(depth + 2) << ")\n"; //ABSOLUTE
693703
}
694-
os << indent(depth + 2) << ")\n"; //ABSOLUTE
695-
}
696-
os << indent(depth + 1) << ")\n"; //DELAY
704+
os << indent(depth + 1) << ")\n"; //DELAY
697705

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);
706+
if (!ports_tsu_.empty() || !ports_thld_.empty()) {
707+
//Setup checks
708+
os << indent(depth + 1) << "(TIMINGCHECK\n";
709+
for (auto kv : ports_tsu_) {
710+
double setup_ps = get_delay_ps(kv.second.first);
703711

704-
std::stringstream delay_triple;
705-
delay_triple << "(" << setup_ps << ":" << setup_ps << ":" << setup_ps << ")";
712+
std::stringstream delay_triple;
713+
delay_triple << "(" << setup_ps << ":" << setup_ps << ":" << setup_ps << ")";
706714

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);
715+
os << indent(depth + 2) << "(SETUP " << escape_sdf_identifier(kv.first) << " (posedge " << escape_sdf_identifier(kv.second.second) << ") " << delay_triple.str() << ")\n";
716+
}
717+
for (auto kv : ports_thld_) {
718+
double hold_ps = get_delay_ps(kv.second.first);
711719

712-
std::stringstream delay_triple;
713-
delay_triple << "(" << hold_ps << ":" << hold_ps << ":" << hold_ps << ")";
720+
std::stringstream delay_triple;
721+
delay_triple << "(" << hold_ps << ":" << hold_ps << ":" << hold_ps << ")";
714722

715-
os << indent(depth + 2) << "(HOLD " << escape_sdf_identifier(kv.first) << " (posedge clock) " << delay_triple.str() << ")\n";
723+
os << indent(depth + 2) << "(HOLD " << escape_sdf_identifier(kv.first) << " (posedge " << escape_sdf_identifier(kv.second.second) << ") " << delay_triple.str() << ")\n";
724+
}
725+
os << indent(depth + 1) << ")\n"; //TIMINGCHECK
716726
}
717-
os << indent(depth + 1) << ")\n"; //TIMINGCHECK
727+
os << indent(depth) << ")\n"; //CELL
718728
}
719-
os << indent(depth) << ")\n"; //CELL
720729
}
721730

722731
size_t find_port_size(std::string port_name) {
@@ -743,9 +752,9 @@ class BlackBoxInst : public Instance {
743752
std::map<std::string, std::vector<std::string>> input_port_conns_;
744753
std::map<std::string, std::vector<std::string>> output_port_conns_;
745754
std::vector<Arc> timing_arcs_;
746-
std::map<std::string, double> ports_tsu_;
747-
std::map<std::string, double> ports_thld_;
748-
std::map<std::string, double> ports_tcq_;
755+
std::map<std::string, sequential_port_delay_pair> ports_tsu_;
756+
std::map<std::string, sequential_port_delay_pair> ports_thld_;
757+
std::map<std::string, sequential_port_delay_pair> ports_tcq_;
749758
};
750759

751760
/**
@@ -894,6 +903,8 @@ class NetlistWriterVisitor : public NetlistVisitor {
894903
}
895904
}
896905

906+
verilog_os_ << indent(depth + 1) << "wire DummyOut;\n";
907+
897908
//connections between primary I/Os and their internal wires
898909
verilog_os_ << "\n";
899910
verilog_os_ << indent(depth + 1) << "//IO assignments\n";
@@ -1277,8 +1288,9 @@ class NetlistWriterVisitor : public NetlistVisitor {
12771288
std::map<std::string, std::vector<std::string>> input_port_conns;
12781289
std::map<std::string, std::vector<std::string>> output_port_conns;
12791290
std::vector<Arc> timing_arcs;
1280-
std::map<std::string, double> ports_tsu;
1281-
std::map<std::string, double> ports_tcq;
1291+
std::map<std::string, sequential_port_delay_pair> ports_tsu;
1292+
std::map<std::string, sequential_port_delay_pair> ports_thld;
1293+
std::map<std::string, sequential_port_delay_pair> ports_tcq;
12821294

12831295
params["ADDR_WIDTH"] = "0";
12841296
params["DATA_WIDTH"] = "0";
@@ -1334,7 +1346,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
13341346
}
13351347

13361348
input_port_conns[port_name].push_back(net);
1337-
ports_tsu[port_name] = pin->tsu;
1349+
ports_tsu[port_name] = std::make_pair(pin->tsu, pin->associated_clock_pin->port->name);
13381350
}
13391351
}
13401352

@@ -1370,7 +1382,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
13701382
"Unrecognized input port class '%s' for primitive '%s' (%s)\n", port_class.c_str(), atom->name, pb_type->name);
13711383
}
13721384
output_port_conns[port_name].push_back(net);
1373-
ports_tcq[port_name] = pin->tco_max;
1385+
ports_tcq[port_name] = std::make_pair(pin->tco_max, pin->associated_clock_pin->port->name);
13741386
}
13751387
}
13761388

@@ -1401,7 +1413,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
14011413
}
14021414
}
14031415

1404-
return std::make_shared<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1416+
return std::make_shared<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
14051417
}
14061418

14071419
///@brief Returns an Instance object representing a Multiplier
@@ -1419,8 +1431,9 @@ class NetlistWriterVisitor : public NetlistVisitor {
14191431
std::map<std::string, std::vector<std::string>> input_port_conns;
14201432
std::map<std::string, std::vector<std::string>> output_port_conns;
14211433
std::vector<Arc> timing_arcs;
1422-
std::map<std::string, double> ports_tsu;
1423-
std::map<std::string, double> ports_tcq;
1434+
std::map<std::string, sequential_port_delay_pair> ports_tsu;
1435+
std::map<std::string, sequential_port_delay_pair> ports_thld;
1436+
std::map<std::string, sequential_port_delay_pair> ports_tcq;
14241437

14251438
params["WIDTH"] = "0";
14261439

@@ -1496,7 +1509,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
14961509

14971510
VTR_ASSERT(pb_graph_node->num_clock_ports == 0); //No clocks
14981511

1499-
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1512+
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);
15001513
}
15011514

15021515
///@brief Returns an Instance object representing an Adder
@@ -1514,8 +1527,9 @@ class NetlistWriterVisitor : public NetlistVisitor {
15141527
std::map<std::string, std::vector<std::string>> input_port_conns;
15151528
std::map<std::string, std::vector<std::string>> output_port_conns;
15161529
std::vector<Arc> timing_arcs;
1517-
std::map<std::string, double> ports_tsu;
1518-
std::map<std::string, double> ports_tcq;
1530+
std::map<std::string, sequential_port_delay_pair> ports_tsu;
1531+
std::map<std::string, sequential_port_delay_pair> ports_thld;
1532+
std::map<std::string, sequential_port_delay_pair> ports_tcq;
15191533

15201534
params["WIDTH"] = "0";
15211535

@@ -1595,23 +1609,33 @@ class NetlistWriterVisitor : public NetlistVisitor {
15951609
}
15961610
}
15971611

1598-
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1612+
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);
15991613
}
16001614

16011615
std::shared_ptr<Instance> make_blackbox_instance(const t_pb* atom) {
16021616
const auto& top_pb_route = find_top_pb_route(atom);
16031617
const t_pb_graph_node* pb_graph_node = atom->pb_graph_node;
16041618
const t_pb_type* pb_type = pb_graph_node->pb_type;
16051619

1620+
auto& timing_ctx = g_vpr_ctx.timing();
16061621
std::string type_name = pb_type->model->name;
16071622
std::string inst_name = join_identifier(type_name, atom->name);
16081623
std::map<std::string, std::string> params;
16091624
std::map<std::string, std::string> attrs;
16101625
std::map<std::string, std::vector<std::string>> input_port_conns;
16111626
std::map<std::string, std::vector<std::string>> output_port_conns;
16121627
std::vector<Arc> timing_arcs;
1613-
std::map<std::string, double> ports_tsu;
1614-
std::map<std::string, double> ports_tcq;
1628+
1629+
// Maps to store a sink's port with the corresponding timing edge to that sink
1630+
// - key : string corresponding to the port's name
1631+
// - value : pair with the delay and the associated clock pin port name
1632+
//
1633+
// tsu : Setup
1634+
// thld: Hold
1635+
// tcq : Clock-to-Q
1636+
std::map<std::string, sequential_port_delay_pair> ports_tsu;
1637+
std::map<std::string, sequential_port_delay_pair> ports_thld;
1638+
std::map<std::string, sequential_port_delay_pair> ports_tcq;
16151639

16161640
//Delay matrix[sink_tnode] -> tuple of source_port_name, pin index, delay
16171641
std::map<tatum::NodeId, std::vector<std::tuple<std::string, int, double>>> tnode_delay_matrix;
@@ -1627,6 +1651,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
16271651
std::string net;
16281652
if (!top_pb_route.count(cluster_pin_idx)) {
16291653
//Disconnected
1654+
net = "";
16301655

16311656
} else {
16321657
//Connected
@@ -1635,9 +1660,22 @@ class NetlistWriterVisitor : public NetlistVisitor {
16351660

16361661
auto src_tnode = find_tnode(atom, cluster_pin_idx);
16371662
net = make_inst_wire(atom_net_id, src_tnode, inst_name, PortType::INPUT, iport, ipin);
1663+
//Delays
1664+
//
1665+
//We record the source's sink tnodes and their delays here
1666+
for (tatum::EdgeId edge : timing_ctx.graph->node_out_edges(src_tnode)) {
1667+
double delay = delay_calc_->max_edge_delay(*timing_ctx.graph, edge);
1668+
1669+
auto sink_tnode = timing_ctx.graph->edge_sink_node(edge);
1670+
tnode_delay_matrix[sink_tnode].emplace_back(port->name, ipin, delay);
1671+
}
16381672
}
16391673

16401674
input_port_conns[port->name].push_back(net);
1675+
if (pin->type == PB_PIN_SEQUENTIAL) {
1676+
if (!std::isnan(pin->tsu)) ports_tsu[port->name] = std::make_pair(pin->tsu, pin->associated_clock_pin->port->name);
1677+
if (!std::isnan(pin->thld)) ports_thld[port->name] = std::make_pair(pin->thld, pin->associated_clock_pin->port->name);
1678+
}
16411679
}
16421680
}
16431681

@@ -1660,9 +1698,17 @@ class NetlistWriterVisitor : public NetlistVisitor {
16601698

16611699
auto inode = find_tnode(atom, cluster_pin_idx);
16621700
net = make_inst_wire(atom_net_id, inode, inst_name, PortType::OUTPUT, iport, ipin);
1701+
//Record the timing arcs
1702+
for (auto& data_tuple : tnode_delay_matrix[inode]) {
1703+
auto src_name = std::get<0>(data_tuple);
1704+
auto src_ipin = std::get<1>(data_tuple);
1705+
auto delay = std::get<2>(data_tuple);
1706+
timing_arcs.emplace_back(src_name, src_ipin, port->name, ipin, delay);
1707+
}
16631708
}
16641709

16651710
output_port_conns[port->name].push_back(net);
1711+
if (pin->type == PB_PIN_SEQUENTIAL && !std::isnan(pin->tco_max)) ports_tcq[port->name] = std::make_pair(pin->tco_max, pin->associated_clock_pin->port->name);
16661712
}
16671713
}
16681714

@@ -1701,7 +1747,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
17011747
attrs[attr.first] = attr.second;
17021748
}
17031749

1704-
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_tcq);
1750+
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);
17051751
}
17061752

17071753
///@brief Returns the top level pb_route associated with the given pb
@@ -2116,7 +2162,7 @@ void print_verilog_port(std::ostream& os, const std::string& port_name, const st
21162162
os << "1'b0";
21172163
} else {
21182164
VTR_ASSERT(type == PortType::OUTPUT);
2119-
os << "";
2165+
os << "DummyOut";
21202166
}
21212167
} else {
21222168
//Connected
@@ -2135,7 +2181,7 @@ void print_verilog_port(std::ostream& os, const std::string& port_name, const st
21352181
os << "1'b0";
21362182
} else {
21372183
VTR_ASSERT(type == PortType::OUTPUT);
2138-
os << "";
2184+
os << "DummyOut";
21392185
}
21402186
} else {
21412187
//Connected

0 commit comments

Comments
 (0)