blob: 3fa6fb2bfa718ed9b47f87937f775d7d12056d0b [file] [log] [blame]
#include <cstdio>
using namespace std;
#include "vtr_memory.h"
#include "vtr_log.h"
#include "vpr_types.h"
#include "vpr_error.h"
#include "globals.h"
#include "net_delay.h"
#include "route_tree_timing.h"
/* This module keeps track of the time delays for signals to arrive at *
* each pin in every net after timing-driven routing is complete. It *
* achieves this by first constructing the skeleton route tree *
* from the traceback. Next, to obtain the completed route tree, it *
* calls functions to calculate the resistance, capacitance, and time *
* delays associated with each node. Then, it recursively traverses *
* the tree, copying the time delay from each node into the *
* net_delay data structure. Essentially, the delays are calculated *
* by building the completed route tree from scratch, and is used *
* to check against the time delays computed incrementally during *
* timing-driven routing. */
/********************** Variables local to this module ***********************/
/* Unordered map below stores the pair whose key is the index of the rr_node *
* that corresponds to the rt_node, and whose value is the time delay *
* associated with that node. The map will be used to store delays while *
* traversing the nodes of the route tree in load_one_net_delay_recurr. */
static std::unordered_map<int, float> inode_to_Tdel_map;
/*********************** Subroutines local to this module ********************/
static void load_one_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id);
static void load_one_net_delay_recurr(t_rt_node* node, ClusterNetId net_id);
static void load_one_constant_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id, float delay_value);
/*************************** Subroutine definitions **************************/
/* Allocates space for the net_delay data structure *
* [0..nets.size()-1][1..num_pins-1]. I chunk the data *
* to save space on large problems. */
vtr::vector<ClusterNetId, float*> alloc_net_delay(vtr::t_chunk* chunk_list_ptr) {
auto& cluster_ctx = g_vpr_ctx.clustering();
vtr::vector<ClusterNetId, float*> net_delay; /* [0..nets.size()-1][1..num_pins-1] */
auto nets = cluster_ctx.clb_nlist.nets();
net_delay.resize(nets.size());
for (auto net_id : nets) {
float* tmp_ptr = (float*)vtr::chunk_malloc(cluster_ctx.clb_nlist.net_sinks(net_id).size() * sizeof(float), chunk_list_ptr);
net_delay[net_id] = tmp_ptr - 1; /* [1..num_pins-1] */
//Ensure the net delays are initialized with non-garbage values
for (size_t ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ++ipin) {
net_delay[net_id][ipin] = std::numeric_limits<float>::quiet_NaN();
}
}
return (net_delay);
}
void free_net_delay(vtr::vector<ClusterNetId, float*>& net_delay,
vtr::t_chunk* chunk_list_ptr) {
net_delay.clear();
vtr::free_chunk_memory(chunk_list_ptr);
}
void load_net_delay_from_routing(vtr::vector<ClusterNetId, float*>& net_delay) {
/* This routine loads net_delay[0..nets.size()-1][1..num_pins-1]. Each entry *
* is the Elmore delay from the net source to the appropriate sink. Both *
* the rr_graph and the routing traceback must be completely constructed *
* before this routine is called, and the net_delay array must have been *
* allocated. */
auto& cluster_ctx = g_vpr_ctx.clustering();
for (auto net_id : cluster_ctx.clb_nlist.nets()) {
if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) {
load_one_constant_net_delay(net_delay, net_id, 0.);
} else {
load_one_net_delay(net_delay, net_id);
}
}
}
static void load_one_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id) {
/* This routine loads delay values for one net in *
* net_delay[net_id][1..num_pins-1]. First, from the traceback, it *
* constructs the route tree and computes its values for R, C, and Tdel. *
* Next, it walks the route tree recursively, storing the time delays for *
* each node into the map inode_to_Tdel. Then, while looping through the *
* net_delay array we search for the inode corresponding to the pin *
* identifiers, and correspondingly update the entry in net_delay. *
* Finally, it frees the route tree and clears the inode_to_Tdel_map *
* associated with that net. */
auto& route_ctx = g_vpr_ctx.routing();
if (route_ctx.trace[net_id].head == nullptr) {
VPR_FATAL_ERROR(VPR_ERROR_TIMING,
"in load_one_net_delay: Traceback for net %lu does not exist.\n", size_t(net_id));
}
auto& cluster_ctx = g_vpr_ctx.clustering();
int inode;
t_rt_node* rt_root = traceback_to_route_tree(net_id); // obtain the root of the tree constructed from the traceback
load_new_subtree_R_upstream(rt_root); // load in the resistance values for the route tree
load_new_subtree_C_downstream(rt_root); // load in the capacitance values for the route tree
load_route_tree_Tdel(rt_root, 0.); // load the time delay values for the route tree
load_one_net_delay_recurr(rt_root, net_id); // recursively traverse the tree and load entries into the inode_to_Tdel map
for (unsigned int ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++) {
inode = route_ctx.net_rr_terminals[net_id][ipin]; // look for the index of the rr node that corresponds to the sink that was used to route a certain connection.
net_delay[net_id][ipin] = inode_to_Tdel_map.find(inode)->second; // search for the value of Tdel in the inode map and load into net_delay
}
free_route_tree(rt_root); // free the route tree
inode_to_Tdel_map.clear(); // clear the map
}
static void load_one_net_delay_recurr(t_rt_node* node, ClusterNetId net_id) {
/* This routine recursively traverses the route tree, and copies the Tdel of the node into the map. */
inode_to_Tdel_map[node->inode] = node->Tdel; // add to the map, process current node
for (t_linked_rt_edge* edge = node->u.child_list; edge != nullptr; edge = edge->next) { // process children
load_one_net_delay_recurr(edge->child, net_id);
}
}
static void load_one_constant_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id, float delay_value) {
/* Sets each entry of the net_delay array for net inet to delay_value. */
auto& cluster_ctx = g_vpr_ctx.clustering();
for (unsigned int ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++)
net_delay[net_id][ipin] = delay_value;
}