/* ptcmp - a program for comparing PRIMETIME(tm) output By Jeff Winston http://www.kwcpa.com/tools Rev. 1.02, 2/19/04 Copyright (C) 2002, 2003, 2004 PTCMP is a program used to compare similar outputs from PRIMETIME. Given 2 primetime files, it builds a database from the first file, using the Startpoint, Endpoint, Type, Group, and Slack information. It then scans the 2nd file for the same information, and compares the first four items against the same items from the first file. If it finds a match, it compares the slack and flags differences greater than a specified amount. If it doesn't find a match, it runs the compare again, but ignores the Startpoint information. type ptcmp -h for more information --------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. or check out http://www.gnu.org/copyleft/gpl.html --------------------------------------------------------------------- To compile: gcc ptcmp.c -o ptcmp */ # include # include # define FIRST_LIST_SIZE 20000 /* max number of entries in first PT file */ char instr[255], infile1[80], /* input and output filenames */ infile2[80], outfile[80], c_start[128], /* data captured from the second file */ c_end[128], c_group[32], c_type[4]; float c_slack; /* the database for the first file, string values */ char db_start[FIRST_LIST_SIZE][128], db_end[FIRST_LIST_SIZE][128], db_group[FIRST_LIST_SIZE][32], db_type[FIRST_LIST_SIZE][4]; /* the database for the first file, numeric values */ float db_slack[FIRST_LIST_SIZE]; int db_match[FIRST_LIST_SIZE]; int db_line[FIRST_LIST_SIZE]; float c_slack,thres; /* thres is the user-entered threshold. */ int no_slack_in_1st, /* flags & counters used for scanning first file */ no_slack_in_2nd, startpt_changed, only_in_1st, only_in_2nd, real_errors, /* counters */ lineno1, /* line counters */ lineno2, last_lineno2, c, /* size of first file database */ x, /* temporary variables */ suc, ntk; char tokens[32][128]; /* returned tokens from a verilog statement */ FILE *infile1_ptr,*infile2_ptr,*outfile_ptr; void process_last(); long find_string(char *field, char *source); int get_tokens(char *str); main(argc,argv) int argc; /* Parse input and output file from command line */ char *argv[]; { printf("\nPTCMP Rev 1.01 by J. Winston\n"); if (argc == 2) { ++argv; strcpy(instr,*argv); /* help information */ if (strcmp(instr,"-h")==0) { printf("\nUSAGE: ptcmp \n\n"); printf("PTCMP is a program used to compare similar outputs from PRIMETIME.\n"); printf("Given 2 primetime files, it builds a database from the first file,\n"); printf("using the Startpoint, Endpoint, Type, Group, and Slack information.\n"); printf("It then scans the 2nd file for the same information, and compares the\n"); printf("first four items against the same items from the first file. If it\n"); printf("finds a match, it compares the slack and flags differences greater\n"); printf("than the specified threshold amount (a floating point number expressed\n"); printf("in the same units as the slack). If it doesn't find a match, it runs the\n"); printf("compare again, but ignores the Startpoint information.\n\n"); exit(0); } } else if (argc !=5) { printf("Error: Incorrect number of parameters on command line\n"); printf("Type ptcmp -h for help\n"); exit(0); } ++argv; strcpy(infile1,*argv); if ((infile1_ptr=fopen(*argv, "r")) ==NULL) { printf("Error: Error opening input file /%s/\n\n",infile1); exit(1); } ++argv; strcpy(infile2,*argv); if ((infile2_ptr=fopen(*argv, "r")) ==NULL) { printf("Error: Error opening input file /%s/\n\n",infile2); exit(1); } ++argv; strcpy(outfile,*argv); if ((outfile_ptr=fopen(*argv, "w")) ==NULL) { printf("Error: Error opening output file /%s/\n\n",outfile); exit(2); } ++argv; strcpy(c_start,*argv); sscanf(c_start,"%f",&thres); /* get threshold */ c=-1; /* initialize database length (= c+1) and counters */ no_slack_in_1st=0; no_slack_in_2nd=0; only_in_1st=0; only_in_2nd=0; real_errors=0; startpt_changed=0; lineno1=0; lineno2=0; last_lineno2=0; while (fgets(instr,255,infile1_ptr) != NULL) /* Keep getting lines until no more data */ { lineno1++; if (find_string(instr,"Startpoint")>0) /* new entry */ { c++; /* increase size of database */ if (c == FIRST_LIST_SIZE) { printf ("Too many paths in first file. Increase FIRST_LIST_SIZE\n"); exit(0); } ntk = get_tokens(instr); strcpy(db_start[c],tokens[1]); /* get start point */ db_slack[c] = 99; /* set slack to null value for now */ no_slack_in_1st++; /* and mark as not having slack */ db_match[c] = 0; /* initialize flag */ db_line[c] = lineno1; /* store line number */ } else if (find_string(instr,"Endpoint")>0) /* store end point */ { ntk = get_tokens(instr); strcpy(db_end[c],tokens[1]); } else if (find_string(instr,"Group")>0) /* store group */ { ntk = get_tokens(instr); strcpy(db_group[c],tokens[2]); } else if (find_string(instr,"Type")>0) /* store type */ { ntk = get_tokens(instr); strcpy(db_type[c],tokens[2]); } else if (find_string(instr,"slack")>0) /* if slack - store, and update counter */ { ntk = get_tokens(instr); sscanf(tokens[ntk-1],"%f",&db_slack[c]); no_slack_in_1st--; } } ntk=-1; /* start output file */ fprintf(outfile_ptr,"Primetime Comparator, Rev. 1.0. By Jeff Winston\n"); fprintf(outfile_ptr,"File 1: %s\n",infile1); fprintf(outfile_ptr,"File 2: %s\n",infile2); fprintf(outfile_ptr,"Comparison Threshold %f ns\n---\n\n",thres); while (fgets(instr,255,infile2_ptr) != NULL) /* Keep getting lines until no more data */ { lineno2++; if (find_string(instr,"Startpoint")>0) /* if start of new block */ { if (last_lineno2 == 0) last_lineno2 = lineno2; if (ntk>0) { process_last(); /* if not first block, process last one */ last_lineno2 = lineno2; } ntk = get_tokens(instr); /* parse new block - get Start point */ strcpy(c_start,tokens[1]); c_slack = 99; /* mark as not having slack for now */ no_slack_in_2nd++; } else if (find_string(instr,"Endpoint")>0) /* get endpoint */ { ntk = get_tokens(instr); strcpy(c_end,tokens[1]); } else if (find_string(instr,"Group")>0) /* get group */ { ntk = get_tokens(instr); strcpy(c_group,tokens[2]); } else if (find_string(instr,"Type")>0) /* get type */ { ntk = get_tokens(instr); strcpy(c_type,tokens[2]); } else if (find_string(instr,"slack")>0) /* if slack - get it, and update flags */ { ntk = get_tokens(instr); sscanf(tokens[ntk-1],"%f",&c_slack); no_slack_in_2nd--; } } process_last(); /* process the final entry */ /* finish up reporting - report everything in first file that isn't in 2nd */ for (x=0;x <= c;x++) { if ((db_match[x] ==0) && (db_slack[x] != 99)) { fprintf(outfile_ptr,"\nLine in 1st: %d\n",db_line[x]); fprintf(outfile_ptr,"Startpoint: %s\n",db_start[x]); fprintf(outfile_ptr,"Endpoint: %s\n",db_end[x]); fprintf(outfile_ptr,"Group/Type: %s/%s\n",db_group,db_type[x]); fprintf(outfile_ptr,"Slack: %f. ONLY IN FIRST FILE\n",db_slack[x]); only_in_1st++; } } real_errors = real_errors - startpt_changed; printf("\n%s written\n",outfile); /* report summaries */ fprintf(outfile_ptr,"\n\n---\n%d changed startpoints\n",startpt_changed); printf( "%d changed startpoints\n",startpt_changed); fprintf(outfile_ptr, "%d other mismatches\n",real_errors); printf( "%d other mismatches\n",real_errors); fprintf(outfile_ptr, "%d found only in first file\n",only_in_1st); printf( "%d found only in first file\n",only_in_1st); fprintf(outfile_ptr, "%d found only in second file\n",only_in_2nd); printf( "%d found only in second file\n",only_in_2nd); if (no_slack_in_1st == no_slack_in_2nd) { fprintf(outfile_ptr, "%d nodes without slack requirement\n",no_slack_in_1st); printf( "%d nodes without slack requirement\n",no_slack_in_1st); } else { fprintf(outfile_ptr, "%d nodes without slack requirement in first file\n",no_slack_in_1st); printf( "%d nodes without slack requirement in first file\n",no_slack_in_1st); fprintf(outfile_ptr, "%d nodes without slack requirement in second file\n",no_slack_in_2nd); printf( "%d nodes without slack requirement in second file\n",no_slack_in_2nd); } } /* processing an entry in the second file involves comparing it against all entries in the first file. */ /* we do it once and if we don't find a match we do it again ignoring startpoint mismatches */ /* suc = 0 is the first pass, suc = 1 is the 2nd pass */ void process_last() { for (suc=0; suc<2;suc++) /* suc = 0 look for complete match, suc = 1, skip Startpoint */ { for (x=0; x <= c;x++) { if (((strcmp(db_start[x],c_start)==0) || (suc == 1)) && /* the comparison */ (strcmp(db_type[x],c_type)==0) && (strcmp(db_group[x],c_group)==0) && (strcmp(db_end[x],c_end)==0) && (db_slack[x] != 99) ) { db_match[x]=1; suc=4; /* we have a match, mark it, and kick suc to flag it */ if ( ((db_slack[x] - c_slack) > thres) || /* compare threshold */ ((c_slack - db_slack[x]) > thres) ) { /* report results */ fprintf(outfile_ptr,"\nLine in 1st: %d \\ Line in 2nd: %d\n",db_line[x],last_lineno2); if (strcmp(db_start[x],c_start)==0) fprintf(outfile_ptr,"Startpoint: %s\n",c_start); else { fprintf(outfile_ptr,"Startpoint: %s \\ %s\n",db_start[x],c_start); startpt_changed++; } fprintf(outfile_ptr,"Endpoint: %s\n",c_end); fprintf(outfile_ptr,"Group/Type: %s/%s\n",c_group,c_type); fprintf(outfile_ptr,"1st/2nd Slack: %f \\ %f\n",db_slack[x],c_slack); real_errors++; } } } } if (suc < 4) /* if no success after 2 passes - report it as not found */ { fprintf(outfile_ptr,"\nLine in 2nd: %d\n",last_lineno2); fprintf(outfile_ptr,"Startpoint: %s\n",c_start); fprintf(outfile_ptr,"Endpoint: %s\n",c_end); fprintf(outfile_ptr,"Group/Type: %s/%s\n",c_group,c_type); fprintf(outfile_ptr,"Slack: %f. ONLY IN SECOND FILE\n",c_slack); only_in_2nd++; } } long find_string(char *field, char *source) /* returns LOC of start of source in field, 0= not found */ { long flen; long slen; char *sPtr; long loc; flen = strlen(field); slen = strlen(source); if (slen > flen) return (0); /* error */ else { for (loc=0, sPtr = field; loc <= flen-slen; loc++, sPtr++) { if (strncmp(source,sPtr, slen) ==0) return(loc+1); } } return (0); } int get_tokens(char *str) /* get tokens on line. Put in global tokens[32][32], return count */ { int len, loc, cnt, sp, start; len = strlen(str); sp=1; cnt=0; for (loc=0; loc <= len; loc++) { if ( (loc < len) && (str[loc] != ' ') && (str[loc] != '\n') && (str[loc] != ' ') && (str[loc] != '\0') ) { if (sp==1) /* if state = waiting */ { cnt++; /* incr token count, flip state to running, assign start */ sp=0; start=loc; } } else /* if not valid character */ { if (sp==0) /* if state = running, flip state to waiting, append good characters to string */ { sp=1; strncpy(tokens[cnt-1],&str[start],loc-start); strncpy(&tokens[cnt-1][loc-start],"\0",1); } } } return(cnt); }