/* * Copyright (c) 2000-2001 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form 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 */ #ident "$Id: main.c,v 1.20 2001/06/30 21:53:42 steve Exp $" const char HELP[] = "Usage: iverilog [-ESv] [-B base] [-C path] [-c cmdfile] [-D macro[=defn]] [-I includedir] [-m module] [-N file] [-o filename] [-p flag=value] [-s topmodule] [-t target] [-T min|typ|max] [-W class] source_file(s) See man page for details."; #define MAXSIZE 4096 #include #include #include #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef __MINGW32__ #include #endif #if HAVE_GETOPT_H #include #endif #if defined(__MINGW32__) && !defined(HAVE_GETOPT_H) extern int getopt(int argc, char*argv[], const char*fmt); extern int optind; extern const char*optarg; #endif #if !defined(WIFEXITED) # define WIFEXITED(rc) ((rc&0x7f) == 0) #endif #if !defined(WEXITSTATUS) # define WEXITSTATUS(rc) (rc>>8) #endif #ifndef IVL_ROOT # define IVL_ROOT "." #endif #ifndef RDYNAMIC # define RDYNAMIC "-rdynamic" #endif # include "globals.h" #ifdef __MINGW32__ const char sep = '\\'; #else const char sep = '/'; #endif const char*base = 0; const char*mtm = 0; const char*opath = "a.out" EXEEXT; const char*npath = 0; const char*targ = "vvp"; const char*start = 0; char warning_flags[16] = ""; char*inc_list = 0; char*def_list = 0; char*mod_list = 0; char*command_filename = 0; char*f_list = 0; int synth_flag = 0; int verbose_flag = 0; int command_file = 0; int inside_c_comment = 0; FILE *fp; char line[MAXSIZE]; char tmp[MAXSIZE]; static char ivl_root[MAXSIZE]; /* * This is the default target type. It looks up the bits that are * needed to run the command from the configuration file (which is * already parsed for us) so we can handle must of the generic cases. */ static int t_default(char*cmd, unsigned ncmd) { int rc; const char*pattern; pattern = lookup_pattern(""); if (pattern == 0) { fprintf(stderr, "No such target: %s\n", targ); return -1; } tmp[0] = ' '; tmp[1] = '|'; tmp[2] = ' '; rc = build_string(tmp+3, sizeof tmp - 3, pattern); cmd = realloc(cmd, ncmd+3+rc+1); #ifdef __MINGW32__ { char *t; for (t = tmp; *t; t++) { if (*t == '/') *t = '\\'; } } #endif strcpy(cmd+ncmd, tmp); if (verbose_flag) printf("translate: %s\n", cmd); rc = system(cmd); if (rc != 0) { if (WIFEXITED(rc)) return WEXITSTATUS(rc); fprintf(stderr, "Command signaled: %s\n", cmd); return -1; } return 0; } /* * This function handles the vvm target. After preprocessing, run the * ivl translator to get C++, then run g++ to make an executable * program out of that. */ static int t_vvm(char*cmd, unsigned ncmd) { int rc; const char*pattern = lookup_pattern(""); if (pattern == 0) { fprintf(stderr, "No such target: %s\n", targ); return -1; } tmp[0] = ' '; tmp[1] = '|'; tmp[2] = ' '; rc = build_string(tmp+3, sizeof tmp - 3, pattern); cmd = realloc(cmd, ncmd+3+rc+1); #ifdef __MINGW32__ { char *t; for (t = tmp; *t; t++) { if (*t == '/') *t = '\\'; } } #endif strcpy(cmd+ncmd, tmp); if (verbose_flag) printf("translate: %s\n", cmd); rc = system(cmd); if (rc != 0) { if (WIFEXITED(rc)) { fprintf(stderr, "errors translating Verilog program.\n"); return WEXITSTATUS(rc); } else { fprintf(stderr, "Command signaled: %s\n", cmd); return -1; } } #if defined(__MINGW32__) /* In the Windows world, the path to headers and libraries for vvm is relative the ivl_root, which is in something like: d:\iverilog\lib\ivl <-- ivl_root d:\iverilog\include <-- vvm headers d:\iverilog\lib <-- vvm libraries So we make up all the ugly references that are the g++ command line to compile a .cc file generated by vvm. */ sprintf(tmp, "%s " RDYNAMIC " -s -fno-exceptions -o %s " "-I%s\\..\\..\\include -L%s\\.. %s.cc -lvvm -lvpip %s", CXX, opath, ivl_root, ivl_root, opath, DLLIB); #else /* In the UNIX universe, life is easy. The configure script has figured everything out and wrote it into the Makefile, which passes it on as the IVL_INC and IVL_LIB defines. */ sprintf(tmp, "%s " RDYNAMIC " -s -fno-exceptions -o %s -I%s " "-L%s %s.cc -lvvm -lvpip %s", CXX, opath, IVL_INC, IVL_LIB, opath, DLLIB); #endif if (verbose_flag) printf("compile: %s\n", tmp); rc = system(tmp); if (rc != 0) { if (WIFEXITED(rc)) { fprintf(stderr, "errors compiling translated program.\n"); return WEXITSTATUS(rc); } else { fprintf(stderr, "Command signaled: %s\n", tmp); return -1; } } sprintf(tmp, "%s.cc", opath); unlink(tmp); return 0; } static int t_xnf(char*cmd, unsigned ncmd) { int rc; sprintf(tmp, " | %s%civl %s -o %s -txnf -Fcprop -Fsynth -Fsyn-rules " "-Fnodangle -Fxnfio", base, sep,warning_flags, opath); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); #ifdef __MINGW32__ { char *t; for (t = tmp; *t; t++) { if (*t == '/') *t = '\\'; } } #endif strcpy(cmd+ncmd, tmp); ncmd += rc; if (f_list) { rc = strlen(f_list); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, f_list); ncmd += rc; } if (mtm) { sprintf(tmp, " -T%s", mtm); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); ncmd += rc; } if (npath) { sprintf(tmp, " -N%s", npath); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); ncmd += rc; } if (start) { sprintf(tmp, " -s%s", start); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); ncmd += rc; } sprintf(tmp, " -- -"); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); strcpy(cmd+ncmd, tmp); ncmd += rc; if (verbose_flag) printf("translate: %s\n", cmd); rc = system(cmd); if (rc != 0) { if (WIFEXITED(rc)) { fprintf(stderr, "errors translating Verilog program.\n"); return WEXITSTATUS(rc); } fprintf(stderr, "Command signaled: %s\n", cmd); return -1; } return 0; } static void process_warning_switch(const char*name) { if (warning_flags[0] == 0) strcpy(warning_flags, "-W"); if (strcmp(name,"all") == 0) { strcat(warning_flags, "i"); } else if (strcmp(name,"implicit") == 0) { if (! strchr(warning_flags+2, 'i')) strcat(warning_flags, "i"); } } int main(int argc, char **argv) { const char*config_path = 0; char*cmd; unsigned ncmd; int e_flag = 0; int opt, idx; char*cp; #ifdef __MINGW32__ { char * s; char basepath[1024]; GetModuleFileName(NULL,basepath,1024); /* Calculate the ivl_root from the path to the command. This is necessary because of the installation process in Windows. Mostly, it is those darn drive letters, but oh well. We know the command path is formed like this: D:\iverilog\bin\iverilog.exe The IVL_ROOT in a Windows installation is the path: D:\iverilog\lib\ivl so we chop the file name and the last directory by turning the last two \ characters to null. Then we append the lib\ivl to finish. */ strncpy(ivl_root, basepath, MAXSIZE); s = strrchr(ivl_root, sep); if (s) *s = 0; s = strrchr(ivl_root, sep); if (s) *s = 0; strcat(ivl_root, "\\lib\\ivl"); base = ivl_root; } #else /* In a UNIX environment, the IVL_ROOT from the Makefile is dependable. It points to the $prefix/lib/ivl directory, where the sub-parts are installed. */ strcpy(ivl_root, IVL_ROOT); base = ivl_root; #endif while ((opt = getopt(argc, argv, "B:C:c:D:Ef:hI:m:N::o:p:Ss:T:t:vW:")) != EOF) { switch (opt) { case 'B': base = optarg; break; case 'C': config_path = optarg; break; case 'c': command_filename = malloc(strlen(optarg)+1); strcat(command_filename, optarg); break; case 'D': if (def_list == 0) { def_list = malloc(strlen(" -D")+strlen(optarg)+1); strcpy(def_list, " -D"); strcat(def_list, optarg); } else { def_list = realloc(def_list, strlen(def_list) + strlen(" -D") + strlen(optarg) + 1); strcat(def_list, " -D"); strcat(def_list, optarg); } break; case 'E': e_flag = 1; break; case 'f': fprintf(stderr, "warning: The -f flag is moved to -p\n"); case 'p': if (f_list == 0) { f_list = malloc(strlen(" -p")+strlen(optarg)+1); strcpy(f_list, " -p"); strcat(f_list, optarg); } else { f_list = realloc(f_list, strlen(f_list) + strlen(" -p") + strlen(optarg) + 1); strcat(f_list, " -p"); strcat(f_list, optarg); } break; case 'h': fprintf(stderr, "%s\n", HELP); return 1; case 'I': if (inc_list == 0) { inc_list = malloc(strlen(" -I")+strlen(optarg)+1); strcpy(inc_list, " -I"); strcat(inc_list, optarg); } else { inc_list = realloc(inc_list, strlen(inc_list) + strlen(" -I") + strlen(optarg) + 1); strcat(inc_list, " -I"); strcat(inc_list, optarg); } break; case 'm': if (mod_list == 0) { mod_list = malloc(strlen(" -m")+strlen(optarg)+1); strcpy(mod_list, " -m"); strcat(mod_list, optarg); } else { mod_list = realloc(mod_list, strlen(mod_list) + strlen(" -m") + strlen(optarg) + 1); strcat(mod_list, " -m"); strcat(mod_list, optarg); } break; case 'N': npath = optarg; break; case 'o': opath = optarg; break; case 'S': synth_flag = 1; break; case 's': start = optarg; break; case 'T': if (strcmp(optarg,"min") == 0) { mtm = "min"; } else if (strcmp(optarg,"typ") == 0) { mtm = "typ"; } else if (strcmp(optarg,"max") == 0) { mtm = "max"; } else { fprintf(stderr, "%s: invalid -T%s argument\n", argv[0], optarg); return 1; } break; case 't': targ = optarg; break; case 'v': verbose_flag = 1; break; case 'W': process_warning_switch(optarg); break; case '?': default: return 1; } } if ((optind == argc) && !command_filename) { fprintf(stderr, "%s: No input files.\n", argv[0]); fprintf(stderr, "%s\n", HELP); return 1; } /* Load the iverilog.conf file to get our substitution strings. */ { char path[1024]; FILE*fd; if (config_path) { strcpy(path, config_path); } else { sprintf(path, "%s%civerilog.conf", base,sep); } fd = fopen(path, "r"); if (fd == 0) { fprintf(stderr, "Config file \"%s\" not found\n",path); return 1; } reset_lexor(fd); yyparse(); } /* Start building the preprocess command line. */ sprintf(tmp, "%s%civlpp %s%s", base,sep, verbose_flag?" -v":"", e_flag?"":" -L"); ncmd = strlen(tmp); cmd = malloc(ncmd + 1); strcpy(cmd, tmp); if (inc_list) { cmd = realloc(cmd, ncmd + strlen(inc_list) + 1); strcat(cmd, inc_list); ncmd += strlen(inc_list); } if (def_list) { cmd = realloc(cmd, ncmd + strlen(def_list) + 1); strcat(cmd, def_list); ncmd += strlen(def_list); } /* If user supplied a command file, retain its contents -- this process supersedes command line source files. */ if (command_filename != 0) { if (( fp = fopen(command_filename, "r")) == NULL ) { fprintf(stderr, "%s: Can't open %s\n", argv[0], command_filename); return 1; } else { /* Process file and skip over commented-out lines. Skips over c-like comment as well as '//' or '#' lines. */ sprintf(tmp, ""); while (fgets(line, MAXSIZE, fp) != NULL) { if ( strstr(line, "*/") != NULL ) { inside_c_comment = 0; continue; } if (inside_c_comment || (strstr(line, "/*") != NULL)) { inside_c_comment = 1; continue; } if ( (line[0] != '/' || line[1] != '/') && line[0] != '#' ) { strcat (tmp, " "); strncat (tmp, line, (strlen(line)-1)); } } fclose(fp); } cmd = realloc(cmd, ncmd+strlen(tmp)+1); strcpy(cmd+ncmd, tmp); ncmd += strlen(tmp); } else { /* Add all verilog source files to the preprocess command line. */ for (idx = optind ; idx < argc ; idx += 1) { sprintf(tmp, " %s", argv[idx]); cmd = realloc(cmd, ncmd+strlen(tmp)+1); strcpy(cmd+ncmd, tmp); ncmd += strlen(tmp); } } /* If the -E flag was given on the command line, then all we do is run the preprocessor and put the output where the user wants it. */ if (e_flag) { int rc; if (strcmp(opath,"-") != 0) { sprintf(tmp, " > %s", opath); cmd = realloc(cmd, ncmd+strlen(tmp)+1); strcpy(cmd+ncmd, tmp); ncmd += strlen(tmp); } if (verbose_flag) printf("preprocess: %s\n", cmd); rc = system(cmd); if (rc != 0) { if (WIFEXITED(rc)) { fprintf(stderr, "errors preprocessing Verilog program.\n"); return WEXITSTATUS(rc); } fprintf(stderr, "Command signaled: %s\n", cmd); return -1; } return 0; } if (strcmp(targ,"vvm") == 0) return t_vvm(cmd, ncmd); else if (strcmp(targ,"xnf") == 0) return t_xnf(cmd, ncmd); else { return t_default(cmd, ncmd); } return 0; } /* * $Log: main.c,v $ * Revision 1.20 2001/06/30 21:53:42 steve * Make the vvp target the default. * * Revision 1.19 2001/06/30 04:23:02 steve * Get include and lib paths right for mingw and vvm. * * Revision 1.18 2001/06/30 00:59:24 steve * Redo the ivl_root calculator for mingw. * * Revision 1.17 2001/06/27 02:22:26 steve * Get include and lib paths from Makefile. * * Revision 1.16 2001/06/20 02:25:40 steve * Edit ivl_install_dir only on mingw * * Revision 1.15 2001/06/15 05:14:21 steve * Fix library path calculation on non Windows systems * to include the install directories. (Brendan Simon) * * Revision 1.14 2001/06/12 03:53:10 steve * Change the VPI call process so that loaded .vpi modules * use a function table instead of implicit binding. * * Revision 1.13 2001/05/20 18:22:02 steve * Fix WIFEXITED macro. * * Revision 1.12 2001/05/20 18:06:57 steve * local declares if the header is missing. * * Revision 1.11 2001/05/20 15:09:40 steve * Mingw32 support (Venkat Iyer) * * Revision 1.10 2001/05/17 03:14:26 steve * Update help message. * * Revision 1.9 2001/04/26 16:04:39 steve * Handle missing or uninstalled .conf files. * * Revision 1.8 2001/02/01 17:12:22 steve * Forgot to actually allow the -p flag. * * Revision 1.7 2001/01/20 19:02:05 steve * Switch hte -f flag to the -p flag. */