// $Id$ //************************************************************************* // DESCRIPTION: Verilator: Options parsing // // Code available from: http://www.veripool.com/verilator // // AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli // //************************************************************************* // // Copyright 2003-2006 by Wilson Snyder. This program is free software; you can // redistribute it and/or modify it under the terms of either the GNU // General Public License or the Perl Artistic License. // // Verilator 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. // //************************************************************************* #include "config.h" #include #include #include #include #include #include #include #include "V3Global.h" #include "V3Options.h" #include "V3Error.h" #include "V3File.h" #include "V3PreShell.h" #include "config_rev.h" //###################################################################### // V3 Internal state struct V3OptionsImp { // TYPES typedef std::map > DirMap; // Directory listing // STATE list m_allArgs; // List of every argument encountered list m_incDirs; // Include directories (ordered) set m_incDirSet; // Include directories (for removing duplicates) set m_libExts; // Library extensions DirMap m_dirMap; // Directory listing // ACCESSOR METHODS void addIncDir(const string& incdir) { if (m_incDirSet.find(incdir) == m_incDirSet.end()) { m_incDirSet.insert(incdir); m_incDirs.push_back(incdir); } } void addLibExt(const string& libext) { if (m_libExts.find(libext) == m_libExts.end()) { m_libExts.insert(libext); } } V3OptionsImp() {} }; void V3Options::addIncDir(const string& incdir) { m_impp->addIncDir(incdir); } void V3Options::addLibExt(const string& libext) { m_impp->addLibExt(libext); } void V3Options::addDefine(const string& defline) { // Split +define+foo=value into the appropriate parts and parse string def = defline; string value; string::size_type pos; if ( ((pos=defline.find("+")) != string::npos) || ((pos=defline.find("=")) != string::npos)) { value = def.substr(pos+1); def.erase(pos); } V3PreShell::define(def,value); } void V3Options::addCppFile(const string& filename) { if (m_cppFiles.find(filename) == m_cppFiles.end()) { m_cppFiles.insert(filename); } } void V3Options::addLibraryFile(const string& filename) { if (m_libraryFiles.find(filename) == m_libraryFiles.end()) { m_libraryFiles.insert(filename); } } void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); } string V3Options::allArgsString() { string out; for (list::iterator it=m_impp->m_allArgs.begin(); it!=m_impp->m_allArgs.end(); ++it) { if (out != "") out += " "; out += *it; } return out; } //###################################################################### // File searching string V3Options::filenameFromDirBase (const string& dir, const string& basename) { // Don't return ./{filename} because if filename was absolute, that makes it relative if (dir == ".") return basename; else return dir+"/"+basename; } string V3Options::filenameDir (const string& filename) { string::size_type pos; if ((pos = filename.rfind("/")) != string::npos) { return filename.substr(0,pos); } else { return "."; } } string V3Options::filenameNonDir (const string& filename) { string::size_type pos; if ((pos = filename.rfind("/")) != string::npos) { return filename.substr(pos+1); } else { return filename; } } string V3Options::filenameNonExt (const string& filename) { string base = filenameNonDir(filename); string::size_type pos; if ((pos = base.find(".")) != string::npos) { base.erase(pos); } return base; } bool V3Options::fileStatNormal(const string& filename) { struct stat m_stat; // Stat information int err = stat(filename.c_str(), &m_stat); if (err!=0) return false; if (S_ISDIR(m_stat.st_mode)) return false; return true; } string V3Options::fileExists (const string& filename) { // Surprisingly, for VCS and other simulators, this process // is quite slow; presumably because of re-reading each directory // many times. So we read a whole dir at once and cache it string dir = filenameDir(filename); string basename = filenameNonDir(filename); V3OptionsImp::DirMap::iterator diriter = m_impp->m_dirMap.find(dir); if (diriter == m_impp->m_dirMap.end()) { // Read the listing m_impp->m_dirMap.insert(make_pair(dir, set() )); diriter = m_impp->m_dirMap.find(dir); set* setp = &(diriter->second); if (DIR* dirp = opendir(dir.c_str())) { while (struct dirent* direntp = readdir(dirp)) { setp->insert(direntp->d_name); } closedir(dirp); } } // Find it set* filesetp = &(diriter->second); set::iterator fileiter = filesetp->find(basename); if (fileiter == filesetp->end()) { return ""; // Not found } // Check if it is a directory, ignore if so string filenameOut = filenameFromDirBase (dir, basename); if (!fileStatNormal(filenameOut)) return ""; // Directory return filenameOut; } string V3Options::filePath (FileLine* fl, const string& modname, const string& errmsg) { // Find a filename to read the specified module name, // using the incdir and libext's. // Return "" if not found. for (list::iterator dirIter=m_impp->m_incDirs.begin(); dirIter!=m_impp->m_incDirs.end(); ++dirIter) { for (set::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) { string fn = filenameFromDirBase(*dirIter,modname+*extIter); string exists = fileExists(fn); if (exists!="") { // Strip ./, it just looks ugly if (exists.substr(0,2)=="./") exists.erase(0,2); return exists; } } } // Warn and return not found fl->v3error(errmsg+modname); static bool shown_notfound_msg = false; if (!shown_notfound_msg) { shown_notfound_msg = true; if (m_impp->m_incDirs.empty()) { fl->v3error("This may be because there's no search path specified with -I."<v3error("Looked in:"<::iterator dirIter=m_impp->m_incDirs.begin(); dirIter!=m_impp->m_incDirs.end(); ++dirIter) { for (set::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) { string fn = filenameFromDirBase(*dirIter,modname+*extIter); fl->v3error(" "<v3fatal ("Invalid Option: "<v3fatal("Unknown warning disabled: "<v3fatal("Unknown warning specified: "<v3fatal("Unknown setting for -x-assign: "<v3fatal ("Invalid Option: "<v3fatal ("Top filename specified twice: "< ifp (V3File::new_ifstream(filename)); if (ifp->fail()) { fl->v3error("Cannot open -f command file: "+filename); return; } string whole_file; string::size_type pos; while (!ifp->eof()) { string line; getline(*ifp, line); // Strip simple comments if ((pos=line.find("//")) != string::npos) { line.erase(pos); } whole_file += line + " "; } whole_file += "\n"; // So string match below is simplified fl = new FileLine(filename, 0); // Split into argument list and process // Note we don't respect quotes. It seems most simulators dont. // Woez those that expect it; we'll at least complain. if ((pos=whole_file.find("\"")) != string::npos) { fl->v3error("Double quotes in -f files cause unspecified behavior."); } // Strip off arguments and parse into words vector args; string::size_type startpos = 0; while (startpos < whole_file.length()) { while (isspace(whole_file[startpos])) startpos++; string::size_type endpos = startpos; while (endpos < whole_file.length() && !isspace(whole_file[endpos])) endpos++; if (startpos != endpos) { string arg (whole_file, startpos, endpos-startpos); args.reserve(args.size()+1); args.push_back(arg); } startpos = endpos; } // Convert to argv style arg list and parse them char* argv [args.size()+1]; for (unsigned i=0; i 0; m_oAcycSimp = flag; m_oCase = flag; m_oCombine = flag; m_oConst = flag; m_oExpand = flag; m_oGate = flag; m_oInline = flag; m_oLife = flag; m_oLifePost = flag; m_oLocalize = flag; m_oReorder = flag; m_oSplit = flag; m_oSubst = flag; m_oSubstConst = flag; m_oTable = flag; // And set specific optimization levels if (level >= 3) { m_inlineMult = -1; // Maximum inlining } }