/* Program: mem_time_fpga.c Revision: 8-Feb-2025 This is the program to calculate the signal delays between the FPGA Memory Controller and its DDR4 Memory Chips. This program uses the following input files: aux_fpga_memory_routing_data_packed.txt mem_fpga_2d_trace_lenghts.txt package_delays_all_columns_bank_0_ordered_packed.txt These 3 files are each 71 lines long and each of them has information about 71 signals all in the same net name order. These 3 files contain no blank lines or comments. Notes: - all Lengths are in mm all Delays are in psec - Because of the different propagation velocities along these signal paths, all of the delays must be summed in terms of time (not in terms of physical path length) - At the end, the time error in a signal path is converted back into the equivalent physical length using the propagation velocity for a PCB layer where it is possible to make a routing adjustment. - For now I will assume that the propagations delays of the various PCB layers are: Surface Layer: Dk = 3.45 ---> 6.19 psec/mm Internal Layer: Dk = 3.59 ---> 6.32 psec/mm Via Internal Path: Dk = 4.00 ---> 6.66 psec/mm Recall that 1/c is 3.33 psec/mm - From the package_delays_all_columns_bank_0_ordered_packed.txt file this program learns the time delay from the FPGA Memory Controller to the individual Pins on the FCG1152 package. These delays expressed in psec are in the 10th column of this file. - From the mem_fpga_2d_trace_lenghts.txt file this program learns the 2d X,Y path length for all of the FPGA memory signals. These path lengths are expressed in mm and are in the 2nd column of this file. - From the aux_fpga_memory_routing_data_packed.txt file this program learns: The Fraction of the PCB signal path that is routed on a surface layers (vs an internal layer) This fraction ( 0.00 to 1.00 ) is in Column #3 The length of the signal path in the FPGA BGA Escape Via, i.e. the vertical distance from top layer L1 down to whatever layer this signal is routed on next. This length in mm is in Column #4. The length of the signal path in the Re-Surface Via by the memory chip pin, i.e. the vertical distance from what ever layer the signal is on up to the top layer L1. This length in mm is in Column #5. The length of the signal path in a 3rd Via if a 3rd Via is used in this signal path, i.e. the vertical distance between the incoming signal layer and the out going signal layer. This length in mm is in Column #6. - Until we know the details of the DK Stackup I will assume: L1 Top Traced & Pads 0.000 mm 0.00 mils L2 Ground Plane 0.123 4.85 L3 Traces 0.284 11.20 L4 Traces 0.640 25.20 L5 Ground Plane 0.801 31.55 L6 1 oz Power Fills 0.930 36.60 --- Center 41.3 mils 1.049 mm L7 1 oz Power Fills 1.168 46.00 L8 Ground Plane 1.297 51.05 L9 Traces 1.458 57.40 L10 Traces 1.814 71.40 L11 Ground Plane 1.975 77.75 L12 Bot Traced & Pads 2.098 82.60 - Based on the above copper layer locations, the distances between routing layers are: L1 L3 L4 L9 L10 L12 L1 ---- L3 11.2 ---- all in mils L4 25.2 14.0 ---- L9 57.4 46.2 32.2 ---- L10 71.4 60.2 46.2 14.0 ---- L12 82.6 71.4 57.4 25.2 11.2 ---- L1 L3 L4 L9 L10 L12 L1 ----- L3 0.284 ----- all in mm L4 0.640 0.356 ----- L9 1.458 1.173 0.818 ----- L10 1.814 1.529 1.173 0.356 ----- L12 2.098 1.814 1.458 0.640 0.284 ----- - The basic calculations that this program does are the following: First calculate the total delay time in psec for each of the 71 signals. A given signal's total delay time is the sum of its: Package_Delay + XY 2d Trace Length x Fraction on Surface x Surface Layer Propagation Constant + XY 2d Trace Length x ( 1.0 - Fraction on Surface ) x Internal Layer Propagation Constant + ( the sum of its Via Lengths ) x Via Propagation Constant Next for each of the 5 groups of signal we calculate the Group Average Delay time for that group in psec. The 5 groups are: The CA Bus 25 signals and a Differential Clock D0:D7 Data Bus 9 signals and a Differential Strobe D8:D15 Data Bus 9 signals and a Differential Strobe D16:D23 Data Bus 9 signals and a Differential Strobe D24:D31 Data Bus 9 signals and a Differential Strobe But note that the Clock and Strobe signals themselves are NOT included in calculating the Group Average Delays. This makes sense because the Group Average Delays should be calculated based just on the data type signals in that group and then the clock signal for that group should match that average and not an average that has been skewed by the clock signal itself. There are 71 signals total for which we need to make a timing analysis. The Reset_B, Alert_B, and TEN signals are not part of the timing analysis. Finally for each of the 71 signals calculate its error in psec relative to the average delay for the signals in its group. Express this error both as a time in psec and as a distance in mm on the PCB layer where this signals physical routing length could be adjusted. - There are a number of source files that are combined into into the overall source for this program when it is built. These source files are: mem_time_fpga_introduction.c mem_time_fpga_read_files.c mem_time_fpga_calculate_delays.c mem_time_fpga_output_differences.c - The order of these 71 memory signals in all three of the files that are inputs to the delay calculation program is the following. This is the same for both the FPGA memory data and for the CPU memory data. The Line Number in a file starts at "1". The Element Number of C Array starts at "0". File Line Numb Signal ---- --------- 1 CLK_DIR 2 CLK_CMP 3 CLK_ENB 4 ADRS0 5 ADRS1 6 ADRS2 7 ADRS3 8 ADRS4 9 ADRS5 10 ADRS6 11 ADRS7 12 ADRS8 13 ADRS9 14 ADRS10 15 ADRS11 16 ADRS12 17 ADRS13 18 ADRS14_WE_B 19 ADRS15_CAS_B 20 ADRS16_RAS_B 21 BA0 22 BA1 23 BG0 24 CS_B 25 PARITY 26 ACT_B 27 ODT 28 DQS0_DIR 29 DQS0_CMP 30 DM0_B 31 DQ0 32 DQ1 33 DQ2 34 DQ3 35 DQ4 36 DQ5 37 DQ6 38 DQ7 39 DQS1_DIR 40 DQS1_CMP 41 DM1_B 42 DQ8 43 DQ9 44 DQ10 45 DQ11 46 DQ12 47 DQ13 48 DQ14 49 DQ15 50 DQS2_DIR 51 DQS2_CMP 52 DM2_B 53 DQ16 54 DQ17 55 DQ18 56 DQ19 57 DQ20 58 DQ21 59 DQ22 60 DQ23 61 DQS3_DIR 62 DQS3_CMP 63 DM3_B 64 DQ24 65 DQ25 66 DQ26 67 DQ27 68 DQ28 69 DQ29 70 DQ30 71 DQ31 */ /* Program Section: mem_time_fpga_read_files.c Revision: 9-Feb-2025 */ #include #include #include #define MAX_BUFF 200 #define MAX_LINE 120 #define MAX_ARRAY 200 #define INPUT_FILE_LINE_COUNT 71 #define MAX_NET_NAME 30 #define MAX_PIN_NAME 7 /** Define the Propagation Constants in psec/mm **/ #define PROP_CNST_SURFACE 6.19 /** Surface Trace psec/mm **/ #define PROP_CNST_INTERNAL 6.32 /** Internal Trace psec/mm **/ #define PROP_CNST_VIA 6.66 /** Via Tunnel psec/mm **/ main( int argc, char *argv[] ) { /** Declare the functions aka provide the function prototypes **/ /** with dummy arguments **/ double calculate_delay( double package_delay, double xy_length, \ double surface_fraction, double escp_via, \ double return_via, double extra_via ) ; /** Declare some Character Arrays 1d and 2d **/ char filename[MAX_LINE] ; char this_net_name[MAX_NET_NAME] ; char array_of_net_names[MAX_BUFF][MAX_NET_NAME] ; char this_pin_name[MAX_PIN_NAME] ; char array_of_pin_names[MAX_BUFF][MAX_PIN_NAME] ; /** Declare the File Pointers to the 3 Input and 2 Output files **/ FILE *fp_pkg_delays_file ; FILE *fp_2d_trace_lengths_file ; FILE *fp_aux_routing_data_file ; FILE *fp_check_file ; FILE *fp_trace_diff_report_file ; /** Declare some Integer Variables **/ int parse_count = 0 ; int return_cnt = 0 ; /** Declare some Double Floating Point Variables **/ double this_delay = 0.0 ; double this_xy_length = 0.0 ; double this_fraction_on_surface = 0.0 ; double this_via_escape_length = 0.0 ; double this_via_return_length = 0.0 ; double this_via_third_length = 0.0 ; /** Declare the Propagation Constants in psec/mm double prop_cnst_surface = 6.19 ; double prop_cnst_internal = 6.32 ; double prop_cnst_via = 6.66 ; **/ /** Declare the Arrays that will hold the Input Data **/ double package_delay[MAX_ARRAY] ; double trace_xy_length[MAX_ARRAY] ; double fraction_on_surface[MAX_ARRAY] ; double via_escape_length[MAX_ARRAY] ; double via_return_length[MAX_ARRAY] ; double via_third_length[MAX_ARRAY] ; /** **/ /** Get the filenames of the 3x Input and 2x Output Files: **/ /** **/ /** input: package_delays_packed.txt **/ /** input: mem_2d_trace_lenghts_packed.txt **/ /** input: aux_memory_routing_packed.txt **/ /** **/ /** output: check_file.txt **/ /** output: mem_trace_differences_by_group.txt **/ /** **/ /** Recall that each of the inputs files has 71 lines of **/ /** ascii data divided into various columns which are **/ /** separated by white space. **/ /** **/ /** This program allows two different ways to specify **/ /** these 5 filenames: **/ /** **/ /** If no filename is specified on the command line that **/ /** starts this program then this program will prompt the **/ /** user for these 5 filenames one at a time. **/ /** **/ if ( argc == 1) /** Prompt the user for 5 filenames **/ { printf("Enter the filename of the Package Delays file to READ: "); scanf( "%50s", filename ); if ((fp_pkg_delays_file = fopen(filename, "r")) == NULL) { printf("\nERROR: Can't open input Package Delays file %s\n", filename); exit (1); } printf("Enter the filename of the 2d Trace Lengths file to READ: "); scanf( "%50s", filename ); if ((fp_2d_trace_lengths_file = fopen(filename, "r")) == NULL) { printf("\nERROR: Can't open input 2d Trace Lengths file %s\n", filename); exit (2); } printf("Enter the filename of the Aux Routing Data file to READ: "); scanf( "%50s", filename ); if ((fp_aux_routing_data_file = fopen(filename, "r")) == NULL) { printf("\nERROR: Can't open input Aux Routing Data file %s\n", filename); exit (3); } printf("Enter the filename to receive the Check information: "); scanf( "%50s", filename ); if ((fp_check_file = fopen(filename, "w")) == NULL) { printf("\nERROR: Can't open the Check output file %s\n", filename); exit (4); } printf("Enter the filename to receive the Trace Differences Report: "); scanf( "%50s", filename ); if ((fp_trace_diff_report_file = fopen(filename, "w")) == NULL) { printf("\nERROR: Can't open Trace Differences output file %s\n", filename); exit (4); } } else if ( argc == 6 ) /** 4 filenames come from the command line **/ { printf( "\n\n\n " ); printf( "The 5 filenames are received from the command line. \n\n\n "); strcpy( filename, argv[1] ) ; if ((fp_pkg_delays_file = fopen(filename, "r")) == NULL) { printf("\nERROR: Can't open input Package Delays file %s\n", filename); exit (2); } strcpy( filename, argv[2] ) ; if ((fp_2d_trace_lengths_file = fopen(filename, "r")) == NULL) { printf("\nERROR: Can't open input 2d Trace Lengths file %s\n", filename); exit (2); } strcpy( filename, argv[3] ) ; if ((fp_aux_routing_data_file = fopen(filename, "r")) == NULL) { printf("\nERROR: Can't open input Aux Routing Data file %s\n", filename); exit (3); } strcpy( filename, argv[4] ) ; if ((fp_check_file = fopen(filename, "w")) == NULL) { printf("\nERROR: Can't open the Check output file %s\n", filename); exit (4); } strcpy( filename, argv[5] ) ; if ((fp_trace_diff_report_file = fopen(filename, "w")) == NULL) { printf("\nERROR: Can't open Trace Differences output file %s\n", filename); exit (4); } } else { printf( "\n\n\n " ); printf( "ERROR an illegal number of arguments was present \n "); printf( "on the command line. The user should either provide \n "); printf( "no arguments on the command line in which case this \n "); printf( "program will prompted the user for all required \n "); printf( "arguments or the user should supply all 5 \n "); printf( "filenames on the command line. \n\n\n "); exit (1); } /** **/ /** We now have all the information that we need to start the actual work **/ /** **/ /** Read the input files one at a time. For each input file read it **/ /** one line at a time and extract the useful column(s) of data **/ /** into Array variables. Recall that each of the inputs files has **/ /** 71 lines of ascii data divided into various columns which are **/ /** separated by white space. **/ /** **/ /** The fscanf funtion can be used to extract this information **/ /** into strings and normal double floating point variables. **/ /** **/ /** **/ /** First read the Package Delay input file. The pin delay values **/ /** that we want are in the 10th column of each line. Skip over **/ /** the first 9 columns by using edit masks that do not assign **/ /** these first 9 character strings in a line to a variable. **/ /** **/ /** The Package Delay values are between about 75 and 125 psec. **/ /** **/ parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { return_cnt = fscanf( fp_pkg_delays_file, \ "%6s %*20s %*20s %*20s %*20s \ %*20s %*20s %*20s %*20s %lf", \ this_pin_name, &this_delay ) ; package_delay[parse_count] = this_delay ; strcpy( array_of_pin_names[parse_count], this_pin_name ) ; ++parse_count ; } fclose( fp_pkg_delays_file ) ; /** **/ /** The 71 values of Package Delay are now in the **/ /** double float array package_delay[]. **/ /** **/ /** **/ /** Next read the XY 2d Trace Lengths input file. **/ /** **/ /** The first column of this file is the full Net_Name ascii string **/ /** The net names are less than 25 characters. **/ /** **/ /** The second column is the X,Y 2d Trace Length in mm ascii string **/ /** Trace Lengths are between about 20 and 55 mm **/ /** and are in the format JK.LM **/ /** **/ parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { return_cnt = fscanf( fp_2d_trace_lengths_file, \ "%25s %lf", this_net_name, &this_xy_length ) ; trace_xy_length[parse_count] = this_xy_length ; strcpy( array_of_net_names[parse_count], this_net_name ) ; ++parse_count ; } fclose( fp_2d_trace_lengths_file ) ; /** **/ /** The 71 values of XY 2d Trace Length are now in the **/ /** double float array trace_xy_length[]. **/ /** **/ /** **/ /** Next read the Aux Routing Data input file. **/ /** **/ /** The first column of this file is the Pin Number ascii string **/ /** Pin Numbers are less than 6 characters. **/ /** For now we will just skip over the first column. **/ /** **/ /** The second column is an abreviation of the Net Name ascii string **/ /** Net Names are less than 28 characters. **/ /** For now we will just skip over the second column. **/ /** **/ /** The third column is the Fraction of the Trace Length on **/ /** a Surface Layer. This is a value between 0.00 and 1.00 **/ /** Read this value into the fraction_on_surface array. **/ /** **/ /** The 4th, 5th, and 6th columns are the: **/ /** Length of the Escape Via in the FPGA BGA **/ /** Length of the Return Via in the Memory Chip BGA **/ /** Length of the Third Via in the routing if there is one **/ /** These mm values of form J.KLM are read into the arrays: **/ /** via_escape_length, via_return_length, via_third_length **/ /** These via are between about 0.0 mm and 2.2 mm long. **/ /** **/ parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { return_cnt = fscanf( fp_aux_routing_data_file, \ "%*20s %*20s %lf %lf %lf %lf", \ &this_fraction_on_surface, \ &this_via_escape_length, \ &this_via_return_length, \ &this_via_third_length ) ; fraction_on_surface[parse_count] = this_fraction_on_surface ; via_escape_length[parse_count] = this_via_escape_length ; via_return_length[parse_count] = this_via_return_length ; via_third_length[parse_count] = this_via_third_length ; ++parse_count ; } fclose( fp_aux_routing_data_file ) ; /** **/ /** The 71 values of: **/ /** Fraction on Surface Layers **/ /** Escape Via Length **/ /** Return Via Length **/ /** Third Via Length **/ /** **/ /** are now all in double float arrays. **/ /** **/ /** Write out information to the Check file: **/ /** **/ /** Package Delay in psec **/ /** XY 2d Trace Length in mm **/ /** **/ /** **/ fprintf( fp_check_file, \ "\n\n Package Trace Fract Via Lengths \n" ); fprintf( fp_check_file, \ " Pin Net Delay Length on Escp Rtrn 3rd \n" ); fprintf( fp_check_file, \ " Number Name psec mm Surf mm mm mm \n\n" ); parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { fprintf( fp_check_file, \ "%6s %25s %10.5f %6.2f %5.2f %4.2f %4.2f %4.2f \n", \ array_of_pin_names[parse_count], \ array_of_net_names[parse_count], \ package_delay[parse_count], \ trace_xy_length[parse_count], \ fraction_on_surface[parse_count], \ via_escape_length[parse_count], \ via_return_length[parse_count], \ via_third_length[parse_count] ); ++parse_count ; } fclose( fp_check_file ) ; /** **/ /** The Check file has now been written and closed. **/ /** **/ /** **/ /** Now start the code section that does the timing **/ /** analysis and writes out the Memory Timing Report. **/ /* Program Section: mem_time_analysis.c Revision: 11-Feb-2025 */ /** Declare the Arrays that will hold the Delay Analysis Data **/ double trace_delay[MAX_ARRAY] ; double trace_error_psec[MAX_ARRAY] ; double trace_error_mm[MAX_ARRAY] ; /** Declare some Double Floating Point Variables **/ double ca_bus_avg_delay = 0.0 ; double d0d7_bus_avg_delay = 0.0 ; double d8d15_bus_avg_delay = 0.0 ; double d16d23_bus_avg_delay = 0.0 ; double d24d31_bus_avg_delay = 0.0 ; double bus_delay_total = 0.0 ; double ca_bus_clk_delay = 0.0 ; double d0d7_bus_clk_delay = 0.0 ; double d8d15_bus_clk_delay = 0.0 ; double d16d23_bus_clk_delay = 0.0 ; double d24d31_bus_clk_delay = 0.0 ; /** **/ /** Calculate the Delay in psec of the 71 routes. **/ /** **/ parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { trace_delay[parse_count] = calculate_delay( \ package_delay[parse_count], \ trace_xy_length[parse_count], \ fraction_on_surface[parse_count], \ via_escape_length[parse_count], \ via_return_length[parse_count], \ via_third_length[parse_count] ) ; ++parse_count ; } /**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/ /** **/ /** This First Delay Error Calculation and is based **/ /** on comparing the delay of a given signal to the **/ /** Average Delay of that signal's in that Bus Group **/ /** where the Average Bus Group Delay is based on **/ /** just the Data Type signal in that Bus Group **/ /** and specifically not on the Clock Type signals **/ /** for that Group. **/ /** **/ /**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/ /** **/ /** Calculate the Average Delay of the Data Type **/ /** signals in the CA Bus. **/ /** -------- **/ bus_delay_total = 0.0 ; parse_count = 2 ; while( parse_count < 27 ) { bus_delay_total = bus_delay_total + trace_delay[parse_count] ; ca_bus_avg_delay = bus_delay_total / 25.0 ; ++parse_count ; } /** **/ /** Calculate the Average Delay of the Data Type **/ /** signals in the D0:D7 Bus. **/ /** ----------- **/ bus_delay_total = 0.0 ; parse_count = 29 ; while( parse_count < 38 ) { bus_delay_total = bus_delay_total + trace_delay[parse_count] ; d0d7_bus_avg_delay = bus_delay_total / 9.0 ; ++parse_count ; } /** **/ /** Calculate the Average Delay of the Data Type **/ /** signals in the D8:D15 Bus. **/ /** ------------ **/ bus_delay_total = 0.0 ; parse_count = 40 ; while( parse_count < 49 ) { bus_delay_total = bus_delay_total + trace_delay[parse_count] ; d8d15_bus_avg_delay = bus_delay_total / 9.0 ; ++parse_count ; } /** **/ /** Calculate the Average Delay of the Data Type **/ /** signals in the D16:D23 Bus. **/ /** ------------- **/ bus_delay_total = 0.0 ; parse_count = 51 ; while( parse_count < 60 ) { bus_delay_total = bus_delay_total + trace_delay[parse_count] ; d16d23_bus_avg_delay = bus_delay_total / 9.0 ; ++parse_count ; } /** **/ /** Calculate the Average Delay of the Data Type **/ /** signals in the D24:D31 Bus. **/ /** ------------- **/ bus_delay_total = 0.0 ; parse_count = 62 ; while( parse_count < 71 ) { bus_delay_total = bus_delay_total + trace_delay[parse_count] ; d24d31_bus_avg_delay = bus_delay_total / 9.0 ; ++parse_count ; } /** **/ /** Now for each of the 71 signals - Calculate the Error **/ /** between it and the Average for Its Group in pasec. **/ /** **/ /** **/ /** CA Bus Signal Delay Errors wrt CA Bus Average in psec. **/ /** **/ parse_count = 0 ; while( parse_count < 27 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - ca_bus_avg_delay ; ++parse_count ; } /** **/ /** D0:D7 Bus Signal Delay Errors wrt D0:D7 Bus Average in psec. **/ /** **/ parse_count = 27 ; while( parse_count < 38 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d0d7_bus_avg_delay ; ++parse_count ; } /** **/ /** D8:D15 Bus Signal Delay Errors wrt D8:D15 Bus Average in psec. **/ /** **/ parse_count = 38 ; while( parse_count < 49 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d8d15_bus_avg_delay ; ++parse_count ; } /** **/ /** D16:D23 Bus Signal Delay Errors wrt D16:D23 Bus Average in psec. **/ /** **/ parse_count = 49 ; while( parse_count < 60 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d16d23_bus_avg_delay ; ++parse_count ; } /** **/ /** D24:D31 Bus Signal Delay Errors wrt D24:D31 Bus Average in psec. **/ /** **/ parse_count = 60 ; while( parse_count < 71 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d24d31_bus_avg_delay ; ++parse_count ; } /** **/ /** Now for each of the 71 signals - Calculate the Error **/ /** between it and the Average for Its Group in mm. **/ /** ---- **/ /** **/ /** The translation from psec to mm is made based **/ /** on whether most of the trace length is on a **/ /** Surface Layer or on an Internal Layer. **/ /** **/ parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { if (fraction_on_surface[parse_count] > 0.50) { trace_error_mm[parse_count] = \ trace_error_psec[parse_count] / PROP_CNST_SURFACE ; } else { trace_error_mm[parse_count] = \ trace_error_psec[parse_count] / PROP_CNST_INTERNAL ; } ++parse_count ; } /** **/ /** This ends the First Delay Analysis section of the program. **/ /** **/ /** **/ /** Start the First Delay Error Report File Generation **/ /** section of the program. **/ /** **/ /** **/ /** Write out the Trace Delay and Delay Error Information: **/ /** to the Report file: **/ /** **/ /** First write out the Average Delay for the data type **/ /** signals in each of the 5 buses. **/ /** **/ /** Then for each line in the Input Data Files write out: **/ /** **/ /** Pin Number of this Trace **/ /** Net Name of this Trace **/ /** Total delay in psec along this trace **/ /** Difference between this trace and its Group average in psec **/ /** Difference between this trace and its Group average in mm **/ /** **/ fprintf( fp_trace_diff_report_file, \ "\n\n Delay Errors wrt Average Bus Group Delay: \n" ); fprintf( fp_trace_diff_report_file, \ "\n Average CA Bus Delay = %7.2f psec \n", \ ca_bus_avg_delay ); fprintf( fp_trace_diff_report_file, \ " Average D0-D7 Bus Delay = %7.2f psec \n", \ d0d7_bus_avg_delay ); fprintf( fp_trace_diff_report_file, \ " Average D8-D15 Bus Delay = %7.2f psec \n", \ d8d15_bus_avg_delay ); fprintf( fp_trace_diff_report_file, \ " Average D16-D23 Bus Delay = %7.2f psec \n", \ d16d23_bus_avg_delay ); fprintf( fp_trace_diff_report_file, \ " Average D24-D31 Bus Delay = %7.2f psec \n", \ d24d31_bus_avg_delay ); fprintf( fp_trace_diff_report_file, \ "\n\n Pin Net Delay Error Error \n" ); fprintf( fp_trace_diff_report_file, \ " Number Name psec psec mm \n\n" ); parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { fprintf( fp_trace_diff_report_file, \ "%6s %25s %7.2f %7.2f %7.2f\n", \ array_of_pin_names[parse_count], \ array_of_net_names[parse_count], \ trace_delay[parse_count], \ trace_error_psec[parse_count], \ trace_error_mm[parse_count] ); ++parse_count ; } /** **/ /** This finishes the First Delay Error Report based on a **/ /** given signal's delay wrt its Bus Group's Average Delay. **/ /** **/ /**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/ /** **/ /** Now the Second Delay Error Calculation based on **/ /** comparing a given signal's delay to the delay of the **/ /** longest Clock Type signal that services that Bus Group. **/ /** **/ /**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/ /** **/ /** For each of the 5 Bus Groups - determine which of its **/ /** two Clock Type signals has the longer delay. **/ /** **/ if ( trace_delay[0] > trace_delay[1] ) { ca_bus_clk_delay = trace_delay[0] ; } else { ca_bus_clk_delay = trace_delay[1] ; } if ( trace_delay[27] > trace_delay[28] ) { d0d7_bus_clk_delay = trace_delay[27] ; } else { d0d7_bus_clk_delay = trace_delay[28] ; } if ( trace_delay[38] > trace_delay[39] ) { d8d15_bus_clk_delay = trace_delay[38] ; } else { d8d15_bus_clk_delay = trace_delay[39] ; } if ( trace_delay[49] > trace_delay[50] ) { d16d23_bus_clk_delay = trace_delay[49] ; } else { d16d23_bus_clk_delay = trace_delay[50] ; } if ( trace_delay[60] > trace_delay[61] ) { d24d31_bus_clk_delay = trace_delay[60] ; } else { d24d31_bus_clk_delay = trace_delay[61] ; } /** **/ /** Now calculate the 71 Delay Errors based on comparing **/ /** each signal to the longer of the two Clock Type signals **/ /** in its Bus Group. **/ /** **/ /** CA Bus Signal Delay Errors wrt CA Bus Average in psec. **/ /** **/ parse_count = 0 ; while( parse_count < 27 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - ca_bus_clk_delay ; ++parse_count ; } /** **/ /** D0:D7 Bus Signal Delay Errors wrt D0:D7 Bus Average in psec. **/ /** **/ parse_count = 27 ; while( parse_count < 38 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d0d7_bus_clk_delay ; ++parse_count ; } /** **/ /** D8:D15 Bus Signal Delay Errors wrt D8:D15 Bus Average in psec. **/ /** **/ parse_count = 38 ; while( parse_count < 49 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d8d15_bus_clk_delay ; ++parse_count ; } /** **/ /** D16:D23 Bus Signal Delay Errors wrt D16:D23 Bus Average in psec. **/ /** **/ parse_count = 49 ; while( parse_count < 60 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d16d23_bus_clk_delay ; ++parse_count ; } /** **/ /** D24:D31 Bus Signal Delay Errors wrt D24:D31 Bus Average in psec. **/ /** **/ parse_count = 60 ; while( parse_count < 71 ) { trace_error_psec[parse_count] = \ trace_delay[parse_count] - d24d31_bus_clk_delay ; ++parse_count ; } /** **/ /** Now for each of the 71 signals - Calculate the Error **/ /** between it and the longer Clock for Its Group in mm. **/ /** ---- **/ /** **/ /** The translation from psec to mm is made based **/ /** on whether most of the trace length is on a **/ /** Surface Layer or on an Internal Layer. **/ /** **/ parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { if (fraction_on_surface[parse_count] > 0.50) { trace_error_mm[parse_count] = \ trace_error_psec[parse_count] / PROP_CNST_SURFACE ; } else { trace_error_mm[parse_count] = \ trace_error_psec[parse_count] / PROP_CNST_INTERNAL ; } ++parse_count ; } /** **/ /** This ends the Second Delay Analysis section of the program. **/ /** **/ /** **/ /** Start the Second Delay Error Report File Generation **/ /** section of the program. **/ /** **/ /** **/ /** Write out the Trace Delay and Delay Error Information: **/ /** to the Report file: **/ /** **/ /** First write out the longer of the two Clock Delays **/ /** for each of the 5 Buses Groups. **/ /** **/ /** Then for each line in the Input Data Files write out: **/ /** **/ /** Pin Number of this Trace **/ /** Net Name of this Trace **/ /** Total delay in psec along this trace **/ /** Difference between this trace and its Group average in psec **/ /** Difference between this trace and its Group average in mm **/ /** **/ fprintf( fp_trace_diff_report_file, \ "\n\n Delay Errors wrt Bus Group's Clock Delay: \n" ); fprintf( fp_trace_diff_report_file, \ "\n CA Bus Clock Delay = %7.2f psec \n", \ ca_bus_clk_delay ); fprintf( fp_trace_diff_report_file, \ " D0-D7 Bus Clock Delay = %7.2f psec \n", \ d0d7_bus_clk_delay ); fprintf( fp_trace_diff_report_file, \ " D8-D15 Bus Clock Delay = %7.2f psec \n", \ d8d15_bus_clk_delay ); fprintf( fp_trace_diff_report_file, \ " D16-D23 Bus Clock Delay = %7.2f psec \n", \ d16d23_bus_clk_delay ); fprintf( fp_trace_diff_report_file, \ " D24-D31 Bus Clock Delay = %7.2f psec \n", \ d24d31_bus_clk_delay ); fprintf( fp_trace_diff_report_file, \ "\n\n Pin Net Delay Error Error \n" ); fprintf( fp_trace_diff_report_file, \ " Number Name psec psec mm \n\n" ); parse_count = 0 ; while( parse_count < INPUT_FILE_LINE_COUNT ) { fprintf( fp_trace_diff_report_file, \ "%6s %25s %7.2f %7.2f %7.2f\n", \ array_of_pin_names[parse_count], \ array_of_net_names[parse_count], \ trace_delay[parse_count], \ trace_error_psec[parse_count], \ trace_error_mm[parse_count] ); ++parse_count ; } fclose( fp_trace_diff_report_file ) ; /** **/ /** This finishes the Second Delay Error Report based on a **/ /** given signal's delay wrt its Bus Group's Longer Clock Delay. **/ /** **/ return (1); } /** **/ /** End of the main program - now for the Function Definitions **/ /** **/ /** **/ /** This is the calculate_delay function. It is called **/ /** for each of the 71 lines in the input data files **/ /** **/ /** When calling this function the arguments are: **/ /** **/ /** X,Y 2d Trace Length in mm **/ /** Package Delay in psec **/ /** Fraction of Trace Length that is on a Surface Layer **/ /** Length of the FPGA BGA Escape Via in mm **/ /** Length of the Memory Chip Return Via in mm **/ /** Length of a 3rd Via if one is used in mm **/ /** **/ /** This function has access to the Surface, Internal, **/ /** and Via Propagation Constants that were Defined **/ /** near the top of the read files program section. **/ /** Propagation Constants are in psec/mm **/ /** **/ /** This function returns the overall delay **/ /** in psec of this route. **/ /** **/ double calculate_delay( double package_delay, double xy_length, \ double surface_fraction, double escp_via, \ double return_via, double extra_via ) { double delay_psec = 0.0 ; delay_psec = package_delay + \ ( xy_length * surface_fraction * PROP_CNST_SURFACE ) + \ ( xy_length * ( 1.0 - surface_fraction) * PROP_CNST_INTERNAL ) + \ ( (escp_via + return_via + extra_via) * PROP_CNST_VIA ) ; return (delay_psec) ; }