VPR-6.0

vpr/SRC/timing/path_delay.c File Reference

#include <stdio.h>
#include <string.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "path_delay.h"
#include "path_delay2.h"
#include "net_delay.h"
#include "vpr_utils.h"
#include <assert.h>
#include "read_xml_arch_file.h"
Include dependency graph for path_delay.c:

Go to the source code of this file.

Defines

#define T_CONSTANT_GENERATOR   -1000

Enumerations

enum  e_subblock_pin_type { SUB_INPUT = 0, SUB_OUTPUT, SUB_CLOCK, NUM_SUB_PIN_TYPES }

Functions

static float ** alloc_net_slack ()
static void compute_net_slacks (float **net_slack)
static void build_cb_tnodes (int iblk)
static void alloc_and_load_tnodes (t_timing_inf timing_inf)
static void alloc_and_load_tnodes_from_prepacked_netlist (float block_delay, float inter_cluster_net_delay)
static void load_tnode (INP t_pb_graph_pin *pb_graph_pin, INP int iblock, INOUTP int *inode, INP t_timing_inf timing_inf)
static void normalize_costs (float t_crit, long max_critical_input_paths, long max_critical_output_paths)
static void print_primitive_as_blif (FILE *fpout, int iblk)
float ** alloc_and_load_timing_graph (t_timing_inf timing_inf)
float ** alloc_and_load_pre_packing_timing_graph (float block_delay, float inter_cluster_net_delay, t_model *models)
void load_timing_graph_net_delays (float **net_delay)
void free_timing_graph (float **net_slack)
void print_net_slack (char *fname, float **net_slack)
void print_timing_graph (char *fname)
float load_net_slack (float **net_slack, float target_cycle_time)
void print_critical_path (char *fname)
t_linked_intallocate_and_load_critical_path (void)
void get_tnode_block_and_output_net (int inode, int *iblk_ptr, int *inet_ptr)
void do_constant_net_delay_timing_analysis (t_timing_inf timing_inf, float constant_net_delay_value)
void print_timing_graph_as_blif (char *fname, t_model *models)

Variables

static struct s_nettiming_nets = NULL
static int num_timing_nets = 0
static struct s_linked_vptrtedge_ch_list_head = NULL
static int tedge_ch_bytes_avail = 0
static char * tedge_ch_next_avail = NULL

Define Documentation

#define T_CONSTANT_GENERATOR   -1000

Essentially -ve infinity

Definition at line 77 of file path_delay.c.


Enumeration Type Documentation

Enumerator:
SUB_INPUT 
SUB_OUTPUT 
SUB_CLOCK 
NUM_SUB_PIN_TYPES 

Definition at line 81 of file path_delay.c.


Function Documentation

float** alloc_and_load_pre_packing_timing_graph ( float  block_delay,
float  inter_cluster_net_delay,
t_model models 
)

This routine builds the graph used for timing analysis. Every technology mapped netlist pin is a timing node (tnode). The connectivity between pins is represented by timing edges (tedges). All delay is marked on edges, not on nodes. This routine returns an array that will store slack values: net_slack[0..num_nets-1][1..num_pins-1].

Definition at line 172 of file path_delay.c.

{

/* The are below are valid only for CBs, not pads.                  */
    
/* Array for mapping from a pin on a block to a tnode index. For pads, only *
 * the first two pin locations are used (input to pad is first, output of   *
 * pad is second).  For CLBs, all OPEN pins on the cb have their mapping   *
 * set to OPEN so I won't use it by mistake.                                */

    int num_sinks;

        float **net_slack;

/************* End of variable declarations ********************************/

    if(tedge_ch_list_head != NULL)
        {
            printf("Error in alloc_and_load_timing_graph:\n"
                   "\tAn old timing graph still exists.\n");
            exit(1);
        }

        num_timing_nets = num_logical_nets;
        timing_nets = vpack_net;

        alloc_and_load_tnodes_from_prepacked_netlist(block_delay, inter_cluster_net_delay);

    num_sinks = alloc_and_load_timing_graph_levels();

        net_slack = alloc_net_slack();

        #ifdef CREATE_ECHO_FILES
                print_timing_graph("pre_packing_timing_graph.echo");
                print_timing_graph_as_blif("pre_packing_timing_graph_as_blif.blif", models);
        #endif

        check_timing_graph(num_sinks);

        return net_slack;
}

Here is the call graph for this function:

Here is the caller graph for this function:

float** alloc_and_load_timing_graph ( t_timing_inf  timing_inf)

This routine builds the graph used for timing analysis. Every cb pin is a timing node (tnode). The connectivity between pins is represented by timing edges (tedges). All delay is marked on edges, not on nodes. This routine returns an array that will store slack values: net_slack[0..num_nets-1][1..num_pins-1].

Definition at line 127 of file path_delay.c.

{

/* The are below are valid only for CBs, not pads.                  */

/* Array for mapping from a pin on a block to a tnode index. For pads, only *
 * the first two pin locations are used (input to pad is first, output of   *
 * pad is second).  For CLBs, all OPEN pins on the cb have their mapping   *
 * set to OPEN so I won't use it by mistake.                                */

    int num_sinks;
    float **net_slack;          /* [0..num_nets-1][1..num_pins-1]. */

/************* End of variable declarations ********************************/

    if(tedge_ch_list_head != NULL)
        {
            printf("Error in alloc_and_load_timing_graph:\n"
                   "\tAn old timing graph still exists.\n");
            exit(1);
        }
        num_timing_nets = num_nets;
        timing_nets = clb_net;

        alloc_and_load_tnodes(timing_inf);

    num_sinks = alloc_and_load_timing_graph_levels();

        #ifdef CREATE_ECHO_FILES
                print_timing_graph("initial_timing_graph.echo");
        #endif

        check_timing_graph(num_sinks);
        
    net_slack = alloc_net_slack();

        return (net_slack);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void alloc_and_load_tnodes ( t_timing_inf  timing_inf) [static]

Count # of tnodes, allocates space, and loads the tnodes and its associated edges

Definition at line 315 of file path_delay.c.

                                                           {
        int i, j, k;
        int inode;
        int num_nodes_in_block;
        int count;
        int iblock, irr_node;
        int inet, dport, dpin, dblock, dnode;
        int normalized_pin, normalization;
        t_pb_graph_pin *ipb_graph_pin;
        t_rr_node *local_rr_graph, *d_rr_graph;

        net_to_driver_tnode = my_malloc(num_timing_nets * sizeof(int));

        for(i = 0; i < num_timing_nets; i++) {
                net_to_driver_tnode[i] = OPEN;
        }

        /* allocate space for tnodes */
        num_tnodes = 0;
        for(i = 0; i < num_blocks; i++) {
                num_nodes_in_block = 0;
                for(j = 0; j < block[i].pb->pb_graph_node->total_pb_pins; j++) {
                        if(block[i].pb->rr_graph[j].net_num != OPEN) {
                                if(block[i].pb->rr_graph[j].pb_graph_pin->type == PB_PIN_INPAD ||
                                   block[i].pb->rr_graph[j].pb_graph_pin->type == PB_PIN_OUTPAD ||
                                   block[i].pb->rr_graph[j].pb_graph_pin->type == PB_PIN_SEQUENTIAL) {
                                        num_nodes_in_block += 2;
                                } else {
                                        num_nodes_in_block++;
                                }
                        }
                }
                num_tnodes += num_nodes_in_block;
        }
        tnode = my_calloc(num_tnodes, sizeof(t_tnode));

        /* load tnodes with all info except edge info */
        /* populate tnode lookups for edge info */
        inode = 0;
        for(i = 0; i < num_blocks; i++) {
                for(j = 0; j < block[i].pb->pb_graph_node->total_pb_pins; j++) {
                        if(block[i].pb->rr_graph[j].net_num != OPEN) {
                                assert(tnode[inode].pb_graph_pin == NULL);
                                load_tnode(block[i].pb->rr_graph[j].pb_graph_pin, i, &inode, timing_inf);                       
                        }
                }
        }
        assert(inode == num_tnodes);

        /* load edge delays */
        for(i = 0; i < num_tnodes; i++) {
                /* 3 primary scenarios for edge delays
                1.  Point-to-point delays inside block
                2.  
                */
                count = 0;
                iblock = tnode[i].block;
                switch (tnode[i].type) {
                        case INPAD_OPIN:
                        case INTERMEDIATE_NODE:
                        case PRIMITIVE_OPIN:
                        case FF_OPIN:
                        case CB_IPIN:
                                /* fanout is determined by intra-cluster connections */
                                /* Allocate space for edges  */
                                irr_node = tnode[i].pb_graph_pin->pin_count_in_cluster;
                                local_rr_graph = block[iblock].pb->rr_graph;
                                ipb_graph_pin = local_rr_graph[irr_node].pb_graph_pin;

                                if(ipb_graph_pin->parent_node->pb_type->max_internal_delay != UNDEFINED) {
                                        if(pb_max_internal_delay == UNDEFINED) {
                                                pb_max_internal_delay = ipb_graph_pin->parent_node->pb_type->max_internal_delay;
                                                pbtype_max_internal_delay = ipb_graph_pin->parent_node->pb_type;
                                        } else if(pb_max_internal_delay < ipb_graph_pin->parent_node->pb_type->max_internal_delay) {
                                                pb_max_internal_delay = ipb_graph_pin->parent_node->pb_type->max_internal_delay;
                                                pbtype_max_internal_delay = ipb_graph_pin->parent_node->pb_type;
                                        }
                                }

                                for(j = 0; j < block[iblock].pb->rr_graph[irr_node].num_edges; j++) {
                                        dnode = local_rr_graph[irr_node].edges[j];
                                        if((local_rr_graph[dnode].prev_node == irr_node) && (j == local_rr_graph[dnode].prev_edge)) {
                                                count++;
                                        }
                                }
                                assert(count > 0);
                                tnode[i].num_edges = count;
                                tnode[i].out_edges = (t_tedge *) my_chunk_malloc(count *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);

                                /* Load edges */
                                count = 0;
                                for(j = 0; j < local_rr_graph[irr_node].num_edges; j++) {
                                        dnode = local_rr_graph[irr_node].edges[j];
                                        if((local_rr_graph[dnode].prev_node == irr_node) && (j == local_rr_graph[dnode].prev_edge)) {
                                                assert((ipb_graph_pin->output_edges[j]->num_output_pins == 1) &&
                                                        (local_rr_graph[ipb_graph_pin->output_edges[j]->output_pins[0]->pin_count_in_cluster].net_num == local_rr_graph[irr_node].net_num));


                                                tnode[i].out_edges[count].Tdel = ipb_graph_pin->output_edges[j]->delay_max;
                                                tnode[i].out_edges[count].to_node = local_rr_graph[dnode].tnode->index;
                                                
                                                if(vpack_net[local_rr_graph[irr_node].net_num].is_const_gen == TRUE && tnode[i].type == PRIMITIVE_OPIN) {
                                                        tnode[i].out_edges[count].Tdel = T_CONSTANT_GENERATOR;
                                                        tnode[i].type = CONSTANT_GEN_SOURCE;
                                                }
                                                
                                                count++;
                                        }
                                }
                                assert(count > 0);

                                break;
                        case PRIMITIVE_IPIN:
                                /* Pin info comes from pb_graph block delays
                                */
                                irr_node = tnode[i].pb_graph_pin->pin_count_in_cluster;
                                local_rr_graph = block[iblock].pb->rr_graph;
                                ipb_graph_pin = local_rr_graph[irr_node].pb_graph_pin;
                                tnode[i].num_edges = ipb_graph_pin->num_pin_timing;
                                tnode[i].out_edges = (t_tedge *) my_chunk_malloc(ipb_graph_pin->num_pin_timing *
                                                                                                sizeof(t_tedge),
                                                                                                &tedge_ch_list_head,
                                                                                                &tedge_ch_bytes_avail,
                                                                                                &tedge_ch_next_avail);                                  
                                k = 0;

                                for(j = 0; j < tnode[i].num_edges; j++) {
                                        /* Some outpins aren't used, ignore these.  Only consider output pins that are used */
                                        if(local_rr_graph[ipb_graph_pin->pin_timing[j]->pin_count_in_cluster].net_num != OPEN) {
                                                tnode[i].out_edges[k].Tdel = ipb_graph_pin->pin_timing_del_max[j];
                                                tnode[i].out_edges[k].to_node = local_rr_graph[ipb_graph_pin->pin_timing[j]->pin_count_in_cluster].tnode->index;
                                                assert(tnode[i].out_edges[k].to_node != OPEN);
                                                k++;
                                        }
                                }
                                tnode[i].num_edges -= (j - k); /* remove unused edges */
                                if(tnode[i].num_edges == 0) {
                                        printf(ERRTAG "No timing information for pin %s.%s[%d]\n", tnode[i].pb_graph_pin->parent_node->pb_type->name, tnode[i].pb_graph_pin->port->name,tnode[i].pb_graph_pin->pin_number);
                                        exit(1);
                                }
                                break;
                        case CB_OPIN:
                                /* load up net info */
                                irr_node = tnode[i].pb_graph_pin->pin_count_in_cluster;
                                local_rr_graph = block[iblock].pb->rr_graph;
                                ipb_graph_pin = local_rr_graph[irr_node].pb_graph_pin;
                                assert(local_rr_graph[irr_node].net_num != OPEN);
                                inet = vpack_to_clb_net_mapping[local_rr_graph[irr_node].net_num];
                                assert(inet != OPEN);
                                net_to_driver_tnode[inet] = i;
                                tnode[i].num_edges = clb_net[inet].num_sinks;
                                tnode[i].out_edges = (t_tedge *) my_chunk_malloc(clb_net[inet].num_sinks *
                                                                                                sizeof(t_tedge),
                                                                                                &tedge_ch_list_head,
                                                                                                &tedge_ch_bytes_avail,
                                                                                                &tedge_ch_next_avail);                                  
                                for(j = 1; j <= clb_net[inet].num_sinks; j++) {
                                        dblock = clb_net[inet].node_block[j];
                                        normalization = block[dblock].type->num_pins / block[dblock].type->capacity;
                                        normalized_pin = clb_net[inet].node_block_pin[j] % normalization;
                                        d_rr_graph = block[dblock].pb->rr_graph;
                                        dpin = OPEN;
                                        dport = OPEN;
                                        count = 0;

                                        for(k = 0; k < block[dblock].pb->pb_graph_node->num_input_ports && dpin == OPEN; k++) {
                                                if(normalized_pin >= count && (count + block[dblock].pb->pb_graph_node->num_input_pins[k] > normalized_pin)) {
                                                        dpin = normalized_pin - count;
                                                        dport = k;
                                                        break;
                                                }
                                                count += block[dblock].pb->pb_graph_node->num_input_pins[k];
                                        }
                                        if(dpin == OPEN) {
                                                for(k = 0; k < block[dblock].pb->pb_graph_node->num_output_ports && dpin == OPEN; k++) {
                                                        count += block[dblock].pb->pb_graph_node->num_output_pins[k];
                                                }
                                                for(k = 0; k < block[dblock].pb->pb_graph_node->num_clock_ports && dpin == OPEN; k++) {
                                                        if(normalized_pin >= count && (count + block[dblock].pb->pb_graph_node->num_clock_pins[k] > normalized_pin)) {
                                                                dpin = normalized_pin - count;
                                                                dport = k;                                                              
                                                        }
                                                        count += block[dblock].pb->pb_graph_node->num_clock_pins[k];
                                                }
                                                assert(dpin != OPEN);
                                                assert(inet == vpack_to_clb_net_mapping[d_rr_graph[block[dblock].pb->pb_graph_node->clock_pins[dport][dpin].pin_count_in_cluster].net_num]);                                            
                                                tnode[i].out_edges[j-1].to_node = d_rr_graph[block[dblock].pb->pb_graph_node->clock_pins[dport][dpin].pin_count_in_cluster].tnode->index;
                                        } else {
                                                assert(dpin != OPEN);
                                                assert(inet == vpack_to_clb_net_mapping[d_rr_graph[block[dblock].pb->pb_graph_node->input_pins[dport][dpin].pin_count_in_cluster].net_num]);
                                                /* delays are assigned post routing */
                                                tnode[i].out_edges[j-1].to_node = d_rr_graph[block[dblock].pb->pb_graph_node->input_pins[dport][dpin].pin_count_in_cluster].tnode->index;
                                        }
                                        assert(inet != OPEN);
                                }
                                break;
                        case OUTPAD_IPIN:
                        case INPAD_SOURCE:
                        case OUTPAD_SINK:
                        case FF_SINK:
                        case FF_SOURCE:
                        case FF_IPIN:
                                break;
                        default:
                                printf(ERRTAG "Consistency check failed: Unknown tnode type %d\n", tnode[i].type);
                                assert(0);
                        break;
                }
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void alloc_and_load_tnodes_from_prepacked_netlist ( float  block_delay,
float  inter_cluster_net_delay 
) [static]

Allocate timing graph for pre packed netlist. Count number of tnodes first. Then connect up tnodes with edges.

Definition at line 534 of file path_delay.c.

                                                                                                           {
        int i, j, k;
        t_model *model;
        t_model_ports *model_port;
        int inode, inet, iblock;
        int incr;
        int count;

        net_to_driver_tnode = my_malloc(num_logical_nets * sizeof(int));

        for(i = 0; i < num_logical_nets; i++) {
                net_to_driver_tnode[i] = OPEN;
        }

        
        /* allocate space for tnodes */
        num_tnodes = 0;
        for(i = 0; i < num_logical_blocks; i++) {
                model = logical_block[i].model;
                logical_block[i].clock_net_tnode = NULL;
                if(logical_block[i].type == VPACK_INPAD) {
                        logical_block[i].output_net_tnodes = my_calloc(1, sizeof(t_tnode**));
                        num_tnodes += 2;
                } else if(logical_block[i].type == VPACK_OUTPAD) {
                        logical_block[i].input_net_tnodes = my_calloc(1, sizeof(t_tnode**));
                        num_tnodes += 2;
                } else {                
                        if(logical_block[i].clock_net == OPEN) {
                                incr = 1;
                        } else {
                                incr = 2;
                        }
                        j = 0;
                        model_port = model->inputs;
                        while(model_port) {
                                if(model_port->is_clock == FALSE) {
                                        for(k = 0; k < model_port->size; k++) {
                                                if(logical_block[i].input_nets[j][k] != OPEN) {
                                                        num_tnodes += incr;
                                                }
                                        }
                                        j++;
                                } else {
                                        num_tnodes++;
                                }                               
                                model_port = model_port->next;
                        }
                        logical_block[i].input_net_tnodes = my_calloc(j, sizeof(t_tnode**));
                        
                        j = 0;
                        model_port = model->outputs;
                        while(model_port) {
                                for(k = 0; k < model_port->size; k++) {
                                        if(logical_block[i].output_nets[j][k] != OPEN) {
                                                num_tnodes += incr;
                                        }
                                }
                                j++;
                                model_port = model_port->next;
                        }
                        logical_block[i].output_net_tnodes = my_calloc(j, sizeof(t_tnode**));
                }
        }
        tnode = my_calloc(num_tnodes, sizeof(t_tnode));
        for(i = 0; i < num_tnodes; i++) {
                tnode[i].index = i;
        }

        /* load tnodes, alloc edges for tnodes, load all known tnodes */
        inode = 0;
        for(i = 0; i < num_logical_blocks; i++) {
                model = logical_block[i].model;
                if(logical_block[i].type == VPACK_INPAD) {
                        logical_block[i].output_net_tnodes[0] = my_calloc(1, sizeof(t_tnode*));
                        logical_block[i].output_net_tnodes[0][0] = &tnode[inode];
                        net_to_driver_tnode[logical_block[i].output_nets[0][0]] = inode;
                        tnode[inode].model_pin = 0;
                        tnode[inode].model_port = 0;
                        tnode[inode].block = i;
                        tnode[inode].type = INPAD_OPIN;
                        
                        tnode[inode].num_edges = vpack_net[logical_block[i].output_nets[0][0]].num_sinks;
                        tnode[inode].out_edges = 
                                                                (t_tedge *) my_chunk_malloc(tnode[inode].num_edges *
                                                                                                sizeof(t_tedge),
                                                                                                &tedge_ch_list_head,
                                                                                                &tedge_ch_bytes_avail,
                                                                                                &tedge_ch_next_avail);
                        tnode[inode + 1].num_edges = 1;
                        tnode[inode + 1].out_edges = 
                                (t_tedge *) my_chunk_malloc(1 *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);
                        tnode[inode + 1].out_edges->Tdel = 0;
                        tnode[inode + 1].out_edges->to_node = inode;
                        tnode[inode + 1].T_req = 0;
                        tnode[inode + 1].T_arr = 0;
                        tnode[inode + 1].type = INPAD_SOURCE;
                        tnode[inode + 1].block = i;
                        inode += 2;
                } else if (logical_block[i].type == VPACK_OUTPAD) {
                        logical_block[i].input_net_tnodes[0] = my_calloc(1, sizeof(t_tnode*));
                        logical_block[i].input_net_tnodes[0][0] = &tnode[inode];
                        tnode[inode].model_pin = 0;
                        tnode[inode].model_port = 0;
                        tnode[inode].block = i;
                        tnode[inode].type = OUTPAD_IPIN;
                        tnode[inode].num_edges = 1;
                        tnode[inode].out_edges = 
                                (t_tedge *) my_chunk_malloc(1 *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);
                        tnode[inode].out_edges->Tdel = 0;
                        tnode[inode].out_edges->to_node = inode + 1;
                        tnode[inode + 1].T_req = 0;
                        tnode[inode + 1].T_arr = 0;
                        tnode[inode + 1].type = OUTPAD_SINK;
                        tnode[inode + 1].block = i;
                        tnode[inode + 1].num_edges = 0;
                        tnode[inode + 1].out_edges = NULL;
                        tnode[inode + 1].index = inode + 1;
                        inode += 2;
                } else {                
                        j = 0;
                        model_port = model->outputs;
                        count = 0;
                        while(model_port) {
                                logical_block[i].output_net_tnodes[j] = my_calloc(model_port->size, sizeof(t_tnode*));
                                for(k = 0; k < model_port->size; k++) {
                                        if(logical_block[i].output_nets[j][k] != OPEN) {
                                                count++;
                                                tnode[inode].model_pin = k;
                                                tnode[inode].model_port = j;
                                                tnode[inode].block = i;
                                                net_to_driver_tnode[logical_block[i].output_nets[j][k]] = inode;
                                                logical_block[i].output_net_tnodes[j][k] = &tnode[inode];
                                                        
                                                tnode[inode].num_edges = vpack_net[logical_block[i].output_nets[j][k]].num_sinks;
                                                tnode[inode].out_edges = 
                                                                (t_tedge *) my_chunk_malloc(tnode[inode].num_edges *
                                                                                                sizeof(t_tedge),
                                                                                                &tedge_ch_list_head,
                                                                                                &tedge_ch_bytes_avail,
                                                                                                &tedge_ch_next_avail);
                                                
                                                if (logical_block[i].clock_net == OPEN) {
                                                        tnode[inode].type = PRIMITIVE_OPIN;
                                                        inode++;
                                                } else {
                                                        tnode[inode].type = FF_OPIN;
                                                        tnode[inode + 1].num_edges = 1;
                                                        tnode[inode + 1].out_edges = 
                                                                (t_tedge *) my_chunk_malloc(1 *
                                                                                                sizeof(t_tedge),
                                                                                                &tedge_ch_list_head,
                                                                                                &tedge_ch_bytes_avail,
                                                                                                &tedge_ch_next_avail);
                                                        tnode[inode + 1].out_edges->to_node = inode;
                                                        tnode[inode + 1].out_edges->Tdel = 0;
                                                        tnode[inode + 1].type = FF_SOURCE;
                                                        tnode[inode + 1].block = i;
                                                        inode += 2;
                                                }
                                        }
                                }
                                j++;
                                model_port = model_port->next;
                        }

                        j = 0;                  
                        model_port = model->inputs;
                        while(model_port) {
                                if(model_port->is_clock == FALSE) {
                                        logical_block[i].input_net_tnodes[j] = my_calloc(model_port->size, sizeof(t_tnode*));
                                        for(k = 0; k < model_port->size; k++) {
                                                if(logical_block[i].input_nets[j][k] != OPEN) {
                                                        tnode[inode].model_pin = k;
                                                        tnode[inode].model_port = j;
                                                        tnode[inode].block = i;
                                                        logical_block[i].input_net_tnodes[j][k] = &tnode[inode];
                                                                
                                                        if (logical_block[i].clock_net == OPEN) {
                                                                tnode[inode].type = PRIMITIVE_IPIN;
                                                                tnode[inode].out_edges = 
                                                                                (t_tedge *) my_chunk_malloc(count *
                                                                                                                sizeof(t_tedge),
                                                                                                                &tedge_ch_list_head,
                                                                                                                &tedge_ch_bytes_avail,
                                                                                                                &tedge_ch_next_avail);
                                                                tnode[inode].num_edges = count;
                                                                inode++;
                                                        } else {
                                                                tnode[inode].type = FF_IPIN;
                                                                tnode[inode].num_edges = 1;
                                                                tnode[inode].out_edges = 
                                                                        (t_tedge *) my_chunk_malloc(1 *
                                                                                                        sizeof(t_tedge),
                                                                                                        &tedge_ch_list_head,
                                                                                                        &tedge_ch_bytes_avail,
                                                                                                        &tedge_ch_next_avail);
                                                                tnode[inode].out_edges->to_node = inode + 1;
                                                                tnode[inode].out_edges->Tdel = 0;
                                                                tnode[inode + 1].type = FF_SINK;
                                                                tnode[inode + 1].num_edges = 0;
                                                                tnode[inode + 1].out_edges = NULL;
                                                                inode += 2;
                                                        }
                                                }
                                        }                                       
                                        j++;
                                } else {
                                        if(logical_block[i].clock_net != OPEN) {
                                                assert(logical_block[i].clock_net_tnode == NULL);
                                                logical_block[i].clock_net_tnode = &tnode[inode];
                                                tnode[inode].block = i;
                                                tnode[inode].model_pin = 0;
                                                tnode[inode].model_port = 0;
                                                tnode[inode].num_edges = 0;
                                                tnode[inode].out_edges = NULL;
                                                tnode[inode].type = FF_SINK;
                                                inode++;
                                        }
                                }
                                model_port = model_port->next;
                        }
                }
        }
        assert(inode == num_tnodes);

        /* load edge delays */
        for(i = 0; i < num_tnodes; i++) {
                /* 3 primary scenarios for edge delays
                1.  Point-to-point delays inside block
                2.  
                */
                count = 0;
                iblock = tnode[i].block;
                switch (tnode[i].type) {
                        case INPAD_OPIN:
                        case PRIMITIVE_OPIN:
                        case FF_OPIN:
                                /* fanout is determined by intra-cluster connections */
                                /* Allocate space for edges  */
                                inet = logical_block[tnode[i].block].output_nets[tnode[i].model_port][tnode[i].model_pin];
                                assert(inet != OPEN);
                
                                for(j = 1; j <= vpack_net[inet].num_sinks; j++) {
                                        if(vpack_net[inet].is_const_gen) {
                                                tnode[i].out_edges[j - 1].Tdel = T_CONSTANT_GENERATOR;
                                                tnode[i].type = CONSTANT_GEN_SOURCE;
                                        } else {
                                                tnode[i].out_edges[j - 1].Tdel = inter_cluster_net_delay;                                               
                                        }
                                        assert(logical_block[vpack_net[inet].node_block[j]].input_net_tnodes[vpack_net[inet].node_block_port[j]][vpack_net[inet].node_block_pin[j]] != NULL);
                                        if(vpack_net[inet].is_global) {
                                                assert(logical_block[vpack_net[inet].node_block[j]].clock_net == inet);
                                                tnode[i].out_edges[j - 1].to_node = logical_block[vpack_net[inet].node_block[j]].clock_net_tnode->index;
                                        } else {
                                                tnode[i].out_edges[j - 1].to_node = logical_block[vpack_net[inet].node_block[j]].input_net_tnodes[vpack_net[inet].node_block_port[j]][vpack_net[inet].node_block_pin[j]]->index;
                                        }
                                }
                                assert(tnode[i].num_edges == vpack_net[inet].num_sinks);
                                break;
                        case PRIMITIVE_IPIN:
                                model_port = logical_block[iblock].model->outputs;
                                count = 0;
                                j = 0;
                                while(model_port) {
                                        for(k = 0; k < model_port->size; k++) {
                                                if(logical_block[iblock].output_nets[j][k] != OPEN) {
                                                        tnode[i].out_edges[count].Tdel = block_delay;
                                                        tnode[i].out_edges[count].to_node = logical_block[iblock].output_net_tnodes[j][k]->index;
                                                        count++;                                                        
                                                }
                                                else {
                                                        assert(logical_block[iblock].output_net_tnodes[j][k] == NULL);
                                                }
                                        }
                                        j++;
                                        model_port = model_port->next;
                                }
                                assert(count == tnode[i].num_edges);
                                break;
                        case OUTPAD_IPIN:
                        case INPAD_SOURCE:
                        case OUTPAD_SINK:
                        case FF_SINK:
                        case FF_SOURCE:
                        case FF_IPIN:
                                break;
                        default:
                                printf(ERRTAG "Consistency check failed: Unknown tnode type %d\n", tnode[i].type);
                                assert(0);
                        break;
                }
        }

        for(i = 0; i < num_logical_nets; i++) {
                assert(net_to_driver_tnode[i] != OPEN);
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static float ** alloc_net_slack ( ) [static]

Allocates the net_slack structure. Chunk allocated to save space.

Definition at line 217 of file path_delay.c.

{
    float **net_slack;          /* [0..num_nets-1][1..num_pins-1]  */
    int inet, j;

    net_slack = (float **)my_malloc(num_timing_nets * sizeof(float *));

    for(inet = 0; inet < num_timing_nets; inet++)
        {
            net_slack[inet] = (float *)my_chunk_malloc((timing_nets[inet].num_sinks + 1) *
                                         sizeof(float), &tedge_ch_list_head,
                                         &tedge_ch_bytes_avail,
                                         &tedge_ch_next_avail);
                for(j = 0; j <= timing_nets[inet].num_sinks; j++) {
                        net_slack[inet][j] = UNDEFINED;
                }
        }

    return (net_slack);
}

Here is the call graph for this function:

Here is the caller graph for this function:

t_linked_int* allocate_and_load_critical_path ( void  )

Finds the critical path and puts a list of the tnodes on the critical path in a linked list, from the path SOURCE to the path SINK.

Definition at line 1286 of file path_delay.c.

{

    t_linked_int *critical_path_head, *curr_crit_node, *prev_crit_node;
    int inode, iedge, to_node, num_at_level, i, crit_node, num_edges;
    float min_slack, slack;
    t_tedge *tedge;

    num_at_level = tnodes_at_level[0].nelem;
    min_slack = HUGE_FLOAT;
    crit_node = OPEN;           /* Stops compiler warnings. */

    for(i = 0; i < num_at_level; i++)
        {                       /* Path must start at SOURCE (no inputs) */
            inode = tnodes_at_level[0].list[i];
            slack = tnode[inode].T_req - tnode[inode].T_arr;

            if(slack < min_slack)
                {
                    crit_node = inode;
                    min_slack = slack;
                }
        }

    critical_path_head = (t_linked_int *) my_malloc(sizeof(t_linked_int));
    critical_path_head->data = crit_node;
    prev_crit_node = critical_path_head;
    num_edges = tnode[crit_node].num_edges;

    while(num_edges != 0)
        {                       /* Path will end at SINK (no fanout) */
            curr_crit_node = (t_linked_int *) my_malloc(sizeof(t_linked_int));
            prev_crit_node->next = curr_crit_node;
            tedge = tnode[crit_node].out_edges;
            min_slack = HUGE_FLOAT;

            for(iedge = 0; iedge < num_edges; iedge++)
                {
                    to_node = tedge[iedge].to_node;
                    slack = tnode[to_node].T_req - tnode[to_node].T_arr;

                    if(slack < min_slack)
                        {
                            crit_node = to_node;
                            min_slack = slack;
                        }
                }

            curr_crit_node->data = crit_node;
            prev_crit_node = curr_crit_node;
            num_edges = tnode[crit_node].num_edges;
        }

    prev_crit_node->next = NULL;
    return (critical_path_head);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void build_cb_tnodes ( int  iblk) [static]
static void compute_net_slacks ( float **  net_slack) [static]

Puts the slack of each source-sink pair of block pins in net_slack.

Definition at line 1192 of file path_delay.c.

{
    int inet, iedge, inode, to_node, num_edges;
    t_tedge *tedge;
    float T_arr, Tdel, T_req;

    for(inet = 0; inet < num_timing_nets; inet++)
        {
            inode = net_to_driver_tnode[inet];
            T_arr = tnode[inode].T_arr;
            num_edges = tnode[inode].num_edges;
            tedge = tnode[inode].out_edges;

            for(iedge = 0; iedge < num_edges; iedge++)
                {
                    to_node = tedge[iedge].to_node;
                    Tdel = tedge[iedge].Tdel;
                    T_req = tnode[to_node].T_req;
                    net_slack[inet][iedge + 1] = T_req - T_arr - Tdel;
                }
        }
}

Here is the caller graph for this function:

void do_constant_net_delay_timing_analysis ( t_timing_inf  timing_inf,
float  constant_net_delay_value 
)

Does a timing analysis (simple) where it assumes that each net has a constant delay value. Used only when operation == TIMING_ANALYSIS_ONLY.

Definition at line 1379 of file path_delay.c.

{

    struct s_linked_vptr *net_delay_chunk_list_head;
    float **net_delay, **net_slack;

    float T_crit;

    net_slack = alloc_and_load_timing_graph(timing_inf);
    net_delay = alloc_net_delay(&net_delay_chunk_list_head, timing_nets, num_timing_nets);

    load_constant_net_delay(net_delay, constant_net_delay_value, timing_nets, num_timing_nets);
    load_timing_graph_net_delays(net_delay);
    T_crit = load_net_slack(net_slack, 0);

    printf("\n");
    printf("\nCritical Path: %g (s)\n", T_crit);

#ifdef CREATE_ECHO_FILES
    print_critical_path("critical_path.echo");
    print_timing_graph("timing_graph.echo");
    print_net_slack("net_slack.echo", net_slack);
    print_net_delay(net_delay, "net_delay.echo", timing_nets, num_timing_nets);
#endif /* CREATE_ECHO_FILES */

    free_timing_graph(net_slack);
    free_net_delay(net_delay, &net_delay_chunk_list_head);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void free_timing_graph ( float **  net_slack)

Frees the timing graph data.

Definition at line 265 of file path_delay.c.

{
    if(tedge_ch_list_head == NULL)
        {
            printf("Error in free_timing_graph: No timing graph to free.\n");
            exit(1);
        }

    free_chunk_memory(tedge_ch_list_head);
    free(tnode);
    free(net_to_driver_tnode);
    free_ivec_vector(tnodes_at_level, 0, num_tnode_levels - 1);
    free(net_slack);

    tedge_ch_list_head = NULL;
    tedge_ch_bytes_avail = 0;
    tedge_ch_next_avail = NULL;

    tnode = NULL;
    num_tnodes = 0;
    net_to_driver_tnode = NULL;
    tnodes_at_level = NULL;
    num_tnode_levels = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void get_tnode_block_and_output_net ( int  inode,
int *  iblk_ptr,
int *  inet_ptr 
)

Returns the index of the block that this tnode is part of. If the tnode is a CB_OPIN or INPAD_OPIN (i.e. if it drives a net), the net index is returned via inet_ptr. Otherwise inet_ptr points at OPEN.

Definition at line 1348 of file path_delay.c.

{

    int inet, ipin, iblk;
    t_tnode_type tnode_type;

    iblk = tnode[inode].block;
    tnode_type = tnode[inode].type;

    if(tnode_type == CB_OPIN)
        {
            ipin = tnode[inode].pb_graph_pin->pin_count_in_cluster;
                inet = block[iblk].pb->rr_graph[ipin].net_num;
                assert(inet != OPEN);
                inet = vpack_to_clb_net_mapping[inet];
        }
    else
        {
            inet = OPEN;
        }

    *iblk_ptr = iblk;
    *inet_ptr = inet;
}

Here is the caller graph for this function:

float load_net_slack ( float **  net_slack,
float  target_cycle_time 
)

Determines the slack of every source-sink pair of block pins in the circuit. The timing graph must have already been built. target_cycle_ time is the target delay for the circuit -- if 0, the target_cycle_time is set to the critical path found in the timing graph. This routine loads net_slack, and returns the current critical path delay.

Definition at line 1038 of file path_delay.c.

{

    float T_crit, T_arr, Tdel, T_cycle, T_req;
    int inode, ilevel, num_at_level, i, num_edges, iedge, to_node;
        int total;
    t_tedge *tedge;

/* Reset all arrival times to -ve infinity.  Can't just set to zero or the   *
 * constant propagation (constant generators work at -ve infinity) won't     *
 * work.                                                                     */

        long max_critical_input_paths = 0;
        long max_critical_output_paths = 0;

    for(inode = 0; inode < num_tnodes; inode++)
        tnode[inode].T_arr = T_CONSTANT_GENERATOR;

/* Compute all arrival times with a breadth-first analysis from inputs to   *
 * outputs.  Also compute critical path (T_crit).                           */

    T_crit = 0.;

/* Primary inputs arrive at T = 0. */

    num_at_level = tnodes_at_level[0].nelem;
    for(i = 0; i < num_at_level; i++)
        {
            inode = tnodes_at_level[0].list[i];
            tnode[inode].T_arr = 0.;
        }

        total = 0;
    for(ilevel = 0; ilevel < num_tnode_levels; ilevel++)
        {
            num_at_level = tnodes_at_level[ilevel].nelem;
                total += num_at_level;

            for(i = 0; i < num_at_level; i++)
                {
                    inode = tnodes_at_level[ilevel].list[i];
                        if(i == 0) {
                                tnode[i].num_critical_input_paths = 1;
                        }
                    T_arr = tnode[inode].T_arr;
                    num_edges = tnode[inode].num_edges;
                    tedge = tnode[inode].out_edges;
                    T_crit = max(T_crit, T_arr);

                    for(iedge = 0; iedge < num_edges; iedge++)
                        {
                            to_node = tedge[iedge].to_node;
                            Tdel = tedge[iedge].Tdel;

                                /* Update number of near critical paths entering tnode */
                                        /*check for approximate equality*/
                                if (fabs(tnode[to_node].T_arr - (T_arr + Tdel)) < EQUAL_DEF){
                                        tnode[to_node].num_critical_input_paths += tnode[inode].num_critical_input_paths;
                                }
                                else if (tnode[to_node].T_arr < T_arr + Tdel) {
                                        tnode[to_node].num_critical_input_paths = tnode[inode].num_critical_input_paths;
                                }

                                if (tnode[to_node].num_critical_input_paths > max_critical_input_paths)
                                        max_critical_input_paths = tnode[to_node].num_critical_input_paths;


                            tnode[to_node].T_arr =
                                max(tnode[to_node].T_arr, T_arr + Tdel);
                        }
                }

        }
        assert(total == num_tnodes);

    if(target_cycle_time > 0.)  /* User specified target cycle time */
        T_cycle = target_cycle_time;
    else                        /* Otherwise, target = critical path */
        T_cycle = T_crit;

/* Compute the required arrival times with a backward breadth-first analysis *
 * from sinks (output pads, etc.) to primary inputs.                         */

    for(ilevel = num_tnode_levels - 1; ilevel >= 0; ilevel--)
        {
            num_at_level = tnodes_at_level[ilevel].nelem;

            for(i = 0; i < num_at_level; i++)
                {
                    inode = tnodes_at_level[ilevel].list[i];
                    num_edges = tnode[inode].num_edges;

                        if(ilevel == 0) {                               
                                assert(tnode[inode].type == INPAD_SOURCE || tnode[inode].type == FF_SOURCE || tnode[inode].type == CONSTANT_GEN_SOURCE);
                        } else {
                                assert(!(tnode[inode].type == INPAD_SOURCE || tnode[inode].type == FF_SOURCE || tnode[inode].type == CONSTANT_GEN_SOURCE));
                        }

                    if(num_edges == 0)
                        {       /* sink */
                                assert(tnode[inode].type == OUTPAD_SINK || tnode[inode].type == FF_SINK);
                            tnode[inode].T_req = T_cycle;
                                tnode[inode].num_critical_output_paths = 1;
                        }
                    else
                        {
                                assert(!(tnode[inode].type == OUTPAD_SINK || tnode[inode].type == FF_SINK));
                            tedge = tnode[inode].out_edges;
                            to_node = tedge[0].to_node;
                            Tdel = tedge[0].Tdel;
                            T_req = tnode[to_node].T_req - Tdel;

                                tnode[inode].num_critical_output_paths = tnode[to_node].num_critical_output_paths;
                                if (tnode[to_node].num_critical_output_paths > max_critical_output_paths)
                                        max_critical_output_paths = tnode[to_node].num_critical_output_paths;

                            for(iedge = 1; iedge < num_edges; iedge++)
                                {
                                    to_node = tedge[iedge].to_node;
                                    Tdel = tedge[iedge].Tdel;

                                        /* Update number of near critical paths affected by output of tnode */
                                                /*check for approximate equality*/
                                        if (fabs(tnode[to_node].T_req - Tdel - T_req) < EQUAL_DEF){
                                                tnode[inode].num_critical_output_paths += tnode[to_node].num_critical_output_paths;
                                        }
                                        else if (tnode[to_node].T_req - Tdel < T_req) {
                                                tnode[inode].num_critical_output_paths = tnode[to_node].num_critical_output_paths;
                                        }

                                        if (tnode[to_node].num_critical_output_paths > max_critical_output_paths)
                                                max_critical_output_paths = tnode[to_node].num_critical_output_paths;

                                    T_req =
                                        min(T_req,
                                            tnode[to_node].T_req - Tdel);
                                }

                            tnode[inode].T_req = T_req;
                        }
                }
        }

        normalize_costs(T_crit, max_critical_input_paths, max_critical_output_paths);

    compute_net_slacks(net_slack);

    return (T_crit);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void load_timing_graph_net_delays ( float **  net_delay)

Sets the delays of the inter-CLB nets to the values specified by net_delay[0..num_nets-1][1..num_pins-1]. These net delays should have been allocated and loaded with the net_delay routines. This routine marks the corresponding edges in the timing graph with the proper delay.

Definition at line 244 of file path_delay.c.

{
    int inet, ipin, inode;
    t_tedge *tedge;

    for(inet = 0; inet < num_timing_nets; inet++)
        {
            inode = net_to_driver_tnode[inet];
            tedge = tnode[inode].out_edges;

/* Note that the edges of a tnode corresponding to a CLB or INPAD opin must  *
 * be in the same order as the pins of the net driven by the tnode.          */

            for(ipin = 1; ipin < (timing_nets[inet].num_sinks + 1); ipin++)
                tedge[ipin - 1].Tdel = net_delay[inet][ipin];
        }
}

Here is the caller graph for this function:

static void load_tnode ( INP t_pb_graph_pin pb_graph_pin,
INP int  iblock,
INOUTP int *  inode,
INP t_timing_inf  timing_inf 
) [static]

Definition at line 840 of file path_delay.c.

                                                                                                                         {
        int i;
        i = *inode;
        tnode[i].pb_graph_pin = pb_graph_pin;
        tnode[i].block = iblock;
        tnode[i].index = i;
        block[iblock].pb->rr_graph[pb_graph_pin->pin_count_in_cluster].tnode = &tnode[i];
        if(tnode[i].pb_graph_pin->parent_node->pb_type->blif_model == NULL) {
                assert(tnode[i].pb_graph_pin->type == PB_PIN_NORMAL);
                if(tnode[i].pb_graph_pin->parent_node->parent_pb_graph_node == NULL) {
                        if(tnode[i].pb_graph_pin->port->type == IN_PORT) {
                                tnode[i].type = CB_IPIN;                                
                        } else {
                                assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
                                tnode[i].type = CB_OPIN;
                        }
                } else {
                        tnode[i].type = INTERMEDIATE_NODE;
                }
        } else {
                if(tnode[i].pb_graph_pin->type == PB_PIN_INPAD) {
                        assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
                        tnode[i].type = INPAD_OPIN;
                        tnode[i + 1].num_edges = 1;
                        tnode[i + 1].out_edges = 
                                (t_tedge *) my_chunk_malloc(1 *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);
                        tnode[i + 1].out_edges->Tdel = 0;
                        tnode[i + 1].out_edges->to_node = i;
                        tnode[i + 1].pb_graph_pin = NULL;
                        tnode[i + 1].T_req = 0;
                        tnode[i + 1].T_arr = 0;
                        tnode[i + 1].type = INPAD_SOURCE;
                        tnode[i + 1].block = iblock;
                        tnode[i + 1].index = i + 1;
                        (*inode)++;
                } else if(tnode[i].pb_graph_pin->type == PB_PIN_OUTPAD) {
                        assert(tnode[i].pb_graph_pin->port->type == IN_PORT);
                        tnode[i].type = OUTPAD_IPIN;
                        tnode[i].num_edges = 1;
                        tnode[i].out_edges = 
                                (t_tedge *) my_chunk_malloc(1 *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);
                        tnode[i].out_edges->Tdel = 0;
                        tnode[i].out_edges->to_node = i + 1;
                        tnode[i + 1].pb_graph_pin = NULL;
                        tnode[i + 1].T_req = 0;
                        tnode[i + 1].T_arr = 0;
                        tnode[i + 1].type = OUTPAD_SINK;
                        tnode[i + 1].block = iblock;
                        tnode[i + 1].num_edges = 0;
                        tnode[i + 1].out_edges = NULL;
                        tnode[i + 1].index = i + 1;
                        (*inode)++;
                } else if(tnode[i].pb_graph_pin->type == PB_PIN_SEQUENTIAL) {
                        if(tnode[i].pb_graph_pin->port->type == IN_PORT) {
                                tnode[i].type = FF_IPIN;
                                tnode[i].num_edges = 1;
                                tnode[i].out_edges = (t_tedge *) my_chunk_malloc(1 *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);
                                tnode[i].out_edges->Tdel = pb_graph_pin->tsu_tco;
                                tnode[i].out_edges->to_node = i + 1;
                                tnode[i + 1].pb_graph_pin = NULL;
                                tnode[i + 1].T_req = 0;
                                tnode[i + 1].T_arr = 0;
                                tnode[i + 1].type = FF_SINK;
                                tnode[i + 1].block = iblock;
                                tnode[i + 1].num_edges = 0;
                                tnode[i + 1].out_edges = NULL;
                                tnode[i + 1].index = i + 1;
                        } else {
                                assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
                                tnode[i].type = FF_OPIN;
                                tnode[i + 1].num_edges = 1;
                                tnode[i + 1].out_edges = (t_tedge *) my_chunk_malloc(1 *
                                                            sizeof(t_tedge),
                                                            &tedge_ch_list_head,
                                                            &tedge_ch_bytes_avail,
                                                            &tedge_ch_next_avail);
                                tnode[i + 1].out_edges->Tdel = pb_graph_pin->tsu_tco;
                                tnode[i + 1].out_edges->to_node = i;
                                tnode[i + 1].pb_graph_pin = NULL;
                                tnode[i + 1].T_req = 0;
                                tnode[i + 1].T_arr = 0;
                                tnode[i + 1].type = FF_SOURCE;
                                tnode[i + 1].block = iblock;
                                tnode[i + 1].index = i + 1;
                        }
                        (*inode)++;
                } else if (tnode[i].pb_graph_pin->type == PB_PIN_CLOCK) {
                        tnode[i].type = FF_SINK;
                        tnode[i].num_edges = 0;
                        tnode[i].out_edges = NULL;                              
                } else {
                        if(tnode[i].pb_graph_pin->port->type == IN_PORT) {
                                assert(tnode[i].pb_graph_pin->type == PB_PIN_TERMINAL);
                                tnode[i].type = PRIMITIVE_IPIN;
                        } else {
                                assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
                                assert(tnode[i].pb_graph_pin->type == PB_PIN_TERMINAL);
                                tnode[i].type = PRIMITIVE_OPIN;
                        }
                }
        }
        (*inode)++;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void normalize_costs ( float  t_crit,
long  max_critical_input_paths,
long  max_critical_output_paths 
) [static]

Definition at line 1409 of file path_delay.c.

                                                                                                         {
        int i;
        for(i = 0; i < num_tnodes; i++) {
                tnode[i].normalized_slack = ((float)tnode[i].T_req - tnode[i].T_arr) / t_crit;
                tnode[i].normalized_T_arr = (float)tnode[i].T_arr/(float)t_crit;
                tnode[i].normalized_total_critical_paths = ((float)tnode[i].num_critical_input_paths + tnode[i].num_critical_output_paths) / ((float)max_critical_input_paths + max_critical_output_paths);
        }
}

Here is the caller graph for this function:

void print_critical_path ( char *  fname)

Prints out the critical path to a file.

Definition at line 1218 of file path_delay.c.

{
    t_linked_int *critical_path_head, *critical_path_node;
    FILE *fp;
    int non_global_nets_on_crit_path, global_nets_on_crit_path;
    int tnodes_on_crit_path, inode, iblk, inet;
    t_tnode_type type;
    float total_net_delay, total_logic_delay, Tdel;

    critical_path_head = allocate_and_load_critical_path();
    critical_path_node = critical_path_head;

    fp = my_fopen(fname, "w", 0);

    non_global_nets_on_crit_path = 0;
    global_nets_on_crit_path = 0;
    tnodes_on_crit_path = 0;
    total_net_delay = 0.;
    total_logic_delay = 0.;

    while(critical_path_node != NULL)
        {
            Tdel =
                print_critical_path_node(fp, critical_path_node);
            inode = critical_path_node->data;
            type = tnode[inode].type;
            tnodes_on_crit_path++;

            if(type == CB_OPIN)
                {
                    get_tnode_block_and_output_net(inode, &iblk, &inet);

                    if(!timing_nets[inet].is_global)
                        non_global_nets_on_crit_path++;
                    else
                        global_nets_on_crit_path++;

                    total_net_delay += Tdel;
                }
            else
                {
                    total_logic_delay += Tdel;
                }

            critical_path_node = critical_path_node->next;
        }

    fprintf(fp,
            "\nTnodes on crit. path: %d  Non-global nets on crit. path: %d."
            "\n", tnodes_on_crit_path, non_global_nets_on_crit_path);
    fprintf(fp, "Global nets on crit. path: %d.\n", global_nets_on_crit_path);
    fprintf(fp, "Total logic delay: %g (s)  Total net delay: %g (s)\n",
            total_logic_delay, total_net_delay);

    printf("Nets on crit. path: %d normal, %d global.\n",
           non_global_nets_on_crit_path, global_nets_on_crit_path);

    printf("Total logic delay: %g (s)  Total net delay: %g (s)\n",
           total_logic_delay, total_net_delay);

    fclose(fp);
    free_int_list(&critical_path_head);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void print_net_slack ( char *  fname,
float **  net_slack 
)

Prints the net slacks into a file.

Definition at line 293 of file path_delay.c.

{
    int inet, ipin;
    FILE *fp;

    fp = my_fopen(fname, "w", 0);

    fprintf(fp, "Net #\tSlacks\n\n");

    for(inet = 0; inet < num_timing_nets; inet++)
        {
            fprintf(fp, "%5d", inet);
            for(ipin = 1; ipin < (timing_nets[inet].num_sinks + 1); ipin++)
                {
                    fprintf(fp, "\t%g", net_slack[inet][ipin]);
                }
            fprintf(fp, "\n");
        }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void print_primitive_as_blif ( FILE *  fpout,
int  iblk 
) [static]

Print primitives found in timing graph in blif format based on whether this is a logical primitive or a physical primitive

Definition at line 1513 of file path_delay.c.

                                                            {
        int i, j;
        struct s_model_ports *port;
        struct s_linked_vptr *truth_table;
        t_rr_node *irr_graph;
        t_pb_graph_node *pb_graph_node;
        int node;

        
        if(logical_block[iblk].type == VPACK_INPAD) {
                if(logical_block[iblk].pb == NULL) {
                        fprintf(fpout, ".names %s tnode_%d\n", logical_block[iblk].name, logical_block[iblk].output_net_tnodes[0][0]->index);
                } else {
                        fprintf(fpout, ".names %s tnode_%d\n", logical_block[iblk].name, 
                                logical_block[iblk].pb->rr_graph[logical_block[iblk].pb->pb_graph_node->output_pins[0][0].pin_count_in_cluster].tnode->index);
                }
                fprintf(fpout, "1 1\n\n");
        } else if(logical_block[iblk].type == VPACK_OUTPAD) {
                /* outputs have the symbol out: automatically prepended to it, must remove */
                if(logical_block[iblk].pb == NULL) {
                        fprintf(fpout, ".names tnode_%d %s\n", logical_block[iblk].input_net_tnodes[0][0]->index, &logical_block[iblk].name[4]);
                } else {
                        /* avoid the out: from output pad naming */
                        fprintf(fpout, ".names tnode_%d %s\n", 
                                logical_block[iblk].pb->rr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][0].pin_count_in_cluster].tnode->index,
                                (logical_block[iblk].name + 4));
                }
                fprintf(fpout, "1 1\n\n");
        } else if(strcmp(logical_block[iblk].model->name, "latch") == 0) {
                fprintf(fpout, ".latch ");
                node = OPEN;
                
                if(logical_block[iblk].pb == NULL) {
                        i = 0;
                        port = logical_block[iblk].model->inputs;
                        while(port) {
                                if(!port->is_clock) {
                                        assert(port->size == 1);
                                        for(j = 0; j < port->size; j++) {
                                                if(logical_block[iblk].input_net_tnodes[i][j] != NULL) {
                                                        fprintf(fpout, "tnode_%d ", logical_block[iblk].input_net_tnodes[i][j]->index);
                                                } else {
                                                        assert(0);
                                                }
                                        }
                                        i++;
                                }
                                port = port->next;
                        }
                        assert(i == 1);

                        i = 0;
                        port = logical_block[iblk].model->outputs;
                        while(port) {
                                assert(port->size == 1);
                                for(j = 0; j < port->size; j++) {
                                        if(logical_block[iblk].output_net_tnodes[i][j] != NULL) {
                                                node = logical_block[iblk].output_net_tnodes[i][j]->index;
                                                fprintf(fpout, "latch_%s re ", logical_block[iblk].name);
                                        } else {
                                                assert(0);
                                        }
                                }
                                i++;
                                port = port->next;
                        }
                        assert(i == 1);

                        i = 0;
                        port = logical_block[iblk].model->inputs;
                        while(port) {
                                if(port->is_clock) {
                                        for(j = 0; j < port->size; j++) {
                                                if(logical_block[iblk].clock_net_tnode != NULL) {
                                                        fprintf(fpout, "tnode_%d 0\n\n", logical_block[iblk].clock_net_tnode->index);
                                                } else {
                                                        assert(0);
                                                }
                                        }
                                        i++;
                                }
                                port = port->next;
                        }
                        assert(i == 1);
                } else {
                        irr_graph = logical_block[iblk].pb->rr_graph;
                        assert(irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][0].pin_count_in_cluster].net_num != OPEN);
                        fprintf(fpout, "tnode_%d ", irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][0].pin_count_in_cluster].tnode->index);
                        node = irr_graph[logical_block[iblk].pb->pb_graph_node->output_pins[0][0].pin_count_in_cluster].tnode->index;
                        fprintf(fpout, "latch_%s re ", logical_block[iblk].name);
                        assert(irr_graph[logical_block[iblk].pb->pb_graph_node->clock_pins[0][0].pin_count_in_cluster].net_num != OPEN);
                        fprintf(fpout, "tnode_%d 0\n\n", irr_graph[logical_block[iblk].pb->pb_graph_node->clock_pins[0][0].pin_count_in_cluster].tnode->index);
                }
                assert(node != OPEN);
                fprintf(fpout, ".names latch_%s tnode_%d\n", logical_block[iblk].name, node);
                fprintf(fpout, "1 1\n\n");
        } else if(strcmp(logical_block[iblk].model->name, "names") == 0) {
                fprintf(fpout, ".names ");
                node = OPEN;

                if(logical_block[iblk].pb == NULL) {
                        i = 0;
                        port = logical_block[iblk].model->inputs;
                        while(port) {
                                assert(!port->is_clock);
                                for(j = 0; j < port->size; j++) {
                                        if(logical_block[iblk].input_net_tnodes[i][j] != NULL) {
                                                fprintf(fpout, "tnode_%d ", logical_block[iblk].input_net_tnodes[i][j]->index);
                                        } else {
                                                break;
                                        }
                                }
                                i++;
                                port = port->next;
                        }
                        assert(i == 1);

                        i = 0;
                        port = logical_block[iblk].model->outputs;
                        while(port) {
                                assert(port->size == 1);
                                fprintf(fpout, "lut_%s\n", logical_block[iblk].name);
                                node = logical_block[iblk].output_net_tnodes[0][0]->index;
                                assert(node != OPEN);                   
                                i++;
                                port = port->next;
                        }
                        assert(i == 1);
                } else {
                        irr_graph = logical_block[iblk].pb->rr_graph;
                        assert(logical_block[iblk].pb->pb_graph_node->num_input_ports == 1);
                        for(i = 0; i < logical_block[iblk].pb->pb_graph_node->num_input_pins[0]; i++) {
                                if(irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][i].pin_count_in_cluster].net_num != OPEN) {
                                        fprintf(fpout, "tnode_%d ", irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][i].pin_count_in_cluster].tnode->index);
                                } else {
                                        if(i > 0 && i < logical_block[iblk].pb->pb_graph_node->num_input_pins[0] - 1) {
                                                assert(irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][i + 1].pin_count_in_cluster].net_num == OPEN);
                                        }
                                }
                        }
                        assert(logical_block[iblk].pb->pb_graph_node->num_output_ports == 1);
                        assert(logical_block[iblk].pb->pb_graph_node->num_output_pins[0] == 1);
                        fprintf(fpout, "lut_%s\n", logical_block[iblk].name);
                        node = irr_graph[logical_block[iblk].pb->pb_graph_node->output_pins[0][0].pin_count_in_cluster].tnode->index;
                }
                assert(node != OPEN);
                truth_table = logical_block[iblk].truth_table;
                while(truth_table) {
                        fprintf(fpout, "%s\n", (char*)truth_table->data_vptr);
                        truth_table = truth_table->next;
                }
                fprintf(fpout, "\n");
                fprintf(fpout, ".names lut_%s tnode_%d\n", logical_block[iblk].name, node);
                fprintf(fpout, "1 1\n\n");
        } else {
                /* This is a standard .subckt blif structure */
                fprintf(fpout, ".subckt %s ", logical_block[iblk].model->name);
                if(logical_block[iblk].pb == NULL) {
                        i = 0;
                        port = logical_block[iblk].model->inputs;
                        while(port) {
                                if(!port->is_clock) {
                                        for(j = 0; j < port->size; j++) {
                                                if(logical_block[iblk].input_net_tnodes[i][j] != NULL) {
                                                        if(port->size > 1) {
                                                                fprintf(fpout, "\\\n%s[%d]=tnode_%d ", port->name, j, logical_block[iblk].input_net_tnodes[i][j]->index);
                                                        } else {
                                                                fprintf(fpout, "\\\n%s=tnode_%d ", port->name, logical_block[iblk].input_net_tnodes[i][j]->index);
                                                        }
                                                } else {
                                                        if(port->size > 1) {
                                                                fprintf(fpout, "\\\n%s[%d]=unconn ", port->name, j);
                                                        } else {
                                                                fprintf(fpout, "\\\n%s=unconn ", port->name);
                                                        }
                                                }
                                        }
                                        i++;
                                }               
                                port = port->next;
                        }

                        i = 0;
                        port = logical_block[iblk].model->outputs;
                        while(port) {
                                for(j = 0; j < port->size; j++) {
                                        if(logical_block[iblk].output_net_tnodes[i][j] != NULL) {
                                                if(port->size > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=%s ", port->name, j, vpack_net[logical_block[iblk].output_nets[i][j]].name);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=%s ", port->name, vpack_net[logical_block[iblk].output_nets[i][j]].name);
                                                }
                                        } else {
                                                if(port->size > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=unconn_%d_%s_%d ", port->name, j, iblk, port->name, j);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=unconn_%d_%s_%d ", port->name, iblk, port->name);
                                                }
                                        }
                                }
                                i++;
                                port = port->next;
                        }


                        i = 0;
                        port = logical_block[iblk].model->inputs;
                        while(port) {
                                if(port->is_clock) {
                                        assert(port->size == 1);
                                        if(logical_block[iblk].clock_net_tnode != NULL) {
                                                fprintf(fpout, "\\\n%s=tnode_%d ", port->name, logical_block[iblk].clock_net_tnode->index);
                                        } else {
                                                fprintf(fpout, "\\\n%s=unconn ", port->name);
                                        }
                                        i++;
                                }               
                                port = port->next;
                        }

                        fprintf(fpout, "\n\n");

                        
                        i = 0;
                        port = logical_block[iblk].model->outputs;
                        while(port) {
                                for(j = 0; j < port->size; j++) {
                                        if(logical_block[iblk].output_net_tnodes[i][j] != NULL) {
                                                fprintf(fpout, ".names %s tnode_%d\n", vpack_net[logical_block[iblk].output_nets[i][j]].name, logical_block[iblk].output_net_tnodes[i][j]->index);
                                                fprintf(fpout, "1 1\n\n");
                                        }
                                }
                                i++;
                                port = port->next;
                        }
                } else {
                        irr_graph = logical_block[iblk].pb->rr_graph;
                        pb_graph_node = logical_block[iblk].pb->pb_graph_node;
                        for(i = 0; i < pb_graph_node->num_input_ports; i++) {
                                for(j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
                                        if(irr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
                                                if(pb_graph_node->num_input_pins[i] > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=tnode_%d ", pb_graph_node->input_pins[i][j].port->name, j, irr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].tnode->index);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=tnode_%d ", pb_graph_node->input_pins[i][j].port->name, irr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].tnode->index);
                                                }
                                        } else {
                                                if(pb_graph_node->num_input_pins[i] > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=unconn ", pb_graph_node->input_pins[i][j].port->name, j);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=unconn ", pb_graph_node->input_pins[i][j].port->name);
                                                }
                                        }
                                }
                        }
                        for(i = 0; i < pb_graph_node->num_output_ports; i++) {
                                for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
                                        if(irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
                                                if(pb_graph_node->num_output_pins[i] > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=%s ", pb_graph_node->output_pins[i][j].port->name, j, 
                                                                vpack_net[irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num].name);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=%s ", pb_graph_node->output_pins[i][j].port->name, 
                                                                vpack_net[irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].tnode->index].name);
                                                }
                                        } else {
                                                if(pb_graph_node->num_output_pins[i] > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=unconn ", pb_graph_node->output_pins[i][j].port->name, j);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=unconn ", pb_graph_node->output_pins[i][j].port->name);
                                                }
                                        }
                                }
                        }
                        for(i = 0; i < pb_graph_node->num_clock_ports; i++) {
                                for(j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
                                        if(irr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
                                                if(pb_graph_node->num_clock_pins[i] > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=tnode_%d ", pb_graph_node->clock_pins[i][j].port->name, j, irr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].tnode->index);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=tnode_%d ", pb_graph_node->clock_pins[i][j].port->name, irr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].tnode->index);
                                                }
                                        } else {
                                                if(pb_graph_node->num_clock_pins[i] > 1) {
                                                        fprintf(fpout, "\\\n%s[%d]=unconn ", pb_graph_node->clock_pins[i][j].port->name, j);
                                                } else {
                                                        fprintf(fpout, "\\\n%s=unconn ", pb_graph_node->clock_pins[i][j].port->name);
                                                }
                                        }
                                }
                        }

                        fprintf(fpout, "\n\n");
                        /* connect up output port names to output tnodes */
                        for(i = 0; i < pb_graph_node->num_output_ports; i++) {
                                for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
                                        if(irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
                                                fprintf(fpout, ".names %s tnode_%d\n", vpack_net[irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num].name, irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].tnode->index);
                                                fprintf(fpout, "1 1\n\n");
                                        }
                                }
                        }
                }
        }
}

Here is the caller graph for this function:

void print_timing_graph ( char *  fname)

Prints the timing graph into a file.

Definition at line 958 of file path_delay.c.

{
    FILE *fp;
    int inode, iedge, ilevel, i;
    t_tedge *tedge;
    t_tnode_type itype;
    char *tnode_type_names[] = { "INPAD_SOURCE", "INPAD_OPIN", "OUTPAD_IPIN", 
                "OUTPAD_SINK", "CB_IPIN", "CB_OPIN", "INTERMEDIATE_NODE", "PRIMITIVE_IPIN", "PRIMITIVE_OPIN", 
                "FF_IPIN", "FF_OPIN",
                "FF_SINK", "FF_SOURCE",
                "CONSTANT_GEN_SOURCE"
    };


    fp = my_fopen(fname, "w", 0);

    fprintf(fp, "num_tnodes: %d\n", num_tnodes);
    fprintf(fp, "Node #\tType\t\tipin\tiblk\t# edges\t"
            "Edges (to_node, Tdel)\n\n");

        
    for(inode = 0; inode < num_tnodes; inode++)
        {
            fprintf(fp, "%d\t", inode);

            itype = tnode[inode].type;
            fprintf(fp, "%-15.15s\t", tnode_type_names[itype]);

                if(tnode[inode].pb_graph_pin != NULL) {
                        fprintf(fp, "%d\t%d\t", tnode[inode].pb_graph_pin->pin_count_in_cluster,
                    tnode[inode].block);
                } else {
                        fprintf(fp, "%d\t",  tnode[inode].block);
                }

            fprintf(fp, "%d\t", tnode[inode].num_edges);

                
            tedge = tnode[inode].out_edges;
                for(iedge = 0; iedge < tnode[inode].num_edges; iedge++)
                {
                        fprintf(fp, "\t(%4d,%7.3g)", tedge[iedge].to_node,
                            tedge[iedge].Tdel);
                }
            fprintf(fp, "\n");
        }

    fprintf(fp, "\n\nnum_tnode_levels: %d\n", num_tnode_levels);

    for(ilevel = 0; ilevel < num_tnode_levels; ilevel++)
        {
            fprintf(fp, "\n\nLevel: %d  Num_nodes: %d\nNodes:", ilevel,
                    tnodes_at_level[ilevel].nelem);
            for(i = 0; i < tnodes_at_level[ilevel].nelem; i++)
                fprintf(fp, "\t%d", tnodes_at_level[ilevel].list[i]);
        }

    fprintf(fp, "\n");
    fprintf(fp, "\n\nNet #\tNet_to_driver_tnode\n");

    for(i = 0; i < num_nets; i++)
        fprintf(fp, "%4d\t%6d\n", i, net_to_driver_tnode[i]);

    fprintf(fp, "\n\nNode #\t\tT_arr\t\tT_req\n\n");

        for(inode = 0; inode < num_tnodes; inode++) {
                fprintf(fp, "%d\t%12g\t%12g\n", inode, tnode[inode].T_arr,
                        tnode[inode].T_req);
        }

    fclose(fp);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void print_timing_graph_as_blif ( char *  fname,
t_model models 
)

Prints out the critical path to a file.

Definition at line 1423 of file path_delay.c.

{
        struct s_model_ports *port;
        struct s_linked_vptr *p_io_removed;

    FILE *fp;
        int i, j;

    fp = my_fopen(fname, "w", 0);

        fprintf(fp, ".model %s\n", blif_circuit_name);
        
        fprintf(fp, ".inputs ");
        for(i = 0; i < num_logical_blocks; i++) {
                if(logical_block[i].type == VPACK_INPAD) {
                        fprintf(fp, "\\\n%s ", logical_block[i].name);
                }
        }
        p_io_removed = circuit_p_io_removed;
        while(p_io_removed) {
                fprintf(fp, "\\\n%s ", (char *) p_io_removed->data_vptr);
                p_io_removed = p_io_removed->next;
        }

        fprintf(fp, "\n");
        
        fprintf(fp, ".outputs ");
        for(i = 0; i < num_logical_blocks; i++) {
                if(logical_block[i].type == VPACK_OUTPAD) {
                        /* Outputs have a "out:" prepended to them, must remove */
                        fprintf(fp, "\\\n%s ", &logical_block[i].name[4]);
                }
        }
        fprintf(fp, "\n");
        fprintf(fp, ".names unconn\n");
        fprintf(fp, " 0\n\n");

        /* Print out primitives */
        for(i = 0; i < num_logical_blocks; i++) {
                print_primitive_as_blif(fp, i);
        }

        /* Print out tnode connections */
        for(i = 0; i < num_tnodes; i++) {
                if(tnode[i].type != PRIMITIVE_IPIN && tnode[i].type != FF_SOURCE && tnode[i].type != INPAD_SOURCE && tnode[i].type != OUTPAD_IPIN) {
                        for(j = 0; j < tnode[i].num_edges; j++) {
                                fprintf(fp, ".names tnode_%d tnode_%d\n", i, tnode[i].out_edges[j]);
                                fprintf(fp, "1 1\n\n");
                        }
                }
        }
        
        fprintf(fp, ".end\n\n");

        /* Print out .subckt models */
        while(models) {
                fprintf(fp, ".model %s\n", models->name);
                fprintf(fp, ".inputs ");
                port = models->inputs;
                while(port) {
                        if(port->size > 1) {
                                for(j = 0; j < port->size; j++) {
                                        fprintf(fp, "%s[%d] ", port->name, j);
                                }
                        } else {
                                fprintf(fp, "%s ", port->name);
                        }
                        port = port->next;
                }
                fprintf(fp, "\n");
                fprintf(fp, ".outputs ");
                port = models->outputs;
                while(port) {
                        if(port->size > 1) {
                                for(j = 0; j < port->size; j++) {
                                        fprintf(fp, "%s[%d] ", port->name, j);
                                }
                        } else {
                                fprintf(fp, "%s ", port->name);
                        }
                        port = port->next;
                }
                fprintf(fp, "\n.blackbox\n.end\n\n");
                fprintf(fp, "\n\n");
                models = models->next;
        }
    fclose(fp);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

int num_timing_nets = 0 [static]

Definition at line 96 of file path_delay.c.

int tedge_ch_bytes_avail = 0 [static]

Variables for "chunking" the tedge memory. If the head pointer is NULL, no timing graph exists now.

Definition at line 91 of file path_delay.c.

struct s_linked_vptr* tedge_ch_list_head = NULL [static]

Variables for "chunking" the tedge memory. If the head pointer is NULL, no timing graph exists now.

Definition at line 90 of file path_delay.c.

char* tedge_ch_next_avail = NULL [static]

Variables for "chunking" the tedge memory. If the head pointer is NULL, no timing graph exists now.

Definition at line 92 of file path_delay.c.

struct s_net* timing_nets = NULL [static]

Definition at line 95 of file path_delay.c.