blob: 545979c535771e9425da20866b92c03153af3c63 [file] [log] [blame]
#include "VprTimingGraphResolver.h"
#include "atom_netlist.h"
#include "atom_lookup.h"
VprTimingGraphResolver::VprTimingGraphResolver(const AtomNetlist& netlist, const AtomLookup& netlist_lookup, const tatum::TimingGraph& timing_graph, const AnalysisDelayCalculator& delay_calc)
: netlist_(netlist)
, netlist_lookup_(netlist_lookup)
, timing_graph_(timing_graph)
, delay_calc_(delay_calc) {}
std::string VprTimingGraphResolver::node_name(tatum::NodeId node) const {
AtomPinId pin = netlist_lookup_.tnode_atom_pin(node);
return netlist_.pin_name(pin);
}
std::string VprTimingGraphResolver::node_type_name(tatum::NodeId node) const {
AtomPinId pin = netlist_lookup_.tnode_atom_pin(node);
AtomBlockId blk = netlist_.pin_block(pin);
std::string name = netlist_.block_model(blk)->name;
if (detail_level() == e_timing_report_detail::AGGREGATED) {
//Annotate primitive grid location, if known
auto& atom_ctx = g_vpr_ctx.atom();
auto& place_ctx = g_vpr_ctx.placement();
ClusterBlockId cb = atom_ctx.lookup.atom_clb(blk);
if (cb && place_ctx.block_locs.count(cb)) {
int x = place_ctx.block_locs[cb].loc.x;
int y = place_ctx.block_locs[cb].loc.y;
name += " at (" + std::to_string(x) + "," + std::to_string(y) + ")";
}
}
return name;
}
tatum::EdgeDelayBreakdown VprTimingGraphResolver::edge_delay_breakdown(tatum::EdgeId edge, tatum::DelayType tatum_delay_type) const {
tatum::EdgeDelayBreakdown delay_breakdown;
if (edge && detail_level() == e_timing_report_detail::AGGREGATED) {
auto edge_type = timing_graph_.edge_type(edge);
DelayType delay_type; //TODO: should unify vpr/tatum DelayType
if (tatum_delay_type == tatum::DelayType::MAX) {
delay_type = DelayType::MAX;
} else {
VTR_ASSERT(tatum_delay_type == tatum::DelayType::MIN);
delay_type = DelayType::MIN;
}
if (edge_type == tatum::EdgeType::INTERCONNECT) {
delay_breakdown.components = interconnect_delay_breakdown(edge, delay_type);
} else {
//Primtiive edge
//
tatum::DelayComponent component;
tatum::NodeId node = timing_graph_.edge_sink_node(edge);
AtomPinId atom_pin = netlist_lookup_.tnode_atom_pin(node);
AtomBlockId atom_blk = netlist_.pin_block(atom_pin);
//component.inst_name = netlist_.block_name(atom_blk);
component.type_name = "primitive '";
component.type_name += netlist_.block_model(atom_blk)->name;
component.type_name += "'";
if (edge_type == tatum::EdgeType::PRIMITIVE_COMBINATIONAL) {
component.type_name += " combinational delay";
if (delay_type == DelayType::MAX) {
component.delay = delay_calc_.max_edge_delay(timing_graph_, edge);
} else {
VTR_ASSERT(delay_type == DelayType::MIN);
component.delay = delay_calc_.min_edge_delay(timing_graph_, edge);
}
} else if (edge_type == tatum::EdgeType::PRIMITIVE_CLOCK_LAUNCH) {
if (delay_type == DelayType::MAX) {
component.type_name += " Tcq_max";
component.delay = delay_calc_.max_edge_delay(timing_graph_, edge);
} else {
VTR_ASSERT(delay_type == DelayType::MIN);
component.type_name += " Tcq_min";
component.delay = delay_calc_.min_edge_delay(timing_graph_, edge);
}
} else {
VTR_ASSERT(edge_type == tatum::EdgeType::PRIMITIVE_CLOCK_CAPTURE);
if (delay_type == DelayType::MAX) {
component.type_name += " Tsu";
component.delay = delay_calc_.setup_time(timing_graph_, edge);
} else {
component.type_name += " Thld";
component.delay = delay_calc_.hold_time(timing_graph_, edge);
}
}
delay_breakdown.components.push_back(component);
}
}
return delay_breakdown;
}
std::vector<tatum::DelayComponent> VprTimingGraphResolver::interconnect_delay_breakdown(tatum::EdgeId edge, DelayType delay_type) const {
VTR_ASSERT(timing_graph_.edge_type(edge) == tatum::EdgeType::INTERCONNECT);
auto& cluster_ctx = g_vpr_ctx.clustering();
std::vector<tatum::DelayComponent> components;
//We assume that the delay calculator has already cached all of the relevant delays,
//we just retrieve the cached values. This assumption greatly simplifies the calculation
//process and avoids us duplicating the complex delay calculation logic from the delay
//calcualtor.
//
//However note that this does couple this code tightly with the delay calculator implementation.
//Force delay calculation to ensure results are cached (redundant if already up-to-date)
delay_calc_.atom_net_delay(timing_graph_, edge, delay_type);
ClusterPinId src_pin = ClusterPinId::INVALID();
ClusterPinId sink_pin = ClusterPinId::INVALID();
std::tie(src_pin, sink_pin) = delay_calc_.get_cached_pins(edge, delay_type);
if (!src_pin && !sink_pin) {
//Cluster internal
tatum::NodeId node = timing_graph_.edge_sink_node(edge);
AtomPinId atom_pin = netlist_lookup_.tnode_atom_pin(node);
AtomBlockId atom_blk = netlist_.pin_block(atom_pin);
ClusterBlockId clb_blk = netlist_lookup_.atom_clb(atom_blk);
tatum::DelayComponent internal_component;
//internal_component.inst_name = cluster_ctx.clb_nlist.block_name(clb_blk);
internal_component.type_name = "intra '";
internal_component.type_name += cluster_ctx.clb_nlist.block_type(clb_blk)->name;
internal_component.type_name += "' routing";
internal_component.delay = delay_calc_.get_cached_delay(edge, delay_type);
components.push_back(internal_component);
} else {
//Cluster external
VTR_ASSERT(src_pin);
VTR_ASSERT(sink_pin);
ClusterBlockId src_blk = cluster_ctx.clb_nlist.pin_block(src_pin);
ClusterBlockId sink_blk = cluster_ctx.clb_nlist.pin_block(sink_pin);
tatum::Time driver_clb_delay = delay_calc_.get_driver_clb_cached_delay(edge, delay_type);
tatum::Time sink_clb_delay = delay_calc_.get_sink_clb_cached_delay(edge, delay_type);
ClusterNetId src_net = cluster_ctx.clb_nlist.pin_net(src_pin);
VTR_ASSERT(src_net == cluster_ctx.clb_nlist.pin_net(sink_pin));
tatum::Time net_delay = tatum::Time(delay_calc_.inter_cluster_delay(src_net,
0,
cluster_ctx.clb_nlist.pin_net_index(sink_pin)));
VTR_ASSERT(driver_clb_delay.valid());
VTR_ASSERT(net_delay.valid());
VTR_ASSERT(sink_clb_delay.valid());
tatum::DelayComponent driver_component;
//driver_component.inst_name = cluster_ctx.clb_nlist.block_name(src_blk);
driver_component.type_name = "intra '";
driver_component.type_name += cluster_ctx.clb_nlist.block_type(src_blk)->name;
driver_component.type_name += "' routing";
driver_component.delay = driver_clb_delay;
components.push_back(driver_component);
tatum::DelayComponent net_component;
//net_component.inst_name = cluster_ctx.clb_nlist.net_name(src_net);
net_component.type_name = "inter-block routing";
net_component.delay = net_delay;
components.push_back(net_component);
tatum::DelayComponent sink_component;
//sink_component.inst_name = cluster_ctx.clb_nlist.block_name(sink_blk);
sink_component.type_name = "intra '";
sink_component.type_name += cluster_ctx.clb_nlist.block_type(sink_blk)->name;
sink_component.type_name += "' routing";
sink_component.delay = sink_clb_delay;
components.push_back(sink_component);
}
return components;
}
e_timing_report_detail VprTimingGraphResolver::detail_level() const {
return detail_level_;
}
void VprTimingGraphResolver::set_detail_level(e_timing_report_detail report_detail) {
detail_level_ = report_detail;
}