/* modsplit.c - a program for splitting Verilog modules By Jeff Winston http://www.kwcpa.com/tools Rev. 1.01, 12/4/06 Copyright (C) 2002 MODSPLIT splits verilog modules into files with a single module per file and the a filename that matches the module name Type modsplit -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 modsplit.c -o modsplit 1.01 - truncate filenames to 128 chars, added header disable */ # include # include char instr[511], /* input string */ rtokens[64][128], /* raw (with comments) parsed tokens from input string */ tokens[64][128], /* parsed (without comments) tokens from input string */ infile[128], /* input filename */ headerfile[128], /* header filename */ headlines[1000][511], /* header contents */ outdir[128], /* output directory */ outfile[128], /* output filename */ filenam[128], /* tmp for output filename */ tmp[3], /* tmp string */ filestr[512], /* string with filename */ oldfilestr[512], /* last string with filename */ buffer[5000][511]; /* storage buffer */ int x,l, /* loop variable, tmp */ buf_lines, /* lines in store buffer */ rntk, /* number of raw tokens */ ntk, /* number of tokens */ writing_outfile, /* flag that we're outputing to output file */ last_file_open, /* flag that output file is open */ long_com, /* static for parser */ file_cnt, /* number of files written */ ifdef_cnt, /* count of ifdefs */ filestr_active, /* using filestring feature */ diag_ena, /* printing flag */ header, /* header exists */ nohead, /* omit "ORIG_FILE" */ err_cnt; /* count of files with ifdef or open errors */ FILE *infile_ptr, *header_ptr, *outfile_ptr; /* file pointers */ int get_tokens(char *str); int raw_get_tokens(char *str); main(argc,argv) int argc; /* Parse input file from command line */ char *argv[]; { printf("\nMODSPLIT Rev 1.01 by J. Winston\n"); ++argv; if ((argc ==2) && (strcmp(*argv,"-h")==0)) { printf("\nUse: modsplit [
] \n"); printf("Where the optional
is a header which can be attached to the top of every file.\n\n"); printf("Modsplit will take any verilog file and parse for module definitions. It will write each module\n"); printf("into an output file having the same name as the module. It tries to be smart about lines that are\n"); printf("outside module definitions. Typically, it prepends them to the next module. However, if it encounters\n"); printf("an `endif, the lines before the `endif will stay with the prior module.\n\n"); printf("One useful way to use this program is to write a script that creates a single large file that contains\n"); printf("all your verilog files concatenated together, preceding each file with a line of the form\n"); printf("\n//ORIG_FILE: \n\n"); printf("Modsplit will parse for this string and use it as a hard separator, keeping lines before this flag with\n"); printf("the prior module, and lines after it with the next one. This will give the best results. However, note\n"); printf("that if Modsplit encounters two of these flags with no module in-between, it will flush the lines\n"); printf("in-between the flags as it won't know what to do with them.\n\n"); printf("If you don't use the //ORIG_FILE: flag, Modsplit will still put a similar line at the top of every\n"); printf("output file (after the header, if used), denoting the [header_file] as \"null\" omits this.\n\n"); printf("Modsplit will also flag unclosed `ifdefs.\n\n"); exit(0); } else if ((argc <2) || (argc > 5)) /* print help if incorrect number of parameters on command line */ { printf("Error: Incorrect number of parameters on command line\n"); printf("Type modsplit -h for help\n"); exit(0); } strcpy(infile,*argv); /* try to open input file */ if ( (infile_ptr=fopen(infile, "r")) ==NULL ) { printf("Error: Error opening input file /%s/\n\n",infile); exit(1); } ++argv; /* get output directory */ strcpy(outdir,*argv); header=0; diag_ena=0; nohead=0; if (argc > 3) { ++argv; /* try to open header file */ strcpy(headerfile,*argv); if (strcmp(headerfile,"d")==0) { diag_ena=1; argv++; if (argc > 4) strcpy(headerfile,*argv); } if (strcmp(headerfile,"null")==0) { nohead=1; argv++; if (argc > 4) strcpy(headerfile,*argv); } if (((diag_ena==0) && (nohead==0)) || (argc ==5)) { if ( (header_ptr=fopen(headerfile, "r")) ==NULL ) { printf("Error: Error opening input file /%s/\n\n",infile); exit(1); } while(fgets(headlines[header],511,header_ptr) != NULL) header++; } } writing_outfile=0;/* init globals */ filestr_active=0; buf_lines=0; last_file_open=0; err_cnt=0; ifdef_cnt=0; file_cnt = 0; long_com=0; while (fgets(instr,511,infile_ptr) != NULL) /* Keep getting lines until no more data */ { rntk = raw_get_tokens(instr); if (rntk > 0) { if (strcmp(rtokens[0],"//ORIG_FILE:")==0) /* if file label (always 1st line) */ { strcpy(oldfilestr,filestr); strcpy(filestr,instr); /* capture it */ fgets(instr,511,infile_ptr); /* get next line */ if (last_file_open==1) { for (x=0;x 0) printf("%s written with Error: %d un-closed ifdefs\n",outfile,ifdef_cnt); /* flag error */ else if (diag_ena == 1) printf("%s written\n",outfile); /* close old file */ fclose(outfile_ptr); /* close file */ file_cnt++; last_file_open=0; buf_lines=0; ifdef_cnt=0; /* clear counters and flags */ } else if (buf_lines > 0) /* error, no place to dump lines */ { err_cnt++; buf_lines=0; if (filestr_active) { printf("Error: Dumped lines for file %s\n",oldfilestr); } else { printf("Error: Dumped lines for unknown file before %s\n",instr); } } filestr_active=1; } } ntk = get_tokens(instr); if (ntk > 0) /* if more than 0 tokens */ { if (strcmp(tokens[0],"module") ==0) /* if module call */ { if (last_file_open == 1) /* if last output file was open */ { if (ifdef_cnt > 0) /* if there are hanging ifdefs */ { for (x=0;x 124) { l = (123 - strlen(outdir)); strncpy(filenam,tokens[1],l); strcat(filenam,"\0"); } else { strcpy(filenam,tokens[1]); } strcpy(outfile,outdir); strcat(outfile,"/"); strcat(outfile,filenam); strcat(outfile,".v"); x=0; while ((outfile_ptr=fopen(outfile, "r")) !=NULL) { printf("Error: file %s already exists. Incrementing filename\n",outfile); if (x==0) err_cnt++; x++; strcpy(outfile,outdir); strcat(outfile,"/"); strcat(outfile,filenam); strcat(outfile,"_"); sprintf(tmp,"%d",x); strcat(outfile,tmp); strcat(outfile,".v"); } if ((outfile_ptr=fopen(outfile, "w")) ==NULL) { printf("Error: Error opening output file /%s/\n\n",outfile); exit(1); } /* write header */ for (x=0; x 0) printf("%s written with Error: %d un-closed ifdefs\n",outfile,ifdef_cnt); /* flag error */ else if (diag_ena==1) printf("%s written\n",outfile); fclose(outfile_ptr); } printf("%d files written\n",file_cnt); if (err_cnt > 0) printf("%d with errors\n",err_cnt); } int get_tokens(char *str) /* get tokens on line. Put in global tokens[][], return count */ { int len, loc, cnt, start, waiting_for_token; /* waiting_for_token is a state variable that indicates if we're collecting characters into a token, or waiting for a valid token to start */ len = strlen(str); waiting_for_token=1; cnt=0; for (loc=0; loc <= len; loc++) { /* process comment conditions first */ if (loc <= len - 1) { if ((long_com==0) && (str[loc] == '/') && (str[loc+1] == '/')) /* the start of a single line comment */ { if (waiting_for_token==0) /* if state = running, append good characters to string and we're done */ { strncpy(tokens[cnt-1],&str[start],loc-start); strncpy(&tokens[cnt-1][loc-start],"\0",1); } return(cnt); } else if ((long_com==0) && (str[loc] == '/') && (str[loc+1] == '*')) /* the start of a long comment */ { long_com = 1; /* set flag, advance past comment identifier */ loc=loc+2; if (waiting_for_token==0) /* if state = running, append good characters to string and change state to waiting */ { waiting_for_token=1; strncpy(tokens[cnt-1],&str[start],loc-start); strncpy(&tokens[cnt-1][loc-start],"\0",1); } } else if ((long_com==1) && (str[loc] == '*') && (str[loc+1] == '/')) /* the end of a long comment */ { long_com = 0; /* clear flag and advance past comment identifier */ loc=loc+2; } } if ((long_com==0) && (loc <=len)) /* if not a comment, process string */ { if ( (loc < len) && (str[loc] != ' ') /* if not a terminating character */ && (str[loc] != ' ') && (str[loc] != '\n') && (str[loc] != '(') ) { if (waiting_for_token==1) /* and state = waiting */ { cnt++; /* incr token count, flip state to running, assign start location */ waiting_for_token=0; start=loc; } } else /* if a terminating character */ { if (waiting_for_token==0) /* and state = running, flip state to waiting, append good characters to token string */ { waiting_for_token=1; strncpy(tokens[cnt-1],&str[start],loc-start); strncpy(&tokens[cnt-1][loc-start],"\0",1); } } } } return(cnt); } int raw_get_tokens(char *str) /* get tokens on line. Put in global rtokens[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(rtokens[cnt-1],&str[start],loc-start); strncpy(&rtokens[cnt-1][loc-start],"\0",1); } } } return(cnt); }