📄 path_delay.c
字号:
} /* First pass, load the subblock input pins to output pins without connecting edges to output pins. * If the subblock is used in sequential mode (i.e. is clocked), the two clock pin nodes. * Connect edges to output pins and take care of constant generators in second pass */ for(isub = 0; isub < num_subs; isub++) { has_outputs = FALSE; for(opin = 0; opin < type->max_subblock_outputs; opin++) { if(sub_pin_to_tnode[isub][SUB_OUTPUT][opin] != OPEN) { has_outputs = TRUE; } } if(!has_outputs && type != IO_TYPE) { /* Empty, so skip */ continue; } if(sub_inf[isub].clock != OPEN) { /* Sequential mode */ inode = sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin]; /* Each output of a subblock has a flip-flop sink and source */ for(opin = 0; opin < type->max_subblock_outputs; opin++) { if(sub_inf[isub].outputs[opin] != OPEN) { /* First node is the clock input pin; it feeds the sequential output */ tnode[inode].num_edges = 1; tnode[inode].out_edges = (t_tedge *) my_chunk_malloc(sizeof(t_tedge), &tedge_ch_list_head, &tedge_ch_bytes_avail, &tedge_ch_next_avail); tnode_descript[inode].type = FF_SOURCE; tnode_descript[inode].ipin = OPEN; tnode_descript[inode].isubblk = isub; tnode_descript[inode].iblk = iblk; /* Now create the "sequential sink" -- i.e. the FF input node. */ inode++; tnode[inode].num_edges = 0; tnode[inode].out_edges = NULL; tnode_descript[inode].type = FF_SINK; tnode_descript[inode].ipin = OPEN; tnode_descript[inode].isubblk = isub; tnode_descript[inode].iblk = iblk; inode++; } } } /* Build and hook up subblock inputs. */ for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) { inode = sub_pin_to_tnode[isub][SUB_INPUT][ipin]; if(inode != OPEN) { /* tnode exists -> pin is used */ if(type == IO_TYPE) { /* Output pad */ tnode[inode].num_edges = 1; opin = 0; tnode[inode].out_edges = (t_tedge *) my_chunk_malloc(sizeof(t_tedge), &tedge_ch_list_head, &tedge_ch_bytes_avail, &tedge_ch_next_avail); tnode_descript[inode].type = OUTPAD_IPIN; tnode[inode + 1].num_edges = 0; tnode[inode + 1].out_edges = NULL; tedge = tnode[inode].out_edges; tedge[0].to_node = inode + 1; /* For output pads, use subblock combinational time * and sequential in for timing (treat as register) */ tedge[0].Tdel = type->type_timing_inf. T_subblock[isub].T_comb[ipin][opin] + type->type_timing_inf. T_subblock[isub].T_seq_in[opin]; tnode_descript[inode + 1].type = OUTPAD_SINK; tnode_descript[inode + 1].ipin = OPEN; tnode_descript[inode + 1].isubblk = isub; tnode_descript[inode + 1].iblk = iblk; } else { tnode[inode].num_edges = num_opin_used_in_sblk[isub]; tnode[inode].out_edges = (t_tedge *) my_chunk_malloc(num_opin_used_in_sblk [isub] * sizeof(t_tedge), &tedge_ch_list_head, &tedge_ch_bytes_avail, &tedge_ch_next_avail); tnode[inode].num_edges = num_opin_used_in_sblk[isub]; tnode_descript[inode].type = SUBBLK_IPIN; } tnode_descript[inode].ipin = ipin; tnode_descript[inode].isubblk = isub; tnode_descript[inode].iblk = iblk; } } } /* End for each subblock */ /* Second pass load the input pins to output pins array */ /* Load the output pins edge arrays. */ for(isub = 0; isub < num_subs; isub++) { used_opin_count = 0; for(opin = 0; opin < type->max_subblock_outputs; opin++) { if(sub_pin_to_tnode[isub][SUB_OUTPUT][opin] == OPEN) { /* Empty, so skip */ continue; } for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) { /* sblk opin to sblk ipin */ from_pin = sub_inf[isub].inputs[ipin]; /* Not OPEN and comes from local subblock output? */ if(from_pin >= type->num_pins) { /* Convention for numbering netlist pins. * Internal connections are numbered subblock_index + subblock_output_index + num_pins */ from_sub = (from_pin - type->num_pins) / type->max_subblock_outputs; from_opin = (from_pin - type->num_pins) % type->max_subblock_outputs; inode = sub_pin_to_tnode[from_sub][SUB_OUTPUT] [from_opin]; to_node = sub_pin_to_tnode[isub][SUB_INPUT] [ipin]; tedge = tnode[inode].out_edges; iedge = next_sblk_opin_edge[from_sub] [from_opin]++; tedge[iedge].to_node = to_node; tedge[iedge].Tdel = type->type_timing_inf. T_sblk_opin_to_sblk_ipin; } } from_pin = sub_inf[isub].clock; /* sblk opin to sblk clock */ /* Not OPEN and comes from local subblock output? */ if(from_pin >= type->num_pins) { from_sub = (from_pin - type->num_pins) / type->max_subblock_outputs; from_opin = (from_pin - type->num_pins) % type->max_subblock_outputs; inode = sub_pin_to_tnode[from_sub][SUB_OUTPUT] [from_opin]; /* Feeds seq. output, one ff per output pin */ to_node = sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin] + 2 * used_opin_count; tedge = tnode[inode].out_edges; iedge = next_sblk_opin_edge[from_sub][from_opin]++; tedge[iedge].to_node = to_node; /* NB: Could make sblk opin to clk delay parameter; not worth it right now. */ tedge[iedge].Tdel = type->type_timing_inf. T_sblk_opin_to_sblk_ipin; } to_pin = sub_inf[isub].outputs[opin]; if(to_pin != OPEN) { /* sblk opin goes to fb opin? */ /* Check that FB pin connects to something -> * * not just a mandatory BLE to FB opin connection */ if(block[iblk].nets[to_pin] != OPEN) { to_node = node_block_pin_to_tnode[to_pin]; inode = sub_pin_to_tnode[isub][SUB_OUTPUT] [opin]; tedge = tnode[inode].out_edges; iedge = next_sblk_opin_edge[isub][opin]++; tedge[iedge].to_node = to_node; tedge[iedge].Tdel = type->type_timing_inf. T_sblk_opin_to_fb_opin; } } used_opin_count++; } } /* Now load the subblock input pins and, if the subblock is used in * * sequential mode (i.e. is clocked), the two clock pin nodes for the output pin. */ for(isub = 0; isub < num_subs; isub++) { used_opin_count = 0; for(opin = 0; opin < type->max_subblock_outputs; opin++) { if(sub_pin_to_tnode[isub][SUB_OUTPUT][opin] == OPEN) /* Empty, so skip */ continue; /* Begin loading */ if(sub_inf[isub].clock == OPEN) { /* Combinational mode */ to_node = sub_pin_to_tnode[isub][SUB_OUTPUT][opin]; sink_delay = 0; } else { /* Sequential mode. Load two clock nodes. */ inode = sub_pin_to_tnode[isub][SUB_CLOCK][clk_pin] + 2 * used_opin_count; /* First node is the clock input pin; it feeds the sequential output */ tedge = tnode[inode].out_edges; tedge[0].to_node = sub_pin_to_tnode[isub][SUB_OUTPUT][opin]; tedge[0].Tdel = type->type_timing_inf.T_subblock[isub]. T_seq_out[opin]; /* Now create the "sequential sink" -- i.e. the FF input node. */ inode++; to_node = inode; sink_delay = type->type_timing_inf.T_subblock[isub]. T_seq_in[opin]; } /* Build and hook up subblock inputs. */ has_inputs = FALSE; for(ipin = 0; ipin < type->max_subblock_inputs; ipin++) { inode = sub_pin_to_tnode[isub][SUB_INPUT][ipin]; if(inode != OPEN) { /* tnode exists -> pin is used */ has_inputs = TRUE; tedge = tnode[inode].out_edges; tedge[used_opin_count].to_node = to_node; tedge[used_opin_count].Tdel = sink_delay + type->type_timing_inf. T_subblock[isub].T_comb[ipin][opin]; } } if(!has_inputs && type != IO_TYPE) { /* Constant generator. Give fake input. */ inode = sub_pin_to_tnode[isub][SUB_OUTPUT][opin] + 1; tnode[inode].num_edges = 1; tnode[inode].out_edges = (t_tedge *) my_chunk_malloc(sizeof(t_tedge), &tedge_ch_list_head, &tedge_ch_bytes_avail, &tedge_ch_next_avail); tedge = tnode[inode].out_edges; tedge[used_opin_count].to_node = to_node; /* Want constants generated early so they never affect the critical path. */ tedge[used_opin_count].Tdel = T_CONSTANT_GENERATOR; tnode_descript[inode].type = CONSTANT_GEN_SOURCE; tnode_descript[inode].ipin = OPEN; tnode_descript[inode].isubblk = isub; tnode_descript[inode].iblk = iblk; } used_opin_count++; } } free_matrix(next_sblk_opin_edge, 0, type->max_subblocks - 1, 0, sizeof(int)); free(num_opin_used_in_sblk);}static booleanis_global_clock(int iblk, int sub, int subpin, int *num_subblocks_per_block, t_subblock ** subblock_inf){/* Returns TRUE if the net driven by this block (which must be an INPAD) is * (1) a global signal, and (2) used as a clock input to at least one block. Assumes that there is only one subblock in an IO */ int inet, ipin, to_blk, to_pin, isub; t_type_ptr type = block[iblk].type; assert(type == IO_TYPE); inet = block[iblk].nets[subblock_inf[iblk][sub].outputs[subpin]]; assert(inet != OPEN); if(!net[inet].is_global) return (FALSE); for(ipin = 1; ipin < (net[inet].num_sinks + 1); ipin++) { to_blk = net[inet].node_block[ipin]; to_pin = net[inet].node_block_pin[ipin]; for(isub = 0; isub < num_subblocks_per_block[to_blk]; isub++) { if(subblock_inf[to_blk][isub].clock == to_pin) return (TRUE); } } return (FALSE);}voidload_timing_graph_net_delays(float **net_delay){/* Sets the delays of the inter-FB 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. */ int inet, ipin, inode; t_tedge *tedge; for(inet = 0; inet < num_nets; inet++) { inode = net_to_driver_tnode[inet]; tedge = tnode[inode].out_edges;/* Note that the edges of a tnode corresponding to a FB or INPAD opin must * * be in the same order as the pins of the net driven by the tnode. */ for(ipin = 1; ipin < (net[inet].num_sinks + 1); ipin++) tedge[ipin - 1].Tdel = net_delay[inet][ipin]; }}voidfree_timing_graph(float **net_slack){/* Frees the timing graph data. */ 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(tnode_descript); 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; tnode_descript = NULL; num_tnodes = 0; net_to_driver_tnode = NULL; tnodes_at_level = NULL; num_tnode_levels = 0;}voidprint_net_slack(char *fname, float **net_slack){/* Prints the net slacks into a file. */ int inet, ipin; FILE *fp; fp = my_fopen(fname, "w"); fprintf(fp, "Net #\tSlacks\n\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -